install.packages("tidyverse")
library("tidyverse")
library(dplyr)
library(tidyr)
library(ggplot2)
library(lubridate)
library(knitr)
library(markdown)
install.packages("corrplot")
library("corrplot")
install.packages("car")
library("car")
install.packages("ggpubr")
library("ggpubr")

install.packages("GGally")

library("GGally")



library(tidyverse)
library(modelr)
install.packages("plotly")
library("plotly")

1-Preparacion de los datos (I) a-

propiedad<-read_csv(file="C:/Users/PC/Desktop/EE/TP1/ar_properties.csv")
Parsed with column specification:
cols(
  .default = col_character(),
  start_date = col_date(format = ""),
  end_date = col_date(format = ""),
  created_on = col_date(format = ""),
  lat = col_double(),
  lon = col_double(),
  l6 = col_logical(),
  rooms = col_double(),
  bedrooms = col_double(),
  bathrooms = col_double(),
  surface_total = col_double(),
  surface_covered = col_double(),
  price = col_double()
)
See spec(...) for full column specifications.
prop=data.frame(propiedad)
glimpse(propiedad)
Observations: 388,891
Variables: 24
$ id              <chr> "S0we3z3V2JpHUJreqQ2t/w==", "kMxcmAS8NvrynGBVbMOEaQ=="...
$ ad_type         <chr> "Propiedad", "Propiedad", "Propiedad", "Propiedad", "P...
$ start_date      <date> 2019-04-14, 2019-04-14, 2019-04-14, 2019-04-14, 2019-...
$ end_date        <date> 2019-06-14, 2019-04-16, 9999-12-31, 9999-12-31, 2019-...
$ created_on      <date> 2019-04-14, 2019-04-14, 2019-04-14, 2019-04-14, 2019-...
$ lat             <dbl> -34.94331, -34.63181, NA, -34.65471, -34.65495, -32.93...
$ lon             <dbl> -54.92966, -58.42060, NA, -58.79089, -58.78712, -60.68...
$ l1              <chr> "Uruguay", "Argentina", "Argentina", "Argentina", "Arg...
$ l2              <chr> "Maldonado", "Capital Federal", "Bs.As. G.B.A. Zona No...
$ l3              <chr> "Punta del Este", "Boedo", NA, "Moreno", "Moreno", "Ro...
$ l4              <chr> NA, NA, NA, "Moreno", "Moreno", NA, "Ituzaingó", NA, N...
$ l5              <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ l6              <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ rooms           <dbl> 2, NA, 2, 2, 2, 4, NA, 6, NA, NA, NA, NA, NA, NA, NA, ...
$ bedrooms        <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ bathrooms       <dbl> 1, NA, 1, 2, 3, 1, 3, 3, NA, NA, NA, NA, NA, NA, NA, N...
$ surface_total   <dbl> 45, NA, 200, 460, 660, NA, 70, NA, 1300, 405, 352, 373...
$ surface_covered <dbl> 40, NA, NA, 100, 148, 89, 122, NA, NA, NA, NA, NA, NA,...
$ price           <dbl> 13000, 0, NA, NA, NA, NA, NA, NA, 0, NA, 0, NA, NA, NA...
$ currency        <chr> "UYU", NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA,...
$ price_period    <chr> "Mensual", "Mensual", NA, "Mensual", "Mensual", "Mensu...
$ title           <chr> "Departamento - Roosevelt", "PH - Boedo", "Ituzaingo  ...
$ property_type   <chr> "Departamento", "PH", "Casa", "Casa", "Casa", "Casa", ...
$ operation_type  <chr> "Alquiler", "Venta", "Alquiler", "Venta", "Venta", "Ve...

b,c-Filtrado de datos y seleccion de varialbes Se filtran registros que pertenecen a Argentina y capital federal, cuyo precio esta en dolares(USD), el tipo de propiedad es Departamento, PH, ? Casa; y el tipo de operacion es Venta. Se seleccinan las variables id, l3, rooms, beedrooms, bathrooms, surfece_total, surface_covered, price y property_type.

datofil <- prop %>%
  filter( l1 == "Argentina",
          l2 == "Capital Federal",
          currency == "USD",
          property_type %in% c("Departamento", "PH", "Casa"),
          operation_type =="Venta"
          ) %>%
  select("id", "l3", "rooms", "bedrooms", "bathrooms", "surface_total", "surface_covered", "price","property_type")
glimpse(datofil)
Observations: 61,905
Variables: 9
$ id              <chr> "oyj+f764ALCYodIqBvWAww==", "HdjpKrqdwYfH9YU1DKjltg=="...
$ l3              <chr> "Barracas", "Boedo", "Palermo", "Belgrano", "Versalles...
$ rooms           <dbl> NA, 6, NA, 3, NA, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
$ bedrooms        <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA...
$ bathrooms       <dbl> NA, 2, 2, 4, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
$ surface_total   <dbl> 300, 178, 240, 157, 140, 95, 44, 40, 49, 40, 40, 40, 4...
$ surface_covered <dbl> 180, 240, 157, NA, 110, 69, 38, 37, 44, 37, 37, 37, 44...
$ price           <dbl> 320000, 500000, 350000, 470000, 155000, 199900, 147000...
$ property_type   <chr> "PH", "Casa", "Casa", "Casa", "Casa", "Casa", "Departa...

