Es posible que en tu trabajo tengas que presentar informes o resultados de tu análisis de datos. Tal vez te hayas encontrando guardando una y otra vez gráficos y tablas o copiando resultados de un archivo al otro hasta que el informe quedó como querías. Los archivos y el paquete RMarkdown vienen al rescate.

Un archivo de R Markdown (generalmente con la extensión .Rmd), a diferencia de un script .R (los que utilizamos hasta este momento), es un archivo de texto plano que combina código de R que genera resultados (gráficos, tablas, etc…) y el texto que lo describe. Al poder intercalar cálculos y gráficos con su análisis o explicación, se unifica el flujo de trabajo y deja de ser necesario guardar figuras o tablas para luego insertarlas en un documento de texto. Esto es muy importante si buscamos que nuestro trabajo sea reproducible, pero además ahorra tiempo.

Creando archivos .Rmd

En RStudio podés crear un nuevo archivo de R Markdown con el menú desplegable:

File → New File → R Markdown

Y se abrirá un menú donde podés agregar el título de tu informe y tu nombre. Por ahora vamos a usar el formato HTML como salida, pero más adelante vas a ver que hay muchos otros formatos de salida posibles.

Al aceptar, se abrirá un nuevo archivo con una plantilla de ejemplo (en inglés).

Primer desafío: Creá un nuevo archivo R Markdown

Revisá la plantilla que trae el documento. ¿Podés identificar los bloques de código?

Para generar el archivo de salida, el paquete knitr (que viene de tejer en inglés) ejecutará el código en una sesión independiente de R e interpretará el texto, su formato y cualquier otra cosa que agreguemos (por ejemplo imágenes o links externos). Esto significa que nuestro archivo debe tener todo lo necesario para generar el análisis y si nos olvidamos de algo va a dar error.

Por esta razón es recomendable knitear (generar) el archivo seguido, para encontrarnos con los errores a tiempo y de paso asegurarnos que el análisis es reproducible.

Segundo desafío: kniteá tu R Markdown

Aprovechando la plantilla de RStudio, obtené el archivo de salida en formato HTML haciendo click en el botón knit (el que tiene un ovillo de lana y un par de agujas).

Estructura de un .Rmd

Cualquier archivo de este tipo tiene 3 partes principales:

(Podés encontrar este archivo de ejemplo acá.)

Encabezado

El encabezado es una serie de instrucciones organizadas entre tres guiones (---) que determinan las propiedades globales del documento, como el título, el formato de salida, información de autoría, etc… También ahí se pueden cambiar opciones asociadas al formato de salida, como el estilo de la tabla de contenidos o índice.

Éstas propiedades se definen en un formato llamado YAML, el cual permite definir listas jerarquizadas de una forma humanamente legible. Por ejemplo:

---
title: "Mi primer RMarkdown"
output: 
  html_document:
    code_download: true
    toc: true
    toc_float: false
---

define dos variables principales, “title” y “output”. “Output” a su vez contiene un elemento “htm_document”, el cual contiene tres elementos: “code_download”, “toc” y “toc_float”.

Es muy importante mantener el escalonado, o identación de los elementos, ya que ésta define la jerarquía de cada elemento. Muchos de los errores a la hora de knitear ocurren porque el archivo tiene problemas en la identación del encabezado.

Bloques de código

