Se cargan las librerías que se utilizarán a lo largo del trabajo.

library(tidyverse)
library(OneR)
library(broom)
library(modelr)

1. Regresión Lineal Múltiple

1.1. Creación del modelo

Se carga un dataset de propiedades.

properties <- read_rds('ar_properties.rds')

Éste cuenta con 8 variables:

  • id
  • l3 (barrio en el que se ubica la propiedad)
  • rooms (cantidad de habitaciones)
  • bathrooms (cantidad de baños)
  • surface_total (superficie total)
  • surface_covered (superficie cubierta)
  • price (precio)
  • property_type (tipo de propiedad)

Exceptuando la variable id que contiene valores únicos con el fin de identificar las propiedades, se crea un modelo de Regresión Lineal Múltiple para predecir el precio de cada propiedad a partir de las covariables restantes.

modelo <- lm(price ~ l3 + rooms + bathrooms + surface_total + surface_covered + property_type,
            data=properties)
summary(modelo)

Call:
lm(formula = price ~ l3 + rooms + bathrooms + surface_total + 
    surface_covered + property_type, data = properties)

Residuals:
    Min      1Q  Median      3Q     Max 
-400904  -33817   -3307   24660  560915 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)               -109406.61    4788.67 -22.847  < 2e-16 ***
l3Agronomía                   623.53    8846.14   0.070 0.943807    
l3Almagro                   -4520.04    4295.24  -1.052 0.292650    
l3Balvanera                -24788.27    4551.65  -5.446 5.18e-08 ***
l3Barracas                 -10128.24    5351.06  -1.893 0.058397 .  
l3Barrio Norte              49921.81    4417.82  11.300  < 2e-16 ***
l3Belgrano                  69648.12    4283.55  16.259  < 2e-16 ***
l3Boca                     -47540.60    7076.20  -6.718 1.86e-11 ***
l3Boedo                    -19034.38    5219.54  -3.647 0.000266 ***
l3Caballito                  6220.15    4301.29   1.446 0.148153    
l3Catalinas                -76321.95   33563.74  -2.274 0.022974 *  
l3Centro / Microcentro     -29046.49    6781.80  -4.283 1.85e-05 ***
l3Chacarita                 11903.39    5299.02   2.246 0.024687 *  
l3Coghlan                   40820.55    5462.90   7.472 8.02e-14 ***
l3Colegiales                34073.02    4816.54   7.074 1.52e-12 ***
l3Congreso                 -32314.97    5494.75  -5.881 4.10e-09 ***
l3Constitución             -47292.98    6321.63  -7.481 7.50e-14 ***
l3Flores                   -22510.27    4536.15  -4.962 6.99e-07 ***
l3Floresta                 -28315.65    5069.38  -5.586 2.34e-08 ***
l3Las Cañitas               90455.90    5883.38  15.375  < 2e-16 ***
l3Liniers                  -20080.34    5366.27  -3.742 0.000183 ***
l3Mataderos                -33863.43    5424.79  -6.242 4.35e-10 ***
l3Monserrat                -32431.49    5228.46  -6.203 5.59e-10 ***
l3Monte Castro              -8770.72    5949.63  -1.474 0.140445    
l3Nuñez                     56958.42    4559.69  12.492  < 2e-16 ***
l3Once                     -30757.83    5456.51  -5.637 1.74e-08 ***
l3Palermo                   66169.58    4221.50  15.674  < 2e-16 ***
l3Parque Avellaneda        -34398.95    7598.09  -4.527 5.99e-06 ***
l3Parque Centenario        -12288.30    5016.45  -2.450 0.014305 *  
l3Parque Chacabuco         -22537.83    5314.36  -4.241 2.23e-05 ***
l3Parque Chas                5195.26    7542.97   0.689 0.490981    
l3Parque Patricios         -36808.02    5973.29  -6.162 7.24e-10 ***
l3Paternal                 -13314.50    5189.69  -2.566 0.010304 *  
l3Pompeya                  -79977.17    8035.74  -9.953  < 2e-16 ***
l3Puerto Madero            259015.83    5095.12  50.836  < 2e-16 ***
l3Recoleta                  64088.22    4360.34  14.698  < 2e-16 ***
l3Retiro                    26067.40    5281.27   4.936 8.01e-07 ***
l3Saavedra                  19492.00    4914.18   3.966 7.31e-05 ***
l3San Cristobal            -23739.75    4955.13  -4.791 1.67e-06 ***
l3San Nicolás              -26247.55    5168.96  -5.078 3.83e-07 ***
l3San Telmo                 -5653.85    4877.12  -1.159 0.246356    
l3Tribunales               -34608.17    8924.63  -3.878 0.000106 ***
l3Velez Sarsfield          -25943.69    8303.75  -3.124 0.001783 ** 
l3Versalles                -22232.13    6758.40  -3.290 0.001004 ** 
l3Villa Crespo               1595.26    4317.54   0.369 0.711770    
l3Villa del Parque          -3290.17    4866.59  -0.676 0.498997    
l3Villa Devoto              13301.39    4807.08   2.767 0.005659 ** 
l3Villa General Mitre      -19170.08    6802.25  -2.818 0.004831 ** 
l3Villa Lugano             -83039.18    6533.35 -12.710  < 2e-16 ***
l3Villa Luro                -7579.11    5404.78  -1.402 0.160833    
l3Villa Ortuzar             18667.61    6829.18   2.734 0.006269 ** 
l3Villa Pueyrredón          10516.80    5349.56   1.966 0.049314 *  
l3Villa Real                -8823.37    8745.56  -1.009 0.313030    
l3Villa Riachuelo          -32775.66   17171.10  -1.909 0.056298 .  
l3Villa Santa Rita          -5767.71    6383.86  -0.903 0.366274    
l3Villa Soldati           -136489.91   18944.29  -7.205 5.90e-13 ***
l3Villa Urquiza             30648.43    4418.91   6.936 4.09e-12 ***
rooms                       -3961.27     444.58  -8.910  < 2e-16 ***
bathrooms                   34040.98     644.28  52.836  < 2e-16 ***
surface_total                 919.08      23.52  39.069  < 2e-16 ***
surface_covered              1457.18      28.73  50.715  < 2e-16 ***
property_typeDepartamento   92653.32    2191.23  42.284  < 2e-16 ***
property_typePH             46779.37    2274.94  20.563  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 66580 on 45841 degrees of freedom
Multiple R-squared:  0.7764,    Adjusted R-squared:  0.7761 
F-statistic:  2568 on 62 and 45841 DF,  p-value: < 2.2e-16

1.2. Análisis del modelo

1.2.1. Interpretación de los coeficientes estimados

Según este modelo, -109406.61 es la ordenada al origen. Esto significa que, si encontrásemos una propiedad en la que todas las variables tuviesen un valor igual a 0, el modelo predeciría que dicha propiedad tendría un precio de -109406.61. Esto claramente no tiene sentido. No solo porque no tendríamos una propiedad con precio negativo sino porque, además, difícilemtne tendríamos una propiedad cuya superficie total fuese 0.

El resto de los coeficientes indica cómo varía, según la predicción de nuestro modelo, dicho precio inicial al aumentar en una unidad cada variable en cuestión y dejando el resto de las variables con un valor constante.

En el caso de las variables l3 y property_type, nos encontramos ante variables dummies, variales categóricas que indican que la propiedad tiene cierta cualidad o no. l3 se refiere al barrio donde se ubica la propiedad y property_type, al tipo de propiedad en que consiste (PH o departamento).

Dado que una propiedad no puede encontrarse en más de un lugar ni ser de más de un tipo, solo uno de los coeficientes para la variable l3 y uno para la variable property_type tendrá influencia en la predicción que realice nuestro modelo para cada propiedad. Por ejemplo, en el caso de un departamento de Caballito, nuestro modeo utilizará el coeficiente 6220.15 para la variable l3 y el coefciente 92653.32 para property_type. El resto de los coeficientes relacionados a l3 y a property_type no se utilizarán dado que la variable reflejará un valor igual a 0 en dichos casos, dejándolos anulados.

Es pertinente resaltar que, en los casos de variables dummies, nos encontraremos con k-1 coeficientes, donde k es la cantidad de clases que puede tomar la variable considerada. Esto se debe a que, de otra forma, el modelo estaría sobreparametrizado y las variables presentarían dependencia lineal, lo que impediría que el sistma de ecuaciones generado tuviese una única solución.

En particular, se observa que los barrios de Puerto Madero, Las Cañitas, Belgrano, Palermos, Recoleta, Núñez, Barrio Norte, Coghlan, Colegiales, Villa Urquiza, Retiro, Saavedra, Villa Ortúzar, Villa Devoto, Chacarita, Pueyrredń, Caballito, Parque Chas, Villa Crespo y Agronomía influirán positivamente en el precio estimado por el modelo puesto que sus coeficientes son positivos. El resto de los barrios, en cambio, presenta un coeficiente negativo por lo que el valor estimado presentará un decremento si la propiedad se encuentra ubicada en uno de ellos.

Las variables rooms, bathrooms, surface_total y surface_covered, por otro lado, son numéricas, y pueden tomar cualquier valor. La multiplicación de sus valores por sus respectivos coeficientes también tendrá un impacto en la predicción de nuestro modelo, ya sea generando un aumento en el precio estimado, en el caso de los baños, la superficie total y la superficie cubierta, o ya sea provocando una disminución, en el caso de los dormitorios.

1.2.2. Significatividad de las variables dummies

Resulta interesante destacar que, a excepeción de los barrios de Agronomía, Almagro, Barracas, Caballito, Monte Castro, Parque Chas, San Telmo, Villa Crespo, Villa del Parque, Villa Luro, Villa Real y Santa Rita, los valores de la variable dummy l3 presentan un p-valor menor a 0.05, lo que significa que la variable es útil para explicar y cuando en el modelo se encuentran presentes las demás variables, pero no en otro caso. Lo mismo sucede con la variable dummy property_type.

Los coeficientes calculados para Agronomía y Villa Crespo, por su parte, muestran un valor mayor a 0.7, indicando que en estos casos la variable resulta significativa incluso en ausencia de las demás variables.

1.2.3. Evaluación del modelo

Respecto de la evaluación del modelo, podemos ver que éste presenta un R² de 0.77, lo que indica que nuestro modelo es capaz de explicar el 77% de la variabilidad de la variable depediente Y a partir de las variables independientes proporcionadas.

1.3. Predicciones

A continuación, se proponen dos nuevos casos y se utiliza el modelo ajustado para predecir sus precios.

El primer caso consiste en un departamento de 120 metros cuadrados cubiertos, ubicado en el barrio de Abasto, con 3 dormitorios y 2 baños. El segundo se trata de un PH en Balvanera, con 80 metros cuadrados cubiertos, 20 metros cuadrados no cubiertos, 2 dormitorios y 3 baños.

Se genera un nuevo dataset con estos casos y se utiliza la función predict para predecir sus precios.

nuevos_casos <- data.frame(
  l3 = c('Abasto', 'Balvanera'),
  rooms = c(3, 2),
  bathrooms = c(2, 3),
  surface_total = c(120, 100),
  surface_covered = c(120, 80),
  property_type = c('Departamento', 'PH') 
)
nuevos_casos %>% 
  mutate(predict = predict(modelo, newdata = .)) %>% 
  select(l3, predict, everything())

El modelo predice que la propiedad en el barrio de Abasto vale 324596.4, mientras que la del barrio de Balvanera cuesta 215267.6, por lo que resulta preferible tener la primera para vender.

1.4. Creación de un nuevo modelo

Se crea un nuevo modelo sin la variable l3.

modelo_sin_l3 <- lm(price ~ rooms + bathrooms + surface_total + surface_covered + property_type,
                   data=properties)
summary(modelo_sin_l3)

Call:
lm(formula = price ~ rooms + bathrooms + surface_total + surface_covered + 
    property_type, data = properties)

Residuals:
    Min      1Q  Median      3Q     Max 
-518799  -36177   -9643   25740  724251 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)               -131096.86    2750.50  -47.66   <2e-16 ***
rooms                      -13348.53     519.02  -25.72   <2e-16 ***
bathrooms                   42664.68     756.37   56.41   <2e-16 ***
surface_total                 877.03      27.59   31.79   <2e-16 ***
surface_covered              1783.80      33.53   53.21   <2e-16 ***
property_typeDepartamento  135177.47    2513.93   53.77   <2e-16 ***
property_typePH             68598.52    2677.46   25.62   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 79210 on 45897 degrees of freedom
Multiple R-squared:  0.6832,    Adjusted R-squared:  0.6831 
F-statistic: 1.649e+04 on 6 and 45897 DF,  p-value: < 2.2e-16

Se observa que la mediana de los residuos de este modelo se encuentra más alejada del 0 que en el modelo anterior (-3307), lo que nos indica que su distribución presenta mayor asimetría. Lo deseable sería que este valor se encontrase próximo al 0 para poder verificar una distribución normal de los residuos, i.e. de la diferencia entre los valors Ŷ predichos y los valores de Y observados.

Por otro lado, si bien los coeficientes estimados han variado su valor, no han cambiado su signo, por lo que su incidencia en la estimación de precios se mantiene: aquellas variables que incrementaban el valor de los precios continuan haciéndolo y lo mismo ocurre con las que disminuían este valor.

