1 Graficos en R

R dispone de múltiples funciones diseñadas para la representación gráfica de datos. Estas funciones se dividen en dos grandes grupos: funciones gráficas de alto nivel y de bajo nivel.

1.1 Plot en R

La función gráfica más básica en R es la función plot. Esta función tiene múltiples argumentos para configurar el gráfico final, que permiten agregar un título, cambiar las etiquetas de los ejes, personalizar colores, cambiar tipos de línea, etc. Con la función plot se puede crear una amplia gama de gráficos, dependiendo de los argumentos de entrada. El siguiente codigo realiza un diagrama de dispersion usando la funcion plot.

set.seed(1)

# Generamos datos de ejemplo
x <- rnorm(500)
y <- x + rnorm(500)

# Dibujamos los datos
plot(x, y)
title("Grafico con plot")


1.2 Gráfico de dispersión en R

Los diagramas o gráficos de dispersión, también conocidos como nubes de puntos, scatter plots o scatter chart por su nombre en inglés, representan las observaciones de las variables (generalmente dos, pero también pueden ser tres). El uso principal de un gráfico de dispersión en R es verificar visualmente si existe alguna relación entre ciertas variables numéricas.

El uso principal de los diagramas de dispersión en R es verificar la relación entre variables. Para ese propósito, puedes añadir líneas de regresión (o agregar curvas en caso de estimaciones no lineales) con la función lines, que permite personalizar el ancho de línea con el argumento lwd o el tipo de línea con el argumento lty, entre otros argumentos. En este ejemplo, vamos a ajustar un modelo lineal y otro no paramétrico con las funciones lm y lowess respectivamente, con los argumentos predeterminados.

plot(x, y, pch = 19, col = "gray52")
title("Grafico de dispersion")

# Modelo subyacente
lines(seq(0, 1, 0.05), 2 + 3 * seq(0, 1, 0.05)^2, col = "2", lwd = 3, lty = 2)

# Ajsute lineal
abline(lm(y ~ x), col = "orange", lwd = 3)

# Ajuste suavizado
lines(lowess(x, y), col = "blue", lwd = 3)

# Leyenda
legend("topleft", legend = c("Teórico", "Lineal", "Suavizado"),
       lwd = 3, lty = c(2, 1, 1), col = c("red", "orange", "blue"))

1.3 Gráfico de barras en R

Cuando una variable toma pocos valores, es común resumir la información con una tabla de frecuencias que se puede representar con un gráfico de barras en R. Este tipo de gráficos se suelen utilizar, por ejemplo, para representar precipitaciones y temperaturas (si añadimos una curva por encima), en lo que se conoce como climogramas. En este artículo vamos a explicar los conceptos básicos de la creación de diagramas de barras en R.

Para crear un gráfico de barras en R, puedes usar la función de R base barplot.

# Cargamos los datos
data(mtcars)
attach(mtcars)
## The following object is masked from package:ggplot2:
## 
##     mpg

# Tabla de frecuencias
mi_tabla <- table(cyl)

barplot(mi_tabla, main = "Grafico de barras",
        col = rainbow(3))


1.4 Histograma en R

Un histograma en R es el gráfico más habitual para representar datos continuos. Este tipo de gráfico es similar a un diagrama de barras, pero que representa las frecuencias en las que aparecen las mediciones agrupadas en ciertos intervalos y cuenta cuántas observaciones caen en cada intervalo. Además, la altura está determinada por el ratio entre la frecuencia y el ancho del intervalo.

Puedes dibujar un histograma en R con la función hist. Por defecto, la función creará un histograma de frecuencias.

#datos
distancia <- c(241.1, 284.4, 220.2, 272.4, 271.1, 268.3,
               291.6, 241.6, 286.1, 285.9, 259.6, 299.6,
               253.1, 239.6, 277.8, 263.8, 267.2, 272.6,
               283.4, 234.5, 260.4, 264.2, 295.1, 276.4,
               263.1, 251.4, 264.0, 269.2, 281.0, 283.2)

hist(distancia, main = "Histograma de frecuencias", # Frecuencia
     ylab = "Frecuencia",col = "lightblue")