El código de R que va a leer datos, analizarlos y generar figuras, tablas o números se organiza en bloques (o chunks) delimitados por tres acentos graves (```) y se diferencia del resto de archivo con un fondo gris. Todo lo que incluyas entre estos delimitadores será interpretado por R como código e intentará ejecutarlo al knitear el archivo. Cualquier resultado del código (gráficos, tablas, texto, etc…) será insertado en el documento final en el mismo orden que están en el archivo R Markdown.

Para insertar un nuevo chunk podés:

  • Usar el botón Insert
  • El atajo de teclado Ctrl+Alt+I
  • Escribir a mano!

El código en cada bloque se ejecuta como si fuera ejecutado en la terminal y todo resultado se muestra en el documento (ya vamos a ver formas de controlar esto). Por ejemplo, este bloque de código

```{r sumar}
1 + 1
```

va a insertar esto en el documento de salida:

[1] 2

Es muy importante no romper los límites de los bloques. Un problema común es accidentalmente eliminar un acento grave al final de un bloque de código y que luego el documento no se genere correctamente. Si al knitear te sale un error como “attempt to use zero-length variable name”, revisá bien que todos tus bloques de código estén correctamente definidos.

Los bloques pueden tener nombre, lo cual es útil para identificar donde ocurren los errores al momento de knitear pero también para tener una pista de lo que hace el código que incluye.

Si bien el código se ejecuta cuando uno knitea, cuando estés escribiendo un informe es muy cómodo ir corriendo bloques individuales interactivamente como si fuera en la consola.

Para correr una línea de código, tendrás que pararte sobre esa línea y apretar:

Ctrl+Enter

Pero también podés correr el código de todo el chunk con:

Ctrl+Shift+Enter

Los resultados van a aparecer inmediatamente debajo del bloque.

Cuarto desafío: Sumá un chunk a tu archivo

Usando el archivo con el que venís trabajando insertá un nuevo chunk y:

  1. Cargá el paquete readr.
  2. Creá una variable que se llame variable_prueba y asignale un valor.
  3. Mostrá ese valor.
  4. Volvé a knitear el archivo para ver el resultado

Finalmente, es posible que te encuentres mencionando resultados en el texto, por ejemplo algo así como “el rendimiento máximo de la última campaña de maíz fue de 15000 kg/ha”. Y también es posible que ese valor cambie si utilizas una base de datos distinta o si luego generas un informe pero para otra campaña. Las chances de de que te olvides de actualizar ese “15000” son super altas, por eso R Markdown también tiene la posibilidad de incorporar código en línea con el texto.

Si tenés una una variable rendimiento_maximo que vale “15000”:

rendimiento_maximo <- "15000"

Para mencionarla en el texto entonces escribirías:

el rendimiento máximo de la última campaña de maíz fue de `r rendimiento_maximo` kg/ha.

y el resultado en el documento kniteado sería

el rendimiento máximo de la última campaña de maíz fue de 15000 kg/ha.

prueba: 15000

El texto propio del documento.

Este es el texto dirigido a las personas que van a leer el reporte. Incluirá una introducción, descripción de los datos y de los resultados; es lo que escribirías en el archivo de Word.

A diferencia de Word, el formato del texto se define usando markdown, que es un lenguaje simple que permite indicar si un texto va en negrita, cursiva, es un título, etc…usando símbolos especiales dentro del texto.

Markdown

Markdown permite escribir en texto plano pero definiendo el formato usando símbolos. Por ejemplo podés resaltar con negrita usando dos asteriscos así: **negrita** o italizada con un asterisco de cada lado: *itálicas*.

También podés hacer una lista de elementos utilizando asteriscos:

* la negrita se consigue con dos asteriscos
* la italizada con un asterisco
* y para resaltar código se usa el acento grave `

o guiones medios:

- la negrita se consigue con dos asteriscos
- la italizada con un asterisco
- y para resaltar código se usa el acento grave `

Ambas listas se van a ver de esta manera:

  • la negrita se consigue con dos asteriscos
  • la italizada con un asterisco
  • y para resaltar código se usa el acento grave `

Si en realidad querés una lista numerada, simplemente comenzá el renglón un número y un punto. Podrías usar siempre el mismo número, markdown se encarga del resto:

1. la negrita se consigue con dos asteriscos
1. la italizada con un asterisco
1. y para resaltar código se usa el acento grave `

Ahora la lista numerada se ve así:

  1. la negrita se consigue con dos asteriscos
  2. la italizada con un asterisco
  3. y para resaltar código se usa el acento grave `

Podés agregar títulos con distinta jerarquía agregando # al comienzo. Esto además define secciones dentro del documento:

# Título
## El primer subtítulo
### Otro subtítulo de menor jerarquía
#### Otro más, y podría seguir!

Podés escribir estos símbolos a mano o usando el Editor Visual de RStudio (sólo disponible para la versión 1.4 en adelante) haciendo click en el ícono de compás que está a la derecha del documento (icono del editor visual) . El Editor Visual permite dar formato al texto usando markdown sin saber usar markdown.

Tercer desafío: Agregale texto a tu archivo

Sin tocar el encabezado (el YAML), borrá el contenido del archivo .Rmd que creaste y probá escribir algo y darle formato. Luego volvé a apretar el botón knit para ver el resultado.

Markdown permite muchas otras cosas, por ejemplo:

Podés agregar un link a una página externa: [texto que se muestra con el link](http://google.com). Resultado: texto que se muestra con el link

Podés incluir una imagen: ![descripción de la figura](img/kitty100.jpeg): Resultado:

descripción de la figura

Y también podés agregar ecuaciones (usando LaTeX) en la misma línea (esto:$E = mc^2$ se ve así: \(E = mc^2\)) o en una línea propia. Esto:

$$
y = \mu + \sum_{i=1}^p \beta_i x_i + \epsilon
$$

se ve así:

\[ y = \mu + \sum_{i=1}^p \beta_i x_i + \epsilon \]

Podés revisar la guía rápida de Markdown desde RStudio (en inglés):

Help → Markdown Quick Reference

Publicando reportes

Estos reportes se pueden publicar en Internet porque son páginas HTML. Para hacerlo de forma sencilla podemos utilizar este sitio web:

https://app.netlify.com/drop

Todo lo que necesitamos hacer es subir la carpeta con los archivos HTML, PNG, CSS, etc que forman nuestro reporte.

LS0tDQp0aXRsZTogIlJlcG9ydGVzIGNvbiBSTWFya2Rvd24iDQpvdXRwdXQ6IA0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICBoaWdobGlnaHQ6IHRhbmdvDQotLS0NCg0KDQpFcyBwb3NpYmxlIHF1ZSBlbiB0dSB0cmFiYWpvIHRlbmdhcyBxdWUgcHJlc2VudGFyIGluZm9ybWVzIG8gcmVzdWx0YWRvcyBkZSB0dSBhbsOhbGlzaXMgZGUgZGF0b3MuDQpUYWwgdmV6IHRlIGhheWFzIGVuY29udHJhbmRvIGd1YXJkYW5kbyB1bmEgeSBvdHJhIHZleiBncsOhZmljb3MgeSB0YWJsYXMgbyBjb3BpYW5kbyByZXN1bHRhZG9zIGRlIHVuIGFyY2hpdm8gYWwgb3RybyBoYXN0YSBxdWUgZWwgaW5mb3JtZSBxdWVkw7MgY29tbyBxdWVyw61hcy4NCkxvcyBhcmNoaXZvcyB5IGVsIHBhcXVldGUgKipSTWFya2Rvd24qKiB2aWVuZW4gYWwgcmVzY2F0ZS4NCg0KVW4gYXJjaGl2byBkZSBSIE1hcmtkb3duIChnZW5lcmFsbWVudGUgY29uIGxhIGV4dGVuc2nDs24gYC5SbWRgKSwgYSBkaWZlcmVuY2lhIGRlIHVuIHNjcmlwdCBgLlJgIChsb3MgcXVlIHV0aWxpemFtb3MgaGFzdGEgZXN0ZSBtb21lbnRvKSwgZXMgdW4gYXJjaGl2byBkZSB0ZXh0byBwbGFubyBxdWUgY29tYmluYSBjw7NkaWdvIGRlIFIgcXVlIGdlbmVyYSByZXN1bHRhZG9zIChncsOhZmljb3MsIHRhYmxhcywgZXRjLi4uKSB5IGVsIHRleHRvIHF1ZSBsbyBkZXNjcmliZS4NCkFsIHBvZGVyIGludGVyY2FsYXIgY8OhbGN1bG9zIHkgZ3LDoWZpY29zIGNvbiBzdSBhbsOhbGlzaXMgbyBleHBsaWNhY2nDs24sIHNlIHVuaWZpY2EgZWwgZmx1am8gZGUgdHJhYmFqbyB5IGRlamEgZGUgc2VyIG5lY2VzYXJpbyBndWFyZGFyIGZpZ3VyYXMgbyB0YWJsYXMgcGFyYSBsdWVnbyBpbnNlcnRhcmxhcyBlbiB1biBkb2N1bWVudG8gZGUgdGV4dG8uDQpFc3RvIGVzIG11eSBpbXBvcnRhbnRlIHNpIGJ1c2NhbW9zIHF1ZSBudWVzdHJvIHRyYWJham8gc2VhIHJlcHJvZHVjaWJsZSwgcGVybyBhZGVtw6FzIGFob3JyYSB0aWVtcG8uDQoNCiMjIENyZWFuZG8gYXJjaGl2b3MgLlJtZA0KDQpFbiBSU3R1ZGlvIHBvZMOpcyBjcmVhciB1biBudWV2byBhcmNoaXZvIGRlIFIgTWFya2Rvd24gY29uIGVsIG1lbsO6IGRlc3BsZWdhYmxlOg0KDQo6Ojogey5hbGVydCAuYWxlcnQtc2Vjb25kYXJ5fQ0KRmlsZSDihpIgTmV3IEZpbGUg4oaSIFIgTWFya2Rvd24NCjo6Og0KDQpZIHNlIGFicmlyw6EgdW4gbWVuw7ogZG9uZGUgcG9kw6lzIGFncmVnYXIgZWwgdMOtdHVsbyBkZSB0dSBpbmZvcm1lIHkgdHUgbm9tYnJlLg0KUG9yIGFob3JhIHZhbW9zIGEgdXNhciBlbCBmb3JtYXRvIEhUTUwgY29tbyBzYWxpZGEsIHBlcm8gbcOhcyBhZGVsYW50ZSB2YXMgYSB2ZXIgcXVlIGhheSBtdWNob3Mgb3Ryb3MgZm9ybWF0b3MgZGUgc2FsaWRhIHBvc2libGVzLg0KDQohW10oaW1nL251ZXZvLXJtZC5wbmcpDQoNCkFsIGFjZXB0YXIsIHNlIGFicmlyw6EgdW4gbnVldm8gYXJjaGl2byBjb24gdW5hIHBsYW50aWxsYSBkZSBlamVtcGxvIChlbiBpbmdsw6lzKS4NCg0KOjo6IHsuYWxlcnQgLmFsZXJ0LWluZm99DQoqKlByaW1lciBkZXNhZsOtbzogQ3Jlw6EgdW4gbnVldm8gYXJjaGl2byBSIE1hcmtkb3duKioNCg0KUmV2aXPDoSBsYSBwbGFudGlsbGEgcXVlIHRyYWUgZWwgZG9jdW1lbnRvLg0Kwr9Qb2TDqXMgaWRlbnRpZmljYXIgbG9zIGJsb3F1ZXMgZGUgY8OzZGlnbz8NCjo6Og0KDQpQYXJhIGdlbmVyYXIgZWwgYXJjaGl2byBkZSBzYWxpZGEsIGVsIHBhcXVldGUgKiprbml0cioqIChxdWUgdmllbmUgZGUgKnRlamVyKiBlbiBpbmdsw6lzKSBlamVjdXRhcsOhIGVsIGPDs2RpZ28gZW4gdW5hIHNlc2nDs24gaW5kZXBlbmRpZW50ZSBkZSBSIGUgaW50ZXJwcmV0YXLDoSBlbCB0ZXh0bywgc3UgZm9ybWF0byB5IGN1YWxxdWllciBvdHJhIGNvc2EgcXVlIGFncmVndWVtb3MgKHBvciBlamVtcGxvIGltw6FnZW5lcyBvIGxpbmtzIGV4dGVybm9zKS4NCkVzdG8gc2lnbmlmaWNhIHF1ZSBudWVzdHJvIGFyY2hpdm8gZGViZSB0ZW5lciAqKnRvZG8qKiBsbyBuZWNlc2FyaW8gcGFyYSBnZW5lcmFyIGVsIGFuw6FsaXNpcyB5IHNpIG5vcyBvbHZpZGFtb3MgZGUgYWxnbyB2YSBhIGRhciBlcnJvci4NCg0KUG9yIGVzdGEgcmF6w7NuIGVzIHJlY29tZW5kYWJsZSAqa25pdGVhciogKGdlbmVyYXIpIGVsIGFyY2hpdm8gc2VndWlkbywgcGFyYSBlbmNvbnRyYXJub3MgY29uIGxvcyBlcnJvcmVzIGEgdGllbXBvIHkgZGUgcGFzbyBhc2VndXJhcm5vcyBxdWUgZWwgYW7DoWxpc2lzIGVzIHJlcHJvZHVjaWJsZS4NCg0KOjo6IHsuYWxlcnQgLmFsZXJ0LWluZm99DQoqKlNlZ3VuZG8gZGVzYWbDrW86IGtuaXRlw6EgdHUgUiBNYXJrZG93bioqDQoNCkFwcm92ZWNoYW5kbyBsYSBwbGFudGlsbGEgZGUgUlN0dWRpbywgb2J0ZW7DqSBlbCBhcmNoaXZvIGRlIHNhbGlkYSBlbiBmb3JtYXRvIEhUTUwgaGFjaWVuZG8gY2xpY2sgZW4gZWwgYm90w7NuICoqa25pdCoqIChlbCBxdWUgdGllbmUgdW4gb3ZpbGxvIGRlIGxhbmEgeSB1biBwYXIgZGUgYWd1amFzKS4NCjo6Og0KDQojIyBFc3RydWN0dXJhIGRlIHVuIC5SbWQNCg0KQ3VhbHF1aWVyIGFyY2hpdm8gZGUgZXN0ZSB0aXBvIHRpZW5lIDMgcGFydGVzIHByaW5jaXBhbGVzOg0KDQohW10oaW1nL3JtZC1lamVtcGxvLXNlY2Npb25lcy5wbmcpDQoNCihQb2TDqXMgZW5jb250cmFyIGVzdGUgYXJjaGl2byBkZSBlamVtcGxvIFthY8OhXShmaWxlcy9taS1wcmltZXItcm1hcmtkb3duLlJtZCkuKQ0KDQojIyMgRW5jYWJlemFkbw0KDQpFbCBlbmNhYmV6YWRvIGVzIHVuYSBzZXJpZSBkZSBpbnN0cnVjY2lvbmVzIG9yZ2FuaXphZGFzIGVudHJlIHRyZXMgZ3Vpb25lcyAoYC0tLWApIHF1ZSBkZXRlcm1pbmFuIGxhcyBwcm9waWVkYWRlcyBnbG9iYWxlcyBkZWwgZG9jdW1lbnRvLCBjb21vIGVsIHTDrXR1bG8sIGVsIGZvcm1hdG8gZGUgc2FsaWRhLCBpbmZvcm1hY2nDs24gZGUgYXV0b3LDrWEsIGV0Yy4uLiBUYW1iacOpbiBhaMOtIHNlIHB1ZWRlbiBjYW1iaWFyIG9wY2lvbmVzIGFzb2NpYWRhcyBhbCBmb3JtYXRvIGRlIHNhbGlkYSwgY29tbyBlbCBlc3RpbG8gZGUgbGEgdGFibGEgZGUgY29udGVuaWRvcyBvIMOtbmRpY2UuDQoNCsOJc3RhcyBwcm9waWVkYWRlcyBzZSBkZWZpbmVuIGVuIHVuIGZvcm1hdG8gbGxhbWFkbyBbWUFNTF0oaHR0cHM6Ly9lcy53aWtpcGVkaWEub3JnL3dpa2kvWUFNTCksIGVsIGN1YWwgcGVybWl0ZSBkZWZpbmlyIGxpc3RhcyBqZXJhcnF1aXphZGFzIGRlIHVuYSBmb3JtYSBodW1hbmFtZW50ZSBsZWdpYmxlLg0KUG9yIGVqZW1wbG86DQoNCmBgYCB7LnlhbWx9DQotLS0NCnRpdGxlOiAiTWkgcHJpbWVyIFJNYXJrZG93biINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQ0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogZmFsc2UNCi0tLQ0KYGBgDQoNCmRlZmluZSBkb3MgdmFyaWFibGVzIHByaW5jaXBhbGVzLCAidGl0bGUiIHkgIm91dHB1dCIuDQoiT3V0cHV0IiBhIHN1IHZleiBjb250aWVuZSB1biBlbGVtZW50byAiaHRtX2RvY3VtZW50IiwgZWwgY3VhbCBjb250aWVuZSB0cmVzIGVsZW1lbnRvczogImNvZGVfZG93bmxvYWQiLCAidG9jIiB5ICJ0b2NfZmxvYXQiLg0KDQo6Ojogey5hbGVydCAuYWxlcnQtc3VjY2Vzc30NCkVzIG11eSBpbXBvcnRhbnRlIG1hbnRlbmVyIGVsIGVzY2Fsb25hZG8sIG8gKmlkZW50YWNpw7NuKiBkZSBsb3MgZWxlbWVudG9zLCB5YSBxdWUgw6lzdGEgZGVmaW5lIGxhIGplcmFycXXDrWEgZGUgY2FkYSBlbGVtZW50by4NCk11Y2hvcyBkZSBsb3MgZXJyb3JlcyBhIGxhIGhvcmEgZGUga25pdGVhciBvY3VycmVuIHBvcnF1ZSBlbCBhcmNoaXZvIHRpZW5lIHByb2JsZW1hcyBlbiBsYSBpZGVudGFjacOzbiBkZWwgZW5jYWJlemFkby4NCjo6Og0KDQojIyMgQmxvcXVlcyBkZSBjw7NkaWdvDQoNCkVsIGPDs2RpZ28gZGUgUiBxdWUgdmEgYSBsZWVyIGRhdG9zLCBhbmFsaXphcmxvcyB5IGdlbmVyYXIgZmlndXJhcywgdGFibGFzIG8gbsO6bWVyb3Mgc2Ugb3JnYW5pemEgZW4gYmxvcXVlcyAobyBgY2h1bmtzYCkgZGVsaW1pdGFkb3MgcG9yIHRyZXMgYWNlbnRvcyBncmF2ZXMgKGBgYGAgYGBgIGBgYGApIHkgc2UgZGlmZXJlbmNpYSBkZWwgcmVzdG8gZGUgYXJjaGl2byBjb24gdW4gZm9uZG8gZ3Jpcy4NClRvZG8gbG8gcXVlIGluY2x1eWFzIGVudHJlIGVzdG9zIGRlbGltaXRhZG9yZXMgc2Vyw6EgaW50ZXJwcmV0YWRvIHBvciBSIGNvbW8gY8OzZGlnbyBlIGludGVudGFyw6EgZWplY3V0YXJsbyBhbCAqa25pdGVhciogZWwgYXJjaGl2by4NCkN1YWxxdWllciByZXN1bHRhZG8gZGVsIGPDs2RpZ28gKGdyw6FmaWNvcywgdGFibGFzLCB0ZXh0bywgZXRjLi4uKSBzZXLDoSBpbnNlcnRhZG8gZW4gZWwgZG9jdW1lbnRvIGZpbmFsIGVuIGVsIG1pc21vIG9yZGVuIHF1ZSBlc3TDoW4gZW4gZWwgYXJjaGl2byBSIE1hcmtkb3duLg0KDQo6Ojogey5hbGVydCAuYWxlcnQtc3VjY2Vzc30NClBhcmEgaW5zZXJ0YXIgdW4gbnVldm8gY2h1bmsgcG9kw6lzOg0KDQotICAgVXNhciBlbCBib3TDs24gKipJbnNlcnQqKg0KLSAgIEVsIGF0YWpvIGRlIHRlY2xhZG8gQ3RybCtBbHQrSQ0KLSAgIEVzY3JpYmlyIGEgbWFubyENCjo6Og0KDQpFbCBjw7NkaWdvIGVuIGNhZGEgYmxvcXVlIHNlIGVqZWN1dGEgY29tbyBzaSBmdWVyYSBlamVjdXRhZG8gZW4gbGEgdGVybWluYWwgeSB0b2RvIHJlc3VsdGFkbyBzZSBtdWVzdHJhIGVuIGVsIGRvY3VtZW50byAoeWEgdmFtb3MgYSB2ZXIgZm9ybWFzIGRlIGNvbnRyb2xhciBlc3RvKS4NClBvciBlamVtcGxvLCBlc3RlIGJsb3F1ZSBkZSBjw7NkaWdvDQoNCiAgICBgYGB7ciBzdW1hcn1gciAnJ2ANCiAgICAxICsgMQ0KICAgIGBgYA0KDQp2YSBhIGluc2VydGFyIGVzdG8gZW4gZWwgZG9jdW1lbnRvIGRlIHNhbGlkYToNCg0KICAgIFsxXSAyDQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1zdWNjZXNzfQ0KRXMgbXV5IGltcG9ydGFudGUgbm8gcm9tcGVyIGxvcyBsw61taXRlcyBkZSBsb3MgYmxvcXVlcy4NClVuIHByb2JsZW1hIGNvbcO6biBlcyBhY2NpZGVudGFsbWVudGUgZWxpbWluYXIgdW4gYWNlbnRvIGdyYXZlIGFsIGZpbmFsIGRlIHVuIGJsb3F1ZSBkZSBjw7NkaWdvIHkgcXVlIGx1ZWdvIGVsIGRvY3VtZW50byBubyBzZSBnZW5lcmUgY29ycmVjdGFtZW50ZS4NClNpIGFsIGtuaXRlYXIgdGUgc2FsZSB1biBlcnJvciBjb21vIF8iYXR0ZW1wdCB0byB1c2UgemVyby1sZW5ndGggdmFyaWFibGUgbmFtZSJfLCByZXZpc8OhIGJpZW4gcXVlIHRvZG9zIHR1cyBibG9xdWVzIGRlIGPDs2RpZ28gZXN0w6luIGNvcnJlY3RhbWVudGUgZGVmaW5pZG9zLg0KOjo6DQoNCkxvcyBibG9xdWVzIHB1ZWRlbiB0ZW5lciBub21icmUsIGxvIGN1YWwgZXMgw7p0aWwgcGFyYSBpZGVudGlmaWNhciBkb25kZSBvY3VycmVuIGxvcyBlcnJvcmVzIGFsIG1vbWVudG8gZGUgKmtuaXRlYXIqIHBlcm8gdGFtYmnDqW4gcGFyYSB0ZW5lciB1bmEgcGlzdGEgZGUgbG8gcXVlIGhhY2UgZWwgY8OzZGlnbyBxdWUgaW5jbHV5ZS4NCg0KU2kgYmllbiBlbCBjw7NkaWdvIHNlIGVqZWN1dGEgY3VhbmRvIHVubyBrbml0ZWEsIGN1YW5kbyBlc3TDqXMgZXNjcmliaWVuZG8gdW4gaW5mb3JtZSBlcyBtdXkgY8OzbW9kbyBpciBjb3JyaWVuZG8gYmxvcXVlcyBpbmRpdmlkdWFsZXMgaW50ZXJhY3RpdmFtZW50ZSBjb21vIHNpIGZ1ZXJhIGVuIGxhIGNvbnNvbGEuDQoNClBhcmEgY29ycmVyIHVuYSBsw61uZWEgZGUgY8OzZGlnbywgdGVuZHLDoXMgcXVlIHBhcmFydGUgc29icmUgZXNhIGzDrW5lYSB5IGFwcmV0YXI6DQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1zZWNvbmRhcnl9DQpDdHJsK0VudGVyDQo6OjoNCg0KUGVybyB0YW1iacOpbiBwb2TDqXMgY29ycmVyIGVsIGPDs2RpZ28gZGUgdG9kbyBlbCBjaHVuayBjb246DQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1zZWNvbmRhcnl9DQpDdHJsK1NoaWZ0K0VudGVyDQo6OjoNCg0KTG9zIHJlc3VsdGFkb3MgdmFuIGEgYXBhcmVjZXIgaW5tZWRpYXRhbWVudGUgZGViYWpvIGRlbCBibG9xdWUuDQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1pbmZvfQ0KKipDdWFydG8gZGVzYWbDrW86IFN1bcOhIHVuIGNodW5rIGEgdHUgYXJjaGl2byoqDQoNClVzYW5kbyBlbCBhcmNoaXZvIGNvbiBlbCBxdWUgdmVuw61zIHRyYWJhamFuZG8gaW5zZXJ0w6EgdW4gbnVldm8gY2h1bmsgeToNCg0KMS4gIENhcmfDoSBlbCBwYXF1ZXRlIGByZWFkcmAuDQoyLiAgQ3Jlw6EgdW5hIHZhcmlhYmxlIHF1ZSBzZSBsbGFtZSBgdmFyaWFibGVfcHJ1ZWJhYCB5IGFzaWduYWxlIHVuIHZhbG9yLg0KMy4gIE1vc3Ryw6EgZXNlIHZhbG9yLg0KNC4gIFZvbHbDqSBhICprbml0ZWFyKiBlbCBhcmNoaXZvIHBhcmEgdmVyIGVsIHJlc3VsdGFkbw0KOjo6DQoNCkZpbmFsbWVudGUsIGVzIHBvc2libGUgcXVlIHRlIGVuY3VlbnRyZXMgbWVuY2lvbmFuZG8gcmVzdWx0YWRvcyBlbiBlbCB0ZXh0bywgcG9yIGVqZW1wbG8gYWxnbyBhc8OtIGNvbW8gImVsIHJlbmRpbWllbnRvIG3DoXhpbW8gZGUgbGEgw7psdGltYSBjYW1wYcOxYSBkZSBtYcOteiBmdWUgZGUgMTUwMDAga2cvaGEiLg0KWSB0YW1iacOpbiBlcyBwb3NpYmxlIHF1ZSBlc2UgdmFsb3IgY2FtYmllIHNpIHV0aWxpemFzIHVuYSBiYXNlIGRlIGRhdG9zIGRpc3RpbnRhIG8gc2kgbHVlZ28gZ2VuZXJhcyB1biBpbmZvcm1lIHBlcm8gcGFyYSBvdHJhIGNhbXBhw7FhLg0KTGFzIGNoYW5jZXMgZGUgZGUgcXVlIHRlIG9sdmlkZXMgZGUgYWN0dWFsaXphciBlc2UgIjE1MDAwIiBzb24gc3VwZXIgYWx0YXMsIHBvciBlc28gUiBNYXJrZG93biB0YW1iacOpbiB0aWVuZSBsYSBwb3NpYmlsaWRhZCBkZSBpbmNvcnBvcmFyIGPDs2RpZ28gZW4gbMOtbmVhIGNvbiBlbCB0ZXh0by4NCg0KU2kgdGVuw6lzIHVuYSB1bmEgdmFyaWFibGUgYHJlbmRpbWllbnRvX21heGltb2AgcXVlIHZhbGUgIjE1MDAwIjoNCg0KYGBge3J9DQpyZW5kaW1pZW50b19tYXhpbW8gPC0gIjE1MDAwIg0KYGBgDQoNClBhcmEgbWVuY2lvbmFybGEgZW4gZWwgdGV4dG8gZW50b25jZXMgZXNjcmliaXLDrWFzOg0KDQo+IGVsIHJlbmRpbWllbnRvIG3DoXhpbW8gZGUgbGEgw7psdGltYSBjYW1wYcOxYSBkZSBtYcOteiBmdWUgZGUgYGAgYGByICJyImAgcmVuZGltaWVudG9fbWF4aW1vYCBgYCBrZy9oYS4NCiANCnkgZWwgcmVzdWx0YWRvIGVuIGVsIGRvY3VtZW50byBrbml0ZWFkbyBzZXLDrWEgDQoNCj4gZWwgcmVuZGltaWVudG8gbcOheGltbyBkZSBsYSDDumx0aW1hIGNhbXBhw7FhIGRlIG1hw616IGZ1ZSBkZSBgciByZW5kaW1pZW50b19tYXhpbW9gIGtnL2hhLg0KDQoNCnBydWViYTogYGAgYHIgcmVuZGltaWVudG9fbWF4aW1vYCBgYA0KDQoNCiMjIyBFbCB0ZXh0byBwcm9waW8gZGVsIGRvY3VtZW50by4NCg0KRXN0ZSBlcyBlbCB0ZXh0byBkaXJpZ2lkbyBhIGxhcyBwZXJzb25hcyBxdWUgdmFuIGEgbGVlciBlbCByZXBvcnRlLg0KSW5jbHVpcsOhIHVuYSBpbnRyb2R1Y2Npw7NuLCBkZXNjcmlwY2nDs24gZGUgbG9zIGRhdG9zIHkgZGUgbG9zIHJlc3VsdGFkb3M7IGVzIGxvIHF1ZSBlc2NyaWJpcsOtYXMgZW4gZWwgYXJjaGl2byBkZSBXb3JkLg0KDQpBIGRpZmVyZW5jaWEgZGUgV29yZCwgZWwgZm9ybWF0byBkZWwgdGV4dG8gc2UgZGVmaW5lIHVzYW5kbyBbbWFya2Rvd25dKDxodHRwczovL2VzLndpa2lwZWRpYS5vcmcvd2lraS9NYXJrZG93bj4pLCBxdWUgZXMgdW4gbGVuZ3VhamUgc2ltcGxlIHF1ZSBwZXJtaXRlIGluZGljYXIgc2kgdW4gdGV4dG8gdmEgZW4gbmVncml0YSwgY3Vyc2l2YSwgZXMgdW4gdMOtdHVsbywgZXRjLi4udXNhbmRvIHPDrW1ib2xvcyBlc3BlY2lhbGVzIGRlbnRybyBkZWwgdGV4dG8uDQoNCiMjIE1hcmtkb3duDQoNCk1hcmtkb3duIHBlcm1pdGUgZXNjcmliaXIgZW4gdGV4dG8gcGxhbm8gcGVybyBkZWZpbmllbmRvIGVsIGZvcm1hdG8gdXNhbmRvIHPDrW1ib2xvcy4NClBvciBlamVtcGxvIHBvZMOpcyByZXNhbHRhciBjb24gKipuZWdyaXRhKiogdXNhbmRvIGRvcyBhc3RlcmlzY29zIGFzw606IGAqKm5lZ3JpdGEqKmAgbyAqaXRhbGl6YWRhKiBjb24gdW4gYXN0ZXJpc2NvIGRlIGNhZGEgbGFkbzogYCppdMOhbGljYXMqYC4NCg0KVGFtYmnDqW4gcG9kw6lzIGhhY2VyIHVuYSBsaXN0YSBkZSBlbGVtZW50b3MgdXRpbGl6YW5kbyBhc3RlcmlzY29zOg0KDQogICAgKiBsYSBuZWdyaXRhIHNlIGNvbnNpZ3VlIGNvbiBkb3MgYXN0ZXJpc2Nvcw0KICAgICogbGEgaXRhbGl6YWRhIGNvbiB1biBhc3RlcmlzY28NCiAgICAqIHkgcGFyYSByZXNhbHRhciBjw7NkaWdvIHNlIHVzYSBlbCBhY2VudG8gZ3JhdmUgYA0KDQpvIGd1aW9uZXMgbWVkaW9zOg0KDQogICAgLSBsYSBuZWdyaXRhIHNlIGNvbnNpZ3VlIGNvbiBkb3MgYXN0ZXJpc2Nvcw0KICAgIC0gbGEgaXRhbGl6YWRhIGNvbiB1biBhc3RlcmlzY28NCiAgICAtIHkgcGFyYSByZXNhbHRhciBjw7NkaWdvIHNlIHVzYSBlbCBhY2VudG8gZ3JhdmUgYA0KDQpBbWJhcyBsaXN0YXMgc2UgdmFuIGEgdmVyIGRlIGVzdGEgbWFuZXJhOg0KDQotICAgbGEgbmVncml0YSBzZSBjb25zaWd1ZSBjb24gZG9zIGFzdGVyaXNjb3MNCi0gICBsYSBpdGFsaXphZGEgY29uIHVuIGFzdGVyaXNjbw0KLSAgIHkgcGFyYSByZXNhbHRhciBjw7NkaWdvIHNlIHVzYSBlbCBhY2VudG8gZ3JhdmUgXGANCg0KU2kgZW4gcmVhbGlkYWQgcXVlcsOpcyB1bmEgbGlzdGEgbnVtZXJhZGEsIHNpbXBsZW1lbnRlIGNvbWVuesOhIGVsIHJlbmdsw7NuIHVuIG7Dum1lcm8geSB1biBwdW50by4NClBvZHLDrWFzIHVzYXIgc2llbXByZSBlbCBtaXNtbyBuw7ptZXJvLCBtYXJrZG93biBzZSBlbmNhcmdhIGRlbCByZXN0bzoNCg0KICAgIDEuIGxhIG5lZ3JpdGEgc2UgY29uc2lndWUgY29uIGRvcyBhc3RlcmlzY29zDQogICAgMS4gbGEgaXRhbGl6YWRhIGNvbiB1biBhc3RlcmlzY28NCiAgICAxLiB5IHBhcmEgcmVzYWx0YXIgY8OzZGlnbyBzZSB1c2EgZWwgYWNlbnRvIGdyYXZlIGANCg0KQWhvcmEgbGEgbGlzdGEgbnVtZXJhZGEgc2UgdmUgYXPDrToNCg0KMS4gIGxhIG5lZ3JpdGEgc2UgY29uc2lndWUgY29uIGRvcyBhc3RlcmlzY29zDQoyLiAgbGEgaXRhbGl6YWRhIGNvbiB1biBhc3RlcmlzY28NCjMuICB5IHBhcmEgcmVzYWx0YXIgY8OzZGlnbyBzZSB1c2EgZWwgYWNlbnRvIGdyYXZlIFxgDQoNClBvZMOpcyBhZ3JlZ2FyIHTDrXR1bG9zIGNvbiBkaXN0aW50YSBqZXJhcnF1w61hIGFncmVnYW5kbyBgI2AgYWwgY29taWVuem8uDQpFc3RvIGFkZW3DoXMgZGVmaW5lIHNlY2Npb25lcyBkZW50cm8gZGVsIGRvY3VtZW50bzoNCg0KICAgICMgVMOtdHVsbw0KICAgICMjIEVsIHByaW1lciBzdWJ0w610dWxvDQogICAgIyMjIE90cm8gc3VidMOtdHVsbyBkZSBtZW5vciBqZXJhcnF1w61hDQogICAgIyMjIyBPdHJvIG3DoXMsIHkgcG9kcsOtYSBzZWd1aXIhDQoNClBvZMOpcyBlc2NyaWJpciBlc3RvcyBzw61tYm9sb3MgYSBtYW5vIG8gdXNhbmRvIGVsIEVkaXRvciBWaXN1YWwgZGUgUlN0dWRpbyAoc8OzbG8gZGlzcG9uaWJsZSBwYXJhIGxhIHZlcnNpw7NuIDEuNCBlbiBhZGVsYW50ZSkgaGFjaWVuZG8gY2xpY2sgZW4gZWwgw61jb25vIGRlIGNvbXDDoXMgcXVlIGVzdMOhIGEgbGEgZGVyZWNoYSBkZWwgZG9jdW1lbnRvICghW2ljb25vIGRlbCBlZGl0b3IgdmlzdWFsXShpbWcvaWNvbm8tZWRpdG9yLXZpc3VhbC5wbmcpKSAuIA0KRWwgRWRpdG9yIFZpc3VhbCBwZXJtaXRlIGRhciBmb3JtYXRvIGFsIHRleHRvIHVzYW5kbyBtYXJrZG93biBzaW4gc2FiZXIgdXNhciBtYXJrZG93bi4NCg0KDQo6Ojogey5hbGVydCAuYWxlcnQtaW5mb30NCioqVGVyY2VyIGRlc2Fmw61vOiBBZ3JlZ2FsZSB0ZXh0byBhIHR1IGFyY2hpdm8qKg0KDQpTaW4gdG9jYXIgZWwgIGVuY2FiZXphZG8gKGVsIFlBTUwpLCBib3Jyw6EgZWwgY29udGVuaWRvIGRlbCBhcmNoaXZvIGAuUm1kYCBxdWUgY3JlYXN0ZSB5IHByb2LDoSBlc2NyaWJpciBhbGdvIHkgZGFybGUgZm9ybWF0by4NCkx1ZWdvIHZvbHbDqSBhIGFwcmV0YXIgZWwgYm90w7NuICoqa25pdCoqIHBhcmEgdmVyIGVsIHJlc3VsdGFkby4NCjo6Og0KDQpNYXJrZG93biBwZXJtaXRlIG11Y2hhcyBvdHJhcyBjb3NhcywgcG9yIGVqZW1wbG86DQoNClBvZMOpcyBhZ3JlZ2FyIHVuIGxpbmsgYSB1bmEgcMOhZ2luYSBleHRlcm5hOiBgW3RleHRvIHF1ZSBzZSBtdWVzdHJhIGNvbiBlbCBsaW5rXShodHRwOi8vZ29vZ2xlLmNvbSlgLiANClJlc3VsdGFkbzogW3RleHRvIHF1ZSBzZSBtdWVzdHJhIGNvbiBlbCBsaW5rXShodHRwOi8vZ29vZ2xlLmNvbSkNCg0KUG9kw6lzIGluY2x1aXIgdW5hIGltYWdlbjogYCFbZGVzY3JpcGNpw7NuIGRlIGxhIGZpZ3VyYV0oaW1nL2tpdHR5MTAwLmpwZWcpYDogUmVzdWx0YWRvOiANCg0KDQohW2Rlc2NyaXBjacOzbiBkZSBsYSBmaWd1cmFdKGltZy9pbmNlbmRpby5wbmcpDQoNClkgdGFtYmnDqW4gcG9kw6lzIGFncmVnYXIgZWN1YWNpb25lcyAodXNhbmRvIFtMYVRlWF0oaHR0cHM6Ly9lcy53aWtpcGVkaWEub3JnL3dpa2kvTGFUZVgpKSBlbiBsYSBtaXNtYSBsw61uZWEgKGVzdG86YCRFID0gbWNeMiRgIHNlIHZlIGFzw606ICRFID0gbWNeMiQpIG8gZW4gdW5hIGzDrW5lYSBwcm9waWEuDQpFc3RvOg0KDQogICAgJCQNCiAgICB5ID0gXG11ICsgXHN1bV97aT0xfV5wIFxiZXRhX2kgeF9pICsgXGVwc2lsb24NCiAgICAkJA0KDQpzZSB2ZSBhc8OtOg0KDQokJA0KeSA9IFxtdSArIFxzdW1fe2k9MX1ecCBcYmV0YV9pIHhfaSArIFxlcHNpbG9uDQokJA0KDQo6Ojogey5hbGVydCAuYWxlcnQtc3VjY2Vzc30NClBvZMOpcyByZXZpc2FyIGxhIGd1w61hIHLDoXBpZGEgZGUgTWFya2Rvd24gZGVzZGUgUlN0dWRpbyAoZW4gaW5nbMOpcyk6DQoNCkhlbHAg4oaSIE1hcmtkb3duIFF1aWNrIFJlZmVyZW5jZQ0KOjo6DQoNCiMjIFB1YmxpY2FuZG8gcmVwb3J0ZXMNCg0KRXN0b3MgcmVwb3J0ZXMgc2UgcHVlZGVuIHB1YmxpY2FyIGVuIEludGVybmV0IHBvcnF1ZSBzb24gcMOhZ2luYXMgSFRNTC4gIFBhcmEgaGFjZXJsbyBkZSBmb3JtYSBzZW5jaWxsYSBwb2RlbW9zIHV0aWxpemFyIGVzdGUgc2l0aW8gd2ViOg0KDQpodHRwczovL2FwcC5uZXRsaWZ5LmNvbS9kcm9wDQoNClRvZG8gbG8gcXVlIG5lY2VzaXRhbW9zIGhhY2VyIGVzIHN1YmlyIGxhIGNhcnBldGEgY29uIGxvcyBhcmNoaXZvcyBIVE1MLA0KUE5HLCBDU1MsIGV0YyBxdWUgZm9ybWFuIG51ZXN0cm8gcmVwb3J0ZS4NCg==