1.5. Comparación de modelos

El segundo modelo generado posee una menor capacidad explicativa de la variable Y. Su R² nos indica que las variables independientes solo pueden explicar el 68% de la variable dependiente. Este decremento resulta esperable en tanto este modelo utiliza menos variables.

Los modelos de Regresión Lineal aumentan su R² conforme aumentan la cantidad de variables empleadas en la predicción, sin importar si éstas están o no correlacionadas con la variable a predecir.

Sin embargo, si observamos el R² ajustado, vemos que también aquí el primer modelo supera al segundo (77% contra 68%). Esto resulta relevante puesto que el R² ajustado indica la capacidad de explicación de un modelo considerando las variables independientes que sí se encuentran relacionadas con la dependiente. Esta medida disminuye al añadir variables no relacionadas y aumneta solo si las agregadas son efecitvamente explicativas. Debido a esto, el R² ajustado posibilita la comparación de modelos con distinta cantidad de variables.

Así, el modelo que mejor explica la variable precios es el modelo que incluye la variable l3, dado que su R² ajustado es mayor que el último modelo realizado.

2. Creación de variables

2.1. Variable barrios

Con el propósito de crear una nueva variable barrios de tipo categórica que distinga entre barrios con precio alto, medio y bajo, se grafica un scatter plot de precios que nos permita visualizar si existen puntos críticos capaces de funcionar como puntos de corte entre las categorías definidas.

plot(sort(properties$price, decreasing = FALSE),
     main  = 'Precios ordenados en forma creciente',
     ylab = 'Precios',
     xlab = 'Índice',
     col = 'cyan4')

Dado que no se observa la presencia de tales puntos, se opta por generar 3 bins de manera automática utilizando el método de “clusters” de la función bin del paquete OneR. Para ello, primero se agrupan los precios por barrios y se calcula su media, este será el input que tomará la función.

precios <- properties %>% 
  select(l3, price) %>% 
  group_by(l3) %>% 
  summarise(media_precio = mean(price)) %>% 
  arrange(media_precio)
precios
precios$clusters <- bin(precios$media_precio,
                        nbins=3, 
                        labels=c("bajo", "medio", "alto"), 
                        method="clusters")
precios

Dado que deseamos tener clases balanceadas, revisamos cuántos barrios han quedado agrupados en cada clase.

precios %>% 
  count(clusters)

Vemos que no se han obtenido clases balanceadas. La categoría bajo cuenta con muchos más barrios que las otras dos. Y la categría alto agrupa un único barrio.

Volvemos a generar los bins pero ahora utilizamos el método de content, que arma bins con igual cantidad de elementos.

precios$bins <- bin(precios$media_precio, 
                    nbins=3, 
                    labels=c("bajo", "medio", "alto"), 
                    method="content")
precios

Chequeamos para confirmar:

precios %>% 
  count(bins)

Agregamos la nueva información al data frame de datos que ya teníamos. Para ello, utilizamos la función left_join. Además, cambiamos el nombre de la nueva variable bins por barrios.

properties_barrios <- left_join(properties, precios[,c('l3', 'bins')], by='l3')
names(properties_barrios)[names(properties_barrios) == 'bins'] <- 'barrios'
properties_barrios

2.2. Modelo con variable barrios

Se ajusta un nuevo modelo. Esta vez, se utiliza la variable barrios creada en el apartado anterior en lugar de la variable l3.

model_con_barrios <- lm(price ~ rooms + bathrooms + surface_total + surface_covered +
                          property_type + barrios, data=properties_barrios)
summary(model_con_barrios)

Call:
lm(formula = price ~ rooms + bathrooms + surface_total + surface_covered + 
    property_type + barrios, data = properties_barrios)

Residuals:
    Min      1Q  Median      3Q     Max 
-457728  -36989   -5510   25167  701372 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)               -155886.83    2662.38  -58.55   <2e-16 ***
rooms                       -8868.58     481.81  -18.41   <2e-16 ***
bathrooms                   36265.52     702.19   51.65   <2e-16 ***
surface_total                 804.49      25.49   31.57   <2e-16 ***
surface_covered              1727.13      30.98   55.76   <2e-16 ***
property_typeDepartamento  113911.17    2333.81   48.81   <2e-16 ***
property_typePH             59415.69    2474.16   24.02   <2e-16 ***
barriosmedio                20501.46    1154.63   17.76   <2e-16 ***
barriosalto                 76571.89    1070.82   71.51   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 73130 on 45895 degrees of freedom
Multiple R-squared:   0.73, Adjusted R-squared:  0.7299 
F-statistic: 1.551e+04 on 8 and 45895 DF,  p-value: < 2.2e-16

Es posible notar que la mediana de los residuos de este modelo presenta signo negativo, al igual que el modelo que incluía a la variable l3. Esto nos indica que al menos la mitad de los valores Ŷ predichos por ambos modelos son valores que se encuentran por encima de los valores Y observados. No obstante, la mediana de los residuos de este segundo modelo se encuentra más cerca del 0 que la mediana del modelo con l3, lo que podría indicar que, en rangos generales, los valores Ŷ predichos en este caso y los valores Y reales se encuentran a menor distancia.

En cuanto a los coeficientes calculados, podemo observar que, si bien sus valores han cambiado, no lo ha hecho así su signo. Lo que nos implica que aquellas variables que influían positivamente en la variable a predecir lo siguen haciendo y lo mismo ocurre con la variable rooms, cuya incidencia era negativa.

Por último, notamos que la variabilidad explicada por este modelo es del 73% (valor de R²). Sin embargo, como ya se advirtió previamente, no debemos fiarnos de esta medida para establecer una comparación con el modelo de l3, sino que debemos utilizar su valor ajustado. Dado que el R² ajustado de este modelo resulta menor que el del modelo de l3 (73% contra 77%), podemos afirmar que es este último el que mejor explica la variabilidad de los datos.

De todos modos, cabe hacer la reflexión de qué modelo resulta más útil a la hora de estimar el precio de una propiedad. Si bien el modelo de l3 explica mejor a la variable Y, la cantidad de valores posibles que puede adoptar la variable l3 y sus correspondientes coeficientes (igualmente variados) no permite establecer un patrón claro que dé cuenta de cómo influye esta variable en la predicción. El modelo ajustado con la variable barrios, en cambio, si bien posee un menor poder explicativo, sí nos da una idea de esta relación: en todos los casos en los que la propiedad se encuentre ubicada en un barrio de precio “bajo”, el valor predicho de la misma no se verá incrementado; si, en cambio, el inmueble se encuentra en un barrio de precio “medio”, su valor aumentará 20501,46, y se incrementará en 76571,89 en los casos en los que se ubique en un barrio de precio “alto”.

2.3. Variable surface_patio

Dado que las variable surface_covered y surface_total están correlacionadas, se propone crear una nueva variable llamada surface_patio que refleje la diferencia entre ambas superficies. De este modo:

surface_patio = surface_total - surface_patio

Sin embargo, podría ocurrir que se encontrasen casos de inconsistencia donde la superficie total de una vivienda fuese menor a su superficie cubierta. De encontrarse tales casos, se propone eliminarlos, puesto que se trataría de registros mal ingresados.

Entonces, como primer paso, se chequea la existencia de casos de inconsistencia.

nrow(properties_barrios[properties_barrios$surface_covered > properties_barrios$surface_total,])
[1] 0

No se observan casos en los que la superficie total sea menor que la cubierta. Se procede a generar la nueva variable previamente definida.

properties_barriosYpatio <- properties_barrios %>% 
  mutate(surface_patio = surface_total-surface_covered)
properties_barriosYpatio

2.4. Modelo con la variable surface_patio

Se entrena un nuevo modelo utilizando ahora la variable barrios en lugar de l3 y la variable surface_patio en lugar de surface_total.

modelo_barriosYpatio <- lm(price ~ barrios + rooms + bathrooms + surface_covered + surface_patio+ property_type, data=properties_barriosYpatio)
summary(modelo_barriosYpatio)

Call:
lm(formula = price ~ barrios + rooms + bathrooms + surface_covered + 
    surface_patio + property_type, data = properties_barriosYpatio)

Residuals:
    Min      1Q  Median      3Q     Max 
-457728  -36989   -5510   25167  701372 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)               -155886.83    2662.38  -58.55   <2e-16 ***
barriosmedio                20501.46    1154.63   17.76   <2e-16 ***
barriosalto                 76571.89    1070.82   71.51   <2e-16 ***
rooms                       -8868.58     481.81  -18.41   <2e-16 ***
bathrooms                   36265.52     702.19   51.65   <2e-16 ***
surface_covered              2531.62      16.35  154.81   <2e-16 ***
surface_patio                 804.49      25.49   31.57   <2e-16 ***
property_typeDepartamento  113911.17    2333.81   48.81   <2e-16 ***
property_typePH             59415.69    2474.16   24.02   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 73130 on 45895 degrees of freedom
Multiple R-squared:   0.73, Adjusted R-squared:  0.7299 
F-statistic: 1.551e+04 on 8 and 45895 DF,  p-value: < 2.2e-16

Vemos que la variable surface_patio posee el mismo coeficiente que la variable surface_total del modelo anterior. Esto se debe a que la capacidad explicativa de la variable surface_total ahora está representada por surface_patio. Se comprueba que aquellos casos en los que la superficie total y la supericie cubierta eran iguales nada aportaban al modelo, pues estos caso ahora presentan valor 0 y el coeficiente asignado se ha mantenido.

Por otro lado, la variable surface_covered presenta un coeficiente mayor: ha ganado poder explicativo en el aumento de precios como consecuencia de haber quitado del modelo la variable correlacionada surface_total.

3. Evaluación de modelo

A continuación, analizaremos los residuos del modelo generado con las variables barrios y surface_patio.

En primer lugar, generamos un data frame que contiene, además de las variables independientes y la variale dependiente, los residuos del modelo ajustado.

resid_barriosYpatio <- properties_barriosYpatio %>% 
  add_residuals(modelo_barriosYpatio)
resid_barriosYpatio

Calculamos la media de estos residuos.

mean(resid_barriosYpatio$resid)
[1] 5.589609e-09

Confirmamos que la media es un valor muy cercano a 0. Esto era esperable dado que justamente es uno de los supuestos que asumidos a la hora de generar el modelo y ajustar la recta por mínimos cuadrados.

A continuación, se realizan distintos gráficos de los reisudos que nos permitirán analizarlos mejor.

plot(modelo_barriosYpatio)

En el primer gráfico, podemos observar los residuos versus los valores predichos por el modelo. Esta visualización nos muestra que, conforme aumentan los valores predichos, también lo hace la varianza de sus residuos, por lo cual el supuesto de homogeneidad de la varianza no se satisface. Esto indica que los residuos presentan cierta estructura que no se explica por el modelo lineal ajustado.

El segundo gráfico muestra que los residuos estandarizados no se ajustan a la distribución normal. Sería deseable que esto ocurriese, puesto que, de ese modo, los test e intervalos de confianza construídos serían más apropiados.

Finalmente, el último gráfico, permite observar los residuos en relación a su leverage, es decir, en relación a su grado de influencia en el modelo. Dado que el leverage de cada observación puede tomar valores entre 0 y 1 y aquí todos los varlores se encuentran por debajo de 0.05, podríamos afirmar que ninguna observación aislada está forzando a la recta a desviarse del curso establecido por un conjunto de observaciones mayor.

4. Modelo de elasticidad constante

Se implementa un modelo de elasticidad constante definido del siguiente modo:

\[ log(price) = \beta_0 + \beta_1log(rooms) + \beta_2log(bathrooms) + \beta_3log(surface\_covered) + \beta_4property\_type + \beta_5barrio + \beta_6surface\_patio \]

model_log = lm(log(price) ~ log(rooms) + log(bathrooms) + log(surface_covered) + property_type +
                 barrios + surface_patio, data=properties_barriosYpatio)
summary(model_log)

Call:
lm(formula = log(price) ~ log(rooms) + log(bathrooms) + log(surface_covered) + 
    property_type + barrios + surface_patio, data = properties_barriosYpatio)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.35966 -0.15330 -0.00635  0.14266  1.39173 

Coefficients:
                            Estimate Std. Error t value Pr(>|t|)    
(Intercept)                8.154e+00  1.943e-02  419.76   <2e-16 ***
log(rooms)                -4.850e-02  3.948e-03  -12.28   <2e-16 ***
log(bathrooms)             1.809e-01  3.986e-03   45.39   <2e-16 ***
log(surface_covered)       8.229e-01  4.638e-03  177.41   <2e-16 ***
property_typeDepartamento  2.897e-01  7.494e-03   38.66   <2e-16 ***
property_typePH            9.848e-02  7.979e-03   12.34   <2e-16 ***
barriosmedio               1.402e-01  3.761e-03   37.27   <2e-16 ***
barriosalto                3.851e-01  3.487e-03  110.43   <2e-16 ***
surface_patio              3.478e-03  8.322e-05   41.79   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.2382 on 45895 degrees of freedom
Multiple R-squared:  0.8045,    Adjusted R-squared:  0.8045 
F-statistic: 2.361e+04 on 8 and 45895 DF,  p-value: < 2.2e-16

