Las funciones de los títulos de los ejes

Para empezar a conocer las diferentes opciones que existen para los ejes de las gráficas vamos a utilizar una gráfica de dispersión como ejemplo base.

ggplot(mpg, aes(displ, hwy)) + 
  geom_point(aes(color = class))

En esta ocasión tenemos una gráfica de dispersión que relaciona las variables hwy y displ, distinguiendo la clase del vehículo con color diferente.

Si observamos la gráfica podemos observar que el título de las variables de los ejes “x” y “y”, así como también el color, aparecen con el mismo nombre que tienen las variables en la base de datos.

names(mpg)
 [1] "manufacturer" "model"        "displ"        "year"         "cyl"         
 [6] "trans"        "drv"          "cty"          "hwy"          "fl"          
[11] "class"       

El abreviar el nombre de las variables en la base de datos es común pero en nuestra gráfica no queremos que se presenten de esta forma. La variable hwy representa highway miles per gallon, la variable displ representa engine displacement, in litres, mientras que la variable class significa “type” of car.

Con base en esto, cambiaremos el título de las variables. Para hacer esto, tendremos que agregar algunos layers que dependen de las variables que queremos modificar. Por ejemplo, tenemos estas opciones:

  • scale_x_*
  • scale_y_*
  • scale_color_*

donde el * representa el tipo de variable, discreta o continua. Por ejemplo, en nuestro ejemplo las variables hwy y displ son variables continuas, mientras que class es una variable discreta.

Para nuestra gráfica tendríamos que utilizar los siguientes layers:

  • scale_x_continuous()
  • scale_y_continuous()
  • scale_color_discrete()

Títulos

Para que no aparezca título de los ejes en las gráficas solo debemos de escribir NULL dentro los paréntesis.

ggplot(mpg, aes(displ, hwy)) + 
  geom_point(aes(color = class)) + 
  scale_x_continuous(NULL) + 
  scale_y_continuous(NULL) + 
  scale_color_discrete(NULL)

Como podemos observar en la gráfica, los títulos de los ejes y la leyenda de colores desaparecieron.

Para asignarle título solo tenemos que indicarlo dentro los paréntesis de los layers, por ejemplo:

ggplot(mpg, aes(displ, hwy)) + 
  geom_point(aes(color = class)) + 
  scale_x_continuous("Engine Displacement") + 
  scale_y_continuous("Highway miles per gallon") + 
  scale_color_discrete("Type of car")

¡Listo! Ya le hemos asignado el título a los ejes y leyenda de nuestra gráfica.

Otra forma de tener el mismo resultado, probablemente más rápido, es utilizar el layer labs, abreviación de labels.

ggplot(mpg, aes(displ, hwy)) + 
  geom_point(aes(color = class)) + 
  labs(x = "Engine Displacement" , y = "Highway miles per gallon" , color = "Type of car")

Más de un renglón en un título

Supongamos que queremos tener un título muy extenso y para no cubrir toda el área del eje queremos utilizar más de un renglón. Esto es muy sencillo, solo tenemos que incluir *** sin espacio entre el texto o caracteres para indicar que se quiere usar más de un renglón. Por ejemplo:

ggplot(mpg, aes(x = displ, hwy)) + 
  geom_point(aes(color = class)) + 
  scale_x_continuous("Engine\nDisplacement") + 
  scale_y_continuous("Highway\nmiles per gallon") + 
  scale_color_discrete("Type\nof\ncar")

De esta forma podemos usar más de un renglón en los títulos de los ejes.

Escala y etiquetas de los ejes

En ocasiones vamos a querer manipular los ejes de la gráfica. Para poder realizar esto, los argumentos más utilizados son:

  • labels(), que sirve para asignar la etiqueta que llevará el eje.
  • limits(), que sirve para asignar el rango que llevará el eje
  • breaks(), que sirve para indicar las líneas de referencia o “quiebres” que tendrá el eje

Esta es la gráfica original:

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color=class)) 

Cambiando el contenido de los breaks y las etiquetas:

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color=class)) + 
  scale_x_continuous(breaks = c(1:7),
                   labels = c("I","II", "III", "IV", "V", "VI", "VII"))