Para crear un histograma con el paquete ggplot2, debes usar las funciones ggplot + geom_histogram y pasar los datos como data frame. En el argumento aes debes especificar el nombre de la variable del data frame.

nbreaks <- pretty(range(distancia), n = nclass.Sturges(distancia), min.n = 1)

ggplot(data.frame(distancia), aes(x = distancia)) + 
      geom_histogram(breaks = nbreaks, color = "gray", fill = "white")

1.5 Gráfico de densidad en R

La función de densidad de probabilidad de un vector x, que se suele denotar como f(x) describe la probabilidad de que la variable tome un determinado valor. La función de densidad de probabilidad empírica es una versión suavizada del histograma. Esta suavización también se conoce como estimador de Parzen-Rosenblatt o estimador kernel. Puedes hacer un gráfico de densidad en R de manera muy sencilla tal y como mostraremos en este tutorial. Al final de la lectura sabrás cómo dibujar diagramas de densidad tanto en R como en RStudio.

Para crear un gráfico de densidad en R, puedes pasar a la función plot un objeto creado con la función density de R, que dibujará una curva de densidad en una nueva ventana. Si lo prefieres, también puedes superponer la línea de densidad sobre un histograma con la función lines.

set.seed(1234)

# Generamos datos
x <- rnorm(500)
par(mfrow = c(1, 2))

# Creamos un histograma
hist(x, freq = FALSE, main = "Histograma y densidad",
     ylab = "Densidad")

# Calculamos la densidad
dx <- density(x)

# Añadimos la línea de densidad
lines(dx, lwd = 2, col = "red")

# Curva de densidad sin histograma
plot(dx, lwd = 2, col = "red",
     main = "Densidad")

# Añadimos los datos con riudo en el eje X
rug(jitter(x))


1.6 Box plot en R

Los box plots, también conocidos como diagramas de cajas y bigotes, son una representación gráfica que permite resumir las características principales de los datos (posición, dispersión, asimetría, …) e identificar la presencia de valores atípicos. En este tutorial revisaremos cómo hacer box plots en R base y en ggplot2.

Cómo hacer un boxplot en R a partir de un vector, solo necesitas pasar el vector a la función boxplot. Por defecto, el diagrama de caja será vertical, pero puedes cambiar la orientación estableciendo el argumento horizontal como TRUE.

x <- c(8, 5, 14, -9, 19, 12, 3, 9, 7, 4,
       4, 6, 8, 12, -8, 2, 0, -1, 5, 3)