En comparación con el anterior, vemos que este modelo posee mayor capacidad explicativa. No solo su R² es mayor, sino que también lo es su R² ajustado, medida que nos permite realizar esta comparación. Mientras que el modelo anterior presentaba un R² ajustado de 73%, este es capaz de explicar el 80% de la variable dependiente.

Además, la mediana de sus residuos se aproxima en gran medida al 0, lo que nos indica que los residuos presentan una distribución normal, una característica deseable desde los supuestos del modelo de regresipon lineal.

Ahora bien, en cuanto a los parámetros, cabe hacer una aclaración: éstos no deben recibir la misma interpretación que en los modelos previos.

El hecho de aplicar el logaritmo a nuestra variable independiente nos permite plasmar el efecto porcentual constante que las variables explicativas tienen sobre aquella. De este modo, la variable porperty_type, por ejemplo, incrementa el precio un 0.2897% al tomar el valor Departamento.

A su vez, el que a algunas variables numéricas, como rooms, bathrooms y surface_covered también se les aplique el logaritmo posibilita considerar su propio incremento en términos porcentuales. Así, en el caso de la variable surface_covered, por ejemplo, su coeficiente no indica cuánto aumenta el precio cuando la superficie cubierta se incrementa en una unidad y el resto de las variables se mantienen constantes, sino que estima cuánto aumenta el precio cuando la superficie cubierta se incrementa en un 1%. Dado que, como ya dijimos, el efecto de las variables también debe ser entendido en términos porcentuales, al aumentar el 1% la superficie cubierta, el valor de la propiedad se incrementará un 0.8229%. De este coeficiciente se dice que refleja la elasticidad estimada del precio en relación a la superficie cubierta.

Esa modificación en en la fórmula nos permite ajustar un modelo más adecuado para la realidad, puesto que es de esperar que el aumento en el precio de una propiedad no sea uniforme respecto de la superficie cubierta, no esperamos que por cada metro² añadido la propiedad aumente la misma cantidad de dinero. Por el contrario, parecería sensato esperar que los inumuebles muy pequeños, al aumentar su superficie cubierta, tuviesen un incremento de precio menor en relación a aquellas propiedades muy grandes. El logaritmo de la variable a explicar nos permite realizar una estimación semjante.

5. Modelos por tipo de propiedad

En este apartado se agrupa el data frame por tipo de propiedad y se genera una nueva tabla con dos columnas: en la primera se indica el tipo de propiedad y en la segunda se anida el data frame correspondiente.

propTypes <- properties_barriosYpatio %>% 
  group_by(property_type) %>% 
  nest()
propTypes

Para cada tipo de propiedad, se genera un modelo igual al ajustado previamente, con las variables barrios y surface_patio, y se lo almacena en la columna model.

patio_model <- function(df) {
  lm(price ~ barrios + rooms + bathrooms + surface_covered + surface_patio, data=df)
}
propTypes <- propTypes %>% 
  mutate(model = map(data, patio_model))
propTypes

Con el fin de comparar los distintos modelos, se utiliza la función get_coefficients aquí definida y las funciones glance y augment, del paquete broom. La primera muestra los coeficientes estimados de cada modelo, la segunda permite visuaizar información relativa al R², R² ajustado y el desvío estándar de los residuos (sigma), y la última nos brinda información más detallada de estos últimos, lo que nos permitirá observar su distribución.

summary(propTypes$model[[1]])   # datos del modelo Casa

