suppressMessages(library(rpart))
suppressMessages(library(caret))
suppressMessages(library(readr))
suppressMessages(library(dplyr))
suppressMessages(library(ggplot2))
suppressMessages(library(ggmap))

Lectura de Archivos de datos

Leer archivos Entrenamiento y Testeo:

Al usar la funcion read_csv del paquete readr tenemos la posibilidad de definir el tipo de dato que queremos para cada variable.

data_train <- readr::read_csv("./arbolado-mza-dataset.csv",
                              col_types = cols(
  id = col_integer(),
  especie = col_character(),
  ultima_modificacion = col_character(),
  altura = col_character(),
  circ_tronco_cm = col_double(),
  diametro_tronco = col_character(),
  long = col_double(),
  lat = col_double(),
  seccion = col_integer(),
  nombre_seccion = col_character(),
  area_seccion = col_double(),
  inclinacion_peligrosa = col_integer()
))
data_test <-  readr::read_csv("./arbolado-mza-dataset-test.csv",col_types = cols(
  id = col_integer(),
  especie = col_character(),
  ultima_modificacion = col_character(),
  altura = col_character(),
  circ_tronco_cm = col_double(),
  diametro_tronco = col_character(),
  long = col_double(),
  lat = col_double(),
  seccion = col_integer(),
  nombre_seccion = col_character(),
  area_seccion = col_double()
))

Transformaciones:

Algunos algoritmos no permiten nombres de factores como 1 y 0, se transforma la clase inclinacion_peligrosa a si y no

En la tabla de abajo podemos ver el conjunto de datos tal cual quedo despues de esta pequeña transformacion.

data_train<-data_train %>% mutate(inclinacion_peligrosa=ifelse(inclinacion_peligrosa=='1','si','no'))
data_train$inclinacion_peligrosa <-as.factor(data_train$inclinacion_peligrosa)
data_train

Explorando el conjunto de datos

Antes de plantear cualquier algoritmo para intentar predecir el grado de inclinacion es fundamental analizar los datos. Del analisis de los datos pueden surgir diferentes hipotesis que nos permitan proponer soluciones al problema de estudio. Para esto nos valemos fundamentalmente de la visualizacion y de las herramientas para hacer concultas ‘ala SQL’ que provee el paquete dplyr

Algunas PREGUNTAS a responder:

1. Cual es la distribucion de las clase inclinacion_peligrosa?

Para responder esta primer pregunta basta con contabilizar las ocurrencias de cada uno de los valores posibles de clase inclinacion_peligrosa. Usando dplyr, basta con agrupar por cada uno de los valores la clase via (via group_by()) y luego con summarise() contabilizar el total de cada grupo creado. La funcion especial n() permite contabilizar cada uno de los grupos formados.

data_train %>%  group_by(inclinacion_peligrosa) %>% summarise(total=n())

Observamos entonces, que para este conunto de datos, solo cerca del 12% de los registros tiene un inclinacion peligrosa.

2. Se puede considerar alguna sección mas peligrosa que otra?

Podriamos seguir preguntandonos, si existe alguna diferencia en esta distribucion respecto a las distintas secciones administrativas de la ciudad. Y para esto bastaria con modificar ligeramente la linea de arriba para incluir la variable seccion en la funcion group_by().

data_train_seccion_inclinacion<-data_train %>%  group_by(seccion,inclinacion_peligrosa) %>% summarise(total=n())
data_train_seccion_inclinacion

Ahora es posible ver que algunas secciones como ser la 1era seccion mantienen el la misma proporcion de arboles con inclinacion peligrosa. Por otro lado, secciones como la 4ta, tienen solamente cerca del 7%.

A veces, es mas facil visualizarlo en un grafico. Para ello podemos usar muchas herramientas, pero en R, una de las populares es el ggplot.

ggplot(data_train)+
  geom_bar(aes(x=as.factor(inclinacion_peligrosa),fill=as.factor(inclinacion_peligrosa)   ))+
  theme_bw()+
  facet_wrap(~seccion)

Que opinan? Existe alguna diferencia entre las secciones?

Se puede considerar alguna especie mas peligrosa que otra?

Repitamos el mismo razonamiento pero ahora con las especies..

