Lectura de los datos

setwd("/home/andy/maestria/EEA2019/trabajos_practicos/TP-1/TP1") #Elegimos el directorio de trabajo
ar_properties <- read.delim(file = "ar_properties.csv", header = T, sep = ",", stringsAsFactors = F) #Leemos el archivo de datos
str(ar_properties)
'data.frame':   388891 obs. of  24 variables:
 $ id             : chr  "S0we3z3V2JpHUJreqQ2t/w==" "kMxcmAS8NvrynGBVbMOEaQ==" "Ce3ojF+ZTOkB8d+LI9dpxg==" "AUGpj3raGmOCiulSMGIBPA==" ...
 $ ad_type        : chr  "Propiedad" "Propiedad" "Propiedad" "Propiedad" ...
 $ start_date     : chr  "2019-04-14" "2019-04-14" "2019-04-14" "2019-04-14" ...
 $ end_date       : chr  "2019-06-14" "2019-04-16" "9999-12-31" "9999-12-31" ...
 $ created_on     : chr  "2019-04-14" "2019-04-14" "2019-04-14" "2019-04-14" ...
 $ lat            : num  -34.9 -34.6 NA -34.7 -34.7 ...
 $ lon            : num  -54.9 -58.4 NA -58.8 -58.8 ...
 $ l1             : chr  "Uruguay" "Argentina" "Argentina" "Argentina" ...
 $ l2             : chr  "Maldonado" "Capital Federal" "Bs.As. G.B.A. Zona Norte" "Bs.As. G.B.A. Zona Oeste" ...
 $ l3             : chr  "Punta del Este" "Boedo" NA "Moreno" ...
 $ l4             : chr  NA NA NA "Moreno" ...
 $ l5             : chr  NA NA NA NA ...
 $ l6             : logi  NA NA NA NA NA NA ...
 $ rooms          : int  2 NA 2 2 2 4 NA 6 NA NA ...
 $ bedrooms       : int  NA NA NA NA NA NA NA NA NA NA ...
 $ bathrooms      : int  1 NA 1 2 3 1 3 3 NA NA ...
 $ surface_total  : int  45 NA 200 460 660 NA 70 NA 1300 405 ...
 $ surface_covered: int  40 NA NA 100 148 89 122 NA NA NA ...
 $ price          : int  13000 0 NA NA NA NA NA NA 0 NA ...
 $ currency       : chr  "UYU" NA NA NA ...
 $ price_period   : chr  "Mensual" "Mensual" NA "Mensual" ...
 $ title          : chr  "Departamento - Roosevelt" "PH - Boedo" "Ituzaingo  1100 - $ 1 - Casa Alquiler" "Dr. Vera   300 - Consulte precio - Casa en Venta" ...
 $ property_type  : chr  "Departamento" "PH" "Casa" "Casa" ...
 $ operation_type : chr  "Alquiler" "Venta" "Alquiler" "Venta" ...
dim(ar_properties)
[1] 388891     24
head(ar_properties)
View(ar_properties[1:10, ])
  1. Preparación de los datos
unique(ar_properties$l2) #Veamos cuantas formas hay de llamar a capital federal
 [1] "Maldonado"                    "Capital Federal"              "Bs.As. G.B.A. Zona Norte"     "Bs.As. G.B.A. Zona Oeste"     "Santa Fe"                    
 [6] "Buenos Aires Costa Atlántica" "Río Negro"                    "Córdoba"                      "Tucumán"                      "Bs.As. G.B.A. Zona Sur"      
[11] "Neuquén"                      "La Pampa"                     "Corrientes"                   "Tierra Del Fuego"             "Salta"                       
[16] "Buenos Aires Interior"        "Entre Ríos"                   "Misiones"                     "Canelones"                    "Montevideo"                  
[21] "Catamarca"                    "Mendoza"                      "San Juan"                     "Chaco"                        "San Luis"                    
[26] "Chubut"                       "Jujuy"                        "Santa Cruz"                   "Santiago Del Estero"          "La Rioja"                    
[31] "Florida"                      "Colonia"                      "Rio de Janeiro"               "Rocha"                        "Santa Catarina"              
[36] "Miami"                        "Formosa"                      "Michigan"                     "New York"                     "Maryland"                    
[41] "Pennsylvania"                
propiedades <- ar_properties[ar_properties$l1 == "Argentina" & ar_properties$l2 == "Capital Federal", ] #Nos quedamos con los da argentina y cap fed
propiedades <- propiedades[propiedades$currency == "USD", ] #Nos quedamos con las operaciones en dolares
propiedades <- propiedades[propiedades$property_type %in% c("Departamento", "PH", "Casa"), ] #Nos quedamos con los tipos específicos de propiedades
propiedades <- propiedades[propiedades$operation_type == "Venta", ] #Nos quedamos con las operaciones de venta
propiedades <- propiedades[,c("id", "l3", "rooms", "bedrooms", "bathrooms", "surface_total", "surface_covered", "price", "property_type")] #Nos quedamos con los datos de interes
dim(propiedades) #Tenemos los datos esperados
[1] 61905     9
rownames(propiedades) <- propiedades[, 1]
propiedades           <- propiedades[, -1]
rm(ar_properties)
gc()
          used (Mb) gc trigger  (Mb) max used  (Mb)
Ncells 1809393 96.7    4347570 232.2  3302975 176.4
Vcells 6845276 52.3   36558239NA 45625322 348.1
  1. Análisis exploratorio de datos
correlaciones
                     rooms   bedrooms  bathrooms surface_total surface_covered      price
rooms           1.00000000 0.92138719 0.61335026    0.06828238      0.07468335 0.48748747
bedrooms        0.92138719 1.00000000 0.61578024    0.06746895      0.07206826 0.43221753
bathrooms       0.61335026 0.61578024 1.00000000    0.06234262      0.06777010 0.59904254
surface_total   0.06828238 0.06746895 0.06234262    1.00000000      0.69656225 0.05095265
surface_covered 0.07468335 0.07206826 0.06777010    0.69656225      1.00000000 0.06257960
price           0.48748747 0.43221753 0.59904254    0.05095265      0.06257960 1.00000000
  1. Rooms y bedrooms están altamente correlacionados y a bedrooms le faltan muchos datos. Lo sacamos. Sacamos además los registros incompletos.
propiedades <- propiedades[, !colnames(propiedades) %in% "bedrooms"]
propiedades <- propiedades[complete.cases(propiedades), ]
dim(propiedades)
[1] 51210     7
  1. Realizamos analisis exploratorio.
summary(propiedades$price)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   6000  119000  170000  251577  270000 6000000 
library(ggplot2)
library(GGally)
ggplot(propiedades, aes(x = price)) + geom_histogram()

ggplot(propiedades, aes(x = price)) + geom_histogram() + scale_x_log10() #Graficamos logaritmo para que se vea mejor

price_por_type<-aggregate(price ~ property_type, propiedades, summary)
price_por_type
ggplot(propiedades, aes(y = price, color = property_type)) + geom_boxplot()

ggcorr(propiedades)
data in column(s) 'l3', 'property_type' are not numeric and were ignored

  1. Outliers de precios. Sacamos los outliers usando el criterio de boxplot (1er cuartil - 1.5IQR, 3er cuartil + 1.5IQR)
maximo<-aggregate(price ~ property_type, propiedades, function(p){ return(quantile(p, 0.75) + 1.5*IQR(p))})
minimo<-aggregate(price ~ property_type, propiedades, function(p){ return(quantile(p, 0.25) - 1.5*IQR(p))})
maximo <- setNames(maximo$price, maximo$property_type)

Los mínimos incluyen al cero así que sacamos únicamente los que están por arriba del máximo

table(outliers)
outliers
FALSE  TRUE 
46956  4254 
  1. Repetimos los analisis sin los outliers
summary(propiedades$price)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   6000  119000  170000  251577  270000 6000000 
ggplot(propiedades, aes(x = price)) + geom_histogram()

ggplot(propiedades, aes(x = price)) + geom_histogram() + scale_x_log10() #Graficamos logaritmo para que se vea mejor

ggplot(propiedades_sin_outliers, aes(x = price)) + geom_histogram()

ggplot(propiedades_sin_outliers, aes(x = price)) + geom_histogram() + scale_x_log10() #Graficamos logaritmo para que se vea mejor

price_por_type<-aggregate(price ~ property_type, propiedades, summary)
price_por_type
ggplot(propiedades, aes(y = price, color = property_type)) + geom_boxplot()

ggplot(propiedades_sin_outliers, aes(y = price, color = property_type)) + geom_boxplot()

ggcorr(propiedades)
data in column(s) 'l3', 'property_type' are not numeric and were ignored

ggcorr(propiedades_sin_outliers)
data in column(s) 'l3', 'property_type' are not numeric and were ignored

Sacar los outliers permite concentrarse en los valores más típicos y en las escalas más típicas como muestran el histograma y el boxplot. Además, aumentan levemente la correlación entre el precio y la cantidad de habitaciones y baños. Los outliers deben incluir otros aspectos, como ubicación.

  1. Modelo lineal
ml_rooms <- lm(price ~ rooms, propiedades_sin_outliers)
ml_surface_total <- lm(price ~ surface_total, propiedades_sin_outliers)
summary(ml_rooms)

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

Residuals:
    Min      1Q  Median      3Q     Max 
-747427  -47389  -11167   31890  590776 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  51451.2      834.4   61.67   <2e-16 ***
rooms        51943.1      284.7  182.47   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 77900 on 46954 degrees of freedom
Multiple R-squared:  0.4149,    Adjusted R-squared:  0.4149 
F-statistic: 3.33e+04 on 1 and 46954 DF,  p-value: < 2.2e-16
summary(ml_surface_total)

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

Residuals:
    Min      1Q  Median      3Q     Max 
-772520  -73607  -28772   51196  679199 

Coefficients:
               Estimate Std. Error t value Pr(>|t|)    
(Intercept)   1.883e+05  4.720e+02  398.85   <2e-16 ***
surface_total 6.340e+00  5.531e-01   11.46   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 101700 on 46954 degrees of freedom
Multiple R-squared:  0.002791,  Adjusted R-squared:  0.00277 
F-statistic: 131.4 on 1 and 46954 DF,  p-value: < 2.2e-16

Si Bien los coeficientes en ambos ajustes dan significativos, el R2 muestra que surface_total no explica el precio. Viendo los gráficos de residuos y los R2 se observa que surface_total no explica bien el precio, mientras que rooms explica una parte. Usaríamos rooms.