Call:
lm(formula = price ~ barrios + rooms + bathrooms + surface_covered + 
    surface_patio, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-278103  -53057   -8025   39974  487168 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -14242.11   10435.97  -1.365    0.173    
barriosmedio     31290.27    7538.44   4.151 3.55e-05 ***
barriosalto     110453.26    7676.85  14.388  < 2e-16 ***
rooms             6253.83    2593.36   2.411    0.016 *  
bathrooms        30892.73    3833.97   8.058 1.90e-15 ***
surface_covered   1125.88      66.76  16.866  < 2e-16 ***
surface_patio      399.00     101.68   3.924 9.21e-05 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 91120 on 1174 degrees of freedom
Multiple R-squared:  0.5488,    Adjusted R-squared:  0.5465 
F-statistic:   238 on 6 and 1174 DF,  p-value: < 2.2e-16
summary(propTypes$model[[2]])   # datos del modelo Departamento

Call:
lm(formula = price ~ barrios + rooms + bathrooms + surface_covered + 
    surface_patio, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-525687  -34454   -4891   23288  694078 

Coefficients:
                 Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -48235.90    1322.53  -36.47   <2e-16 ***
barriosmedio     20486.58    1228.48   16.68   <2e-16 ***
barriosalto      73331.74    1126.39   65.10   <2e-16 ***
rooms           -14318.29     514.19  -27.85   <2e-16 ***
bathrooms        31750.11     752.89   42.17   <2e-16 ***
surface_covered   2945.13      18.23  161.55   <2e-16 ***
surface_patio      975.45      31.60   30.87   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 70830 on 40348 degrees of freedom
Multiple R-squared:  0.7586,    Adjusted R-squared:  0.7585 
F-statistic: 2.113e+04 on 6 and 40348 DF,  p-value: < 2.2e-16
summary(propTypes$model[[3]])   # datos del modelo PH

Call:
lm(formula = price ~ barrios + rooms + bathrooms + surface_covered + 
    surface_patio, data = df)

Residuals:
    Min      1Q  Median      3Q     Max 
-266658  -32757   -1815   29250  323310 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)    
(Intercept)     -3924.79    3308.05  -1.186    0.236    
barriosmedio    24976.69    2422.32  10.311   <2e-16 ***
barriosalto     74869.51    2406.89  31.106   <2e-16 ***
rooms             908.18    1114.47   0.815    0.415    
bathrooms       25088.75    1588.80  15.791   <2e-16 ***
surface_covered  1362.05      32.93  41.359   <2e-16 ***
surface_patio     423.80      36.49  11.615   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 56060 on 4361 degrees of freedom
Multiple R-squared:  0.6581,    Adjusted R-squared:  0.6576 
F-statistic:  1399 on 6 and 4361 DF,  p-value: < 2.2e-16

Como una primera gran diferencia entre los tres modelos generados (y también con respecto a los anteriores), vemos que la variable rooms solo tiene una influencia negativa sobre el precio en el modelo de Departamentos. En los demás casos ha pasado a ser positiva, lo que indica que el precio aumentará conforme lo haga la cantidad de habitaciones de la propiedad.

Por otro lado, si observamos los R² de cada uno de los modelos, vemos que el que mejor se ajusta también es el modelo de Departamentos, cuyas variables independientes llevan a explicar casi el 76% de la variabilidad de Y. En segudo lugar se ubica el modelo de PH con casi el 66% y último, el de Casa con aproximadamente e 55%.

Esto es consistente con los valores de desvíos estándares observados, en los que el modelo de Casa presenta el mayor desvío y el de PHs, el menor. Adicionalmente, la tabla a continuación confirma que, de los tres modelos, es este último el que presenta una distribución más cercana a la normal.

LS0tCnRpdGxlOiAiVHJhYmFqbyBQcsOhY3RpY28gTsKwMiIKYXV0aG9yOiAiTWFjYXJlbmEgRmVybmFuZGV6IFVycXVpemEiCm91dHB1dDogCiAgaHRtbF9ub3RlYm9vazogCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgZGVwdGg6IDMKICAgIGluY2x1ZGVzOgogICAgICBiZWZvcmVfYm9keTogaGVhZGVyLmh0bWwKICAgICAgYWZ0ZXJfYm9keTogZm9vdGVyLmh0bWwKLS0tCjwvc3R5bGU+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CmRpdi5tYWluLWNvbnRhaW5lciB7CiAgbWF4LXdpZHRoOiAxNjAwcHg7CiAgbWFyZ2luLWxlZnQ6IGF1dG87CiAgbWFyZ2luLXJpZ2h0OiBhdXRvOwp9CmJvZHkgewp0ZXh0LWFsaWduOiBqdXN0aWZ5fQpoMXsKICBmb250LXNpemU6IDE5cHQ7CiAgbWFyZ2luLXRvcDogNzBweDsKfQpoMnsKICBmb250LXNpemU6IDE3cHQ7Cn0KaDN7CiAgZm9udC1zaXplOiAxNXB0Cn0KPC9zdHlsZT4KClNlIGNhcmdhbiBsYXMgbGlicmVyw61hcyBxdWUgc2UgdXRpbGl6YXLDoW4gYSBsbyBsYXJnbyBkZWwgdHJhYmFqby4KCmBgYHtyLCAsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoT25lUikKbGlicmFyeShicm9vbSkKbGlicmFyeShtb2RlbHIpCmBgYAoKIyAxLiBSZWdyZXNpw7NuIExpbmVhbCBNw7psdGlwbGUKCiMjIDEuMS4gQ3JlYWNpw7NuIGRlbCBtb2RlbG8geyNtb2RlbG9fbDN9CgpTZSBjYXJnYSB1biBkYXRhc2V0IGRlIHByb3BpZWRhZGVzLgoKYGBge3J9CnByb3BlcnRpZXMgPC0gcmVhZF9yZHMoJ2FyX3Byb3BlcnRpZXMucmRzJykKYGBgCgrDiXN0ZSBjdWVudGEgY29uIDggdmFyaWFibGVzOgoKLSBfaWRfCi0gX2wzXyAoYmFycmlvIGVuIGVsIHF1ZSBzZSB1YmljYSBsYSBwcm9waWVkYWQpCi0gX3Jvb21zXyAgKGNhbnRpZGFkIGRlIGhhYml0YWNpb25lcykKLSBfYmF0aHJvb21zXyAoY2FudGlkYWQgZGUgYmHDsW9zKQotICpzdXJmYWNlX3RvdGFsKiAoc3VwZXJmaWNpZSB0b3RhbCkKLSAqc3VyZmFjZV9jb3ZlcmVkKiAoc3VwZXJmaWNpZSBjdWJpZXJ0YSkKLSBfcHJpY2VfIChwcmVjaW8pCi0gKnByb3BlcnR5X3R5cGUqICh0aXBvIGRlIHByb3BpZWRhZCkKCkV4Y2VwdHVhbmRvIGxhIHZhcmlhYmxlIF9pZF8gcXVlIGNvbnRpZW5lIHZhbG9yZXMgw7puaWNvcyBjb24gZWwgZmluIGRlIGlkZW50aWZpY2FyIGxhcyBwcm9waWVkYWRlcywKc2UgY3JlYSB1biBtb2RlbG8gZGUgUmVncmVzacOzbiBMaW5lYWwgTcO6bHRpcGxlIHBhcmEgcHJlZGVjaXIgZWwgcHJlY2lvIGRlIGNhZGEgcHJvcGllZGFkIGEgcGFydGlyIGRlIGxhcyBjb3ZhcmlhYmxlcyByZXN0YW50ZXMuCgpgYGB7cn0KbW9kZWxvIDwtIGxtKHByaWNlIH4gbDMgKyByb29tcyArIGJhdGhyb29tcyArIHN1cmZhY2VfdG90YWwgKyBzdXJmYWNlX2NvdmVyZWQgKyBwcm9wZXJ0eV90eXBlLAogICAgICAgICAgICBkYXRhPXByb3BlcnRpZXMpCgpzdW1tYXJ5KG1vZGVsbykKYGBgCgojIyAxLjIuIEFuw6FsaXNpcyBkZWwgbW9kZWxvCgojIyMgMS4yLjEuIEludGVycHJldGFjacOzbiBkZSBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcwoKU2Vnw7puIGVzdGUgbW9kZWxvLCAtMTA5NDA2LjYxIGVzIGxhIG9yZGVuYWRhIGFsIG9yaWdlbi4gRXN0byBzaWduaWZpY2EgcXVlLCBzaSBlbmNvbnRyw6FzZW1vcyB1bmEgcHJvcGllZGFkIGVuIGxhIHF1ZSB0b2RhcyBsYXMgdmFyaWFibGVzIHR1dmllc2VuIHVuIHZhbG9yIGlndWFsIGEgMCwgZWwgbW9kZWxvIHByZWRlY2lyw61hIHF1ZSBkaWNoYSBwcm9waWVkYWQgdGVuZHLDrWEgdW4gcHJlY2lvIGRlIC0xMDk0MDYuNjEuIEVzdG8gY2xhcmFtZW50ZSBubyB0aWVuZSBzZW50aWRvLiBObyBzb2xvIHBvcnF1ZSBubyB0ZW5kcsOtYW1vcyB1bmEgcHJvcGllZGFkIGNvbiBwcmVjaW8gbmVnYXRpdm8gc2lubyBwb3JxdWUsIGFkZW3DoXMsIGRpZsOtY2lsZW10bmUgdGVuZHLDrWFtb3MgdW5hIHByb3BpZWRhZCBjdXlhIHN1cGVyZmljaWUgdG90YWwgZnVlc2UgMC4gCgpFbCByZXN0byBkZSBsb3MgY29lZmljaWVudGVzIGluZGljYSBjw7NtbyB2YXLDrWEsIHNlZ8O6biBsYSBwcmVkaWNjacOzbiBkZSBudWVzdHJvIG1vZGVsbywgZGljaG8gcHJlY2lvIGluaWNpYWwgYWwgYXVtZW50YXIgZW4gdW5hIHVuaWRhZCBjYWRhIHZhcmlhYmxlIGVuIGN1ZXN0acOzbiB5IGRlamFuZG8gZWwgcmVzdG8gZGUgbGFzIHZhcmlhYmxlcyBjb24gdW4gdmFsb3IgY29uc3RhbnRlLgoKRW4gZWwgY2FzbyBkZSBsYXMgdmFyaWFibGVzIF9sM18geSAqcHJvcGVydHlfdHlwZSosIG5vcyBlbmNvbnRyYW1vcyBhbnRlIHZhcmlhYmxlcyBkdW1taWVzLCB2YXJpYWxlcyBjYXRlZ8OzcmljYXMgcXVlIGluZGljYW4gcXVlIGxhIHByb3BpZWRhZCB0aWVuZSBjaWVydGEgY3VhbGlkYWQgbyBuby4gX2wzXyBzZSByZWZpZXJlIGFsIGJhcnJpbyBkb25kZSBzZSB1YmljYSBsYSBwcm9waWVkYWQgeSAqcHJvcGVydHlfdHlwZSosIGFsIHRpcG8gZGUgcHJvcGllZGFkIGVuIHF1ZSBjb25zaXN0ZSAoUEggbyBkZXBhcnRhbWVudG8pLgoKRGFkbyBxdWUgdW5hIHByb3BpZWRhZCBubyBwdWVkZSBlbmNvbnRyYXJzZSBlbiBtw6FzIGRlIHVuIGx1Z2FyIG5pIHNlciBkZSBtw6FzIGRlIHVuIHRpcG8sIHNvbG8gdW5vIGRlIGxvcyBjb2VmaWNpZW50ZXMgcGFyYSBsYSB2YXJpYWJsZSBfbDNfIHkgdW5vIHBhcmEgbGEgdmFyaWFibGUgKnByb3BlcnR5X3R5cGUqIHRlbmRyw6EgaW5mbHVlbmNpYSBlbiBsYSBwcmVkaWNjacOzbiBxdWUgcmVhbGljZSBudWVzdHJvIG1vZGVsbyBwYXJhIGNhZGEgcHJvcGllZGFkLiBQb3IgZWplbXBsbywgZW4gZWwgY2FzbyBkZSB1biBkZXBhcnRhbWVudG8gZGUgQ2FiYWxsaXRvLCBudWVzdHJvIG1vZGVvIHV0aWxpemFyw6EgZWwgY29lZmljaWVudGUgNjIyMC4xNSBwYXJhIGxhIHZhcmlhYmxlIF9sM18geSBlbCBjb2VmY2llbnRlIDkyNjUzLjMyIHBhcmEgKnByb3BlcnR5X3R5cGUqLiBFbCByZXN0byBkZSBsb3MgY29lZmljaWVudGVzIHJlbGFjaW9uYWRvcyBhIF9sM18geSBhICpwcm9wZXJ0eV90eXBlKiBubyBzZSB1dGlsaXphcsOhbiBkYWRvIHF1ZSBsYSB2YXJpYWJsZSByZWZsZWphcsOhIHVuIHZhbG9yIGlndWFsIGEgMCBlbiBkaWNob3MgY2Fzb3MsIGRlasOhbmRvbG9zIGFudWxhZG9zLgoKRXMgcGVydGluZW50ZSByZXNhbHRhciBxdWUsIGVuIGxvcyBjYXNvcyBkZSB2YXJpYWJsZXMgZHVtbWllcywgbm9zIGVuY29udHJhcmVtb3MgY29uIGstMSBjb2VmaWNpZW50ZXMsIGRvbmRlIGsgZXMgbGEgY2FudGlkYWQgZGUgY2xhc2VzIHF1ZSBwdWVkZSB0b21hciBsYSB2YXJpYWJsZSBjb25zaWRlcmFkYS4gRXN0byBzZSBkZWJlIGEgcXVlLCBkZSBvdHJhIGZvcm1hLCBlbCBtb2RlbG8gZXN0YXLDrWEgc29icmVwYXJhbWV0cml6YWRvIHkgbGFzIHZhcmlhYmxlcyBwcmVzZW50YXLDrWFuIGRlcGVuZGVuY2lhIGxpbmVhbCwgbG8gcXVlIGltcGVkaXLDrWEgcXVlIGVsIHNpc3RtYSBkZSBlY3VhY2lvbmVzIGdlbmVyYWRvIHR1dmllc2UgdW5hIMO6bmljYSBzb2x1Y2nDs24uCgpFbiBwYXJ0aWN1bGFyLCBzZSBvYnNlcnZhIHF1ZSBsb3MgYmFycmlvcyBkZSBQdWVydG8gTWFkZXJvLCBMYXMgQ2HDsWl0YXMsIEJlbGdyYW5vLCBQYWxlcm1vcywgUmVjb2xldGEsIE7DusOxZXosIEJhcnJpbyBOb3J0ZSwgQ29naGxhbiwgQ29sZWdpYWxlcywgVmlsbGEgVXJxdWl6YSwgUmV0aXJvLCBTYWF2ZWRyYSwgVmlsbGEgT3J0w7p6YXIsIFZpbGxhIERldm90bywgQ2hhY2FyaXRhLCBQdWV5cnJlZMWELCBDYWJhbGxpdG8sIFBhcnF1ZSBDaGFzLCBWaWxsYSBDcmVzcG8geSBBZ3Jvbm9tw61hIGluZmx1aXLDoW4gcG9zaXRpdmFtZW50ZSBlbiBlbCBwcmVjaW8gZXN0aW1hZG8gcG9yIGVsIG1vZGVsbyBwdWVzdG8gcXVlIHN1cyBjb2VmaWNpZW50ZXMgc29uIHBvc2l0aXZvcy4gRWwgcmVzdG8gZGUgbG9zIGJhcnJpb3MsIGVuIGNhbWJpbywgcHJlc2VudGEgdW4gY29lZmljaWVudGUgbmVnYXRpdm8gcG9yIGxvIHF1ZSBlbCB2YWxvciBlc3RpbWFkbyBwcmVzZW50YXLDoSB1biBkZWNyZW1lbnRvIHNpIGxhIHByb3BpZWRhZCBzZSBlbmN1ZW50cmEgdWJpY2FkYSBlbiB1bm8gZGUgZWxsb3MuCgpMYXMgdmFyaWFibGVzIF9yb29tc18sIF9iYXRocm9vbXNfLCAqc3VyZmFjZV90b3RhbCogeSAqc3VyZmFjZV9jb3ZlcmVkKiwgcG9yIG90cm8gbGFkbywgc29uIG51bcOpcmljYXMsIHkgcHVlZGVuIHRvbWFyIGN1YWxxdWllciB2YWxvci4gTGEgbXVsdGlwbGljYWNpw7NuIGRlIHN1cyB2YWxvcmVzIHBvciBzdXMgcmVzcGVjdGl2b3MgY29lZmljaWVudGVzIHRhbWJpw6luIHRlbmRyw6EgdW4gaW1wYWN0byBlbiBsYSBwcmVkaWNjacOzbiBkZSBudWVzdHJvIG1vZGVsbywgeWEgc2VhIGdlbmVyYW5kbyB1biBhdW1lbnRvIGVuIGVsIHByZWNpbyBlc3RpbWFkbywgZW4gZWwgY2FzbyBkZSBsb3MgYmHDsW9zLCBsYSBzdXBlcmZpY2llIHRvdGFsIHkgbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSwgbyB5YSBzZWEgcHJvdm9jYW5kbyB1bmEgZGlzbWludWNpw7NuLCBlbiBlbCBjYXNvIGRlIGxvcyBkb3JtaXRvcmlvcy4KCiMjIyAxLjIuMi4gU2lnbmlmaWNhdGl2aWRhZCBkZSBsYXMgdmFyaWFibGVzIGR1bW1pZXMKClJlc3VsdGEgaW50ZXJlc2FudGUgZGVzdGFjYXIgcXVlLCBhIGV4Y2VwZWNpw7NuIGRlIGxvcyBiYXJyaW9zIGRlIEFncm9ub23DrWEsIEFsbWFncm8sIEJhcnJhY2FzLCBDYWJhbGxpdG8sIE1vbnRlIENhc3RybywgUGFycXVlIENoYXMsIFNhbiBUZWxtbywgVmlsbGEgQ3Jlc3BvLCBWaWxsYSBkZWwgUGFycXVlLCBWaWxsYSBMdXJvLCBWaWxsYSBSZWFsIHkgU2FudGEgUml0YSwgbG9zIHZhbG9yZXMgZGUgbGEgdmFyaWFibGUgZHVtbXkgX2wzXyBwcmVzZW50YW4gdW4gKnAtdmFsb3IqIG1lbm9yIGEgMC4wNSwgbG8gcXVlIHNpZ25pZmljYSBxdWUgbGEgdmFyaWFibGUgZXMgw7p0aWwgcGFyYSBleHBsaWNhciBfeV8gY3VhbmRvIGVuIGVsIG1vZGVsbyBzZSBlbmN1ZW50cmFuIHByZXNlbnRlcyBsYXMgZGVtw6FzIHZhcmlhYmxlcywgcGVybyBubyBlbiBvdHJvIGNhc28uIExvIG1pc21vIHN1Y2VkZSBjb24gbGEgdmFyaWFibGUgZHVtbXkgKnByb3BlcnR5X3R5cGUqLgoKTG9zIGNvZWZpY2llbnRlcyBjYWxjdWxhZG9zIHBhcmEgQWdyb25vbcOtYSB5IFZpbGxhIENyZXNwbywgcG9yIHN1IHBhcnRlLCBtdWVzdHJhbiB1biB2YWxvciBtYXlvciBhIDAuNywgaW5kaWNhbmRvIHF1ZSBlbiBlc3RvcyBjYXNvcyBsYSB2YXJpYWJsZSByZXN1bHRhIHNpZ25pZmljYXRpdmEgaW5jbHVzbyBlbiBhdXNlbmNpYSBkZSBsYXMgZGVtw6FzIHZhcmlhYmxlcy4KCiMjIyAxLjIuMy4gRXZhbHVhY2nDs24gZGVsIG1vZGVsbwoKUmVzcGVjdG8gZGUgbGEgZXZhbHVhY2nDs24gZGVsIG1vZGVsbywgcG9kZW1vcyB2ZXIgcXVlIMOpc3RlIHByZXNlbnRhIHVuIFLCsiBkZSAwLjc3LCBsbyBxdWUgaW5kaWNhIHF1ZSBudWVzdHJvIG1vZGVsbyBlcyBjYXBheiBkZSBleHBsaWNhciBlbCA3NyUgZGUgbGEgdmFyaWFiaWxpZGFkIGRlIGxhIHZhcmlhYmxlIGRlcGVkaWVudGUgWSBhIHBhcnRpciBkZSBsYXMgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzIHByb3BvcmNpb25hZGFzLgoKIyMgMS4zLiBQcmVkaWNjaW9uZXMKCkEgY29udGludWFjacOzbiwgc2UgcHJvcG9uZW4gZG9zIG51ZXZvcyBjYXNvcyB5IHNlIHV0aWxpemEgZWwgbW9kZWxvIGFqdXN0YWRvIHBhcmEgcHJlZGVjaXIgc3VzIHByZWNpb3MuCgpFbCBwcmltZXIgY2FzbyBjb25zaXN0ZSBlbiB1biBkZXBhcnRhbWVudG8gZGUgMTIwIG1ldHJvcyBjdWFkcmFkb3MgY3ViaWVydG9zLCB1YmljYWRvIGVuIGVsIGJhcnJpbyBkZSBBYmFzdG8sIGNvbiAzIGRvcm1pdG9yaW9zIHkgMiBiYcOxb3MuIEVsIHNlZ3VuZG8gc2UgdHJhdGEgZGUgdW4gUEggZW4gQmFsdmFuZXJhLCBjb24gODAgbWV0cm9zIGN1YWRyYWRvcyBjdWJpZXJ0b3MsIDIwIG1ldHJvcyBjdWFkcmFkb3Mgbm8gY3ViaWVydG9zLCAyIGRvcm1pdG9yaW9zIHkgMyBiYcOxb3MuCgpTZSBnZW5lcmEgdW4gbnVldm8gZGF0YXNldCBjb24gZXN0b3MgY2Fzb3MgeSBzZSB1dGlsaXphIGxhIGZ1bmNpw7NuIF9wcmVkaWN0XyBwYXJhIHByZWRlY2lyIHN1cyBwcmVjaW9zLgoKYGBge3J9Cm51ZXZvc19jYXNvcyA8LSBkYXRhLmZyYW1lKAogIGwzID0gYygnQWJhc3RvJywgJ0JhbHZhbmVyYScpLAogIHJvb21zID0gYygzLCAyKSwKICBiYXRocm9vbXMgPSBjKDIsIDMpLAogIHN1cmZhY2VfdG90YWwgPSBjKDEyMCwgMTAwKSwKICBzdXJmYWNlX2NvdmVyZWQgPSBjKDEyMCwgODApLAogIHByb3BlcnR5X3R5cGUgPSBjKCdEZXBhcnRhbWVudG8nLCAnUEgnKSAKKQoKbnVldm9zX2Nhc29zICU+JSAKICBtdXRhdGUocHJlZGljdCA9IHByZWRpY3QobW9kZWxvLCBuZXdkYXRhID0gLikpICU+JSAKICBzZWxlY3QobDMsIHByZWRpY3QsIGV2ZXJ5dGhpbmcoKSkKYGBgCgpFbCBtb2RlbG8gcHJlZGljZSBxdWUgbGEgcHJvcGllZGFkIGVuIGVsIGJhcnJpbyBkZSBBYmFzdG8gdmFsZSAzMjQ1OTYuNCwgbWllbnRyYXMgcXVlIGxhIGRlbCBiYXJyaW8gZGUgQmFsdmFuZXJhIGN1ZXN0YSAyMTUyNjcuNiwgcG9yIGxvIHF1ZSByZXN1bHRhIHByZWZlcmlibGUgdGVuZXIgbGEgcHJpbWVyYSBwYXJhIHZlbmRlci4KCiMjIDEuNC4gQ3JlYWNpw7NuIGRlIHVuIG51ZXZvIG1vZGVsbwoKU2UgY3JlYSB1biBudWV2byBtb2RlbG8gc2luIGxhIHZhcmlhYmxlIF9sM18uCgpgYGB7cn0KbW9kZWxvX3Npbl9sMyA8LSBsbShwcmljZSB+IHJvb21zICsgYmF0aHJvb21zICsgc3VyZmFjZV90b3RhbCArIHN1cmZhY2VfY292ZXJlZCArIHByb3BlcnR5X3R5cGUsCiAgICAgICAgICAgICAgICAgICBkYXRhPXByb3BlcnRpZXMpCgpzdW1tYXJ5KG1vZGVsb19zaW5fbDMpCmBgYAoKClNlIG9ic2VydmEgcXVlIGxhIG1lZGlhbmEgZGUgbG9zIHJlc2lkdW9zIGRlIGVzdGUgbW9kZWxvIHNlIGVuY3VlbnRyYSBtw6FzIGFsZWphZGEgZGVsIDAgcXVlIGVuIGVsIFttb2RlbG8gYW50ZXJpb3JdKCNtb2RlbG9fbDMpICgtMzMwNyksIGxvIHF1ZSBub3MgaW5kaWNhIHF1ZSBzdSBkaXN0cmlidWNpw7NuIHByZXNlbnRhIG1heW9yIGFzaW1ldHLDrWEuIExvIGRlc2VhYmxlIHNlcsOtYSBxdWUgZXN0ZSB2YWxvciBzZSBlbmNvbnRyYXNlIHByw7N4aW1vIGFsIDAgcGFyYSBwb2RlciB2ZXJpZmljYXIgdW5hIGRpc3RyaWJ1Y2nDs24gbm9ybWFsIGRlIGxvcyByZXNpZHVvcywgaS5lLiBkZSBsYSBkaWZlcmVuY2lhIGVudHJlIGxvcyB2YWxvcnMgxbYgcHJlZGljaG9zIHkgbG9zIHZhbG9yZXMgZGUgWSBvYnNlcnZhZG9zLgoKUG9yIG90cm8gbGFkbywgc2kgYmllbiBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcyBoYW4gdmFyaWFkbyBzdSB2YWxvciwgbm8gaGFuIGNhbWJpYWRvIHN1IHNpZ25vLCBwb3IgbG8gcXVlIHN1IGluY2lkZW5jaWEgZW4gbGEgZXN0aW1hY2nDs24gZGUgcHJlY2lvcyBzZSBtYW50aWVuZTogYXF1ZWxsYXMgdmFyaWFibGVzIHF1ZSBpbmNyZW1lbnRhYmFuIGVsIHZhbG9yIGRlIGxvcyBwcmVjaW9zIGNvbnRpbnVhbiBoYWNpw6luZG9sbyB5IGxvIG1pc21vIG9jdXJyZSBjb24gbGFzIHF1ZSBkaXNtaW51w61hbiBlc3RlIHZhbG9yLgoKIyMgMS41LiBDb21wYXJhY2nDs24gZGUgbW9kZWxvcwoKRWwgc2VndW5kbyBtb2RlbG8gZ2VuZXJhZG8gcG9zZWUgdW5hIG1lbm9yIGNhcGFjaWRhZCBleHBsaWNhdGl2YSBkZSBsYSB2YXJpYWJsZSBZLiBTdSBSwrIgbm9zIGluZGljYSBxdWUgbGFzIHZhcmlhYmxlcyBpbmRlcGVuZGllbnRlcyBzb2xvIHB1ZWRlbiBleHBsaWNhciBlbCA2OCUgZGUgbGEgdmFyaWFibGUgZGVwZW5kaWVudGUuIEVzdGUgZGVjcmVtZW50byByZXN1bHRhCmVzcGVyYWJsZSBlbiB0YW50byBlc3RlIG1vZGVsbyB1dGlsaXphIG1lbm9zIHZhcmlhYmxlcy4gCgpMb3MgbW9kZWxvcyBkZSBSZWdyZXNpw7NuIExpbmVhbCBhdW1lbnRhbiBzdSBSwrIgY29uZm9ybWUgYXVtZW50YW4gbGEgY2FudGlkYWQgZGUgdmFyaWFibGVzIGVtcGxlYWRhcyBlbiBsYSBwcmVkaWNjacOzbiwgc2luIGltcG9ydGFyIHNpIMOpc3RhcyBlc3TDoW4gbyBubyBjb3JyZWxhY2lvbmFkYXMgY29uIGxhIHZhcmlhYmxlIGEgcHJlZGVjaXIuIAoKU2luIGVtYmFyZ28sIHNpIG9ic2VydmFtb3MgZWwgUsKyIGFqdXN0YWRvLCB2ZW1vcyBxdWUgdGFtYmnDqW4gYXF1w60gZWwgcHJpbWVyIG1vZGVsbyBzdXBlcmEgYWwgc2VndW5kbyAoNzclIGNvbnRyYSA2OCUpLiBFc3RvIHJlc3VsdGEgcmVsZXZhbnRlIHB1ZXN0byBxdWUgZWwgUsKyIGFqdXN0YWRvIGluZGljYSBsYSBjYXBhY2lkYWQgZGUgZXhwbGljYWNpw7NuIGRlIHVuIG1vZGVsbyBjb25zaWRlcmFuZG8gbGFzIHZhcmlhYmxlcyBpbmRlcGVuZGllbnRlcyBxdWUgc8OtIHNlIGVuY3VlbnRyYW4gcmVsYWNpb25hZGFzIGNvbiBsYSBkZXBlbmRpZW50ZS4gRXN0YSBtZWRpZGEgZGlzbWludXllIGFsIGHDsWFkaXIgdmFyaWFibGVzIG5vIHJlbGFjaW9uYWRhcyB5IGF1bW5ldGEgc29sbyBzaSBsYXMgYWdyZWdhZGFzIHNvbiBlZmVjaXR2YW1lbnRlIGV4cGxpY2F0aXZhcy4gRGViaWRvIGEgZXN0bywgZWwgUsKyIGFqdXN0YWRvIHBvc2liaWxpdGEgbGEgY29tcGFyYWNpw7NuIGRlIG1vZGVsb3MgY29uIGRpc3RpbnRhIGNhbnRpZGFkIGRlIHZhcmlhYmxlcy4KCkFzw60sIGVsIG1vZGVsbyBxdWUgbWVqb3IgZXhwbGljYSBsYSB2YXJpYWJsZSBwcmVjaW9zIGVzIGVsIG1vZGVsbyBxdWUgaW5jbHV5ZSBsYSB2YXJpYWJsZSBfbDNfLCBkYWRvIHF1ZSBzdSBSwrIgYWp1c3RhZG8gZXMgbWF5b3IgcXVlIGVsIMO6bHRpbW8gbW9kZWxvIHJlYWxpemFkby4KCiMgMi4gQ3JlYWNpw7NuIGRlIHZhcmlhYmxlcwoKIyMgMi4xLiBWYXJpYWJsZSBfYmFycmlvc18geyNiYXJyaW9zfQoKQ29uIGVsIHByb3DDs3NpdG8gZGUgY3JlYXIgdW5hIG51ZXZhIHZhcmlhYmxlIF9iYXJyaW9zXyBkZSB0aXBvIGNhdGVnw7NyaWNhIHF1ZSBkaXN0aW5nYSBlbnRyZSBiYXJyaW9zIGNvbiBwcmVjaW8gX2FsdG9fLCBfbWVkaW9fIHkgX2Jham9fLCBzZSBncmFmaWNhIHVuIHNjYXR0ZXIgcGxvdCBkZSBwcmVjaW9zIHF1ZSBub3MgcGVybWl0YSB2aXN1YWxpemFyIHNpIGV4aXN0ZW4gcHVudG9zIGNyw610aWNvcyBjYXBhY2VzIGRlIGZ1bmNpb25hciBjb21vIHB1bnRvcyBkZSBjb3J0ZSBlbnRyZSBsYXMgY2F0ZWdvcsOtYXMgZGVmaW5pZGFzLgoKYGBge3J9CnBsb3Qoc29ydChwcm9wZXJ0aWVzJHByaWNlLCBkZWNyZWFzaW5nID0gRkFMU0UpLAogICAgIG1haW4gID0gJ1ByZWNpb3Mgb3JkZW5hZG9zIGVuIGZvcm1hIGNyZWNpZW50ZScsCiAgICAgeWxhYiA9ICdQcmVjaW9zJywKICAgICB4bGFiID0gJ8ONbmRpY2UnLAogICAgIGNvbCA9ICdjeWFuNCcpCmBgYAoKRGFkbyBxdWUgbm8gc2Ugb2JzZXJ2YSBsYSBwcmVzZW5jaWEgZGUgdGFsZXMgcHVudG9zLCBzZSBvcHRhIHBvciBnZW5lcmFyIDMgYmlucyBkZSBtYW5lcmEgYXV0b23DoXRpY2EgdXRpbGl6YW5kbyBlbCBtw6l0b2RvIGRlICJjbHVzdGVycyIgZGUgbGEgZnVuY2nDs24gX2Jpbl8gZGVsIHBhcXVldGUgX09uZVJfLiBQYXJhIGVsbG8sIHByaW1lcm8gc2UgYWdydXBhbiBsb3MgcHJlY2lvcyBwb3IgYmFycmlvcyB5IHNlIGNhbGN1bGEgc3UgbWVkaWEsIGVzdGUgc2Vyw6EgZWwgaW5wdXQgcXVlIHRvbWFyw6EgbGEgZnVuY2nDs24uCgpgYGB7cn0KcHJlY2lvcyA8LSBwcm9wZXJ0aWVzICU+JSAKICBzZWxlY3QobDMsIHByaWNlKSAlPiUgCiAgZ3JvdXBfYnkobDMpICU+JSAKICBzdW1tYXJpc2UobWVkaWFfcHJlY2lvID0gbWVhbihwcmljZSkpICU+JSAKICBhcnJhbmdlKG1lZGlhX3ByZWNpbykKCnByZWNpb3MKYGBgCgpgYGB7cn0KcHJlY2lvcyRjbHVzdGVycyA8LSBiaW4ocHJlY2lvcyRtZWRpYV9wcmVjaW8sCiAgICAgICAgICAgICAgICAgICAgICAgIG5iaW5zPTMsIAogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiYmFqbyIsICJtZWRpbyIsICJhbHRvIiksIAogICAgICAgICAgICAgICAgICAgICAgICBtZXRob2Q9ImNsdXN0ZXJzIikKCnByZWNpb3MKYGBgCgpEYWRvIHF1ZSBkZXNlYW1vcyB0ZW5lciBjbGFzZXMgYmFsYW5jZWFkYXMsIHJldmlzYW1vcyBjdcOhbnRvcyBiYXJyaW9zIGhhbiBxdWVkYWRvIGFncnVwYWRvcyBlbiBjYWRhIGNsYXNlLgoKYGBge3J9CnByZWNpb3MgJT4lIAogIGNvdW50KGNsdXN0ZXJzKQpgYGAKClZlbW9zIHF1ZSBubyBzZSBoYW4gb2J0ZW5pZG8gY2xhc2VzIGJhbGFuY2VhZGFzLiBMYSBjYXRlZ29yw61hIF9iYWpvXyBjdWVudGEgY29uIG11Y2hvcyBtw6FzIGJhcnJpb3MgcXVlIGxhcyBvdHJhcyBkb3MuIFkgbGEgY2F0ZWdyw61hIF9hbHRvXyBhZ3J1cGEgdW4gw7puaWNvIGJhcnJpby4gCgpWb2x2ZW1vcyBhIGdlbmVyYXIgbG9zIGJpbnMgcGVybyBhaG9yYSB1dGlsaXphbW9zIGVsIG3DqXRvZG8gZGUgX2NvbnRlbnRfLCBxdWUgYXJtYSBiaW5zIGNvbiBpZ3VhbCBjYW50aWRhZCBkZSBlbGVtZW50b3MuCgpgYGB7cn0KcHJlY2lvcyRiaW5zIDwtIGJpbihwcmVjaW9zJG1lZGlhX3ByZWNpbywgCiAgICAgICAgICAgICAgICAgICAgbmJpbnM9MywgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoImJham8iLCAibWVkaW8iLCAiYWx0byIpLCAKICAgICAgICAgICAgICAgICAgICBtZXRob2Q9ImNvbnRlbnQiKQoKcHJlY2lvcwpgYGAKCkNoZXF1ZWFtb3MgcGFyYSBjb25maXJtYXI6CgpgYGB7cn0KcHJlY2lvcyAlPiUgCiAgY291bnQoYmlucykKYGBgCgpBZ3JlZ2Ftb3MgbGEgbnVldmEgaW5mb3JtYWNpw7NuIGFsIGRhdGEgZnJhbWUgZGUgZGF0b3MgcXVlIHlhIHRlbsOtYW1vcy4gUGFyYSBlbGxvLCB1dGlsaXphbW9zIGxhIGZ1bmNpw7NuICpsZWZ0X2pvaW4qLiBBZGVtw6FzLCBjYW1iaWFtb3MgZWwgbm9tYnJlIGRlIGxhIG51ZXZhIHZhcmlhYmxlIF9iaW5zXyBwb3IgX2JhcnJpb3NfLgoKYGBge3J9CnByb3BlcnRpZXNfYmFycmlvcyA8LSBsZWZ0X2pvaW4ocHJvcGVydGllcywgcHJlY2lvc1ssYygnbDMnLCAnYmlucycpXSwgYnk9J2wzJykKbmFtZXMocHJvcGVydGllc19iYXJyaW9zKVtuYW1lcyhwcm9wZXJ0aWVzX2JhcnJpb3MpID09ICdiaW5zJ10gPC0gJ2JhcnJpb3MnCgpwcm9wZXJ0aWVzX2JhcnJpb3MKYGBgCgojIyAyLjIuIE1vZGVsbyBjb24gdmFyaWFibGUgX2JhcnJpb3NfIHsjbW9kZWxvX2JhcnJpb30KClNlIGFqdXN0YSB1biBudWV2byBtb2RlbG8uIEVzdGEgdmV6LCBzZSB1dGlsaXphIGxhIHZhcmlhYmxlIF9iYXJyaW9zXyBjcmVhZGEgZW4gZWwgW2FwYXJ0YWRvIGFudGVyaW9yXSgjYmFycmlvcykgZW4gbHVnYXIgZGUgbGEgdmFyaWFibGUgX2wzXy4KCmBgYHtyfQptb2RlbF9jb25fYmFycmlvcyA8LSBsbShwcmljZSB+IHJvb21zICsgYmF0aHJvb21zICsgc3VyZmFjZV90b3RhbCArIHN1cmZhY2VfY292ZXJlZCArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHlfdHlwZSArIGJhcnJpb3MsIGRhdGE9cHJvcGVydGllc19iYXJyaW9zKQoKc3VtbWFyeShtb2RlbF9jb25fYmFycmlvcykKYGBgCgpFcyBwb3NpYmxlIG5vdGFyIHF1ZSBsYSBtZWRpYW5hIGRlIGxvcyByZXNpZHVvcyBkZSBlc3RlIG1vZGVsbyBwcmVzZW50YSBzaWdubyBuZWdhdGl2bywgYWwgaWd1YWwgcXVlIGVsIG1vZGVsbyBxdWUgaW5jbHXDrWEgYSBsYSB2YXJpYWJsZSBfbDNfLiBFc3RvIG5vcyBpbmRpY2EgcXVlIGFsIG1lbm9zIGxhIG1pdGFkIGRlIGxvcyB2YWxvcmVzIMW2IHByZWRpY2hvcyBwb3IgYW1ib3MgbW9kZWxvcyBzb24gdmFsb3JlcyBxdWUgc2UgZW5jdWVudHJhbiBwb3IgZW5jaW1hIGRlIGxvcyB2YWxvcmVzIFkgb2JzZXJ2YWRvcy4KTm8gb2JzdGFudGUsIGxhIG1lZGlhbmEgZGUgbG9zIHJlc2lkdW9zIGRlIGVzdGUgc2VndW5kbyBtb2RlbG8gc2UgZW5jdWVudHJhIG3DoXMgY2VyY2EgZGVsIDAgcXVlIGxhIG1lZGlhbmEgZGVsIG1vZGVsbyBjb24gX2wzXywgbG8gcXVlIHBvZHLDrWEgaW5kaWNhciBxdWUsIGVuIHJhbmdvcyBnZW5lcmFsZXMsIGxvcyB2YWxvcmVzIMW2IHByZWRpY2hvcyBlbiBlc3RlIGNhc28geSBsb3MgdmFsb3JlcyBZIHJlYWxlcyBzZSBlbmN1ZW50cmFuIGEgbWVub3IgZGlzdGFuY2lhLgoKRW4gY3VhbnRvIGEgbG9zIGNvZWZpY2llbnRlcyBjYWxjdWxhZG9zLCBwb2RlbW8gb2JzZXJ2YXIgcXVlLCBzaSBiaWVuIHN1cyB2YWxvcmVzIGhhbiBjYW1iaWFkbywgbm8gbG8gaGEgaGVjaG8gYXPDrSBzdSBzaWduby4gTG8gcXVlIG5vcyBpbXBsaWNhIHF1ZSBhcXVlbGxhcyB2YXJpYWJsZXMgcXVlIGluZmx1w61hbiBwb3NpdGl2YW1lbnRlIGVuIGxhIHZhcmlhYmxlIGEgcHJlZGVjaXIgbG8gc2lndWVuIGhhY2llbmRvIHkgbG8gbWlzbW8gb2N1cnJlIGNvbiBsYSB2YXJpYWJsZSBfcm9vbXNfLCBjdXlhIGluY2lkZW5jaWEgZXJhIG5lZ2F0aXZhLgoKUG9yIMO6bHRpbW8sIG5vdGFtb3MgcXVlIGxhIHZhcmlhYmlsaWRhZCBleHBsaWNhZGEgcG9yIGVzdGUgbW9kZWxvIGVzIGRlbCA3MyUgKHZhbG9yIGRlIFLCsikuIFNpbiBlbWJhcmdvLCBjb21vIHlhIHNlIGFkdmlydGnDsyBwcmV2aWFtZW50ZSwgbm8gZGViZW1vcyBmaWFybm9zIGRlIGVzdGEgbWVkaWRhIHBhcmEgZXN0YWJsZWNlciB1bmEgY29tcGFyYWNpw7NuIGNvbiBlbCBtb2RlbG8gZGUgX2wzXywgc2lubyBxdWUgZGViZW1vcyB1dGlsaXphciBzdSB2YWxvciBhanVzdGFkby4gRGFkbyBxdWUgZWwgUsKyIGFqdXN0YWRvIGRlIGVzdGUgbW9kZWxvIHJlc3VsdGEgbWVub3IgcXVlIGVsIGRlbCBtb2RlbG8gZGUgX2wzXyAoNzMlIGNvbnRyYSA3NyUpLCBwb2RlbW9zIGFmaXJtYXIgcXVlIGVzIGVzdGUgw7psdGltbyBlbCBxdWUgbWVqb3IgZXhwbGljYSBsYSB2YXJpYWJpbGlkYWQgZGUgbG9zIGRhdG9zLgoKRGUgdG9kb3MgbW9kb3MsIGNhYmUgaGFjZXIgbGEgcmVmbGV4acOzbiBkZSBxdcOpIG1vZGVsbyByZXN1bHRhIG3DoXMgw7p0aWwgYSBsYSBob3JhIGRlIGVzdGltYXIgZWwgcHJlY2lvIGRlIHVuYSBwcm9waWVkYWQuIFNpIGJpZW4gZWwgbW9kZWxvIGRlIF9sM18gZXhwbGljYSBtZWpvciBhIGxhIHZhcmlhYmxlIFksIGxhIGNhbnRpZGFkIGRlIHZhbG9yZXMgcG9zaWJsZXMgcXVlIHB1ZWRlIGFkb3B0YXIgbGEgdmFyaWFibGUgX2wzXyB5IHN1cyBjb3JyZXNwb25kaWVudGVzIGNvZWZpY2llbnRlcyAoaWd1YWxtZW50ZSB2YXJpYWRvcykgbm8gcGVybWl0ZSBlc3RhYmxlY2VyIHVuIHBhdHLDs24gY2xhcm8gcXVlIGTDqSBjdWVudGEgZGUgY8OzbW8gaW5mbHV5ZSBlc3RhIHZhcmlhYmxlIGVuIGxhIHByZWRpY2Npw7NuLiBFbCBtb2RlbG8gYWp1c3RhZG8gY29uIGxhIHZhcmlhYmxlIF9iYXJyaW9zXywgZW4gY2FtYmlvLCBzaSBiaWVuIHBvc2VlIHVuIG1lbm9yIHBvZGVyIGV4cGxpY2F0aXZvLCBzw60gbm9zIGRhIHVuYSBpZGVhIGRlIGVzdGEgcmVsYWNpw7NuOiBlbiB0b2RvcyBsb3MgY2Fzb3MgZW4gbG9zIHF1ZSBsYSBwcm9waWVkYWQgc2UgZW5jdWVudHJlIHViaWNhZGEgZW4gdW4gYmFycmlvIGRlIHByZWNpbyAiYmFqbyIsIGVsIHZhbG9yIHByZWRpY2hvIGRlIGxhIG1pc21hIG5vIHNlIHZlcsOhIGluY3JlbWVudGFkbzsgc2ksIGVuIGNhbWJpbywgZWwgaW5tdWVibGUgc2UgZW5jdWVudHJhIGVuIHVuIGJhcnJpbyBkZSBwcmVjaW8gIm1lZGlvIiwgc3UgdmFsb3IgYXVtZW50YXLDoSAyMDUwMSw0NiwgeSBzZSBpbmNyZW1lbnRhcsOhIGVuIDc2NTcxLDg5IGVuIGxvcyBjYXNvcyBlbiBsb3MgcXVlIHNlIHViaXF1ZSBlbiB1biBiYXJyaW8gZGUgcHJlY2lvICJhbHRvIi4KCiMjIDIuMy4gVmFyaWFibGUgKnN1cmZhY2VfcGF0aW8qCgpEYWRvIHF1ZSBsYXMgdmFyaWFibGUgKnN1cmZhY2VfY292ZXJlZCogeSAqc3VyZmFjZV90b3RhbCogZXN0w6FuIGNvcnJlbGFjaW9uYWRhcywgc2UgcHJvcG9uZSBjcmVhciB1bmEgbnVldmEgdmFyaWFibGUgbGxhbWFkYSAqc3VyZmFjZV9wYXRpbyogIHF1ZSByZWZsZWplIGxhIGRpZmVyZW5jaWEgZW50cmUgYW1iYXMgc3VwZXJmaWNpZXMuIERlIGVzdGUgbW9kbzoKCnN1cmZhY2VfcGF0aW8gPSBzdXJmYWNlX3RvdGFsIC0gc3VyZmFjZV9wYXRpbwoKU2luIGVtYmFyZ28sIHBvZHLDrWEgb2N1cnJpciBxdWUgc2UgZW5jb250cmFzZW4gY2Fzb3MgZGUgaW5jb25zaXN0ZW5jaWEgZG9uZGUgbGEgc3VwZXJmaWNpZSB0b3RhbCBkZSB1bmEgdml2aWVuZGEgZnVlc2UgbWVub3IgYSBzdSBzdXBlcmZpY2llIGN1YmllcnRhLiBEZSBlbmNvbnRyYXJzZSB0YWxlcyBjYXNvcywgc2UgcHJvcG9uZSBlbGltaW5hcmxvcywgcHVlc3RvIHF1ZSBzZSB0cmF0YXLDrWEgZGUgcmVnaXN0cm9zIG1hbCBpbmdyZXNhZG9zLiAKCkVudG9uY2VzLCBjb21vIHByaW1lciBwYXNvLCBzZSBjaGVxdWVhIGxhIGV4aXN0ZW5jaWEgZGUgY2Fzb3MgZGUgaW5jb25zaXN0ZW5jaWEuCgpgYGB7cn0KbnJvdyhwcm9wZXJ0aWVzX2JhcnJpb3NbcHJvcGVydGllc19iYXJyaW9zJHN1cmZhY2VfY292ZXJlZCA+IHByb3BlcnRpZXNfYmFycmlvcyRzdXJmYWNlX3RvdGFsLF0pCmBgYAoKTm8gc2Ugb2JzZXJ2YW4gY2Fzb3MgZW4gbG9zIHF1ZSBsYSBzdXBlcmZpY2llIHRvdGFsIHNlYSBtZW5vciBxdWUgbGEgY3ViaWVydGEuIFNlIHByb2NlZGUgYSBnZW5lcmFyIGxhIG51ZXZhIHZhcmlhYmxlIHByZXZpYW1lbnRlIGRlZmluaWRhLgoKYGBge3J9CnByb3BlcnRpZXNfYmFycmlvc1lwYXRpbyA8LSBwcm9wZXJ0aWVzX2JhcnJpb3MgJT4lIAogIG11dGF0ZShzdXJmYWNlX3BhdGlvID0gc3VyZmFjZV90b3RhbC1zdXJmYWNlX2NvdmVyZWQpCgpwcm9wZXJ0aWVzX2JhcnJpb3NZcGF0aW8KYGBgCgojIyAyLjQuIE1vZGVsbyBjb24gbGEgdmFyaWFibGUgKnN1cmZhY2VfcGF0aW8qIHsjcGF0aW99CgpTZSBlbnRyZW5hIHVuIG51ZXZvIG1vZGVsbyB1dGlsaXphbmRvIGFob3JhIGxhIHZhcmlhYmxlIF9iYXJyaW9zXyBlbiBsdWdhciBkZSBfbDNfIHkgbGEgdmFyaWFibGUgKnN1cmZhY2VfcGF0aW8qIGVuIGx1Z2FyIGRlICpzdXJmYWNlX3RvdGFsKi4KCmBgYHtyfQptb2RlbG9fYmFycmlvc1lwYXRpbyA8LSBsbShwcmljZSB+IGJhcnJpb3MgKyByb29tcyArIGJhdGhyb29tcyArIHN1cmZhY2VfY292ZXJlZCArIHN1cmZhY2VfcGF0aW8rIHByb3BlcnR5X3R5cGUsIGRhdGE9cHJvcGVydGllc19iYXJyaW9zWXBhdGlvKQoKc3VtbWFyeShtb2RlbG9fYmFycmlvc1lwYXRpbykKYGBgCgpWZW1vcyBxdWUgbGEgdmFyaWFibGUgKnN1cmZhY2VfcGF0aW8qIHBvc2VlIGVsIG1pc21vIGNvZWZpY2llbnRlIHF1ZSBsYSB2YXJpYWJsZSAqc3VyZmFjZV90b3RhbCogZGVsIFttb2RlbG8gYW50ZXJpb3JdKCNtb2RlbG9fYmFycmlvKS4gRXN0byBzZSBkZWJlIGEgcXVlIGxhIGNhcGFjaWRhZCBleHBsaWNhdGl2YSBkZSBsYSB2YXJpYWJsZSAqc3VyZmFjZV90b3RhbCogYWhvcmEgZXN0w6EgcmVwcmVzZW50YWRhIHBvciAqc3VyZmFjZV9wYXRpbyouIFNlIGNvbXBydWViYSBxdWUgYXF1ZWxsb3MgY2Fzb3MgZW4gbG9zIHF1ZSBsYSBzdXBlcmZpY2llIHRvdGFsIHkgbGEgc3VwZXJpY2llIGN1YmllcnRhIGVyYW4gaWd1YWxlcyBuYWRhIGFwb3J0YWJhbiBhbCBtb2RlbG8sIHB1ZXMgZXN0b3MgY2FzbyBhaG9yYSBwcmVzZW50YW4gdmFsb3IgMCB5IGVsIGNvZWZpY2llbnRlIGFzaWduYWRvIHNlIGhhIG1hbnRlbmlkby4KClBvciBvdHJvIGxhZG8sIGxhIHZhcmlhYmxlICpzdXJmYWNlX2NvdmVyZWQqIHByZXNlbnRhIHVuIGNvZWZpY2llbnRlIG1heW9yOiBoYSBnYW5hZG8gcG9kZXIgZXhwbGljYXRpdm8gZW4gZWwgYXVtZW50byBkZSBwcmVjaW9zIGNvbW8gY29uc2VjdWVuY2lhIGRlIGhhYmVyIHF1aXRhZG8gZGVsIG1vZGVsbyBsYSB2YXJpYWJsZSBjb3JyZWxhY2lvbmFkYSAqc3VyZmFjZV90b3RhbCouCgojIDMuIEV2YWx1YWNpw7NuIGRlIG1vZGVsbwoKQSBjb250aW51YWNpw7NuLCBhbmFsaXphcmVtb3MgbG9zIHJlc2lkdW9zIGRlbCBbbW9kZWxvIGdlbmVyYWRvIGNvbiBsYXMgdmFyaWFibGVzIF9iYXJyaW9zXyB5ICpzdXJmYWNlX3BhdGlvKl0oI3BhdGlvKS4KCkVuIHByaW1lciBsdWdhciwgZ2VuZXJhbW9zIHVuIGRhdGEgZnJhbWUgcXVlIGNvbnRpZW5lLCBhZGVtw6FzIGRlIGxhcyB2YXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMgeSBsYSB2YXJpYWxlIGRlcGVuZGllbnRlLCBsb3MgcmVzaWR1b3MgZGVsIG1vZGVsbyBhanVzdGFkby4KCmBgYHtyfQpyZXNpZF9iYXJyaW9zWXBhdGlvIDwtIHByb3BlcnRpZXNfYmFycmlvc1lwYXRpbyAlPiUgCiAgYWRkX3Jlc2lkdWFscyhtb2RlbG9fYmFycmlvc1lwYXRpbykKCnJlc2lkX2JhcnJpb3NZcGF0aW8KYGBgCgpDYWxjdWxhbW9zIGxhIG1lZGlhIGRlIGVzdG9zIHJlc2lkdW9zLgoKYGBge3J9Cm1lYW4ocmVzaWRfYmFycmlvc1lwYXRpbyRyZXNpZCkKYGBgCgpDb25maXJtYW1vcyBxdWUgbGEgbWVkaWEgZXMgdW4gdmFsb3IgbXV5IGNlcmNhbm8gYSAwLiBFc3RvIGVyYSBlc3BlcmFibGUgZGFkbyBxdWUganVzdGFtZW50ZSBlcyB1bm8gZGUgbG9zIHN1cHVlc3RvcyBxdWUgYXN1bWlkb3MgYSBsYSBob3JhIGRlIGdlbmVyYXIgZWwgbW9kZWxvIHkgYWp1c3RhciBsYSByZWN0YSBwb3IgbcOtbmltb3MgY3VhZHJhZG9zLgoKQSBjb250aW51YWNpw7NuLCBzZSByZWFsaXphbiBkaXN0aW50b3MgZ3LDoWZpY29zIGRlIGxvcyByZWlzdWRvcyBxdWUgbm9zIHBlcm1pdGlyw6FuIGFuYWxpemFybG9zIG1lam9yLgoKYGBge3J9CnBsb3QobW9kZWxvX2JhcnJpb3NZcGF0aW8pCmBgYAoKRW4gZWwgcHJpbWVyIGdyw6FmaWNvLCBwb2RlbW9zIG9ic2VydmFyIGxvcyByZXNpZHVvcyB2ZXJzdXMgbG9zIHZhbG9yZXMgcHJlZGljaG9zIHBvciBlbCBtb2RlbG8uIEVzdGEgdmlzdWFsaXphY2nDs24gbm9zIG11ZXN0cmEgcXVlLCBjb25mb3JtZSBhdW1lbnRhbiBsb3MgdmFsb3JlcyBwcmVkaWNob3MsIHRhbWJpw6luIGxvIGhhY2UgbGEgdmFyaWFuemEgZGUgc3VzIHJlc2lkdW9zLCBwb3IgbG8gY3VhbCBlbCBzdXB1ZXN0byBkZSBob21vZ2VuZWlkYWQgZGUgbGEgdmFyaWFuemEgbm8gc2Ugc2F0aXNmYWNlLiBFc3RvIGluZGljYSBxdWUgbG9zIHJlc2lkdW9zIHByZXNlbnRhbiBjaWVydGEgZXN0cnVjdHVyYSBxdWUgbm8gc2UgZXhwbGljYSBwb3IgZWwgbW9kZWxvIGxpbmVhbCBhanVzdGFkby4KCkVsIHNlZ3VuZG8gZ3LDoWZpY28gbXVlc3RyYSBxdWUgbG9zIHJlc2lkdW9zIGVzdGFuZGFyaXphZG9zIG5vIHNlIGFqdXN0YW4gYSBsYSBkaXN0cmlidWNpw7NuIG5vcm1hbC4gU2Vyw61hIGRlc2VhYmxlIHF1ZSBlc3RvIG9jdXJyaWVzZSwgcHVlc3RvIHF1ZSwgZGUgZXNlIG1vZG8sIGxvcyB0ZXN0IGUgaW50ZXJ2YWxvcyBkZSBjb25maWFuemEgY29uc3RydcOtZG9zIHNlcsOtYW4gbcOhcyBhcHJvcGlhZG9zLgoKRmluYWxtZW50ZSwgZWwgw7psdGltbyBncsOhZmljbywgcGVybWl0ZSBvYnNlcnZhciBsb3MgcmVzaWR1b3MgZW4gcmVsYWNpw7NuIGEgc3UgbGV2ZXJhZ2UsIGVzIGRlY2lyLCBlbiByZWxhY2nDs24gYSBzdSBncmFkbyBkZSBpbmZsdWVuY2lhIGVuIGVsIG1vZGVsby4gRGFkbyBxdWUgZWwgbGV2ZXJhZ2UgZGUgY2FkYSBvYnNlcnZhY2nDs24gcHVlZGUgdG9tYXIgdmFsb3JlcyBlbnRyZSAwIHkgMSB5IGFxdcOtIHRvZG9zIGxvcyB2YXJsb3JlcyBzZSBlbmN1ZW50cmFuIHBvciBkZWJham8gZGUgMC4wNSwgcG9kcsOtYW1vcyBhZmlybWFyIHF1ZSBuaW5ndW5hIG9ic2VydmFjacOzbiBhaXNsYWRhIGVzdMOhIGZvcnphbmRvIGEgbGEgcmVjdGEgYSBkZXN2aWFyc2UgZGVsIGN1cnNvIGVzdGFibGVjaWRvIHBvciB1biBjb25qdW50byBkZSBvYnNlcnZhY2lvbmVzIG1heW9yLgoKIyA0LiBNb2RlbG8gZGUgZWxhc3RpY2lkYWQgY29uc3RhbnRlCgpTZSBpbXBsZW1lbnRhIHVuICoqbW9kZWxvIGRlIGVsYXN0aWNpZGFkIGNvbnN0YW50ZSoqIGRlZmluaWRvIGRlbCBzaWd1aWVudGUgbW9kbzoKCiQkCmxvZyhwcmljZSkgPSBcYmV0YV8wICsgXGJldGFfMWxvZyhyb29tcykgKyBcYmV0YV8ybG9nKGJhdGhyb29tcykgKyBcYmV0YV8zbG9nKHN1cmZhY2VcX2NvdmVyZWQpICsgXGJldGFfNHByb3BlcnR5XF90eXBlICsgXGJldGFfNWJhcnJpbyArIFxiZXRhXzZzdXJmYWNlXF9wYXRpbwokJAoKYGBge3J9Cm1vZGVsX2xvZyA9IGxtKGxvZyhwcmljZSkgfiBsb2cocm9vbXMpICsgbG9nKGJhdGhyb29tcykgKyBsb2coc3VyZmFjZV9jb3ZlcmVkKSArIHByb3BlcnR5X3R5cGUgKwogICAgICAgICAgICAgICAgIGJhcnJpb3MgKyBzdXJmYWNlX3BhdGlvLCBkYXRhPXByb3BlcnRpZXNfYmFycmlvc1lwYXRpbykKCnN1bW1hcnkobW9kZWxfbG9nKQpgYGAKCkVuIGNvbXBhcmFjacOzbiBjb24gW2VsIGFudGVyaW9yXSgjcGF0aW8pLCB2ZW1vcyBxdWUgZXN0ZSBtb2RlbG8gcG9zZWUgbWF5b3IgY2FwYWNpZGFkIGV4cGxpY2F0aXZhLiBObyBzb2xvIHN1IFLCsiBlcyBtYXlvciwgc2lubyBxdWUgdGFtYmnDqW4gbG8gZXMgc3UgUsKyIGFqdXN0YWRvLCBtZWRpZGEgcXVlIG5vcyBwZXJtaXRlIHJlYWxpemFyIGVzdGEgY29tcGFyYWNpw7NuLiBNaWVudHJhcyBxdWUgZWwgbW9kZWxvIGFudGVyaW9yIHByZXNlbnRhYmEgdW4gUsKyIGFqdXN0YWRvIGRlIDczJSwgZXN0ZSBlcyBjYXBheiBkZSBleHBsaWNhciBlbCA4MCUgZGUgbGEgdmFyaWFibGUgZGVwZW5kaWVudGUuCgpBZGVtw6FzLCBsYSBtZWRpYW5hIGRlIHN1cyByZXNpZHVvcyBzZSBhcHJveGltYSBlbiBncmFuIG1lZGlkYSBhbCAwLCBsbyBxdWUgbm9zIGluZGljYSBxdWUgbG9zIHJlc2lkdW9zIHByZXNlbnRhbiB1bmEgZGlzdHJpYnVjacOzbiBub3JtYWwsIHVuYSBjYXJhY3RlcsOtc3RpY2EgZGVzZWFibGUgZGVzZGUgbG9zIHN1cHVlc3RvcyBkZWwgbW9kZWxvIGRlIHJlZ3Jlc2lwb24gbGluZWFsLgoKQWhvcmEgYmllbiwgZW4gY3VhbnRvIGEgbG9zIHBhcsOhbWV0cm9zLCBjYWJlIGhhY2VyIHVuYSBhY2xhcmFjacOzbjogw6lzdG9zIG5vIGRlYmVuIHJlY2liaXIgbGEgbWlzbWEgaW50ZXJwcmV0YWNpw7NuIHF1ZSBlbiBsb3MgbW9kZWxvcyBwcmV2aW9zLiAKCkVsIGhlY2hvIGRlIGFwbGljYXIgZWwgbG9nYXJpdG1vIGEgbnVlc3RyYSB2YXJpYWJsZSBpbmRlcGVuZGllbnRlIG5vcyBwZXJtaXRlIHBsYXNtYXIgZWwgZWZlY3RvIHBvcmNlbnR1YWwgY29uc3RhbnRlIHF1ZSBsYXMgdmFyaWFibGVzIGV4cGxpY2F0aXZhcyB0aWVuZW4gc29icmUgYXF1ZWxsYS4gRGUgZXN0ZSBtb2RvLCBsYSB2YXJpYWJsZSAqcG9ycGVydHlfdHlwZSosIHBvciBlamVtcGxvLCBpbmNyZW1lbnRhIGVsIHByZWNpbyB1biAwLjI4OTclIGFsIHRvbWFyIGVsIHZhbG9yIF9EZXBhcnRhbWVudG9fLgoKQSBzdSB2ZXosIGVsIHF1ZSBhIGFsZ3VuYXMgdmFyaWFibGVzIG51bcOpcmljYXMsIGNvbW8gX3Jvb21zXywgX2JhdGhyb29tc18geSAqc3VyZmFjZV9jb3ZlcmVkKiB0YW1iacOpbiBzZSBsZXMgYXBsaXF1ZSBlbCBsb2dhcml0bW8gcG9zaWJpbGl0YSBjb25zaWRlcmFyIHN1IHByb3BpbyBpbmNyZW1lbnRvIGVuIHTDqXJtaW5vcyBwb3JjZW50dWFsZXMuIEFzw60sIGVuIGVsIGNhc28gZGUgbGEgdmFyaWFibGUgKnN1cmZhY2VfY292ZXJlZCosIHBvciBlamVtcGxvLCBzdSBjb2VmaWNpZW50ZSBubyBpbmRpY2EgY3XDoW50byBhdW1lbnRhIGVsIHByZWNpbyBjdWFuZG8gbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSBzZSBpbmNyZW1lbnRhIGVuIHVuYSB1bmlkYWQgeSBlbCByZXN0byBkZSBsYXMgdmFyaWFibGVzIHNlIG1hbnRpZW5lbiBjb25zdGFudGVzLCBzaW5vIHF1ZSBlc3RpbWEgY3XDoW50byBhdW1lbnRhIGVsIHByZWNpbyBjdWFuZG8gbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSBzZSBpbmNyZW1lbnRhIGVuIHVuIDElLiBEYWRvIHF1ZSwgY29tbyB5YSBkaWppbW9zLCBlbCBlZmVjdG8gZGUgbGFzIHZhcmlhYmxlcyB0YW1iacOpbiBkZWJlIHNlciBlbnRlbmRpZG8gZW4gdMOpcm1pbm9zIHBvcmNlbnR1YWxlcywgYWwgYXVtZW50YXIgZWwgMSUgbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSwgZWwgdmFsb3IgZGUgbGEgcHJvcGllZGFkIHNlIGluY3JlbWVudGFyw6EgdW4gMC44MjI5JS4gRGUgZXN0ZSBjb2VmaWNpY2llbnRlIHNlIGRpY2UgcXVlIHJlZmxlamEgbGEgX2VsYXN0aWNpZGFkIGVzdGltYWRhXyBkZWwgcHJlY2lvIGVuIHJlbGFjacOzbiBhIGxhIHN1cGVyZmljaWUgY3ViaWVydGEuCgpFc2EgbW9kaWZpY2FjacOzbiBlbiBlbiBsYSBmw7NybXVsYSBub3MgcGVybWl0ZSBhanVzdGFyIHVuIG1vZGVsbyBtw6FzIGFkZWN1YWRvIHBhcmEgbGEgcmVhbGlkYWQsIHB1ZXN0byBxdWUgZXMgZGUgZXNwZXJhciBxdWUgZWwgYXVtZW50byBlbiBlbCBwcmVjaW8gZGUgdW5hIHByb3BpZWRhZCBubyBzZWEgdW5pZm9ybWUgcmVzcGVjdG8gZGUgbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSwgbm8gZXNwZXJhbW9zIHF1ZSBwb3IgY2FkYSBtZXRyb8KyIGHDsWFkaWRvIGxhIHByb3BpZWRhZCBhdW1lbnRlIGxhIG1pc21hIGNhbnRpZGFkIGRlIGRpbmVyby4gUG9yIGVsIGNvbnRyYXJpbywgcGFyZWNlcsOtYSBzZW5zYXRvIGVzcGVyYXIgcXVlIGxvcyBpbnVtdWVibGVzIG11eSBwZXF1ZcOxb3MsIGFsIGF1bWVudGFyIHN1IHN1cGVyZmljaWUgY3ViaWVydGEsIHR1dmllc2VuIHVuIGluY3JlbWVudG8gZGUgcHJlY2lvIG1lbm9yIGVuIHJlbGFjacOzbiBhIGFxdWVsbGFzIHByb3BpZWRhZGVzIG11eSBncmFuZGVzLiBFbCBsb2dhcml0bW8gZGUgbGEgdmFyaWFibGUgYSBleHBsaWNhciBub3MgcGVybWl0ZSByZWFsaXphciB1bmEgZXN0aW1hY2nDs24gc2VtamFudGUuCgojIDUuIE1vZGVsb3MgcG9yIHRpcG8gZGUgcHJvcGllZGFkCgpFbiBlc3RlIGFwYXJ0YWRvIHNlIGFncnVwYSBlbCBkYXRhIGZyYW1lIHBvciB0aXBvIGRlIHByb3BpZWRhZCB5IHNlIGdlbmVyYSB1bmEgbnVldmEgdGFibGEgY29uIGRvcyBjb2x1bW5hczogZW4gbGEgcHJpbWVyYSBzZSBpbmRpY2EgZWwgdGlwbyBkZSBwcm9waWVkYWQgeSBlbiBsYSBzZWd1bmRhIHNlIGFuaWRhIGVsIGRhdGEgZnJhbWUgY29ycmVzcG9uZGllbnRlLgoKYGBge3J9CnByb3BUeXBlcyA8LSBwcm9wZXJ0aWVzX2JhcnJpb3NZcGF0aW8gJT4lIAogIGdyb3VwX2J5KHByb3BlcnR5X3R5cGUpICU+JSAKICBuZXN0KCkKCnByb3BUeXBlcwpgYGAKClBhcmEgY2FkYSB0aXBvIGRlIHByb3BpZWRhZCwgc2UgZ2VuZXJhIHVuIG1vZGVsbyBpZ3VhbCBhbCBhanVzdGFkbyBwcmV2aWFtZW50ZSwgY29uIGxhcyB2YXJpYWJsZXMgX2JhcnJpb3NfIHkgKnN1cmZhY2VfcGF0aW8qLCB5IHNlIGxvIGFsbWFjZW5hIGVuIGxhIGNvbHVtbmEgX21vZGVsXy4KCmBgYHtyfQpwYXRpb19tb2RlbCA8LSBmdW5jdGlvbihkZikgewogIGxtKHByaWNlIH4gYmFycmlvcyArIHJvb21zICsgYmF0aHJvb21zICsgc3VyZmFjZV9jb3ZlcmVkICsgc3VyZmFjZV9wYXRpbywgZGF0YT1kZikKfQoKcHJvcFR5cGVzIDwtIHByb3BUeXBlcyAlPiUgCiAgbXV0YXRlKG1vZGVsID0gbWFwKGRhdGEsIHBhdGlvX21vZGVsKSkKCnByb3BUeXBlcwpgYGAKCkNvbiBlbCBmaW4gZGUgY29tcGFyYXIgbG9zIGRpc3RpbnRvcyBtb2RlbG9zLCBzZSB1dGlsaXphIGxhIGZ1bmNpw7NuICpnZXRfY29lZmZpY2llbnRzKiBhcXXDrSBkZWZpbmlkYSB5IGxhcyBmdW5jaW9uZXMgKmdsYW5jZSogeSAqYXVnbWVudCosIGRlbCBwYXF1ZXRlIF9icm9vbV8uIExhIHByaW1lcmEgbXVlc3RyYSBsb3MgY29lZmljaWVudGVzIGVzdGltYWRvcyBkZSBjYWRhIG1vZGVsbywgbGEgc2VndW5kYSBwZXJtaXRlIHZpc3VhaXphciBpbmZvcm1hY2nDs24gcmVsYXRpdmEgYWwgUsKyLCBSwrIgYWp1c3RhZG8geSBlbCBkZXN2w61vIGVzdMOhbmRhciBkZSBsb3MgcmVzaWR1b3MgKHNpZ21hKSwgeSBsYSDDumx0aW1hIG5vcyBicmluZGEgaW5mb3JtYWNpw7NuIG3DoXMgZGV0YWxsYWRhIGRlIGVzdG9zIMO6bHRpbW9zLCBsbyBxdWUgbm9zIHBlcm1pdGlyw6Egb2JzZXJ2YXIgc3UgZGlzdHJpYnVjacOzbi4KCmBgYHtyfQpzdW1tYXJ5KHByb3BUeXBlcyRtb2RlbFtbMV1dKSAgICMgZGF0b3MgZGVsIG1vZGVsbyBDYXNhCnN1bW1hcnkocHJvcFR5cGVzJG1vZGVsW1syXV0pICAgIyBkYXRvcyBkZWwgbW9kZWxvIERlcGFydGFtZW50bwpzdW1tYXJ5KHByb3BUeXBlcyRtb2RlbFtbM11dKSAgICMgZGF0b3MgZGVsIG1vZGVsbyBQSApgYGAKCkNvbW8gdW5hIHByaW1lcmEgZ3JhbiBkaWZlcmVuY2lhIGVudHJlIGxvcyB0cmVzIG1vZGVsb3MgZ2VuZXJhZG9zICh5IHRhbWJpw6luIGNvbiByZXNwZWN0byBhIGxvcyBhbnRlcmlvcmVzKSwgdmVtb3MgcXVlIGxhIHZhcmlhYmxlIF9yb29tc18gc29sbyB0aWVuZSB1bmEgaW5mbHVlbmNpYSBuZWdhdGl2YSBzb2JyZSBlbCBwcmVjaW8gZW4gZWwgbW9kZWxvIGRlIERlcGFydGFtZW50b3MuIEVuIGxvcyBkZW3DoXMgY2Fzb3MgaGEgcGFzYWRvIGEgc2VyIHBvc2l0aXZhLCBsbyBxdWUgaW5kaWNhIHF1ZSBlbCBwcmVjaW8gYXVtZW50YXLDoSBjb25mb3JtZSBsbyBoYWdhIGxhIGNhbnRpZGFkIGRlIGhhYml0YWNpb25lcyBkZSBsYSBwcm9waWVkYWQuCgpQb3Igb3RybyBsYWRvLCBzaSBvYnNlcnZhbW9zIGxvcyBSwrIgZGUgY2FkYSB1bm8gZGUgbG9zIG1vZGVsb3MsIHZlbW9zIHF1ZSBlbCBxdWUgbWVqb3Igc2UgYWp1c3RhIHRhbWJpw6luIGVzIGVsIG1vZGVsbyBkZSBEZXBhcnRhbWVudG9zLCBjdXlhcyB2YXJpYWJsZXMgaW5kZXBlbmRpZW50ZXMgbGxldmFuIGEgZXhwbGljYXIgY2FzaSBlbCA3NiUgZGUgbGEgdmFyaWFiaWxpZGFkIGRlIFkuIEVuIHNlZ3VkbyBsdWdhciBzZSB1YmljYSBlbCBtb2RlbG8gZGUgUEggY29uIGNhc2kgZWwgNjYlIHkgw7psdGltbywgZWwgZGUgQ2FzYSBjb24gYXByb3hpbWFkYW1lbnRlIGUgNTUlLiAKCkVzdG8gZXMgY29uc2lzdGVudGUgY29uIGxvcyB2YWxvcmVzIGRlIGRlc3bDrW9zIGVzdMOhbmRhcmVzIG9ic2VydmFkb3MsIGVuIGxvcyBxdWUgZWwgbW9kZWxvIGRlIENhc2EgcHJlc2VudGEgZWwgbWF5b3IgZGVzdsOtbyB5IGVsIGRlIFBIcywgZWwgbWVub3IuIEFkaWNpb25hbG1lbnRlLCBsYSB0YWJsYSBhIGNvbnRpbnVhY2nDs24gY29uZmlybWEgcXVlLCBkZSBsb3MgdHJlcyBtb2RlbG9zLCBlcyBlc3RlIMO6bHRpbW8gZWwgcXVlIHByZXNlbnRhIHVuYSBkaXN0cmlidWNpw7NuIG3DoXMgY2VyY2FuYSBhIGxhIG5vcm1hbC4=
 

Hecho por Macarena Fernandez Urquiza

m.fernandezurquiza@gmail.com