Podriamos preguntarnos, si existe alguna diferencia en esta distribucion respecto a las distintas especies existentes la ciudad. Y para esto bastaria con modificar la linea de dpylr para y reemplazar la variable seccion por la variable especie en la funcion group_by().

data_train_especie_inclinacion<-data_train %>%  group_by(especie,inclinacion_peligrosa) %>% summarise(total=n())
data_train_especie_inclinacion

Aqui sin duda resulta muy dificil observar alguna diferencia. Veamos que pasa con una visualizacion como la anterior pero aplicada a especie

ggplot(data_train)+
  geom_bar(aes(x=as.factor(inclinacion_peligrosa),fill=as.factor(inclinacion_peligrosa)   ))+
  theme_bw()+
  facet_wrap(~especie)# Aca estamos indicando que queremos que diferencie por especie

Que conclusion podemos sacar del grafico? Existe alguna especie que sea mas propensa presentar una inclinacion peligrosa.?

Como estan distribuidas en la ciudad los arboles con inclinacion peligrosa?

Para responder esta pregunta, debemos valernos de las coordenadas geograficas que presenta el conjunto de datos. Aprovechando la informacion de geo posicionamiento podes ver si existe alguna zona o patron en la ciudad que nos permita inferir una posible causa detras del grado de inclinacion peligrosa en la ciudad.

Para visualizar ese tipo de datos en R podemos usar ggmap que se vale de la API de google map para realizar el geo-posicionamiento.

mza_map <- get_map(location = "mendoza", zoom = 14,maptype = "roadmap",color = "bw")
ggmap(mza_map)+ 
  geom_point(aes(x= long, y=lat), color='green',data=data_train %>% filter(inclinacion_peligrosa==1),size=0.4)

A simple vista no resulta facil distingir una zona con mayor densidad de arboles cuya inclinacion sea peligrosa. Quizas sea necesario cambiar la visualizacion y mostrar un diagram de de contornos en 2D. En donde las zonas con mayor densidad de puntos cuya inclinacion sea peligrosa presentan la mayor concentracion de color.

ggmap(mza_map)+ 
stat_density2d(mapping=aes(x = long, y = lat,fill=..level..,alpha=..level..), 
                 data = data_train %>% filter(inclinacion_peligrosa==1), geom="polygon",  bins=8) +
  scale_fill_gradient(low = "black", high = "green")

Que les parece? Ahora podemos decir que hay zonas con mayor inclinacion que otras?

LS0tCnRpdGxlOiAiSEFDS0FUT04gQU0gLSBBcmJvbGFkbyBQdWJsaWNvIC0gRXhwbG9yYWNpb24gaW5pY2lhbCAgZGVsIGNvbmp1bnRvIGRlIGRhdG9zIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6IAogICAgY29kZV9mb2xkaW5nOiBub25lCi0tLQoKYGBge3Igc2V0dXB9CnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShycGFydCkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShjYXJldCkpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShyZWFkcikpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShkcGx5cikpCnN1cHByZXNzTWVzc2FnZXMobGlicmFyeShnZ3Bsb3QyKSkKc3VwcHJlc3NNZXNzYWdlcyhsaWJyYXJ5KGdnbWFwKSkKYGBgCgoKIyBMZWN0dXJhIGRlICBBcmNoaXZvcyBkZSBkYXRvcwoKKiAqKlthcmJvbGFkby1temEtZGF0YXNldC5jc3ZdKGh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3MvNWEwdTRoNTVxbnZrbGhsL2FyYm9sYWRvLW16YS1kYXRhc2V0LmNzdj9kbD0xKSoqIC0gY29uanVudG8gZGUgZGF0b3MgcGFyYSBlbnRyZW5hbWllbnRvCiogKipbYXJib2xhZG8tbXphLWRhdGFzZXQtdGVzdC5jc3ZdKGh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3MvdjZubWcxbnk0N2tqOWR1L2FyYm9sYWRvLW16YS1kYXRhc2V0LXRlc3QuY3N2P2RsPTEpKiogLSBjb25qdW50byBkZSBkYXRvcyBwYXJhIGV2YWx1YWNpb24KKiAqKlthcmJvbGFkby1temEtZGF0YXNldC1kZXNjcmlwY2lvbi5jc3ZdKGh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3MvcXZmMGZyazFlanB1NDc2L2FyYm9sYWRvLW16YS1kYXRhc2V0LWRlc2NyaXBjaW9uLmNzdj9kbD0xKSoqIC0gSW5mb3JtYWNpw7NuIGV4dHJhIHNvYnJlIGxvcyBkYXRvcy4KCiMjIExlZXIgYXJjaGl2b3MgIEVudHJlbmFtaWVudG8geSBUZXN0ZW86CgpBbCB1c2FyIGxhIGZ1bmNpb24gKnJlYWRfY3N2KiBkZWwgcGFxdWV0ZSAqKnJlYWRyKiogdGVuZW1vcyBsYSBwb3NpYmlsaWRhZCBkZSBkZWZpbmlyIGVsIHRpcG8gZGUgZGF0byBxdWUgcXVlcmVtb3MgcGFyYSBjYWRhIHZhcmlhYmxlLgoKYGBge3IgfQpkYXRhX3RyYWluIDwtIHJlYWRyOjpyZWFkX2NzdigiLi9hcmJvbGFkby1temEtZGF0YXNldC5jc3YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKAogIGlkID0gY29sX2ludGVnZXIoKSwKICBlc3BlY2llID0gY29sX2NoYXJhY3RlcigpLAogIHVsdGltYV9tb2RpZmljYWNpb24gPSBjb2xfY2hhcmFjdGVyKCksCiAgYWx0dXJhID0gY29sX2NoYXJhY3RlcigpLAogIGNpcmNfdHJvbmNvX2NtID0gY29sX2RvdWJsZSgpLAogIGRpYW1ldHJvX3Ryb25jbyA9IGNvbF9jaGFyYWN0ZXIoKSwKICBsb25nID0gY29sX2RvdWJsZSgpLAogIGxhdCA9IGNvbF9kb3VibGUoKSwKICBzZWNjaW9uID0gY29sX2ludGVnZXIoKSwKICBub21icmVfc2VjY2lvbiA9IGNvbF9jaGFyYWN0ZXIoKSwKICBhcmVhX3NlY2Npb24gPSBjb2xfZG91YmxlKCksCiAgaW5jbGluYWNpb25fcGVsaWdyb3NhID0gY29sX2ludGVnZXIoKQopKQoKZGF0YV90ZXN0IDwtICByZWFkcjo6cmVhZF9jc3YoIi4vYXJib2xhZG8tbXphLWRhdGFzZXQtdGVzdC5jc3YiLGNvbF90eXBlcyA9IGNvbHMoCiAgaWQgPSBjb2xfaW50ZWdlcigpLAogIGVzcGVjaWUgPSBjb2xfY2hhcmFjdGVyKCksCiAgdWx0aW1hX21vZGlmaWNhY2lvbiA9IGNvbF9jaGFyYWN0ZXIoKSwKICBhbHR1cmEgPSBjb2xfY2hhcmFjdGVyKCksCiAgY2lyY190cm9uY29fY20gPSBjb2xfZG91YmxlKCksCiAgZGlhbWV0cm9fdHJvbmNvID0gY29sX2NoYXJhY3RlcigpLAogIGxvbmcgPSBjb2xfZG91YmxlKCksCiAgbGF0ID0gY29sX2RvdWJsZSgpLAogIHNlY2Npb24gPSBjb2xfaW50ZWdlcigpLAogIG5vbWJyZV9zZWNjaW9uID0gY29sX2NoYXJhY3RlcigpLAogIGFyZWFfc2VjY2lvbiA9IGNvbF9kb3VibGUoKQopKQoKYGBgCgojIyBUcmFuc2Zvcm1hY2lvbmVzOgoKQWxndW5vcyBhbGdvcml0bW9zIG5vIHBlcm1pdGVuIG5vbWJyZXMgZGUgZmFjdG9yZXMgY29tbyAxIHkgMCwgc2UgdHJhbnNmb3JtYSBsYSBjbGFzZSAqKmluY2xpbmFjaW9uX3BlbGlncm9zYSoqIGEgKipzaSoqIHkgKipubyoqCgpFbiBsYSB0YWJsYSBkZSBhYmFqbyBwb2RlbW9zIHZlciBlbCBjb25qdW50byBkZSBkYXRvcyB0YWwgY3VhbCBxdWVkbyBkZXNwdWVzIGRlIGVzdGEgcGVxdWXDsWEgdHJhbnNmb3JtYWNpb24uCgpgYGB7ciBlY2hvPVRSVUV9CmRhdGFfdHJhaW48LWRhdGFfdHJhaW4gJT4lIG11dGF0ZShpbmNsaW5hY2lvbl9wZWxpZ3Jvc2E9aWZlbHNlKGluY2xpbmFjaW9uX3BlbGlncm9zYT09JzEnLCdzaScsJ25vJykpCmRhdGFfdHJhaW4kaW5jbGluYWNpb25fcGVsaWdyb3NhIDwtYXMuZmFjdG9yKGRhdGFfdHJhaW4kaW5jbGluYWNpb25fcGVsaWdyb3NhKQpkYXRhX3RyYWluCmBgYAoKIyBFeHBsb3JhbmRvIGVsIGNvbmp1bnRvIGRlIGRhdG9zCgpBbnRlcyBkZSBwbGFudGVhciBjdWFscXVpZXIgYWxnb3JpdG1vIHBhcmEgaW50ZW50YXIgcHJlZGVjaXIgZWwgZ3JhZG8gZGUgaW5jbGluYWNpb24gZXMgZnVuZGFtZW50YWwgYW5hbGl6YXIgbG9zIGRhdG9zLiBEZWwgYW5hbGlzaXMgZGUgbG9zIGRhdG9zIHB1ZWRlbiBzdXJnaXIgZGlmZXJlbnRlcyAgaGlwb3Rlc2lzIHF1ZSBub3MgcGVybWl0YW4gcHJvcG9uZXIgIHNvbHVjaW9uZXMgYWwgcHJvYmxlbWEgZGUgZXN0dWRpby4gUGFyYSBlc3RvIG5vcyB2YWxlbW9zIGZ1bmRhbWVudGFsbWVudGUgZGUgbGEgdmlzdWFsaXphY2lvbiB5IGRlIGxhcyBoZXJyYW1pZW50YXMgcGFyYSBoYWNlciBjb25jdWx0YXMgJ2FsYSBTUUwnIHF1ZSBwcm92ZWUgZWwgcGFxdWV0ZSAqKmRwbHlyKioKCiMjQWxndW5hcyBQUkVHVU5UQVMgYSByZXNwb25kZXI6CgojIyMjMS4gQ3VhbCBlcyBsYSBkaXN0cmlidWNpb24gZGUgbGFzIGNsYXNlICoqaW5jbGluYWNpb25fcGVsaWdyb3NhPyoqCgpQYXJhIHJlc3BvbmRlciBlc3RhIHByaW1lciBwcmVndW50YSBiYXN0YSBjb24gY29udGFiaWxpemFyIGxhcyBvY3VycmVuY2lhcyBkZSBjYWRhIHVubyBkZSBsb3MgdmFsb3JlcyBwb3NpYmxlcyBkZSAgY2xhc2UgKippbmNsaW5hY2lvbl9wZWxpZ3Jvc2EqKi4gVXNhbmRvIGRwbHlyLCBiYXN0YSBjb24gYWdydXBhciBwb3IgY2FkYSB1bm8gZGUgbG9zIHZhbG9yZXMgbGEgY2xhc2UgdmlhICh2aWEgKipncm91cF9ieSgpKiopIHkgbHVlZ28gY29uICoqc3VtbWFyaXNlKCkqKiBjb250YWJpbGl6YXIgZWwgdG90YWwgZGUgY2FkYSBncnVwbyBjcmVhZG8uIExhIGZ1bmNpb24gZXNwZWNpYWwgKipuKCkqKiBwZXJtaXRlIGNvbnRhYmlsaXphciBjYWRhIHVubyBkZSBsb3MgZ3J1cG9zIGZvcm1hZG9zLgoKYGBge3IgZWNobz1UUlVFfQpkYXRhX3RyYWluICU+JSAgZ3JvdXBfYnkoaW5jbGluYWNpb25fcGVsaWdyb3NhKSAlPiUgc3VtbWFyaXNlKHRvdGFsPW4oKSkKYGBgCgpPYnNlcnZhbW9zIGVudG9uY2VzLCBxdWUgcGFyYSBlc3RlIGNvbnVudG8gZGUgZGF0b3MsIHNvbG8gY2VyY2EgZGVsIDEyJSBkZSBsb3MgcmVnaXN0cm9zIHRpZW5lIHVuIGluY2xpbmFjaW9uIHBlbGlncm9zYS4gCgojIyMjMi4gU2UgcHVlZGUgY29uc2lkZXJhciBhbGd1bmEgc2VjY2nDs24gbWFzIHBlbGlncm9zYSBxdWUgb3RyYT8KClBvZHJpYW1vcyBzZWd1aXIgcHJlZ3VudGFuZG9ub3MsIHNpIGV4aXN0ZSBhbGd1bmEgZGlmZXJlbmNpYSBlbiBlc3RhIGRpc3RyaWJ1Y2lvbiByZXNwZWN0byBhIGxhcyBkaXN0aW50YXMgc2VjY2lvbmVzIGFkbWluaXN0cmF0aXZhcyBkZSBsYSBjaXVkYWQuIFkgcGFyYSBlc3RvIGJhc3RhcmlhIGNvbiBtb2RpZmljYXIgbGlnZXJhbWVudGUgbGEgbGluZWEgZGUgYXJyaWJhIHBhcmEgaW5jbHVpciBsYSB2YXJpYWJsZSAqKnNlY2Npb24qKiBlbiBsYSBmdW5jaW9uICpncm91cF9ieSgpKi4KCgpgYGB7ciBlY2hvPVRSVUV9CmRhdGFfdHJhaW5fc2VjY2lvbl9pbmNsaW5hY2lvbjwtZGF0YV90cmFpbiAlPiUgIGdyb3VwX2J5KHNlY2Npb24saW5jbGluYWNpb25fcGVsaWdyb3NhKSAlPiUgc3VtbWFyaXNlKHRvdGFsPW4oKSkKZGF0YV90cmFpbl9zZWNjaW9uX2luY2xpbmFjaW9uCmBgYAoKQWhvcmEgZXMgcG9zaWJsZSB2ZXIgcXVlIGFsZ3VuYXMgc2VjY2lvbmVzIGNvbW8gc2VyIGxhIDFlcmEgc2VjY2lvbiBtYW50aWVuZW4gZWwgbGEgbWlzbWEgcHJvcG9yY2lvbiBkZSBhcmJvbGVzIGNvbiBpbmNsaW5hY2lvbiBwZWxpZ3Jvc2EuIFBvciBvdHJvIGxhZG8sIHNlY2Npb25lcyBjb21vIGxhIDR0YSwgdGllbmVuIHNvbGFtZW50ZSBjZXJjYSBkZWwgNyUuCgpBIHZlY2VzLCBlcyBtYXMgZmFjaWwgdmlzdWFsaXphcmxvIGVuIHVuIGdyYWZpY28uIFBhcmEgZWxsbyBwb2RlbW9zIHVzYXIgbXVjaGFzIGhlcnJhbWllbnRhcywgcGVybyBlbiBSLCB1bmEgZGUgbGFzIHBvcHVsYXJlcyBlcyBlbCBnZ3Bsb3QuCgpgYGB7ciwgZmlnLmhlaWdodD04fQpnZ3Bsb3QoZGF0YV90cmFpbikrCiAgZ2VvbV9iYXIoYWVzKHg9YXMuZmFjdG9yKGluY2xpbmFjaW9uX3BlbGlncm9zYSksZmlsbD1hcy5mYWN0b3IoaW5jbGluYWNpb25fcGVsaWdyb3NhKSAgICkpKwogIHRoZW1lX2J3KCkrCiAgZmFjZXRfd3JhcCh+c2VjY2lvbikKYGBgCgojIyMjIFF1ZSBvcGluYW4/IEV4aXN0ZSBhbGd1bmEgZGlmZXJlbmNpYSBlbnRyZSBsYXMgc2VjY2lvbmVzPyAKCiMjIyBTZSBwdWVkZSBjb25zaWRlcmFyIGFsZ3VuYSBlc3BlY2llIG1hcyBwZWxpZ3Jvc2EgcXVlIG90cmE/CgpSZXBpdGFtb3MgZWwgbWlzbW8gcmF6b25hbWllbnRvIHBlcm8gYWhvcmEgY29uIGxhcyBlc3BlY2llcy4uCgpQb2RyaWFtb3MgIHByZWd1bnRhcm5vcywgc2kgZXhpc3RlIGFsZ3VuYSBkaWZlcmVuY2lhIGVuIGVzdGEgZGlzdHJpYnVjaW9uIHJlc3BlY3RvIGEgbGFzIGRpc3RpbnRhcyBlc3BlY2llcyBleGlzdGVudGVzIGxhIGNpdWRhZC4gWSBwYXJhIGVzdG8gYmFzdGFyaWEgY29uIG1vZGlmaWNhciBsYSBsaW5lYSBkZSBkcHlsciBwYXJhIHkgcmVlbXBsYXphciBsYSB2YXJpYWJsZSAqKnNlY2Npb24qKiBwb3IgbGEgdmFyaWFibGUgKiplc3BlY2llKiogZW4gbGEgZnVuY2lvbiAqZ3JvdXBfYnkoKSouCgpgYGB7ciwgZWNobz1UUlVFfQpkYXRhX3RyYWluX2VzcGVjaWVfaW5jbGluYWNpb248LWRhdGFfdHJhaW4gJT4lICBncm91cF9ieShlc3BlY2llLGluY2xpbmFjaW9uX3BlbGlncm9zYSkgJT4lIHN1bW1hcmlzZSh0b3RhbD1uKCkpCmRhdGFfdHJhaW5fZXNwZWNpZV9pbmNsaW5hY2lvbgpgYGAKCkFxdWkgc2luIGR1ZGEgcmVzdWx0YSBtdXkgZGlmaWNpbCBvYnNlcnZhciBhbGd1bmEgZGlmZXJlbmNpYS4gVmVhbW9zIHF1ZSBwYXNhIGNvbiB1bmEgdmlzdWFsaXphY2lvbiBjb21vIGxhIGFudGVyaW9yIHBlcm8gYXBsaWNhZGEgYSAqKmVzcGVjaWUqKgpgYGB7ciwgZmlnLmhlaWdodD04fQpnZ3Bsb3QoZGF0YV90cmFpbikrCiAgZ2VvbV9iYXIoYWVzKHg9YXMuZmFjdG9yKGluY2xpbmFjaW9uX3BlbGlncm9zYSksZmlsbD1hcy5mYWN0b3IoaW5jbGluYWNpb25fcGVsaWdyb3NhKSAgICkpKwogIHRoZW1lX2J3KCkrCiAgZmFjZXRfd3JhcCh+ZXNwZWNpZSkjIEFjYSBlc3RhbW9zIGluZGljYW5kbyBxdWUgcXVlcmVtb3MgcXVlIGRpZmVyZW5jaWUgcG9yIGVzcGVjaWUKYGBgCgojIyMjIFF1ZSBjb25jbHVzaW9uIHBvZGVtb3Mgc2FjYXIgZGVsIGdyYWZpY28/IEV4aXN0ZSBhbGd1bmEgZXNwZWNpZSBxdWUgc2VhIG1hcyBwcm9wZW5zYSAgcHJlc2VudGFyIHVuYSBpbmNsaW5hY2lvbiBwZWxpZ3Jvc2EuPwoKIyMjIENvbW8gZXN0YW4gZGlzdHJpYnVpZGFzIGVuIGxhIGNpdWRhZCBsb3MgYXJib2xlcyBjb24gaW5jbGluYWNpb24gcGVsaWdyb3NhPwoKUGFyYSByZXNwb25kZXIgZXN0YSBwcmVndW50YSwgZGViZW1vcyB2YWxlcm5vcyBkZSBsYXMgY29vcmRlbmFkYXMgZ2VvZ3JhZmljYXMgcXVlIHByZXNlbnRhIGVsIGNvbmp1bnRvIGRlIGRhdG9zLiBBcHJvdmVjaGFuZG8gbGEgaW5mb3JtYWNpb24gZGUgZ2VvIHBvc2ljaW9uYW1pZW50byBwb2RlcyB2ZXIgc2kgZXhpc3RlIGFsZ3VuYSB6b25hIG8gcGF0cm9uIGVuIGxhIGNpdWRhZCBxdWUgbm9zIHBlcm1pdGEgaW5mZXJpciB1bmEgcG9zaWJsZSBjYXVzYSBkZXRyYXMgZGVsIGdyYWRvIGRlIGluY2xpbmFjaW9uIHBlbGlncm9zYSBlbiBsYSBjaXVkYWQuCgpQYXJhIHZpc3VhbGl6YXIgZXNlIHRpcG8gZGUgZGF0b3MgZW4gUiBwb2RlbW9zIHVzYXIgKipnZ21hcCoqIHF1ZSBzZSB2YWxlIGRlIGxhIEFQSSBkZSBnb29nbGUgbWFwIHBhcmEgcmVhbGl6YXIgZWwgZ2VvLXBvc2ljaW9uYW1pZW50by4KCmBgYHtyLCBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9OCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbXphX21hcCA8LSBnZXRfbWFwKGxvY2F0aW9uID0gIm1lbmRvemEiLCB6b29tID0gMTQsbWFwdHlwZSA9ICJyb2FkbWFwIixjb2xvciA9ICJidyIpCmdnbWFwKG16YV9tYXApKyAKICBnZW9tX3BvaW50KGFlcyh4PSBsb25nLCB5PWxhdCksIGNvbG9yPSdncmVlbicsZGF0YT1kYXRhX3RyYWluICU+JSBmaWx0ZXIoaW5jbGluYWNpb25fcGVsaWdyb3NhPT0xKSxzaXplPTAuNCkKYGBgCgpBIHNpbXBsZSB2aXN0YSBubyByZXN1bHRhIGZhY2lsIGRpc3RpbmdpciB1bmEgem9uYSBjb24gbWF5b3IgZGVuc2lkYWQgZGUgYXJib2xlcyBjdXlhIGluY2xpbmFjaW9uIHNlYSBwZWxpZ3Jvc2EuIFF1aXphcyBzZWEgbmVjZXNhcmlvIGNhbWJpYXIgbGEgdmlzdWFsaXphY2lvbiB5IG1vc3RyYXIgdW4gZGlhZ3JhbSBkZSBkZSBjb250b3Jub3MgZW4gMkQuIEVuIGRvbmRlIGxhcyB6b25hcyBjb24gbWF5b3IgZGVuc2lkYWQgZGUgcHVudG9zIGN1eWEgaW5jbGluYWNpb24gc2VhIHBlbGlncm9zYSBwcmVzZW50YW4gbGEgbWF5b3IgY29uY2VudHJhY2lvbiBkZSBjb2xvci4KCmBgYHtyLCBlY2hvPVRSVUUsIGZpZy5oZWlnaHQ9OCwgbWVzc2FnZT1GQUxTRX0KZ2dtYXAobXphX21hcCkrIApzdGF0X2RlbnNpdHkyZChtYXBwaW5nPWFlcyh4ID0gbG9uZywgeSA9IGxhdCxmaWxsPS4ubGV2ZWwuLixhbHBoYT0uLmxldmVsLi4pLCAKICAgICAgICAgICAgICAgICBkYXRhID0gZGF0YV90cmFpbiAlPiUgZmlsdGVyKGluY2xpbmFjaW9uX3BlbGlncm9zYT09MSksIGdlb209InBvbHlnb24iLCAgYmlucz04KSArCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiYmxhY2siLCBoaWdoID0gImdyZWVuIikKYGBgCiAKIyMjIFF1ZSBsZXMgcGFyZWNlPyBBaG9yYSBwb2RlbW9zIGRlY2lyIHF1ZSBoYXkgem9uYXMgY29uIG1heW9yIGluY2xpbmFjaW9uIHF1ZSBvdHJhcz8KIAoK