Para cambiar la leyenda es algo muy similar.

ggplot(mpg, aes(x = displ, y = hwy)) + 
There were 45 warnings (use warnings() to see them)
  geom_point(aes(color=class)) + 
  scale_color_discrete(labels = c("Two seater", "Compact", "Mid size", "Mini van",
                                  "Pick up", "Sub compact", "SUV"))

En ocasiones queremos realizar un “zoom” a una parte en específico de la gráfica, para esto necesitamos indicar el rango que utilizará el eje de la gráfica. Para esto, usaremos la función limits()

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color=class)) + 
  scale_color_discrete(labels = c("Two seater", "Compact", "Mid size", "Mini van",
                                  "Pick up", "Sub compact", "SUV")) 

Si queremos hacer un pequeño “zoom” a las observaciones que tienen un hwy entre 20 y 30 y un displ entre 2 y 3, tendríamos que hacer lo siguiente:

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color=class)) + 
  scale_y_continuous(limits = c(20,30)) +
  scale_x_continuous(limits = c(2,4)) + 
  scale_color_discrete(labels = c("Two seater", "Compact", "Mid size", "Mini van",
                                  "Pick up", "Sub compact", "SUV"))

Leyendas

En ocasiones los puntos que se visualizan en la gráfica no coinciden con los que se visualizan en la leyenda. Por ejemplo:

mydata <- data.frame(p = 1:3, q = 1:3, r = c("a","b","c"))

ggplot(mydata, aes(p, q)) +
  geom_point(size = 4) +
  geom_point(aes(color = r), size = 2)

Para resolver esta situación solo debemos de agregar el argumento show.legend y darle el valor de TRUE.

mydata <- data.frame(p = 1:3, q = 1:3, r = c("a","b","c"))
ggplot(mydata, aes(p, q)) +
  geom_point(size = 4, show.legend = TRUE) +
  geom_point(aes(color = r), size = 2)

Ubicación de la leyenda

Para poder manipular la leyenda utilizaremos el layer llamado theme() y el argumento legend.position().

Con este argumento podemos usar las siguientes 4 opciones:

  • legend.position = “top”, para que se ubique en la parte superior.
  • legend.position = “bottom”, para que se ubique en la parte inferior.
  • legend.position= “left”, para que se ubique a la izquierda de la gráfica.
  • legend.position = “right”, para que se ubique a la derecha de la gráfica.
  • legend.position = “none”, para que no se muestre la leyenda en la gráfica.
ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color=class)) + 
  scale_color_discrete(labels = c("Two seater", "Compact", "Mid size", "Mini van",
                                  "Pick up", "Sub compact", "SUV")) + 
  labs(title = "Con la leyenda en la parte superior",
       subtitle = "Manipulando la leyenda") + 
  theme(legend.position = "top")

También se puede modificar la distribución de los elementos de la leyenda. Para esto utilizaremos el argumento legend.direction con las siguientes opciones:

  • legend.direction = “horizontal”
  • legend.direction = “vertical”
ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color=class)) + 
  scale_color_discrete(labels = c("Two seater", "Compact", "Mid size", "Mini van",
                                  "Pick up", "Sub compact", "SUV")) + 
  labs(title = "Con la leyenda en la parte superior",
       subtitle = "Manipulando la leyenda") + 
  theme(legend.position = "top", legend.direction = "vertical")

Otro ejemplo sería:

ggplot(mpg, aes(x = displ, y = hwy)) + 
  geom_point(aes(color=drv)) + 
  labs(title = "Distribución horizontal de los elementos de la leyenda",
       subtitle = "Manipulando la leyenda") + 
  theme(legend.direction = "horizontal")