2-Analisis exploratorios (I)

Se obtienen la cantidad de valores únicos

unicos<-function(x)length(unique(x))
datounico <- datofil %>%
        dplyr::summarise_all(list(unicos = unicos)) %>%
             t()
datounico
                        [,1]
id_unicos              61905
l3_unicos                 58
rooms_unicos              24
bedrooms_unicos           25
bathrooms_unicos          15
surface_total_unicos     671
surface_covered_unicos   573
price_unicos            4095
property_type_unicos       3
    

Se Obtienen la cantidad de valores faltantes

sapply(datofil, function(x) sum(is.na(x)))
             id              l3           rooms        bedrooms       bathrooms 
              0             355            5314           25298            3196 
  surface_total surface_covered           price   property_type 
           3671            2975               0               0 
rs<-round(cor(datofil[,3:8],use="complete.obs"),3)
rs
                rooms bedrooms bathrooms surface_total surface_covered price
rooms           1.000    0.921     0.613         0.068           0.075 0.487
bedrooms        0.921    1.000     0.616         0.067           0.072 0.432
bathrooms       0.613    0.616     1.000         0.062           0.068 0.599
surface_total   0.068    0.067     0.062         1.000           0.697 0.051
surface_covered 0.075    0.072     0.068         0.697           1.000 0.063
price           0.487    0.432     0.599         0.051           0.063 1.000

3-Preparacion de los datos(II) Se elimina la variable bedrooms por estar muy correlacionada con rooms y presentar muchos NAs. Luego se eliminan NAs

data<-datofil[,-4]%>%na.omit(datofinal)
glimpse(data)
Observations: 51,210
Variables: 8
$ id              <chr> "HdjpKrqdwYfH9YU1DKjltg==", "AfdcsqUSelai1ofCAq2B0Q=="...
$ l3              <chr> "Boedo", "Velez Sarsfield", "Nuñez", "Almagro", "Almag...
$ rooms           <dbl> 6, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, ...
$ bathrooms       <dbl> 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, ...
$ surface_total   <dbl> 178, 95, 44, 40, 49, 40, 40, 40, 49, 40, 23, 40, 40, 3...
$ surface_covered <dbl> 240, 69, 38, 37, 44, 37, 37, 37, 44, 37, 23, 37, 37, 3...
$ price           <dbl> 500000, 199900, 147000, 92294, 115000, 77000, 88900, 8...
$ property_type   <chr> "Casa", "Casa", "Departamento", "Departamento", "Depar...

4-Analisis exploratorio (II) a.Estadistica descriptiva de todas las variables

sapply(data[,3:7], function(x) mean(x))
          rooms       bathrooms   surface_total surface_covered           price 
        2.80082         1.50043       101.70801        85.45626    251577.21804 
sapply(data[,3:7], function(x) max(x))
          rooms       bathrooms   surface_total surface_covered           price 
             32              14          126062          126062         6000000 
sapply(data[,3:7], function(x) min(x))
          rooms       bathrooms   surface_total surface_covered           price 
              1               1              10               2            6000 
sapply(data[,3:7], function(x) quantile(x))
     rooms bathrooms surface_total surface_covered   price
0%       1         1            10               2    6000
25%      2         1            45              40  119000
50%      3         1            66              59  170000
75%      4         2           106              91  270000
100%    32        14        126062          126062 6000000

Se puede observar datos atipicos, en el caso del cuantil de mayor precio se ve datos que posiblemente sean outliers ya que 32 habitaciones, 14 baños y 126062 metros cuadrados no pareceria corresponder a una casa PH o departamento.

summary((data$price))# estadisticas descriptivas de variable precio
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   6000  119000  170000  251577  270000 6000000 

Histrogra de la variable precio

ggplot(data, aes(x=price)) +
  ggtitle('Price histogram') +
  xlab('price') +
  ylab('frequency') +
  geom_histogram(fill='red', alpha=0.75, bins=30 )

b-Estadistica descriptiva para la variable precio por cadad tipo de ropiedad (cuartiles, mean, minimo y maximo)

data %>% 
  group_by(property_type) %>%
  summarise(mean = mean(price),
            primerq = quantile(price, 0.25),
            mediana = median(price),
            tercerq = quantile(price, 0.75),
            max = max(price)
            )

c-Boxplot

ggplot(data, aes(x = property_type, y =  price, group = property_type, fill = property_type )) +
  geom_boxplot()+
  scale_y_continuous(limits = c(0, 6100000))

Del Boxplot se pueden observar valores atípicos.

d.Correlograma

library(GGally)
data2<-data[,3:8]
data2%>%ggpairs(., 
          title = "Correlograma",
          mapping = aes(colour= property_type)
  )

Se puede observar que la mayoría de los datos corresponden a departamentos.

5-Outliers

Genero nuevas variables donde analizo las relaciones precio superficie cubierta y precio room

datain <- data %>%
  mutate(Indices=price/surface_covered)
datain <- datain %>%
  mutate(Indicer=price/rooms)
head(datain)

Considerando que en el mercado inmobiliario se utiliza precio por metro cuadrado, se procede a filtrar los datos utilizando la informacón de valores minimos y maximos de precio m2(USD) para eliminar outliers. Luego se aplica otro filtrado considerando la superficie total y que la superficie cubierta no sea mayor a la supeficie total declarada.

