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:
Pero también podés correr el código de todo el chunk con:
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:
- Cargá el paquete
readr
.
- Creá una variable que se llame
variable_prueba
y
asignale un valor.
- Mostrá ese valor.
- 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í:
- la negrita se consigue con dos asteriscos
- la italizada con un asterisco
- 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 () . 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:
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==