LS0tCnRpdGxlOiAiVFAxIEVFQTIwMTkgQW5kcsOpcyBSYWJpbm92aWNoIC0gRmVkZXJpY28gUmFiaW5vdmljaCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKTGVjdHVyYSBkZSBsb3MgZGF0b3MKYGBge3J9CnNldHdkKCIvaG9tZS9hbmR5L21hZXN0cmlhL0VFQTIwMTkvdHJhYmFqb3NfcHJhY3RpY29zL1RQLTEvVFAxIikgI0VsZWdpbW9zIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbwphcl9wcm9wZXJ0aWVzIDwtIHJlYWQuZGVsaW0oZmlsZSA9ICJhcl9wcm9wZXJ0aWVzLmNzdiIsIGhlYWRlciA9IFQsIHNlcCA9ICIsIiwgc3RyaW5nc0FzRmFjdG9ycyA9IEYpICNMZWVtb3MgZWwgYXJjaGl2byBkZSBkYXRvcwpzdHIoYXJfcHJvcGVydGllcykKZGltKGFyX3Byb3BlcnRpZXMpCmhlYWQoYXJfcHJvcGVydGllcykKVmlldyhhcl9wcm9wZXJ0aWVzWzE6MTAsIF0pCmBgYAoKMSkgUHJlcGFyYWNpw7NuIGRlIGxvcyBkYXRvcwpgYGB7cn0KdW5pcXVlKGFyX3Byb3BlcnRpZXMkbDIpICNWZWFtb3MgY3VhbnRhcyBmb3JtYXMgaGF5IGRlIGxsYW1hciBhIGNhcGl0YWwgZmVkZXJhbApwcm9waWVkYWRlcyA8LSBhcl9wcm9wZXJ0aWVzW2FyX3Byb3BlcnRpZXMkbDEgPT0gIkFyZ2VudGluYSIgJiBhcl9wcm9wZXJ0aWVzJGwyID09ICJDYXBpdGFsIEZlZGVyYWwiLCBdICNOb3MgcXVlZGFtb3MgY29uIGxvcyBkYSBhcmdlbnRpbmEgeSBjYXAgZmVkCnByb3BpZWRhZGVzIDwtIHByb3BpZWRhZGVzW3Byb3BpZWRhZGVzJGN1cnJlbmN5ID09ICJVU0QiLCBdICNOb3MgcXVlZGFtb3MgY29uIGxhcyBvcGVyYWNpb25lcyBlbiBkb2xhcmVzCnByb3BpZWRhZGVzIDwtIHByb3BpZWRhZGVzW3Byb3BpZWRhZGVzJHByb3BlcnR5X3R5cGUgJWluJSBjKCJEZXBhcnRhbWVudG8iLCAiUEgiLCAiQ2FzYSIpLCBdICNOb3MgcXVlZGFtb3MgY29uIGxvcyB0aXBvcyBlc3BlY8OtZmljb3MgZGUgcHJvcGllZGFkZXMKcHJvcGllZGFkZXMgPC0gcHJvcGllZGFkZXNbcHJvcGllZGFkZXMkb3BlcmF0aW9uX3R5cGUgPT0gIlZlbnRhIiwgXSAjTm9zIHF1ZWRhbW9zIGNvbiBsYXMgb3BlcmFjaW9uZXMgZGUgdmVudGEKcHJvcGllZGFkZXMgPC0gcHJvcGllZGFkZXNbLGMoImlkIiwgImwzIiwgInJvb21zIiwgImJlZHJvb21zIiwgImJhdGhyb29tcyIsICJzdXJmYWNlX3RvdGFsIiwgInN1cmZhY2VfY292ZXJlZCIsICJwcmljZSIsICJwcm9wZXJ0eV90eXBlIildICNOb3MgcXVlZGFtb3MgY29uIGxvcyBkYXRvcyBkZSBpbnRlcmVzCmRpbShwcm9waWVkYWRlcykgI1RlbmVtb3MgbG9zIGRhdG9zIGVzcGVyYWRvcwpyb3duYW1lcyhwcm9waWVkYWRlcykgPC0gcHJvcGllZGFkZXNbLCAxXQpwcm9waWVkYWRlcyAgICAgICAgICAgPC0gcHJvcGllZGFkZXNbLCAtMV0Kcm0oYXJfcHJvcGVydGllcykKZ2MoKQpgYGAKMikgQW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBkYXRvcwpgYGB7cn0KI0J1c2NhbW9zIHZhbG9yZXMgw7puaWNvcyB5IGZhbHRhbnRlcyBkZSBjYWRhIHVubyBkZSBsb3MgZGF0b3MKdW5pY29zIDwtIGFwcGx5KHByb3BpZWRhZGVzLCAyLCBmdW5jdGlvbihwKXtyZXR1cm4obGVuZ3RoKHVuaXF1ZShwKSkpfSkKbmFzIDwtIGFwcGx5KHByb3BpZWRhZGVzLCAyLCBmdW5jdGlvbihwKXtyZXR1cm4oc3VtKGlzLm5hKHApKSl9KQpkYXRhLmZyYW1lKHZhbG9yZXNfdW5pY29zID0gdW5pY29zLCB2YWxvcmVzX2ZhbHRhbnRlcyA9IG5hcykKY29ycmVsYWNpb25lcyA8LSBjb3IocHJvcGllZGFkZXNbLCBjKC0xLCAtOCldLCB1c2UgPSAiY29tcGxldGUub2JzIikKY29ycmVsYWNpb25lcwpgYGAKMykgUm9vbXMgeSBiZWRyb29tcyBlc3TDoW4gYWx0YW1lbnRlIGNvcnJlbGFjaW9uYWRvcyB5IGEgYmVkcm9vbXMgbGUgZmFsdGFuIG11Y2hvcyBkYXRvcy4gTG8gc2FjYW1vcy4gU2FjYW1vcyBhZGVtw6FzIGxvcyByZWdpc3Ryb3MgaW5jb21wbGV0b3MuCmBgYHtyfQpwcm9waWVkYWRlcyA8LSBwcm9waWVkYWRlc1ssICFjb2xuYW1lcyhwcm9waWVkYWRlcykgJWluJSAiYmVkcm9vbXMiXQpwcm9waWVkYWRlcyA8LSBwcm9waWVkYWRlc1tjb21wbGV0ZS5jYXNlcyhwcm9waWVkYWRlcyksIF0KZGltKHByb3BpZWRhZGVzKQpgYGAKNCkgUmVhbGl6YW1vcyBhbmFsaXNpcyBleHBsb3JhdG9yaW8uCmBgYHtyfQpzdW1tYXJ5KHByb3BpZWRhZGVzJHByaWNlKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoR0dhbGx5KQpnZ3Bsb3QocHJvcGllZGFkZXMsIGFlcyh4ID0gcHJpY2UpKSArIGdlb21faGlzdG9ncmFtKCkKZ2dwbG90KHByb3BpZWRhZGVzLCBhZXMoeCA9IHByaWNlKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgc2NhbGVfeF9sb2cxMCgpICNHcmFmaWNhbW9zIGxvZ2FyaXRtbyBwYXJhIHF1ZSBzZSB2ZWEgbWVqb3IKcHJpY2VfcG9yX3R5cGU8LWFnZ3JlZ2F0ZShwcmljZSB+IHByb3BlcnR5X3R5cGUsIHByb3BpZWRhZGVzLCBzdW1tYXJ5KQpwcmljZV9wb3JfdHlwZQpnZ3Bsb3QocHJvcGllZGFkZXMsIGFlcyh5ID0gcHJpY2UsIGNvbG9yID0gcHJvcGVydHlfdHlwZSkpICsgZ2VvbV9ib3hwbG90KCkKZ2djb3JyKHByb3BpZWRhZGVzKQpgYGAKNSkgT3V0bGllcnMgZGUgcHJlY2lvcy4gU2FjYW1vcyBsb3Mgb3V0bGllcnMgdXNhbmRvIGVsIGNyaXRlcmlvIGRlIGJveHBsb3QgKDFlciBjdWFydGlsIC0gMS41SVFSLCAzZXIgY3VhcnRpbCArIDEuNUlRUikKYGBge3J9Cm1heGltbzwtYWdncmVnYXRlKHByaWNlIH4gcHJvcGVydHlfdHlwZSwgcHJvcGllZGFkZXMsIGZ1bmN0aW9uKHApeyByZXR1cm4ocXVhbnRpbGUocCwgMC43NSkgKyAxLjUqSVFSKHApKX0pCm1pbmltbzwtYWdncmVnYXRlKHByaWNlIH4gcHJvcGVydHlfdHlwZSwgcHJvcGllZGFkZXMsIGZ1bmN0aW9uKHApeyByZXR1cm4ocXVhbnRpbGUocCwgMC4yNSkgLSAxLjUqSVFSKHApKX0pCm1heGltbyA8LSBzZXROYW1lcyhtYXhpbW8kcHJpY2UsIG1heGltbyRwcm9wZXJ0eV90eXBlKQpgYGAKTG9zIG3DrW5pbW9zIGluY2x1eWVuIGFsIGNlcm8gYXPDrSBxdWUgc2FjYW1vcyDDum5pY2FtZW50ZSBsb3MgcXVlIGVzdMOhbiBwb3IgYXJyaWJhIGRlbCBtw6F4aW1vCmBgYHtyfQpvdXRsaWVycyA8LSBwcm9waWVkYWRlcyRwcmljZSA+IG1heGltb1twcm9waWVkYWRlcyRwcm9wZXJ0eV90eXBlXQp0YWJsZShvdXRsaWVycykKcHJvcGllZGFkZXNfc2luX291dGxpZXJzIDwtIHByb3BpZWRhZGVzWyFvdXRsaWVycywgXQpgYGAKNikgUmVwZXRpbW9zIGxvcyBhbmFsaXNpcyBzaW4gbG9zIG91dGxpZXJzCmBgYHtyfQpzdW1tYXJ5KHByb3BpZWRhZGVzJHByaWNlKQpnZ3Bsb3QocHJvcGllZGFkZXMsIGFlcyh4ID0gcHJpY2UpKSArIGdlb21faGlzdG9ncmFtKCkKZ2dwbG90KHByb3BpZWRhZGVzLCBhZXMoeCA9IHByaWNlKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgc2NhbGVfeF9sb2cxMCgpICNHcmFmaWNhbW9zIGxvZ2FyaXRtbyBwYXJhIHF1ZSBzZSB2ZWEgbWVqb3IKZ2dwbG90KHByb3BpZWRhZGVzX3Npbl9vdXRsaWVycywgYWVzKHggPSBwcmljZSkpICsgZ2VvbV9oaXN0b2dyYW0oKQpnZ3Bsb3QocHJvcGllZGFkZXNfc2luX291dGxpZXJzLCBhZXMoeCA9IHByaWNlKSkgKyBnZW9tX2hpc3RvZ3JhbSgpICsgc2NhbGVfeF9sb2cxMCgpICNHcmFmaWNhbW9zIGxvZ2FyaXRtbyBwYXJhIHF1ZSBzZSB2ZWEgbWVqb3IKcHJpY2VfcG9yX3R5cGU8LWFnZ3JlZ2F0ZShwcmljZSB+IHByb3BlcnR5X3R5cGUsIHByb3BpZWRhZGVzLCBzdW1tYXJ5KQpwcmljZV9wb3JfdHlwZQpnZ3Bsb3QocHJvcGllZGFkZXMsIGFlcyh5ID0gcHJpY2UsIGNvbG9yID0gcHJvcGVydHlfdHlwZSkpICsgZ2VvbV9ib3hwbG90KCkKZ2dwbG90KHByb3BpZWRhZGVzX3Npbl9vdXRsaWVycywgYWVzKHkgPSBwcmljZSwgY29sb3IgPSBwcm9wZXJ0eV90eXBlKSkgKyBnZW9tX2JveHBsb3QoKQpnZ2NvcnIocHJvcGllZGFkZXMpCmdnY29ycihwcm9waWVkYWRlc19zaW5fb3V0bGllcnMpCmBgYApTYWNhciBsb3Mgb3V0bGllcnMgcGVybWl0ZSBjb25jZW50cmFyc2UgZW4gbG9zIHZhbG9yZXMgbcOhcyB0w61waWNvcyB5IGVuIGxhcyBlc2NhbGFzIG3DoXMgdMOtcGljYXMgY29tbyBtdWVzdHJhbiBlbCBoaXN0b2dyYW1hIHkgZWwgYm94cGxvdC4KQWRlbcOhcywgYXVtZW50YW4gbGV2ZW1lbnRlIGxhIGNvcnJlbGFjacOzbiBlbnRyZSBlbCBwcmVjaW8geSBsYSBjYW50aWRhZCBkZSBoYWJpdGFjaW9uZXMgeSBiYcOxb3MuIExvcyBvdXRsaWVycyBkZWJlbiBpbmNsdWlyIG90cm9zIGFzcGVjdG9zLCBjb21vIHViaWNhY2nDs24uCgo3KSBNb2RlbG8gbGluZWFsCmBgYHtyfQptbF9yb29tcyA8LSBsbShwcmljZSB+IHJvb21zLCBwcm9waWVkYWRlc19zaW5fb3V0bGllcnMpCm1sX3N1cmZhY2VfdG90YWwgPC0gbG0ocHJpY2UgfiBzdXJmYWNlX3RvdGFsLCBwcm9waWVkYWRlc19zaW5fb3V0bGllcnMpCnN1bW1hcnkobWxfcm9vbXMpCnN1bW1hcnkobWxfc3VyZmFjZV90b3RhbCkKYGBgCmBgYHtyfQpwbG90KG1sX3Jvb21zKQpwbG90KG1sX3N1cmZhY2VfdG90YWwpCmBgYApTaSBCaWVuIGxvcyBjb2VmaWNpZW50ZXMgZW4gYW1ib3MgYWp1c3RlcyBkYW4gc2lnbmlmaWNhdGl2b3MsIGVsIFIyIG11ZXN0cmEgcXVlIHN1cmZhY2VfdG90YWwgbm8gZXhwbGljYSBlbCBwcmVjaW8uClZpZW5kbyBsb3MgZ3LDoWZpY29zIGRlIHJlc2lkdW9zIHkgbG9zIFIyIHNlIG9ic2VydmEgcXVlIHN1cmZhY2VfdG90YWwgbm8gZXhwbGljYSBiaWVuIGVsIHByZWNpbywgbWllbnRyYXMgcXVlIHJvb21zIGV4cGxpY2EgdW5hIHBhcnRlLiBVc2Fyw61hbW9zIHJvb21zLgo=