Filtrado Indice price/suface_covered , tambien agrego filtrado por superficie y los casos donde la superficie total sea menor que la superficie cubierta

dataout<-filter(datain, Indices>=900,Indices<=6700)# al observarse alguno datos anómalos se agrega otro filtrado
dataout<-filter(dataout,surface_total<2500,surface_total>=surface_covered)
glimpse(dataout)
Observations: 49,680
Variables: 10
$ id              <chr> "AfdcsqUSelai1ofCAq2B0Q==", "ESzybdH7YU2uIU1/kHtRGw=="...
$ l3              <chr> "Velez Sarsfield", "Nuñez", "Almagro", "Almagro", "Alm...
$ rooms           <dbl> 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, ...
$ bathrooms       <dbl> 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, ...
$ surface_total   <dbl> 95, 44, 40, 49, 40, 40, 40, 49, 40, 23, 40, 40, 32, 40...
$ surface_covered <dbl> 69, 38, 37, 44, 37, 37, 37, 44, 37, 23, 37, 37, 30, 34...
$ price           <dbl> 199900, 147000, 92294, 115000, 77000, 88900, 88798, 11...
$ property_type   <chr> "Casa", "Departamento", "Departamento", "Departamento"...
$ Indices         <dbl> 2897.101, 3868.421, 2494.432, 2613.636, 2081.081, 2402...
$ Indicer         <dbl> 66633.33, 147000.00, 92294.00, 115000.00, 77000.00, 88...

luego del filtrado quedaron 49680 Observaciones

6-Análisis Exploratorio(III)

a.Estadistica descriptiva de todas las variables

mean1<-round(sapply(dataout[,3:7], function(x) mean(x)),3)
mean1
          rooms       bathrooms   surface_total surface_covered           price 
          2.776           1.473          89.226          76.599      231601.769 
max1<-sapply(dataout[,3:7], function(x) max(x))
max1
          rooms       bathrooms   surface_total surface_covered           price 
             32              14            2000            1400         5000000 
min1<-round(sapply(dataout[,3:7], function(x) min(x)),3)
min1
          rooms       bathrooms   surface_total surface_covered           price 
              1               1              12              12           12000 
quantile1<-round(sapply(dataout[,3:7], function(x) quantile(x)),3)
quantile1
     rooms bathrooms surface_total surface_covered   price
0%       1         1            12              12   12000
25%      2         1            45              40  118000
50%      3         1            65              58  168725
75%      4         2           103              89  265000
100%    32        14          2000            1400 5000000
summary((dataout$price))# estadisticas descriptivas de variable precio
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  12000  118000  168725  231602  265000 5000000 

Histograma de la variable precio filtrado

ggplot(dataout, aes(x=price)) +
  ggtitle('Price histogram') +
  xlab('price') +
  ylab('frequency') +
  geom_histogram(fill='red', alpha=0.75, bins=30 )

b-Estadisticas descriptivas por cada tipo de propiedad

dataout %>% 
  group_by(property_type) %>%
  summarise(mean = mean(price),
            primerq = quantile(price, 0.25),
            mediana = median(price),
            tercerq = quantile(price, 0.75),
            max = max(price)
            )

c-Boxplot

ggplot(dataout, aes(x = property_type, y =  price, group = property_type, fill = property_type )) +
  geom_boxplot()+
  scale_y_continuous(limits = c(0, 5100000))

d-Correlograma

dataout2<-dataout[,3:8]
dataout2%>%ggpairs(., 
          title = "Correlograma datos sin outliers",
          mapping = aes(colour= property_type)
  )

7-Modelo lineal a y b.Se analizan dos modelos lineales simples, uno para explicar el precio en funcion de las habitaciones y otro modelo que explica el precio en funcion de la superficie total.

modsup<-lm(price~surface_total, data=dataout)
modroom<-lm(price~rooms, data=dataout)
summary(modsup)

Call:
lm(formula = price ~ surface_total, data = dataout)

Residuals:
     Min       1Q   Median       3Q      Max 
-3334324   -43509   -17378    21969  2173949 

Coefficients:
              Estimate Std. Error t value Pr(>|t|)    
(Intercept)   51693.22     979.00    52.8   <2e-16 ***
surface_total  2016.32       8.24   244.7   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 144100 on 49678 degrees of freedom
Multiple R-squared:  0.5465,    Adjusted R-squared:  0.5465 
F-statistic: 5.988e+04 on 1 and 49678 DF,  p-value: < 2.2e-16

Según los resultados obtenidos del primer modelo (precio en función de la superficie total, el B0 es 51693.22, corresponde a la ordenada al origen. El B1 del modelo es 2016,32 corresponde al aumento de precio del inmueble en dolares al aumentar cada metro2 de la superficie total.

ggplot(dataout, aes(surface_total, price)) + 
  geom_point(size=1, color = "pink") + 
  geom_smooth(method = 'lm') +
  labs(title = "Precios en funcion de Superficie Total", x = "Superficie total (m2)", y = "Precio (USD)") +
  theme(plot.title = element_text(hjust = 0.5))

summary(modroom)

Call:
lm(formula = price ~ rooms, data = dataout)

Residuals:
     Min       1Q   Median       3Q      Max 
-2372940   -78784   -19979    40021  4090775 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -28826.6     1742.3  -16.55   <2e-16 ***
rooms        93805.2      563.1  166.58   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 171400 on 49678 degrees of freedom
Multiple R-squared:  0.3584,    Adjusted R-squared:  0.3584 
F-statistic: 2.775e+04 on 1 and 49678 DF,  p-value: < 2.2e-16

Los resultados obtenidos del segundo modelo (precio en funcion de room), el B0 es -28826,6 este valor corresponde a la ordenada al origen (precio promedio de una propiedad cuya superficie total es 0). El B1 del modelo es 93805,2, corresponde al aumento de precio del inmueble en dolares al aumentar cada habitación.

ggplot(dataout, aes(rooms, price)) + 
  geom_point(size=1, color = "pink") + 
  geom_smooth(method = 'lm') +
  labs(title = "Precios en funcion de Habitaciones", x = "Habitaciones", y = "Precio (USD)") +
  theme(plot.title = element_text(hjust = 0.5))

7 c.Conclusion: Analizando los R2 de ambos modelos se podria decir que el modelo de precio en funcion de la superficie total logra explicar mayor proporcion de la variabilidad de los precios , su R2 es de 0.5465 versus el R2 del modelo por habitacion que dio 0.3584.

LS0tDQp0aXRsZTogIlRQIDE6IEFuYWxpc2lzIGV4cGxvcmF0b3JpbyBlIEludHJvZHVjY2lvbiBhIFJlZ3Jlc2k/biBsaW5lYWwiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCmxpYnJhcnkoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkobHVicmlkYXRlKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkobWFya2Rvd24pDQppbnN0YWxsLnBhY2thZ2VzKCJjb3JycGxvdCIpDQpsaWJyYXJ5KCJjb3JycGxvdCIpDQppbnN0YWxsLnBhY2thZ2VzKCJjYXIiKQ0KbGlicmFyeSgiY2FyIikNCmluc3RhbGwucGFja2FnZXMoImdncHViciIpDQpsaWJyYXJ5KCJnZ3B1YnIiKQ0KDQppbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQ0KDQpsaWJyYXJ5KCJHR2FsbHkiKQ0KDQoNCg0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KG1vZGVscikNCmluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQpsaWJyYXJ5KCJwbG90bHkiKQ0KDQoNCg0KYGBgDQoNCjEtUHJlcGFyYWNpb24gZGUgbG9zIGRhdG9zIChJKQ0KYS0NCmBgYHtyfQ0KcHJvcGllZGFkPC1yZWFkX2NzdihmaWxlPSJDOi9Vc2Vycy9QQy9EZXNrdG9wL0VFL1RQMS9hcl9wcm9wZXJ0aWVzLmNzdiIpDQpwcm9wPWRhdGEuZnJhbWUocHJvcGllZGFkKQ0KZ2xpbXBzZShwcm9waWVkYWQpDQoNCmBgYA0KDQpiLGMtRmlsdHJhZG8gZGUgZGF0b3MgeSBzZWxlY2Npb24gZGUgdmFyaWFsYmVzDQpTZSBmaWx0cmFuIHJlZ2lzdHJvcyBxdWUgcGVydGVuZWNlbiBhIEFyZ2VudGluYSB5IGNhcGl0YWwgZmVkZXJhbCwgY3V5byBwcmVjaW8gZXN0YSBlbiBkb2xhcmVzKFVTRCksIGVsIHRpcG8gZGUgcHJvcGllZGFkIGVzIERlcGFydGFtZW50bywgUEgsID8gQ2FzYTsgeSBlbCB0aXBvIGRlIG9wZXJhY2lvbiBlcyBWZW50YS4NClNlIHNlbGVjY2luYW4gbGFzIHZhcmlhYmxlcyBpZCwgbDMsIHJvb21zLCBiZWVkcm9vbXMsIGJhdGhyb29tcywgc3VyZmVjZV90b3RhbCwgc3VyZmFjZV9jb3ZlcmVkLCBwcmljZSB5IHByb3BlcnR5X3R5cGUuDQpgYGB7cn0NCg0KZGF0b2ZpbCA8LSBwcm9wICU+JQ0KICBmaWx0ZXIoIGwxID09ICJBcmdlbnRpbmEiLA0KICAgICAgICAgIGwyID09ICJDYXBpdGFsIEZlZGVyYWwiLA0KICAgICAgICAgIGN1cnJlbmN5ID09ICJVU0QiLA0KICAgICAgICAgIHByb3BlcnR5X3R5cGUgJWluJSBjKCJEZXBhcnRhbWVudG8iLCAiUEgiLCAiQ2FzYSIpLA0KICAgICAgICAgIG9wZXJhdGlvbl90eXBlID09IlZlbnRhIg0KICAgICAgICAgICkgJT4lDQogIHNlbGVjdCgiaWQiLCAibDMiLCAicm9vbXMiLCAiYmVkcm9vbXMiLCAiYmF0aHJvb21zIiwgInN1cmZhY2VfdG90YWwiLCAic3VyZmFjZV9jb3ZlcmVkIiwgInByaWNlIiwicHJvcGVydHlfdHlwZSIpDQpnbGltcHNlKGRhdG9maWwpDQoNCg0KYGBgDQoNCjItQW5hbGlzaXMgZXhwbG9yYXRvcmlvcyAoSSkNCg0KU2Ugb2J0aWVuZW4gbGEgY2FudGlkYWQgZGUgdmFsb3JlcyDDum5pY29zDQpgYGB7cn0NCnVuaWNvczwtZnVuY3Rpb24oeClsZW5ndGgodW5pcXVlKHgpKQ0KDQpkYXRvdW5pY28gPC0gZGF0b2ZpbCAlPiUNCiAgICAgICAgZHBseXI6OnN1bW1hcmlzZV9hbGwobGlzdCh1bmljb3MgPSB1bmljb3MpKSAlPiUNCiAgICAgICAgICAgICB0KCkNCg0KZGF0b3VuaWNvDQogICAgDQoNCmBgYA0KDQoNClNlIE9idGllbmVuIGxhIGNhbnRpZGFkIGRlIHZhbG9yZXMgZmFsdGFudGVzDQpgYGB7cn0NCg0Kc2FwcGx5KGRhdG9maWwsIGZ1bmN0aW9uKHgpIHN1bShpcy5uYSh4KSkpDQoNCg0KDQpgYGANCg0KYGBge3J9DQoNCnJzPC1yb3VuZChjb3IoZGF0b2ZpbFssMzo4XSx1c2U9ImNvbXBsZXRlLm9icyIpLDMpDQpycw0KDQoNCmBgYA0KDQoNCjMtUHJlcGFyYWNpb24gZGUgbG9zIGRhdG9zKElJKQ0KU2UgZWxpbWluYSBsYSB2YXJpYWJsZSBiZWRyb29tcyBwb3IgZXN0YXIgbXV5IGNvcnJlbGFjaW9uYWRhIGNvbiByb29tcyB5IHByZXNlbnRhciBtdWNob3MgTkFzLg0KTHVlZ28gc2UgZWxpbWluYW4gTkFzDQpgYGB7cn0NCg0KZGF0YTwtZGF0b2ZpbFssLTRdJT4lbmEub21pdChkYXRvZmluYWwpDQpnbGltcHNlKGRhdGEpDQoNCmBgYA0KDQoNCjQtQW5hbGlzaXMgZXhwbG9yYXRvcmlvIChJSSkNCiBhLkVzdGFkaXN0aWNhIGRlc2NyaXB0aXZhIGRlIHRvZGFzIGxhcyB2YXJpYWJsZXMNCmBgYHtyfQ0Kc2FwcGx5KGRhdGFbLDM6N10sIGZ1bmN0aW9uKHgpIG1lYW4oeCkpDQoNCg0KYGBgDQogDQpgYGB7cn0NCnNhcHBseShkYXRhWywzOjddLCBmdW5jdGlvbih4KSBtYXgoeCkpDQpgYGANCg0KYGBge3J9DQpzYXBwbHkoZGF0YVssMzo3XSwgZnVuY3Rpb24oeCkgbWluKHgpKQ0KYGBgDQoNCmBgYHtyfQ0Kc2FwcGx5KGRhdGFbLDM6N10sIGZ1bmN0aW9uKHgpIHF1YW50aWxlKHgpKQ0KYGBgDQogDQpTZSBwdWVkZSBvYnNlcnZhciBkYXRvcyBhdGlwaWNvcywgZW4gZWwgY2FzbyBkZWwgY3VhbnRpbCBkZSBtYXlvciBwcmVjaW8gc2UgdmUgZGF0b3MgcXVlIHBvc2libGVtZW50ZSBzZWFuIG91dGxpZXJzIHlhIHF1ZSAzMiBoYWJpdGFjaW9uZXMsIDE0IGJhw7FvcyB5IDEyNjA2MiBtZXRyb3MgY3VhZHJhZG9zIG5vIHBhcmVjZXJpYSBjb3JyZXNwb25kZXIgYSB1bmEgY2FzYSBQSCBvIGRlcGFydGFtZW50by4NCiANCiANCmBgYHtyfQ0Kc3VtbWFyeSgoZGF0YSRwcmljZSkpIyBlc3RhZGlzdGljYXMgZGVzY3JpcHRpdmFzIGRlIHZhcmlhYmxlIHByZWNpbw0KYGBgDQogDQogSGlzdHJvZ3JhICBkZSBsYSB2YXJpYWJsZSBwcmVjaW8NCmBgYHtyfQ0KDQpnZ3Bsb3QoZGF0YSwgYWVzKHg9cHJpY2UpKSArDQogIGdndGl0bGUoJ1ByaWNlIGhpc3RvZ3JhbScpICsNCiAgeGxhYigncHJpY2UnKSArDQogIHlsYWIoJ2ZyZXF1ZW5jeScpICsNCiAgZ2VvbV9oaXN0b2dyYW0oZmlsbD0ncmVkJywgYWxwaGE9MC43NSwgYmlucz0zMCApDQoNCg0KYGBgDQoNCmItRXN0YWRpc3RpY2EgZGVzY3JpcHRpdmEgcGFyYSBsYSB2YXJpYWJsZSBwcmVjaW8gcG9yIGNhZGFkIHRpcG8gZGUgcm9waWVkYWQgKGN1YXJ0aWxlcywgbWVhbiwgbWluaW1vIHkgbWF4aW1vKQ0KYGBge3J9DQpkYXRhICU+JSANCiAgZ3JvdXBfYnkocHJvcGVydHlfdHlwZSkgJT4lDQogIHN1bW1hcmlzZShtZWFuID0gbWVhbihwcmljZSksDQogICAgICAgICAgICBwcmltZXJxID0gcXVhbnRpbGUocHJpY2UsIDAuMjUpLA0KICAgICAgICAgICAgbWVkaWFuYSA9IG1lZGlhbihwcmljZSksDQogICAgICAgICAgICB0ZXJjZXJxID0gcXVhbnRpbGUocHJpY2UsIDAuNzUpLA0KICAgICAgICAgICAgbWF4ID0gbWF4KHByaWNlKQ0KICAgICAgICAgICAgKQ0KDQoNCmBgYA0KDQpjLUJveHBsb3QNCmBgYHtyfQ0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gcHJvcGVydHlfdHlwZSwgeSA9ICBwcmljZSwgZ3JvdXAgPSBwcm9wZXJ0eV90eXBlLCBmaWxsID0gcHJvcGVydHlfdHlwZSApKSArDQogIGdlb21fYm94cGxvdCgpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA2MTAwMDAwKSkNCg0KDQoNCmBgYA0KDQpEZWwgQm94cGxvdCBzZSBwdWVkZW4gb2JzZXJ2YXIgdmFsb3JlcyBhdMOtcGljb3MuDQoNCmQuQ29ycmVsb2dyYW1hDQpgYGB7cn0NCmxpYnJhcnkoR0dhbGx5KQ0KZGF0YTI8LWRhdGFbLDM6OF0NCmRhdGEyJT4lZ2dwYWlycyguLCANCiAgICAgICAgICB0aXRsZSA9ICJDb3JyZWxvZ3JhbWEiLA0KICAgICAgICAgIG1hcHBpbmcgPSBhZXMoY29sb3VyPSBwcm9wZXJ0eV90eXBlKQ0KICApDQoNCg0KDQpgYGANCg0KU2UgcHVlZGUgb2JzZXJ2YXIgcXVlIGxhIG1heW9yw61hIGRlIGxvcyBkYXRvcyBjb3JyZXNwb25kZW4gYSBkZXBhcnRhbWVudG9zLg0KDQoNCjUtT3V0bGllcnMNCg0KR2VuZXJvIG51ZXZhcyB2YXJpYWJsZXMgZG9uZGUgYW5hbGl6byBsYXMgcmVsYWNpb25lcyBwcmVjaW8gc3VwZXJmaWNpZSBjdWJpZXJ0YSB5IHByZWNpbyByb29tDQpgYGB7cn0NCg0KZGF0YWluIDwtIGRhdGEgJT4lDQogIG11dGF0ZShJbmRpY2VzPXByaWNlL3N1cmZhY2VfY292ZXJlZCkNCmRhdGFpbiA8LSBkYXRhaW4gJT4lDQogIG11dGF0ZShJbmRpY2VyPXByaWNlL3Jvb21zKQ0KaGVhZChkYXRhaW4pDQoNCg0KYGBgDQogDQpDb25zaWRlcmFuZG8gcXVlIGVuIGVsIG1lcmNhZG8gaW5tb2JpbGlhcmlvIHNlIHV0aWxpemEgcHJlY2lvIHBvciBtZXRybyBjdWFkcmFkbywgc2UgcHJvY2VkZSBhIGZpbHRyYXIgbG9zIGRhdG9zIHV0aWxpemFuZG8gbGEgaW5mb3JtYWPDs24gZGUgdmFsb3JlcyBtaW5pbW9zIHkgbWF4aW1vcyBkZSBwcmVjaW8gbTIoVVNEKSBwYXJhIGVsaW1pbmFyIG91dGxpZXJzLg0KTHVlZ28gc2UgYXBsaWNhIG90cm8gZmlsdHJhZG8gY29uc2lkZXJhbmRvIGxhIHN1cGVyZmljaWUgdG90YWwgeSBxdWUgbGEgc3VwZXJmaWNpZSBjdWJpZXJ0YSBubyBzZWEgbWF5b3IgYSBsYSBzdXBlZmljaWUgdG90YWwgZGVjbGFyYWRhLg0KDQogDQpGaWx0cmFkbyAgSW5kaWNlIHByaWNlL3N1ZmFjZV9jb3ZlcmVkICwgdGFtYmllbiBhZ3JlZ28gZmlsdHJhZG8gcG9yIHN1cGVyZmljaWUgeSBsb3MgY2Fzb3MgZG9uZGUgbGEgc3VwZXJmaWNpZSB0b3RhbCBzZWEgbWVub3IgcXVlIGxhIHN1cGVyZmljaWUgY3ViaWVydGENCmBgYHtyfQ0KDQpkYXRhb3V0PC1maWx0ZXIoZGF0YWluLCBJbmRpY2VzPj05MDAsSW5kaWNlczw9NjcwMCkjIGFsIG9ic2VydmFyc2UgYWxndW5vIGRhdG9zIGFuw7NtYWxvcyBzZSBhZ3JlZ2Egb3RybyBmaWx0cmFkbw0KZGF0YW91dDwtZmlsdGVyKGRhdGFvdXQsc3VyZmFjZV90b3RhbDwyNTAwLHN1cmZhY2VfdG90YWw+PXN1cmZhY2VfY292ZXJlZCkNCmdsaW1wc2UoZGF0YW91dCkNCg0KDQpgYGANCg0KbHVlZ28gZGVsIGZpbHRyYWRvIHF1ZWRhcm9uIDQ5NjgwIE9ic2VydmFjaW9uZXMNCg0KNi1BbsOhbGlzaXMgRXhwbG9yYXRvcmlvKElJSSkgDQoNCg0KIGEuRXN0YWRpc3RpY2EgZGVzY3JpcHRpdmEgZGUgdG9kYXMgbGFzIHZhcmlhYmxlcw0KYGBge3J9DQptZWFuMTwtcm91bmQoc2FwcGx5KGRhdGFvdXRbLDM6N10sIGZ1bmN0aW9uKHgpIG1lYW4oeCkpLDMpDQptZWFuMQ0KDQpgYGANCiANCmBgYHtyfQ0KbWF4MTwtc2FwcGx5KGRhdGFvdXRbLDM6N10sIGZ1bmN0aW9uKHgpIG1heCh4KSkNCm1heDENCg0KDQpgYGANCg0KYGBge3J9DQptaW4xPC1yb3VuZChzYXBwbHkoZGF0YW91dFssMzo3XSwgZnVuY3Rpb24oeCkgbWluKHgpKSwzKQ0KbWluMQ0KYGBgDQoNCmBgYHtyfQ0KcXVhbnRpbGUxPC1yb3VuZChzYXBwbHkoZGF0YW91dFssMzo3XSwgZnVuY3Rpb24oeCkgcXVhbnRpbGUoeCkpLDMpDQpxdWFudGlsZTENCmBgYA0KDQoNCmBgYHtyfQ0Kc3VtbWFyeSgoZGF0YW91dCRwcmljZSkpIyBlc3RhZGlzdGljYXMgZGVzY3JpcHRpdmFzIGRlIHZhcmlhYmxlIHByZWNpbw0KYGBgDQoNCg0KDQpIaXN0b2dyYW1hIGRlIGxhIHZhcmlhYmxlIHByZWNpbyBmaWx0cmFkbw0KYGBge3J9DQoNCmdncGxvdChkYXRhb3V0LCBhZXMoeD1wcmljZSkpICsNCiAgZ2d0aXRsZSgnUHJpY2UgaGlzdG9ncmFtJykgKw0KICB4bGFiKCdwcmljZScpICsNCiAgeWxhYignZnJlcXVlbmN5JykgKw0KICBnZW9tX2hpc3RvZ3JhbShmaWxsPSdyZWQnLCBhbHBoYT0wLjc1LCBiaW5zPTMwICkNCg0KDQpgYGANCg0KYi1Fc3RhZGlzdGljYXMgZGVzY3JpcHRpdmFzIHBvciBjYWRhIHRpcG8gZGUgcHJvcGllZGFkDQpgYGB7cn0NCmRhdGFvdXQgJT4lIA0KICBncm91cF9ieShwcm9wZXJ0eV90eXBlKSAlPiUNCiAgc3VtbWFyaXNlKG1lYW4gPSBtZWFuKHByaWNlKSwNCiAgICAgICAgICAgIHByaW1lcnEgPSBxdWFudGlsZShwcmljZSwgMC4yNSksDQogICAgICAgICAgICBtZWRpYW5hID0gbWVkaWFuKHByaWNlKSwNCiAgICAgICAgICAgIHRlcmNlcnEgPSBxdWFudGlsZShwcmljZSwgMC43NSksDQogICAgICAgICAgICBtYXggPSBtYXgocHJpY2UpDQogICAgICAgICAgICApDQoNCg0KYGBgDQoNCg0KDQpjLUJveHBsb3QNCmBgYHtyfQ0KZ2dwbG90KGRhdGFvdXQsIGFlcyh4ID0gcHJvcGVydHlfdHlwZSwgeSA9ICBwcmljZSwgZ3JvdXAgPSBwcm9wZXJ0eV90eXBlLCBmaWxsID0gcHJvcGVydHlfdHlwZSApKSArDQogIGdlb21fYm94cGxvdCgpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCA1MTAwMDAwKSkNCg0KYGBgDQpkLUNvcnJlbG9ncmFtYQ0KYGBge3J9DQpkYXRhb3V0MjwtZGF0YW91dFssMzo4XQ0KZGF0YW91dDIlPiVnZ3BhaXJzKC4sIA0KICAgICAgICAgIHRpdGxlID0gIkNvcnJlbG9ncmFtYSBkYXRvcyBzaW4gb3V0bGllcnMiLA0KICAgICAgICAgIG1hcHBpbmcgPSBhZXMoY29sb3VyPSBwcm9wZXJ0eV90eXBlKQ0KICApDQoNCmBgYA0KDQo3LU1vZGVsbyBsaW5lYWwNCmEgeSBiLlNlIGFuYWxpemFuIGRvcyBtb2RlbG9zIGxpbmVhbGVzIHNpbXBsZXMsIHVubyBwYXJhIGV4cGxpY2FyIGVsIHByZWNpbyBlbiBmdW5jaW9uIGRlIGxhcyBoYWJpdGFjaW9uZXMgeSBvdHJvIG1vZGVsbyBxdWUgZXhwbGljYSBlbCBwcmVjaW8gZW4gZnVuY2lvbiBkZSBsYSBzdXBlcmZpY2llIHRvdGFsLg0KDQoNCmBgYHtyfQ0KDQptb2RzdXA8LWxtKHByaWNlfnN1cmZhY2VfdG90YWwsIGRhdGE9ZGF0YW91dCkNCm1vZHJvb208LWxtKHByaWNlfnJvb21zLCBkYXRhPWRhdGFvdXQpDQoNCnN1bW1hcnkobW9kc3VwKQ0KDQoNCmBgYA0KDQpTZWfDum4gbG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zIGRlbCBwcmltZXIgbW9kZWxvIChwcmVjaW8gZW4gZnVuY2nDs24gZGUgbGEgc3VwZXJmaWNpZSB0b3RhbCwgZWwgQjAgZXMgNTE2OTMuMjIsIGNvcnJlc3BvbmRlIGEgbGEgb3JkZW5hZGEgYWwgb3JpZ2VuLiBFbCBCMSBkZWwgbW9kZWxvIGVzIDIwMTYsMzIgIGNvcnJlc3BvbmRlIGFsIGF1bWVudG8gZGUgcHJlY2lvIGRlbCBpbm11ZWJsZSBlbiBkb2xhcmVzIGFsIGF1bWVudGFyIGNhZGEgbWV0cm8yIGRlIGxhIHN1cGVyZmljaWUgdG90YWwuDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGFvdXQsIGFlcyhzdXJmYWNlX3RvdGFsLCBwcmljZSkpICsgDQogIGdlb21fcG9pbnQoc2l6ZT0xLCBjb2xvciA9ICJwaW5rIikgKyANCiAgZ2VvbV9zbW9vdGgobWV0aG9kID0gJ2xtJykgKw0KICBsYWJzKHRpdGxlID0gIlByZWNpb3MgZW4gZnVuY2lvbiBkZSBTdXBlcmZpY2llIFRvdGFsIiwgeCA9ICJTdXBlcmZpY2llIHRvdGFsIChtMikiLCB5ID0gIlByZWNpbyAoVVNEKSIpICsNCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpDQoNCg0KYGBgDQoNCg0KDQpgYGB7cn0NCg0Kc3VtbWFyeShtb2Ryb29tKQ0KDQoNCg0KYGBgDQoNCg0KTG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zIGRlbCBzZWd1bmRvIG1vZGVsbyAocHJlY2lvIGVuIGZ1bmNpb24gZGUgcm9vbSksIGVsIEIwIGVzIC0yODgyNiw2IGVzdGUgdmFsb3IgY29ycmVzcG9uZGUgYSBsYSBvcmRlbmFkYSBhbCBvcmlnZW4gKHByZWNpbyBwcm9tZWRpbyBkZSB1bmEgcHJvcGllZGFkIGN1eWEgc3VwZXJmaWNpZSB0b3RhbCBlcyAwKS4gRWwgQjEgZGVsIG1vZGVsbyBlcyA5MzgwNSwyLCBjb3JyZXNwb25kZSBhbCBhdW1lbnRvIGRlIHByZWNpbyBkZWwgaW5tdWVibGUgZW4gZG9sYXJlcyBhbCBhdW1lbnRhciBjYWRhIGhhYml0YWNpw7NuLg0KDQoNCg0KDQpgYGB7cn0NCmdncGxvdChkYXRhb3V0LCBhZXMocm9vbXMsIHByaWNlKSkgKyANCiAgZ2VvbV9wb2ludChzaXplPTEsIGNvbG9yID0gInBpbmsiKSArIA0KICBnZW9tX3Ntb290aChtZXRob2QgPSAnbG0nKSArDQogIGxhYnModGl0bGUgPSAiUHJlY2lvcyBlbiBmdW5jaW9uIGRlIEhhYml0YWNpb25lcyIsIHggPSAiSGFiaXRhY2lvbmVzIiwgeSA9ICJQcmVjaW8gKFVTRCkiKSArDQogIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0KDQpgYGANCg0KDQoNCg0KDQoNCjcgYy5Db25jbHVzaW9uOg0KQW5hbGl6YW5kbyBsb3MgUjIgZGUgYW1ib3MgbW9kZWxvcyBzZSBwb2RyaWEgZGVjaXIgcXVlIGVsIG1vZGVsbyBkZSBwcmVjaW8gZW4gZnVuY2lvbiBkZSBsYSBzdXBlcmZpY2llIHRvdGFsIGxvZ3JhIGV4cGxpY2FyIG1heW9yIHByb3BvcmNpb24gZGUgbGEgdmFyaWFiaWxpZGFkIGRlIGxvcyBwcmVjaW9zICwgc3UgUjIgZXMgZGUgMC41NDY1IHZlcnN1cyBlbCBSMiBkZWwgbW9kZWxvIHBvciBoYWJpdGFjaW9uIHF1ZSBkaW8gMC4zNTg0Lg0KIA0KDQoNCg0K