boxplot(x, horizontal = TRUE)
stripchart(x, method = "jitter", pch = 19, add = TRUE, col = "blue")
LS0tDQp0aXRsZTogIkFwcmVuZGVyIEdyw6FmaWNvcyBlbiBSIg0KYXV0aG9yOiAiRGllZ28gQXJtYW5kbyBTb3RpbCBDY2FtYSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCnN1YnRpdGxlOiAiUiBhbmQgTWFya2Rvd24iDQpwb3NpdGlvbjogU3R1ZGVudA0KZW1haWw6IGRpZWdvLnNvdGlsY2NhbWFAZ21haWwuY29tDQpwaG9uZTogOTQwNTIwMTg3DQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIGNvZGVfZm9sZGluZzogc2hvdw0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHRydWUNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQogICAgdGhlbWU6IHBhcGVyDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQoNCmxpYnJhcnkoImdncGxvdDIiKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KYGBgDQoNCg0KIyBHcmFmaWNvcyBlbiBSDQpbUl0oaHR0cHM6Ly93d3cuci1wcm9qZWN0Lm9yZy8pe3RhcmdldD1fYmxhbmt9IGRpc3BvbmUgZGUgbcO6bHRpcGxlcyBmdW5jaW9uZXMgZGlzZcOxYWRhcyBwYXJhIGxhIHJlcHJlc2VudGFjacOzbiBncsOhZmljYSBkZSBkYXRvcy4gRXN0YXMgZnVuY2lvbmVzIHNlIGRpdmlkZW4gZW4gZG9zIGdyYW5kZXMgZ3J1cG9zOiBmdW5jaW9uZXMgKipncsOhZmljYXMqKiBkZSAqYWx0byBuaXZlbCogeSBkZSAqYmFqbyBuaXZlbCouDQoNCg0KIyMgUGxvdCBlbiBSDQoNCkxhIGZ1bmNpw7NuIGdyw6FmaWNhIG3DoXMgYsOhc2ljYSBlbiBSIGVzIGxhIGZ1bmNpw7NuIGBwbG90YC4gRXN0YSBmdW5jacOzbiB0aWVuZSBtw7psdGlwbGVzIGFyZ3VtZW50b3MgcGFyYSBjb25maWd1cmFyIGVsIGdyw6FmaWNvIGZpbmFsLCBxdWUgcGVybWl0ZW4gYWdyZWdhciB1biB0w610dWxvLCBjYW1iaWFyIGxhcyBldGlxdWV0YXMgZGUgbG9zIGVqZXMsIHBlcnNvbmFsaXphciBjb2xvcmVzLCBjYW1iaWFyIHRpcG9zIGRlIGzDrW5lYSwgZXRjLiBDb24gbGEgZnVuY2nDs24gYHBsb3RgIHNlIHB1ZWRlIGNyZWFyIHVuYSBhbXBsaWEgZ2FtYSBkZSBncsOhZmljb3MsIGRlcGVuZGllbmRvIGRlIGxvcyBhcmd1bWVudG9zIGRlIGVudHJhZGEuIEVsIHNpZ3VpZW50ZSBjb2RpZ28gcmVhbGl6YSB1biAqKipkaWFncmFtYSBkZSBkaXNwZXJzaW9uKioqIHVzYW5kbyBsYSBmdW5jaW9uIGBwbG90YC4NCg0KYGBge3IgUGxvdCwgZmlnLmFsaWduPSdjZW50ZXInfQ0Kc2V0LnNlZWQoMSkNCg0KIyBHZW5lcmFtb3MgZGF0b3MgZGUgZWplbXBsbw0KeCA8LSBybm9ybSg1MDApDQp5IDwtIHggKyBybm9ybSg1MDApDQoNCiMgRGlidWphbW9zIGxvcyBkYXRvcw0KcGxvdCh4LCB5KQ0KdGl0bGUoIkdyYWZpY28gY29uIHBsb3QiKQ0KDQpgYGANCg0KKioqDQojIyBHcsOhZmljbyBkZSBkaXNwZXJzacOzbiBlbiBSDQoqKkxvcyBkaWFncmFtYXMgbyBncsOhZmljb3MgZGUgZGlzcGVyc2nDs24qKiwgdGFtYmnDqW4gY29ub2NpZG9zIGNvbW8gbnViZXMgZGUgcHVudG9zLCAqc2NhdHRlciBwbG90cyogbyAqc2NhdHRlciBjaGFydCogcG9yIHN1IG5vbWJyZSBlbiBpbmdsw6lzLCAqKnJlcHJlc2VudGFuIGxhcyBvYnNlcnZhY2lvbmVzIGRlIGxhcyB2YXJpYWJsZXMqKiAoZ2VuZXJhbG1lbnRlIGRvcywgcGVybyB0YW1iacOpbiBwdWVkZW4gc2VyIHRyZXMpLiBFbCB1c28gcHJpbmNpcGFsIGRlIHVuIGdyw6FmaWNvIGRlIGRpc3BlcnNpw7NuIGVuIFIgZXMgdmVyaWZpY2FyIHZpc3VhbG1lbnRlIHNpIGV4aXN0ZSBhbGd1bmEgcmVsYWNpw7NuIGVudHJlIGNpZXJ0YXMgdmFyaWFibGVzIG51bcOpcmljYXMuDQoNCkVsIHVzbyBwcmluY2lwYWwgZGUgbG9zIGRpYWdyYW1hcyBkZSBkaXNwZXJzacOzbiBlbiBSIGVzICoqdmVyaWZpY2FyIGxhIHJlbGFjacOzbiBlbnRyZSB2YXJpYWJsZXMqKi4gUGFyYSBlc2UgcHJvcMOzc2l0bywgcHVlZGVzIGHDsWFkaXIgKipsw61uZWFzIGRlIHJlZ3Jlc2nDs24qKiAobyBhZ3JlZ2FyIGN1cnZhcyBlbiBjYXNvIGRlIGVzdGltYWNpb25lcyBubyBsaW5lYWxlcykgY29uIGxhIGZ1bmNpw7NuIGBsaW5lc2AsIHF1ZSBwZXJtaXRlIHBlcnNvbmFsaXphciBlbCBhbmNobyBkZSBsw61uZWEgY29uIGVsIGFyZ3VtZW50byBgbHdkYCBvIGVsIHRpcG8gZGUgbMOtbmVhIGNvbiBlbCBhcmd1bWVudG8gYGx0eWAsIGVudHJlIG90cm9zIGFyZ3VtZW50b3MuIEVuIGVzdGUgZWplbXBsbywgdmFtb3MgYSBhanVzdGFyIHVuIG1vZGVsbyBsaW5lYWwgeSBvdHJvIG5vIHBhcmFtw6l0cmljbyBjb24gbGFzIGZ1bmNpb25lcyBgbG1gIHkgYGxvd2Vzc2AgcmVzcGVjdGl2YW1lbnRlLCBjb24gbG9zIGFyZ3VtZW50b3MgcHJlZGV0ZXJtaW5hZG9zLg0KDQoNCmBgYHtyIGRpc3BlcnNpb24sIGZpZy5hbGlnbj0nY2VudGVyJ30NCg0KcGxvdCh4LCB5LCBwY2ggPSAxOSwgY29sID0gImdyYXk1MiIpDQp0aXRsZSgiR3JhZmljbyBkZSBkaXNwZXJzaW9uIikNCg0KIyBNb2RlbG8gc3VieWFjZW50ZQ0KbGluZXMoc2VxKDAsIDEsIDAuMDUpLCAyICsgMyAqIHNlcSgwLCAxLCAwLjA1KV4yLCBjb2wgPSAiMiIsIGx3ZCA9IDMsIGx0eSA9IDIpDQoNCiMgQWpzdXRlIGxpbmVhbA0KYWJsaW5lKGxtKHkgfiB4KSwgY29sID0gIm9yYW5nZSIsIGx3ZCA9IDMpDQoNCiMgQWp1c3RlIHN1YXZpemFkbw0KbGluZXMobG93ZXNzKHgsIHkpLCBjb2wgPSAiYmx1ZSIsIGx3ZCA9IDMpDQoNCiMgTGV5ZW5kYQ0KbGVnZW5kKCJ0b3BsZWZ0IiwgbGVnZW5kID0gYygiVGXDs3JpY28iLCAiTGluZWFsIiwgIlN1YXZpemFkbyIpLA0KICAgICAgIGx3ZCA9IDMsIGx0eSA9IGMoMiwgMSwgMSksIGNvbCA9IGMoInJlZCIsICJvcmFuZ2UiLCAiYmx1ZSIpKQ0KDQpgYGANCjxjZW50ZXI+DQoNCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvM2lwZTA5VldvTGMiIGZyYW1lYm9yZGVyPSIwIiBhbGxvd2Z1bGxzY3JlZW4gZGF0YS1leHRlcm5hbD0xPjwvaWZyYW1lPg0KDQo8L2NlbnRlcj4NCg0KKioqDQojIyBHcsOhZmljbyBkZSBiYXJyYXMgZW4gUg0KQ3VhbmRvIHVuYSB2YXJpYWJsZSB0b21hIHBvY29zIHZhbG9yZXMsIGVzIGNvbcO6biByZXN1bWlyIGxhIGluZm9ybWFjacOzbiBjb24gdW5hIHRhYmxhIGRlIGZyZWN1ZW5jaWFzIHF1ZSBzZSBwdWVkZSByZXByZXNlbnRhciBjb24gdW4gZ3LDoWZpY28gZGUgYmFycmFzIGVuIFIuIEVzdGUgdGlwbyBkZSBncsOhZmljb3Mgc2Ugc3VlbGVuIHV0aWxpemFyLCBwb3IgZWplbXBsbywgcGFyYSByZXByZXNlbnRhciBwcmVjaXBpdGFjaW9uZXMgeSB0ZW1wZXJhdHVyYXMgKHNpIGHDsWFkaW1vcyB1bmEgY3VydmEgcG9yIGVuY2ltYSksIGVuIGxvIHF1ZSBzZSBjb25vY2UgY29tbyBjbGltb2dyYW1hcy4gRW4gZXN0ZSBhcnTDrWN1bG8gdmFtb3MgYSBleHBsaWNhciBsb3MgY29uY2VwdG9zIGLDoXNpY29zIGRlIGxhICoqY3JlYWNpw7NuIGRlIGRpYWdyYW1hcyBkZSBiYXJyYXMgZW4gUioqLg0KDQpQYXJhIGNyZWFyIHVuIGdyw6FmaWNvIGRlIGJhcnJhcyBlbiBSLCBwdWVkZXMgdXNhciBsYSBmdW5jacOzbiBkZSBSIGJhc2UgYGJhcnBsb3RgLg0KDQpgYGB7ciBiYXJyYXMsIGZpZy5hbGlnbj0nY2VudGVyJyxjb2xsYXBzZT1UUlVFfQ0KIyBDYXJnYW1vcyBsb3MgZGF0b3MNCmRhdGEobXRjYXJzKQ0KYXR0YWNoKG10Y2FycykNCg0KIyBUYWJsYSBkZSBmcmVjdWVuY2lhcw0KbWlfdGFibGEgPC0gdGFibGUoY3lsKQ0KDQpiYXJwbG90KG1pX3RhYmxhLCBtYWluID0gIkdyYWZpY28gZGUgYmFycmFzIiwNCiAgICAgICAgY29sID0gcmFpbmJvdygzKSkNCmBgYA0KDQo8Y2VudGVyPg0KDQo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL1c3QlU4RUpEVVVJIiBmcmFtZWJvcmRlcj0iMCIgYWxsb3dmdWxsc2NyZWVuIGRhdGEtZXh0ZXJuYWw9MT48L2lmcmFtZT4NCg0KPGNlbnRlcj4NCg0KKioqDQojIyBIaXN0b2dyYW1hIGVuIFINClVuIGhpc3RvZ3JhbWEgZW4gUiBlcyBlbCBncsOhZmljbyBtw6FzIGhhYml0dWFsIHBhcmEgcmVwcmVzZW50YXIgZGF0b3MgY29udGludW9zLiBFc3RlIHRpcG8gZGUgZ3LDoWZpY28gZXMgc2ltaWxhciBhIHVuIGRpYWdyYW1hIGRlIGJhcnJhcywgcGVybyBxdWUgcmVwcmVzZW50YSBsYXMgZnJlY3VlbmNpYXMgZW4gbGFzIHF1ZSBhcGFyZWNlbiBsYXMgbWVkaWNpb25lcyBhZ3J1cGFkYXMgZW4gY2llcnRvcyBpbnRlcnZhbG9zIHkgY3VlbnRhIGN1w6FudGFzIG9ic2VydmFjaW9uZXMgY2FlbiBlbiBjYWRhIGludGVydmFsby4gQWRlbcOhcywgbGEgYWx0dXJhIGVzdMOhIGRldGVybWluYWRhIHBvciBlbCByYXRpbyBlbnRyZSBsYSBmcmVjdWVuY2lhIHkgZWwgYW5jaG8gZGVsIGludGVydmFsby4NCg0KUHVlZGVzIGRpYnVqYXIgdW4gaGlzdG9ncmFtYSBlbiBSIGNvbiBsYSBmdW5jacOzbiBgaGlzdGAuIFBvciBkZWZlY3RvLCBsYSBmdW5jacOzbiBjcmVhcsOhIHVuIGhpc3RvZ3JhbWEgZGUgZnJlY3VlbmNpYXMuDQoNCg0KYGBge3IgaGlzdG9ncmFtYV8xLCBmaWcuYWxpZ249J2NlbnRlcid9DQojZGF0b3MNCmRpc3RhbmNpYSA8LSBjKDI0MS4xLCAyODQuNCwgMjIwLjIsIDI3Mi40LCAyNzEuMSwgMjY4LjMsDQogICAgICAgICAgICAgICAyOTEuNiwgMjQxLjYsIDI4Ni4xLCAyODUuOSwgMjU5LjYsIDI5OS42LA0KICAgICAgICAgICAgICAgMjUzLjEsIDIzOS42LCAyNzcuOCwgMjYzLjgsIDI2Ny4yLCAyNzIuNiwNCiAgICAgICAgICAgICAgIDI4My40LCAyMzQuNSwgMjYwLjQsIDI2NC4yLCAyOTUuMSwgMjc2LjQsDQogICAgICAgICAgICAgICAyNjMuMSwgMjUxLjQsIDI2NC4wLCAyNjkuMiwgMjgxLjAsIDI4My4yKQ0KDQpoaXN0KGRpc3RhbmNpYSwgbWFpbiA9ICJIaXN0b2dyYW1hIGRlIGZyZWN1ZW5jaWFzIiwgIyBGcmVjdWVuY2lhDQogICAgIHlsYWIgPSAiRnJlY3VlbmNpYSIsY29sID0gImxpZ2h0Ymx1ZSIpDQoNCg0KYGBgDQo8Y2VudGVyPg0KDQo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkL0NmeGZRSVZhVjJ3IiBmcmFtZWJvcmRlcj0iMCIgYWxsb3dmdWxsc2NyZWVuIGRhdGEtZXh0ZXJuYWw9MT48L2lmcmFtZT4NCg0KPC9jZW50ZXI+DQoNCioqKg0KUGFyYSBjcmVhciB1biBoaXN0b2dyYW1hIGNvbiBlbCBwYXF1ZXRlIGBnZ3Bsb3QyYCwgZGViZXMgdXNhciBsYXMgZnVuY2lvbmVzIGBnZ3Bsb3RgICsgYGdlb21faGlzdG9ncmFtYCB5IHBhc2FyIGxvcyBkYXRvcyBjb21vIGRhdGEgZnJhbWUuIEVuIGVsIGFyZ3VtZW50byBgYWVzYCBkZWJlcyBlc3BlY2lmaWNhciBlbCBub21icmUgZGUgbGEgdmFyaWFibGUgZGVsIGRhdGEgZnJhbWUuDQoNCg0KYGBge3IgaGlzdG9ncmFtYV8yLCBmaWcuYWxpZ249J2NlbnRlcid9DQoNCm5icmVha3MgPC0gcHJldHR5KHJhbmdlKGRpc3RhbmNpYSksIG4gPSBuY2xhc3MuU3R1cmdlcyhkaXN0YW5jaWEpLCBtaW4ubiA9IDEpDQoNCmdncGxvdChkYXRhLmZyYW1lKGRpc3RhbmNpYSksIGFlcyh4ID0gZGlzdGFuY2lhKSkgKyANCiAgICAgIGdlb21faGlzdG9ncmFtKGJyZWFrcyA9IG5icmVha3MsIGNvbG9yID0gImdyYXkiLCBmaWxsID0gIndoaXRlIikNCg0KYGBgDQo8Y2VudGVyPg0KDQo8aWZyYW1lIHdpZHRoPSI1NjAiIGhlaWdodD0iMzE1IiBzcmM9Imh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL2VtYmVkLy1BT3RIbm5HVUp3IiBmcmFtZWJvcmRlcj0iMCIgYWxsb3dmdWxsc2NyZWVuIGRhdGEtZXh0ZXJuYWw9MT48L2lmcmFtZT4gDQoNCjwvY2VudGVyPg0KDQoqKioNCiMjIEdyw6FmaWNvIGRlIGRlbnNpZGFkIGVuIFIgDQoNCkxhIGZ1bmNpw7NuIGRlIGRlbnNpZGFkIGRlIHByb2JhYmlsaWRhZCBkZSB1biB2ZWN0b3IgKngqLCBxdWUgc2Ugc3VlbGUgZGVub3RhciBjb21vICpmKHgpKiAqKmRlc2NyaWJlIGxhIHByb2JhYmlsaWRhZCBkZSBxdWUgbGEgdmFyaWFibGUgdG9tZSB1biBkZXRlcm1pbmFkbyB2YWxvcioqLiBMYSBmdW5jacOzbiBkZSBkZW5zaWRhZCBkZSBwcm9iYWJpbGlkYWQgZW1ww61yaWNhIGVzIHVuYSB2ZXJzacOzbiBzdWF2aXphZGEgZGVsIGhpc3RvZ3JhbWEuIEVzdGEgc3Vhdml6YWNpw7NuIHRhbWJpw6luIHNlIGNvbm9jZSBjb21vIGVzdGltYWRvciBkZSBQYXJ6ZW4tUm9zZW5ibGF0dCBvIGVzdGltYWRvciBrZXJuZWwuIFB1ZWRlcyBoYWNlciB1biBncsOhZmljbyBkZSBkZW5zaWRhZCBlbiBSIGRlIG1hbmVyYSBtdXkgc2VuY2lsbGEgdGFsIHkgY29tbyBtb3N0cmFyZW1vcyBlbiBlc3RlIHR1dG9yaWFsLiBBbCBmaW5hbCBkZSBsYSBsZWN0dXJhIHNhYnLDoXMgY8OzbW8gZGlidWphciBkaWFncmFtYXMgZGUgZGVuc2lkYWQgdGFudG8gZW4gUiBjb21vIGVuIFJTdHVkaW8uDQoNClBhcmEgY3JlYXIgdW4gZ3LDoWZpY28gZGUgZGVuc2lkYWQgZW4gUiwgcHVlZGVzIHBhc2FyIGEgbGEgZnVuY2nDs24gYHBsb3RgIHVuIG9iamV0byBjcmVhZG8gY29uIGxhIGZ1bmNpw7NuIGBkZW5zaXR5YCBkZSBSLCBxdWUgZGlidWphcsOhIHVuYSBjdXJ2YSBkZSBkZW5zaWRhZCBlbiB1bmEgbnVldmEgdmVudGFuYS4gU2kgbG8gcHJlZmllcmVzLCB0YW1iacOpbiBwdWVkZXMgc3VwZXJwb25lciBsYSBsw61uZWEgZGUgZGVuc2lkYWQgc29icmUgdW4gaGlzdG9ncmFtYSBjb24gbGEgZnVuY2nDs24gYGxpbmVzYC4NCg0KYGBge3IgZGVuc2lkYWQsIGZpZy5hbGlnbj0nY2VudGVyJ30NCg0Kc2V0LnNlZWQoMTIzNCkNCg0KIyBHZW5lcmFtb3MgZGF0b3MNCnggPC0gcm5vcm0oNTAwKQ0KcGFyKG1mcm93ID0gYygxLCAyKSkNCg0KIyBDcmVhbW9zIHVuIGhpc3RvZ3JhbWENCmhpc3QoeCwgZnJlcSA9IEZBTFNFLCBtYWluID0gIkhpc3RvZ3JhbWEgeSBkZW5zaWRhZCIsDQogICAgIHlsYWIgPSAiRGVuc2lkYWQiKQ0KDQojIENhbGN1bGFtb3MgbGEgZGVuc2lkYWQNCmR4IDwtIGRlbnNpdHkoeCkNCg0KIyBBw7FhZGltb3MgbGEgbMOtbmVhIGRlIGRlbnNpZGFkDQpsaW5lcyhkeCwgbHdkID0gMiwgY29sID0gInJlZCIpDQoNCiMgQ3VydmEgZGUgZGVuc2lkYWQgc2luIGhpc3RvZ3JhbWENCnBsb3QoZHgsIGx3ZCA9IDIsIGNvbCA9ICJyZWQiLA0KICAgICBtYWluID0gIkRlbnNpZGFkIikNCg0KIyBBw7FhZGltb3MgbG9zIGRhdG9zIGNvbiByaXVkbyBlbiBlbCBlamUgWA0KcnVnKGppdHRlcih4KSkNCg0KYGBgDQoNCjxjZW50ZXI+DQoNCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvaG05SkFPNHQ2THMiIGZyYW1lYm9yZGVyPSIwIiBhbGxvd2Z1bGxzY3JlZW4gZGF0YS1leHRlcm5hbD0xPjwvaWZyYW1lPg0KDQo8L2NlbnRlcj4NCg0KDQoqKioNCiMjIEJveCBwbG90IGVuIFINCg0KTG9zIGJveCBwbG90cywgdGFtYmnDqW4gY29ub2NpZG9zIGNvbW8gZGlhZ3JhbWFzIGRlIGNhamFzIHkgYmlnb3Rlcywgc29uIHVuYSByZXByZXNlbnRhY2nDs24gZ3LDoWZpY2EgcXVlIHBlcm1pdGUgcmVzdW1pciBsYXMgY2FyYWN0ZXLDrXN0aWNhcyBwcmluY2lwYWxlcyBkZSBsb3MgZGF0b3MgKHBvc2ljacOzbiwgZGlzcGVyc2nDs24sIGFzaW1ldHLDrWEsIOKApikgZSBpZGVudGlmaWNhciBsYSBwcmVzZW5jaWEgZGUgdmFsb3JlcyBhdMOtcGljb3MuIEVuIGVzdGUgdHV0b3JpYWwgcmV2aXNhcmVtb3MgY8OzbW8gaGFjZXIgYm94IHBsb3RzIGVuIFIgYmFzZSB5IGVuIGdncGxvdDIuDQoNCkPDs21vIGhhY2VyIHVuIGJveHBsb3QgZW4gUiBhIHBhcnRpciBkZSB1biB2ZWN0b3IsIHNvbG8gbmVjZXNpdGFzIHBhc2FyIGVsIHZlY3RvciBhIGxhIGZ1bmNpw7NuIGBib3hwbG90YC4gUG9yIGRlZmVjdG8sIGVsIGRpYWdyYW1hIGRlIGNhamEgc2Vyw6EgdmVydGljYWwsIHBlcm8gcHVlZGVzIGNhbWJpYXIgbGEgb3JpZW50YWNpw7NuIGVzdGFibGVjaWVuZG8gZWwgYXJndW1lbnRvIGBob3Jpem9udGFsYCBjb21vIGBUUlVFYC4NCg0KYGBge3IgYm94cGxvdCwgZmlnLmFsaWduPSdjZW50ZXInfQ0KDQp4IDwtIGMoOCwgNSwgMTQsIC05LCAxOSwgMTIsIDMsIDksIDcsIDQsDQogICAgICAgNCwgNiwgOCwgMTIsIC04LCAyLCAwLCAtMSwgNSwgMykNCmJveHBsb3QoeCwgaG9yaXpvbnRhbCA9IFRSVUUpDQpzdHJpcGNoYXJ0KHgsIG1ldGhvZCA9ICJqaXR0ZXIiLCBwY2ggPSAxOSwgYWRkID0gVFJVRSwgY29sID0gImJsdWUiKQ0KDQpgYGANCjxjZW50ZXI+DQoNCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvRVRiRmRTdlB3VXciIGZyYW1lYm9yZGVyPSIwIiBhbGxvd2Z1bGxzY3JlZW4gZGF0YS1leHRlcm5hbD0xPjwvaWZyYW1lPg0KDQo8L2NlbnRlcj4NCg0KDQoNCg0KIyBCaWJsaW9ncmFmaWENCg0KPGh0dHBzOi8vci1jb2Rlci5jb20vaW5pY2lvLz57dGFyZ2V0PV9ibGFua30NCg0KPGh0dHBzOi8vYm9va2Rvd24ub3JnL3lpaHVpL3JtYXJrZG93bi9odG1sLWRvY3VtZW50Lmh0bWw+e3RhcmdldD1fYmxhbmt9DQoNCg0KDQo8ZGl2IGNsYXNzPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIGRhdGEtdW5pcXVlPSJ0b2NpZnktZXh0ZW5kLXBhZ2UiIHN0eWxlPSJoZWlnaHQ6IDA7Ij48L2Rpdj4NCg0KDQo=