LS0tCnRpdGxlOiAiZ2dwbG90IC0gRWplcyB5IGxleWVuZGFzIGRlIHVuYSBncsOhZmljYSIKYXV0aG9yOiAiSkpHUyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKYGBgCgojIyAqKkxhcyBmdW5jaW9uZXMgZGUgbG9zIHTDrXR1bG9zIGRlIGxvcyBlamVzKioKClBhcmEgZW1wZXphciBhIGNvbm9jZXIgbGFzIGRpZmVyZW50ZXMgb3BjaW9uZXMgcXVlIGV4aXN0ZW4gcGFyYSBsb3MgZWplcyBkZSBsYXMgZ3LDoWZpY2FzIHZhbW9zIGEgdXRpbGl6YXIgdW5hIGdyw6FmaWNhIGRlIGRpc3BlcnNpw7NuIGNvbW8gZWplbXBsbyBiYXNlLiAKCmBgYHtyfQpnZ3Bsb3QobXBnLCBhZXMoZGlzcGwsIGh3eSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBjbGFzcykpCmBgYAoKRW4gZXN0YSBvY2FzacOzbiB0ZW5lbW9zIHVuYSBncsOhZmljYSBkZSBkaXNwZXJzacOzbiBxdWUgcmVsYWNpb25hIGxhcyB2YXJpYWJsZXMgYGh3eWAgeSBgZGlzcGxgLCBkaXN0aW5ndWllbmRvIGxhIGNsYXNlIGRlbCB2ZWjDrWN1bG8gY29uIGNvbG9yIGRpZmVyZW50ZS4KClNpIG9ic2VydmFtb3MgbGEgZ3LDoWZpY2EgcG9kZW1vcyBvYnNlcnZhciBxdWUgZWwgdMOtdHVsbyBkZSBsYXMgdmFyaWFibGVzIGRlIGxvcyBlamVzICoqIngiKiogeSAqKiJ5IioqLCBhc8OtIGNvbW8gdGFtYmnDqW4gZWwgKipjb2xvcioqLCBhcGFyZWNlbiBjb24gZWwgbWlzbW8gbm9tYnJlIHF1ZSB0aWVuZW4gbGFzIHZhcmlhYmxlcyBlbiBsYSBiYXNlIGRlIGRhdG9zLgoKYGBge3J9Cm5hbWVzKG1wZykKYGBgCgpFbCBhYnJldmlhciBlbCBub21icmUgZGUgbGFzIHZhcmlhYmxlcyBlbiBsYSBiYXNlIGRlIGRhdG9zIGVzIGNvbcO6biBwZXJvIGVuIG51ZXN0cmEgZ3LDoWZpY2Egbm8gcXVlcmVtb3MgcXVlIHNlIHByZXNlbnRlbiBkZSBlc3RhIGZvcm1hLiBMYSB2YXJpYWJsZSBgaHd5YCByZXByZXNlbnRhICpoaWdod2F5IG1pbGVzIHBlciBnYWxsb24qLCBsYSB2YXJpYWJsZSBgZGlzcGxgIHJlcHJlc2VudGEgKmVuZ2luZSBkaXNwbGFjZW1lbnQsIGluIGxpdHJlcyosIG1pZW50cmFzIHF1ZSBsYSB2YXJpYWJsZSBjbGFzcyBzaWduaWZpY2EgKiJ0eXBlIiBvZiBjYXIqLgoKQ29uIGJhc2UgZW4gZXN0bywgY2FtYmlhcmVtb3MgZWwgdMOtdHVsbyBkZSBsYXMgdmFyaWFibGVzLiBQYXJhIGhhY2VyIGVzdG8sIHRlbmRyZW1vcyBxdWUgYWdyZWdhciBhbGd1bm9zICpsYXllcnMqIHF1ZSBkZXBlbmRlbiBkZSBsYXMgdmFyaWFibGVzIHF1ZSBxdWVyZW1vcyBtb2RpZmljYXIuIFBvciBlamVtcGxvLCB0ZW5lbW9zIGVzdGFzIG9wY2lvbmVzOgoKKiBzY2FsZV94XyoKKiBzY2FsZV95XyoKKiBzY2FsZV9jb2xvcl8qCgpkb25kZSBlbCAqIHJlcHJlc2VudGEgZWwgdGlwbyBkZSB2YXJpYWJsZSwgKipkaXNjcmV0YSBvIGNvbnRpbnVhKiouIFBvciBlamVtcGxvLCBlbiBudWVzdHJvIGVqZW1wbG8gbGFzIHZhcmlhYmxlcyBgaHd5YCB5IGBkaXNwbGAgc29uIHZhcmlhYmxlcyAqKmNvbnRpbnVhcyoqLCBtaWVudHJhcyBxdWUgYGNsYXNzYCBlcyB1bmEgdmFyaWFibGUgKipkaXNjcmV0YSoqLgoKUGFyYSBudWVzdHJhIGdyw6FmaWNhIHRlbmRyw61hbW9zIHF1ZSB1dGlsaXphciBsb3Mgc2lndWllbnRlcyAqbGF5ZXJzKjoKCiogc2NhbGVfeF8qKmNvbnRpbnVvdXMqKigpCiogc2NhbGVfeV8qKmNvbnRpbnVvdXMqKigpCiogc2NhbGVfY29sb3JfKipkaXNjcmV0ZSoqKCkKCiMjICoqVMOtdHVsb3MqKgoKUGFyYSBxdWUgbm8gYXBhcmV6Y2EgdMOtdHVsbyBkZSBsb3MgZWplcyBlbiBsYXMgZ3LDoWZpY2FzIHNvbG8gZGViZW1vcyBkZSBlc2NyaWJpciAqKk5VTEwqKiBkZW50cm8gbG9zIHBhcsOpbnRlc2lzLgoKYGBge3J9CmdncGxvdChtcGcsIGFlcyhkaXNwbCwgaHd5KSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IGNsYXNzKSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoTlVMTCkgKyAKICBzY2FsZV95X2NvbnRpbnVvdXMoTlVMTCkgKyAKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShOVUxMKQpgYGAKCkNvbW8gcG9kZW1vcyBvYnNlcnZhciBlbiBsYSBncsOhZmljYSwgbG9zIHTDrXR1bG9zIGRlIGxvcyBlamVzIHkgbGEgbGV5ZW5kYSBkZSBjb2xvcmVzIGRlc2FwYXJlY2llcm9uLgoKUGFyYSBhc2lnbmFybGUgdMOtdHVsbyBzb2xvIHRlbmVtb3MgcXVlIGluZGljYXJsbyBkZW50cm8gbG9zIHBhcsOpbnRlc2lzIGRlIGxvcyAqbGF5ZXJzKiwgcG9yIGVqZW1wbG86CgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKGRpc3BsLCBod3kpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY2xhc3MpKSArIAogIHNjYWxlX3hfY29udGludW91cygiRW5naW5lIERpc3BsYWNlbWVudCIpICsgCiAgc2NhbGVfeV9jb250aW51b3VzKCJIaWdod2F5IG1pbGVzIHBlciBnYWxsb24iKSArIAogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKCJUeXBlIG9mIGNhciIpCmBgYAoKwqFMaXN0byEgWWEgbGUgaGVtb3MgYXNpZ25hZG8gZWwgdMOtdHVsbyBhIGxvcyBlamVzIHkgbGV5ZW5kYSBkZSBudWVzdHJhIGdyw6FmaWNhLgoKT3RyYSBmb3JtYSBkZSB0ZW5lciAqKmVsIG1pc21vIHJlc3VsdGFkbyoqLCBwcm9iYWJsZW1lbnRlIG3DoXMgcsOhcGlkbywgZXMgdXRpbGl6YXIgZWwgKmxheWVyKiBgbGFic2AsIGFicmV2aWFjacOzbiBkZSBsYWJlbHMuCgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKGRpc3BsLCBod3kpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY2xhc3MpKSArIAogIGxhYnMoeCA9ICJFbmdpbmUgRGlzcGxhY2VtZW50IiAsIHkgPSAiSGlnaHdheSBtaWxlcyBwZXIgZ2FsbG9uIiAsIGNvbG9yID0gIlR5cGUgb2YgY2FyIikKYGBgCgojIyAqKk3DoXMgZGUgdW4gcmVuZ2zDs24gZW4gdW4gdMOtdHVsbyoqCgpTdXBvbmdhbW9zIHF1ZSBxdWVyZW1vcyB0ZW5lciB1biB0w610dWxvIG11eSBleHRlbnNvIHkgcGFyYSBubyBjdWJyaXIgdG9kYSBlbCDDoXJlYSBkZWwgZWplIHF1ZXJlbW9zIHV0aWxpemFyIG3DoXMgZGUgdW4gcmVuZ2zDs24uIEVzdG8gZXMgIG11eSBzZW5jaWxsbywgc29sbyB0ZW5lbW9zIHF1ZSBpbmNsdWlyICoqXG4qKiBzaW4gZXNwYWNpbyBlbnRyZSBlbCB0ZXh0byBvIGNhcmFjdGVyZXMgcGFyYSBpbmRpY2FyIHF1ZSBzZSBxdWllcmUgdXNhciBtw6FzIGRlIHVuIHJlbmdsw7NuLiBQb3IgZWplbXBsbzoKCmBgYHtyfQpnZ3Bsb3QobXBnLCBhZXMoeCA9IGRpc3BsLCBod3kpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gY2xhc3MpKSArIAogIHNjYWxlX3hfY29udGludW91cygiRW5naW5lXG5EaXNwbGFjZW1lbnQiKSArIAogIHNjYWxlX3lfY29udGludW91cygiSGlnaHdheVxubWlsZXMgcGVyIGdhbGxvbiIpICsgCiAgc2NhbGVfY29sb3JfZGlzY3JldGUoIlR5cGVcbm9mXG5jYXIiKQpgYGAKCkRlIGVzdGEgZm9ybWEgcG9kZW1vcyB1c2FyIG3DoXMgZGUgdW4gcmVuZ2zDs24gZW4gbG9zIHTDrXR1bG9zIGRlIGxvcyBlamVzLgoKIyMgKipFc2NhbGEgeSBldGlxdWV0YXMgZGUgbG9zIGVqZXMqKgoKRW4gb2Nhc2lvbmVzIHZhbW9zIGEgcXVlcmVyIG1hbmlwdWxhciBsb3MgZWplcyBkZSBsYSBncsOhZmljYS4gUGFyYSBwb2RlciByZWFsaXphciBlc3RvLCBsb3MgYXJndW1lbnRvcyBtw6FzIHV0aWxpemFkb3Mgc29uOgoKKiAqKmxhYmVscyoqKCksIHF1ZSBzaXJ2ZSBwYXJhIGFzaWduYXIgKipsYSBldGlxdWV0YSoqIHF1ZSBsbGV2YXLDoSBlbCBlamUuCiogKipsaW1pdHMqKigpLCBxdWUgc2lydmUgcGFyYSBhc2lnbmFyICoqZWwgcmFuZ28qKiBxdWUgbGxldmFyw6EgZWwgZWplCiogKipicmVha3MqKigpLCBxdWUgc2lydmUgcGFyYSBpbmRpY2FyICoqbGFzIGzDrW5lYXMgZGUgcmVmZXJlbmNpYSBvICJxdWllYnJlcyIqKiBxdWUgdGVuZHLDoSBlbCBlamUKCkVzdGEgZXMgbGEgZ3LDoWZpY2Egb3JpZ2luYWw6CgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9Y2xhc3MpKSAKYGBgCgpDYW1iaWFuZG8gZWwgY29udGVuaWRvIGRlIGxvcyBicmVha3MgeSBsYXMgZXRpcXVldGFzOgoKYGBge3J9CmdncGxvdChtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNsYXNzKSkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gYygxOjcpLAogICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygiSSIsIklJIiwgIklJSSIsICJJViIsICJWIiwgIlZJIiwgIlZJSSIpKQpgYGAKClBhcmEgY2FtYmlhciBsYSBsZXllbmRhIGVzIGFsZ28gbXV5IHNpbWlsYXIuCgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9Y2xhc3MpKSArIAogIHNjYWxlX2NvbG9yX2Rpc2NyZXRlKGxhYmVscyA9IGMoIlR3byBzZWF0ZXIiLCAiQ29tcGFjdCIsICJNaWQgc2l6ZSIsICJNaW5pIHZhbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUGljayB1cCIsICJTdWIgY29tcGFjdCIsICJTVVYiKSkKCmBgYAoKRW4gb2Nhc2lvbmVzIHF1ZXJlbW9zIHJlYWxpemFyIHVuICJ6b29tIiBhIHVuYSBwYXJ0ZSBlbiBlc3BlY8OtZmljbyBkZSBsYSBncsOhZmljYSwgcGFyYSBlc3RvIG5lY2VzaXRhbW9zIGluZGljYXIgKiplbCByYW5nbyoqIHF1ZSB1dGlsaXphcsOhIGVsIGVqZSBkZSBsYSBncsOhZmljYS4gUGFyYSBlc3RvLCB1c2FyZW1vcyBsYSBmdW5jacOzbiAqKmxpbWl0cygpKioKCmBgYHtyfQpnZ3Bsb3QobXBnLCBhZXMoeCA9IGRpc3BsLCB5ID0gaHd5KSkgKyAKICBnZW9tX3BvaW50KGFlcyhjb2xvcj1jbGFzcykpICsgCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobGFiZWxzID0gYygiVHdvIHNlYXRlciIsICJDb21wYWN0IiwgIk1pZCBzaXplIiwgIk1pbmkgdmFuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQaWNrIHVwIiwgIlN1YiBjb21wYWN0IiwgIlNVViIpKSAKYGBgCgpTaSBxdWVyZW1vcyBoYWNlciB1biBwZXF1ZcOxbyAiem9vbSIgYSBsYXMgb2JzZXJ2YWNpb25lcyBxdWUgdGllbmVuIHVuIGBod3lgICoqZW50cmUgMjAgeSAzMCoqIHkgdW4gYGRpc3BsYCAqKmVudHJlIDIgeSAzKiosIHRlbmRyw61hbW9zIHF1ZSBoYWNlciBsbyBzaWd1aWVudGU6CgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9Y2xhc3MpKSArIAogIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDIwLDMwKSkgKwogIHNjYWxlX3hfY29udGludW91cyhsaW1pdHMgPSBjKDIsNCkpICsgCiAgc2NhbGVfY29sb3JfZGlzY3JldGUobGFiZWxzID0gYygiVHdvIHNlYXRlciIsICJDb21wYWN0IiwgIk1pZCBzaXplIiwgIk1pbmkgdmFuIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQaWNrIHVwIiwgIlN1YiBjb21wYWN0IiwgIlNVViIpKQpgYGAKCiMjICoqTGV5ZW5kYXMqKgoKRW4gb2Nhc2lvbmVzIGxvcyBwdW50b3MgcXVlIHNlIHZpc3VhbGl6YW4gZW4gbGEgZ3LDoWZpY2Egbm8gY29pbmNpZGVuIGNvbiBsb3MgcXVlIHNlIHZpc3VhbGl6YW4gZW4gbGEgbGV5ZW5kYS4gUG9yIGVqZW1wbG86CgpgYGB7cn0KbXlkYXRhIDwtIGRhdGEuZnJhbWUocCA9IDE6MywgcSA9IDE6MywgciA9IGMoImEiLCJiIiwiYyIpKQoKZ2dwbG90KG15ZGF0YSwgYWVzKHAsIHEpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gciksIHNpemUgPSAyKQpgYGAKClBhcmEgcmVzb2x2ZXIgZXN0YSBzaXR1YWNpw7NuIHNvbG8gZGViZW1vcyBkZSBhZ3JlZ2FyIGVsIGFyZ3VtZW50byBgc2hvdy5sZWdlbmRgIHkgZGFybGUgZWwgdmFsb3IgZGUgKipUUlVFKiouIAoKYGBge3J9Cm15ZGF0YSA8LSBkYXRhLmZyYW1lKHAgPSAxOjMsIHEgPSAxOjMsIHIgPSBjKCJhIiwiYiIsImMiKSkKZ2dwbG90KG15ZGF0YSwgYWVzKHAsIHEpKSArCiAgZ2VvbV9wb2ludChzaXplID0gNCwgc2hvdy5sZWdlbmQgPSBUUlVFKSArCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSByKSwgc2l6ZSA9IDIpCmBgYAoKIyMgKipVYmljYWNpw7NuIGRlIGxhIGxleWVuZGEqKgoKUGFyYSBwb2RlciBtYW5pcHVsYXIgbGEgbGV5ZW5kYSB1dGlsaXphcmVtb3MgZWwgbGF5ZXIgbGxhbWFkbyBgdGhlbWUoKWAgeSBlbCBhcmd1bWVudG8gYGxlZ2VuZC5wb3NpdGlvbigpYC4KCkNvbiBlc3RlIGFyZ3VtZW50byBwb2RlbW9zIHVzYXIgbGFzIHNpZ3VpZW50ZXMgNCBvcGNpb25lczoKCiogKipsZWdlbmQucG9zaXRpb24gPSAidG9wIioqLCBwYXJhIHF1ZSBzZSB1YmlxdWUgZW4gbGEgcGFydGUgc3VwZXJpb3IuCiogKipsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIioqLCBwYXJhIHF1ZSBzZSB1YmlxdWUgZW4gbGEgcGFydGUgaW5mZXJpb3IuCiogKipsZWdlbmQucG9zaXRpb249ICJsZWZ0IioqLCBwYXJhIHF1ZSBzZSB1YmlxdWUgYSBsYSBpenF1aWVyZGEgZGUgbGEgZ3LDoWZpY2EuCiogKipsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKiosIHBhcmEgcXVlIHNlIHViaXF1ZSBhIGxhIGRlcmVjaGEgZGUgbGEgZ3LDoWZpY2EuCiogKipsZWdlbmQucG9zaXRpb24gPSAibm9uZSIqKiwgcGFyYSBxdWUgbm8gc2UgbXVlc3RyZSBsYSBsZXllbmRhIGVuIGxhIGdyw6FmaWNhLgoKYGBge3J9CmdncGxvdChtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNsYXNzKSkgKyAKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShsYWJlbHMgPSBjKCJUd28gc2VhdGVyIiwgIkNvbXBhY3QiLCAiTWlkIHNpemUiLCAiTWluaSB2YW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBpY2sgdXAiLCAiU3ViIGNvbXBhY3QiLCAiU1VWIikpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCmBgYAoKVGFtYmnDqW4gc2UgcHVlZGUgbW9kaWZpY2FyIGxhIGRpc3RyaWJ1Y2nDs24gZGUgbG9zIGVsZW1lbnRvcyBkZSBsYSBsZXllbmRhLiBQYXJhIGVzdG8gdXRpbGl6YXJlbW9zIGVsIGFyZ3VtZW50byBgbGVnZW5kLmRpcmVjdGlvbmAgY29uIGxhcyBzaWd1aWVudGVzIG9wY2lvbmVzOgoKKiAqKmxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIqKgoqICoqbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIqKgoKYGBge3J9CmdncGxvdChtcGcsIGFlcyh4ID0gZGlzcGwsIHkgPSBod3kpKSArIAogIGdlb21fcG9pbnQoYWVzKGNvbG9yPWNsYXNzKSkgKyAKICBzY2FsZV9jb2xvcl9kaXNjcmV0ZShsYWJlbHMgPSBjKCJUd28gc2VhdGVyIiwgIkNvbXBhY3QiLCAiTWlkIHNpemUiLCAiTWluaSB2YW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBpY2sgdXAiLCAiU3ViIGNvbXBhY3QiLCAiU1VWIikpICsgCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAidmVydGljYWwiKQpgYGAKCk90cm8gZWplbXBsbyBzZXLDrWE6CgpgYGB7cn0KZ2dwbG90KG1wZywgYWVzKHggPSBkaXNwbCwgeSA9IGh3eSkpICsgCiAgZ2VvbV9wb2ludChhZXMoY29sb3I9ZHJ2KSkgKyAKICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gaG9yaXpvbnRhbCBkZSBsb3MgZWxlbWVudG9zIGRlIGxhIGxleWVuZGEiLAogICAgICAgc3VidGl0bGUgPSAiTWFuaXB1bGFuZG8gbGEgbGV5ZW5kYSIpICsgCiAgdGhlbWUobGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikKYGBgCgoKCgo=