¿Por qué R?

Excel es un software admirable. Es genial para hacer data entry, para ver los datos crudos y para hacer gráficos rápidos. Si venís usándolo hace tiempo, seguro que aprendiste un montón de trucos para sacarle el jugo al máximo, habrás aprendido a usar fórmulas, tablas dinámicas, e incluso macros. Pero seguro que también sufriste sus limitaciones.

En una hoja de Excel no hay un límite claro entre datos y análisis. Sobrescribir datos es un peligro muy real y análisis complicados son imposibles de entender, especialmente si abrís una hoja de cálculo armada por otra persona (que quizás es tu vos del pasado). Además, repetir el análisis en datos distintos o cambiando algún parámetro se puede volver muy engorroso.

Si lo que necesitás son reportes frecuentes y automáticos, y análisis de datos con muchas partes móviles, estaría bueno poder escribir una receta paso a paso y que la computadora corra todo automáticamente cada vez que se lo pedís. Para poder hacer eso, ese paso a paso tiene que estar escrito en un lenguaje que la computadora pueda entender, ese lenguaje es R.

La forma en la que interactuás con la computadora con R es diametralmente distinta que con Excel. Esto lo hace extremadamente poderoso, pero el precio a pagar es básicamente el de tener que aprender un nuevo idioma.

Cómo decirle a R qué hacer

Orientándose en RStudio

En principio se podría escribir código de R con el Bloc de Notas y luego ejecutarlo, pero nosotros vamos a usar RStudio, que brinda una interfaz gráfica con un montón de herramientas extra para hacernos la vida más fácil.

Cuando abras RStudio te vas a encontrar con una ventana con cuatro paneles como esta:

Ventana de RStudio

Los dos paneles de la izquierda son las dos formas principales de interactuar con R. El panel de abajo a la izquierda es la consola. Es el lugar que te permite conversar con R. Podés escribir comandos que se van a ejecutar inmediátamente cuando aprietes Enter y cuyo resultado se va a mostrar en la consola.

Por ejemplo, hacé click en la consola, escribí 2 + 2 y apretá Enter. Vas a ver algo como esto:

2 + 2
## [1] 4

Le dijiste a R que sume 2 y 2 y R te devolvió el resultado: 4 (no te preocupes del [1] por ahora). Eso está bueno si querés hacer una cuenta rápida o chequear algo pequeño, pero no sirve para hacer un análisis complejo y reproducible.

En el panel de arriba a la izquierda tenemos esencialmente un editor de texto. Ahí es donde vas a escribir si querés guardar instrucciones para ejecutarlas en otro momento y donde vas a estar el 87% de tu tiempo usando R.

A la derecha hay paneles más bien informativos y que tienen varias solapas que vamos a ir descubriendo a su tiempo. Para destacar, arriba a la derecha está el “environment”, que es forma de ver qué es lo que está “pensando” R en este momento. Ahí vas a poder ver un listado de los datos que están abiertos y otros objetos que están cargados en la memoria de R. Ahora está vacío porque todavía no cargaste ni creaste ningún dato. Abajo a la derecha tienen un explorador de archivos rudimentario y también el panel de ayuda, que es donde vas a pasar el otro 13% del tiempo usando R.

Entonces, para resumir:

La cocina de RStudio

Hablando con R

Ya viste cómo usar R como una calculadora.

2 + 2
## [1] 4

Si usaste fórmulas en Excel, esto es muy parecido a poner =2+2 en una celda. R entiende un montón de operaciones aritméticas escritas como seguramente ya te imaginás:

  • +: sumar
  • -: restar
  • *: multiplicar
  • /: dividir
  • ^: exponenciar

Pero además conoce muchas otras operaciones. Para decirle a R que calcule el seno de 1 hay que escribir esto:

sin(1)
## [1] 0.841471

Esto es similar a poner =SIN(1) en Excel. La sintaxis básica para aplicar cualquier función es nombre_funcion(argumentos).

Nota: En Excel el nombre de las funciones dependen del idioma en el que está instalado. Si lo usás en español, la función seno es SEN(). En R, las funciones siempre se escriben igual (que coincide con el inglés).

Desafío

Decile a R que compute las siguientes operaciones:

  • 2 multiplicado por 2
  • 3 al cuadrado
  • dos tercios
  • 5 por 8 más 1

Al hacer todas estas operaciones, lo único que hiciste fue decirle a R que haga esos cálculos. R te devuelve el resultado, pero no lo guarda en ningún lado. Para decirle que guarde el resultado de una operación hay que decirle con qué “nombre” querés guardarlo. El siguiente código hace eso:

x <- 2 + 2

La “flechita” <- es el operador de asignación, que le dice a R que tome el resultado de la derecha y lo guarde en una variable con el nombre que está a la izquierda. Vas a ver que no te devele el resultado. Para verlo, ejecutamos

x
## [1] 4

Esto le dice a R que te “imprima” el contenido de la variable x.

Desafío

¿Qué te imaginás que va a pasar cuando ahora corra el siguiente código?

x + 2

Ponerle nombre a las variables es a veces la parte más difícil de escribir código. A R no le viene bien cualquier nombre de variable siempre y cuando no empiece con un número o un "_". Pero a los seres humanos que lean el código y tengan que interpretarlos les va a resultas más fácil entender qué hace la variable temperatura_cordoba que la variable xxy1.

El consejo es tratar en lo posible usar nombre descriptivos y consistentes. Por ejemplo, siempre usar minúsculas y separar palabras con "_".

Tip: Para hacerse la vida más fácil existen “guías de estilo” para programar que explicitan reglas específicas para escribir código. Por ejemplo esta o esta otra. Se trata de reglas únicamente para los ojos humanos, y que no afectan en absoluto la eficiencia o correctitud de la programación. En general, no existen guías buenas o malas, la idea es elegir una y ser consistente. De esta manera, vas a poder entender tu código con más facilidad.

Extendiendo R

R es un lenguaje creado por estadísticos y pensado para la estadística, por lo que ya viene con un montón de métodos estadísticos incorporados, como mean() o median(). Pero hay tantos métodos estadísticos como gente haciendo estadística así que es imposible que estén todos. La solución es que podés “agregarle” a R funciones que no vienen instaladas por defecto pero que escribieron otras personas en forma de “paquetes”. Este es el poder de la comunidad de R!

Para instalar paquetes de R, la forma mas fácil es con la función install.packages(). Entonces, por ejemplo,

install.packages("readr")

te instala un paquete que contiene funciones para leer datos. Luego, usando el comando

library(readr)

le decís a R que cargue las funciones que vienen en el paquete readr para usarlas.

Desafío: Instalá el paquete {readr} con el comando install.packages("readr")

Nota: Si cerrás y volveś a abrir R, vas a tener que usar library(readr) nuevamente para acceder a la funcionalidad del paquete readr

Buscando ayuda

Entre la enorme cantidad de funciones que tiene R por defecto y las que se pueden agregar instalando paquetes externos, es imposible recordar todas las funciones y cómo usarlas. Por eso, una gran proporción del tiempo que uses R vas a pasarlo leyendo documentación de funciones, ya sea para aprender a usarlas o porque no te acordás algún detalle.

Para acceder a la ayuda de una función simplemente usamos el signo de pregunta:

?sin

Nota: Otra forma de acceder a la ayuda de una función es poniendo el cursor sobre ella y apretando F1

Esto va a abrir el documento de ayuda para la función sin() que, como verás, tiene la documentación de las funciones trigonométricas que trae R por defecto. Todas las ayudas de R vienen divididas en secciones:

Description
Una descripción breve de la función o funciones que se documentan.
Usage
Nombre de los argumentos de la función. La mayoría de las funciones trigonométricas tienen un solo argumento, que se llama x. La función atan2() tiene dos argumentos, llamados x e y.
Arguments
Una descripción de cada argumento. En este caso x e y son vectores numéricos o complejos. Aunque todavía no sepas qué es un “vector”, de esta descripción ya podés intuir que las funciones trigonométricas aceptan números complejos.
Details
Una descripción detallada de las funciones. Por ejemplo, detalla qué es lo que devuelve la función atan2(), describe las unidades en las que tienen que estar x e y, etc..
Value
Describe qué tipo de valor devuelve la función.
Examples
(abajo de todo) Es la sección más importante y probablemente la que vas a buscar primero cuando te encuentres con una función nueva que no sabés cómo usar. Acá vas a encontrar código de R de que ejemplifica el uso típico de la función. Podes copiar y pegar el código en la consola y ver el resultado para entender como funciona.
(Otras secciones)
Pueden haber otras secciones que detallen distintas particularidades de la función, o referencias a los métodos implementados.

Desafío

Abrí y leé la ayuda de la función sd(). Puede que haya cosas que aún no entiendas, pero tratá de captar la idea general. ¿Qué hace esa función? ¿Qué argumentos acepta?

LS0tCnRpdGxlOiAiSW50cm9kdWNjacOzbiIKIyBkYXRlOiAiMjkvMDgvMjAyMCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IGZhbHNlCiAgICBoaWdobGlnaHQ6IHRhbmdvCi0tLQoKCiMjIMK/UG9yIHF1w6kgUj8KCkV4Y2VsIGVzIHVuIHNvZnR3YXJlIGFkbWlyYWJsZS4gRXMgZ2VuaWFsIHBhcmEgaGFjZXIgZGF0YSBlbnRyeSwgcGFyYSB2ZXIgbG9zIGRhdG9zIGNydWRvcyB5IHBhcmEgaGFjZXIgZ3LDoWZpY29zIHLDoXBpZG9zLiBTaSB2ZW7DrXMgdXPDoW5kb2xvIGhhY2UgdGllbXBvLCBzZWd1cm8gcXVlIGFwcmVuZGlzdGUgdW4gbW9udMOzbiBkZSB0cnVjb3MgcGFyYSBzYWNhcmxlIGVsIGp1Z28gYWwgbcOheGltbywgaGFicsOhcyBhcHJlbmRpZG8gYSB1c2FyIGbDs3JtdWxhcywgdGFibGFzIGRpbsOhbWljYXMsIGUgaW5jbHVzbyBtYWNyb3MuIFBlcm8gc2VndXJvIHF1ZSB0YW1iacOpbiBzdWZyaXN0ZSBzdXMgbGltaXRhY2lvbmVzLiAKCkVuIHVuYSBob2phIGRlIEV4Y2VsIG5vIGhheSB1biBsw61taXRlIGNsYXJvIGVudHJlIGRhdG9zIHkgYW7DoWxpc2lzLiBTb2JyZXNjcmliaXIgZGF0b3MgZXMgdW4gcGVsaWdybyBtdXkgcmVhbCB5IGFuw6FsaXNpcyBjb21wbGljYWRvcyBzb24gaW1wb3NpYmxlcyBkZSBlbnRlbmRlciwgZXNwZWNpYWxtZW50ZSBzaSBhYnLDrXMgdW5hIGhvamEgZGUgY8OhbGN1bG8gYXJtYWRhIHBvciBvdHJhIHBlcnNvbmEgKHF1ZSBxdWl6w6FzIGVzIHR1IHZvcyBkZWwgcGFzYWRvKS4gQWRlbcOhcywgcmVwZXRpciBlbCBhbsOhbGlzaXMgZW4gZGF0b3MgZGlzdGludG9zIG8gY2FtYmlhbmRvIGFsZ8O6biBwYXLDoW1ldHJvIHNlIHB1ZWRlIHZvbHZlciBtdXkgZW5nb3Jyb3NvLiAKClNpIGxvIHF1ZSBuZWNlc2l0w6FzIHNvbiByZXBvcnRlcyBmcmVjdWVudGVzIHkgYXV0b23DoXRpY29zLCB5IGFuw6FsaXNpcyBkZSBkYXRvcyBjb24gbXVjaGFzIHBhcnRlcyBtw7N2aWxlcywgZXN0YXLDrWEgYnVlbm8gcG9kZXIgZXNjcmliaXIgdW5hIHJlY2V0YSBwYXNvIGEgcGFzbyB5IHF1ZSBsYSBjb21wdXRhZG9yYSBjb3JyYSB0b2RvIGF1dG9tw6F0aWNhbWVudGUgY2FkYSB2ZXogcXVlIHNlIGxvIHBlZMOtcy4gUGFyYSBwb2RlciBoYWNlciBlc28sIGVzZSBwYXNvIGEgcGFzbyB0aWVuZSBxdWUgZXN0YXIgZXNjcml0byBlbiB1biBsZW5ndWFqZSBxdWUgbGEgY29tcHV0YWRvcmEgcHVlZGEgZW50ZW5kZXIsIGVzZSBsZW5ndWFqZSBlcyBSLgoKTGEgZm9ybWEgZW4gbGEgcXVlIGludGVyYWN0dcOhcyBjb24gbGEgY29tcHV0YWRvcmEgY29uIFIgZXMgZGlhbWV0cmFsbWVudGUgZGlzdGludGEgcXVlIGNvbiBFeGNlbC4gRXN0byBsbyBoYWNlIGV4dHJlbWFkYW1lbnRlIHBvZGVyb3NvLCBwZXJvIGVsIHByZWNpbyBhIHBhZ2FyIGVzIGLDoXNpY2FtZW50ZSBlbCBkZSB0ZW5lciBxdWUgYXByZW5kZXIgdW4gbnVldm8gaWRpb21hLiAKCiMjIEPDs21vIGRlY2lybGUgYSBSIHF1w6kgaGFjZXIKCiMjIyBPcmllbnTDoW5kb3NlIGVuIFJTdHVkaW8KCkVuIHByaW5jaXBpbyBzZSBwb2Ryw61hIGVzY3JpYmlyIGPDs2RpZ28gZGUgUiBjb24gZWwgQmxvYyBkZSBOb3RhcyB5IGx1ZWdvIGVqZWN1dGFybG8sIHBlcm8gbm9zb3Ryb3MgdmFtb3MgYSB1c2FyIFJTdHVkaW8sIHF1ZSBicmluZGEgdW5hIGludGVyZmF6IGdyw6FmaWNhIGNvbiAgdW4gbW9udMOzbiBkZSBoZXJyYW1pZW50YXMgZXh0cmEgcGFyYSBoYWNlcm5vcyBsYSB2aWRhIG3DoXMgZsOhY2lsLiAKCkN1YW5kbyBhYnJhcyBSU3R1ZGlvIHRlIHZhcyBhIGVuY29udHJhciBjb24gdW5hIHZlbnRhbmEgY29uIGN1YXRybyBwYW5lbGVzIGNvbW8gZXN0YToKCiFbVmVudGFuYSBkZSBSU3R1ZGlvXShpbWcvcnN0dWRpby5wbmcpCgpMb3MgZG9zIHBhbmVsZXMgZGUgbGEgaXpxdWllcmRhIHNvbiBsYXMgZG9zIGZvcm1hcyBwcmluY2lwYWxlcyBkZSBpbnRlcmFjdHVhciBjb24gUi4gRWwgcGFuZWwgZGUgYWJham8gYSBsYSBpenF1aWVyZGEgZXMgKipsYSBjb25zb2xhKiouIEVzIGVsIGx1Z2FyIHF1ZSB0ZSBwZXJtaXRlICpjb252ZXJzYXIqIGNvbiBSLiBQb2TDqXMgZXNjcmliaXIgY29tYW5kb3MgcXVlIHNlIHZhbiBhIGVqZWN1dGFyIGlubWVkacOhdGFtZW50ZSBjdWFuZG8gYXByaWV0ZXMgRW50ZXIgeSBjdXlvIHJlc3VsdGFkbyBzZSB2YSBhIG1vc3RyYXIgZW4gbGEgY29uc29sYS4gCgpQb3IgZWplbXBsbywgaGFjw6kgY2xpY2sgZW4gbGEgY29uc29sYSwgZXNjcmliw60gYDIgKyAyYCB5IGFwcmV0w6EgRW50ZXIuIFZhcyBhIHZlciBhbGdvIGNvbW8gZXN0bzoKCmBgYHtyfQoyICsgMgpgYGAKCkxlIGRpamlzdGUgYSBSIHF1ZSBzdW1lIDIgeSAyIHkgUiB0ZSBkZXZvbHZpw7MgZWwgcmVzdWx0YWRvOiA0IChubyB0ZSBwcmVvY3VwZXMgZGVsIGBbMV1gIHBvciBhaG9yYSkuIEVzbyBlc3TDoSBidWVubyBzaSBxdWVyw6lzIGhhY2VyIHVuYSBjdWVudGEgcsOhcGlkYSBvIGNoZXF1ZWFyIGFsZ28gcGVxdWXDsW8sIHBlcm8gbm8gc2lydmUgcGFyYSBoYWNlciB1biBhbsOhbGlzaXMgY29tcGxlam8geSByZXByb2R1Y2libGUuIAoKRW4gZWwgcGFuZWwgZGUgYXJyaWJhIGEgbGEgaXpxdWllcmRhIHRlbmVtb3MgZXNlbmNpYWxtZW50ZSB1biBlZGl0b3IgZGUgdGV4dG8uIEFow60gZXMgZG9uZGUgdmFzIGEgZXNjcmliaXIgc2kgcXVlcsOpcyBndWFyZGFyIGluc3RydWNjaW9uZXMgcGFyYSBlamVjdXRhcmxhcyBlbiBvdHJvIG1vbWVudG8geSBkb25kZSB2YXMgYSBlc3RhciBlbCA4NyUgZGUgdHUgdGllbXBvIHVzYW5kbyBSLiAKCkEgbGEgZGVyZWNoYSBoYXkgcGFuZWxlcyBtw6FzIGJpZW4gaW5mb3JtYXRpdm9zIHkgcXVlIHRpZW5lbiB2YXJpYXMgc29sYXBhcyBxdWUgdmFtb3MgYSBpciBkZXNjdWJyaWVuZG8gYSBzdSB0aWVtcG8uIFBhcmEgZGVzdGFjYXIsIGFycmliYSBhIGxhIGRlcmVjaGEgZXN0w6EgZWwgImVudmlyb25tZW50IiwgcXVlIGVzIGZvcm1hIGRlIHZlciBxdcOpIGVzIGxvIHF1ZSBlc3TDoSAicGVuc2FuZG8iIFIgZW4gZXN0ZSBtb21lbnRvLiBBaMOtIHZhcyBhIHBvZGVyIHZlciB1biBsaXN0YWRvIGRlIGxvcyBkYXRvcyBxdWUgZXN0w6FuIGFiaWVydG9zIHkgb3Ryb3Mgb2JqZXRvcyBxdWUgZXN0w6FuIGNhcmdhZG9zIGVuIGxhIG1lbW9yaWEgZGUgUi4gQWhvcmEgZXN0w6EgdmFjw61vIHBvcnF1ZSB0b2RhdsOtYSBubyBjYXJnYXN0ZSBuaSBjcmVhc3RlIG5pbmfDum4gZGF0by4gQWJham8gYSBsYSBkZXJlY2hhIHRpZW5lbiB1biBleHBsb3JhZG9yIGRlIGFyY2hpdm9zIHJ1ZGltZW50YXJpbyB5IHRhbWJpw6luIGVsIHBhbmVsIGRlIGF5dWRhLCBxdWUgZXMgZG9uZGUgdmFzIGEgcGFzYXIgZWwgb3RybyAxMyUgZGVsIHRpZW1wbyB1c2FuZG8gUi4KCkVudG9uY2VzLCBwYXJhIHJlc3VtaXI6IAoKIVtMYSBjb2NpbmEgZGUgUlN0dWRpb10oaW1nL3JzdHVkaW8tY29jaW5hLnBuZykKCiMjIyBIYWJsYW5kbyBjb24gUgoKWWEgdmlzdGUgY8OzbW8gdXNhciBSIGNvbW8gdW5hIGNhbGN1bGFkb3JhLiAKCmBgYHtyfQoyICsgMgpgYGAKClNpIHVzYXN0ZSBmw7NybXVsYXMgZW4gRXhjZWwsIGVzdG8gZXMgbXV5IHBhcmVjaWRvIGEgcG9uZXIgYD0yKzJgIGVuIHVuYSBjZWxkYS4gUiBlbnRpZW5kZSB1biBtb250w7NuIGRlIG9wZXJhY2lvbmVzIGFyaXRtw6l0aWNhcyBlc2NyaXRhcyBjb21vIHNlZ3VyYW1lbnRlIHlhIHRlIGltYWdpbsOhczoKCiAtIGArYDogc3VtYXIKIC0gYC1gOiByZXN0YXIKIC0gYCpgOiBtdWx0aXBsaWNhcgogLSBgL2A6IGRpdmlkaXIKIC0gYF5gOiBleHBvbmVuY2lhcgoKUGVybyBhZGVtw6FzIGNvbm9jZSBtdWNoYXMgb3RyYXMgb3BlcmFjaW9uZXMuIFBhcmEgZGVjaXJsZSBhIFIgcXVlIGNhbGN1bGUgZWwgc2VubyBkZSAxIGhheSBxdWUgZXNjcmliaXIgZXN0bzoKCmBgYHtyfQpzaW4oMSkKYGBgCkVzdG8gZXMgc2ltaWxhciBhIHBvbmVyIGA9U0lOKDEpYCBlbiBFeGNlbC4gTGEgc2ludGF4aXMgYsOhc2ljYSBwYXJhIGFwbGljYXIgY3VhbHF1aWVyIGZ1bmNpw7NuIGVzIGBub21icmVfZnVuY2lvbihhcmd1bWVudG9zKWAuCgo6Ojogey5hbGVydCAuYWxlcnQtc3VjY2Vzc30KKipOb3RhKio6CkVuIEV4Y2VsIGVsIG5vbWJyZSBkZSBsYXMgZnVuY2lvbmVzIGRlcGVuZGVuIGRlbCBpZGlvbWEgZW4gZWwgcXVlIGVzdMOhIGluc3RhbGFkby4gU2kgbG8gdXPDoXMgZW4gZXNwYcOxb2wsIGxhIGZ1bmNpw7NuIHNlbm8gZXMgYFNFTigpYC4gRW4gUiwgbGFzIGZ1bmNpb25lcyBzaWVtcHJlIHNlIGVzY3JpYmVuIGlndWFsIChxdWUgY29pbmNpZGUgY29uIGVsIGluZ2zDqXMpLgo6OjoKCjo6OiB7LmFsZXJ0IC5hbGVydC1pbmZvfQoqKkRlc2Fmw61vKioKCkRlY2lsZSBhIFIgcXVlIGNvbXB1dGUgbGFzIHNpZ3VpZW50ZXMgb3BlcmFjaW9uZXM6CgotIDIgbXVsdGlwbGljYWRvIHBvciAyCi0gMyBhbCBjdWFkcmFkbwotIGRvcyB0ZXJjaW9zCi0gNSBwb3IgOCBtw6FzIDEKOjo6CgoKQWwgaGFjZXIgdG9kYXMgZXN0YXMgb3BlcmFjaW9uZXMsIGxvIMO6bmljbyBxdWUgaGljaXN0ZSBmdWUgZGVjaXJsZSBhIFIgcXVlIGhhZ2EgZXNvcyBjw6FsY3Vsb3MuIFIgdGUgZGV2dWVsdmUgZWwgcmVzdWx0YWRvLCBwZXJvIG5vIGxvIGd1YXJkYSBlbiBuaW5nw7puIGxhZG8uIFBhcmEgZGVjaXJsZSBxdWUgZ3VhcmRlIGVsIHJlc3VsdGFkbyBkZSB1bmEgb3BlcmFjacOzbiBoYXkgcXVlIGRlY2lybGUgY29uIHF1w6kgIm5vbWJyZSIgcXVlcsOpcyBndWFyZGFybG8uIEVsIHNpZ3VpZW50ZSBjw7NkaWdvIGhhY2UgZXNvOgoKCmBgYHtyfQp4IDwtIDIgKyAyCmBgYAoKTGEgImZsZWNoaXRhIiBgPC1gIGVzIGVsIG9wZXJhZG9yIGRlIGFzaWduYWNpw7NuLCBxdWUgbGUgZGljZSBhIFIgcXVlIHRvbWUgZWwgcmVzdWx0YWRvIGRlIGxhIGRlcmVjaGEgeSBsbyBndWFyZGUgZW4gdW5hIHZhcmlhYmxlIGNvbiBlbCBub21icmUgcXVlIGVzdMOhIGEgbGEgaXpxdWllcmRhLiBWYXMgYSB2ZXIgcXVlIG5vIHRlIGRldmVsZSBlbCByZXN1bHRhZG8uIFBhcmEgdmVybG8sIGVqZWN1dGFtb3MKCmBgYHtyfQp4CmBgYAoKRXN0byBsZSBkaWNlIGEgUiBxdWUgdGUgImltcHJpbWEiIGVsIGNvbnRlbmlkbyBkZSBsYSB2YXJpYWJsZSB4LiAKCjo6OiB7LmFsZXJ0IC5hbGVydC1pbmZvfQoqKkRlc2Fmw61vICoqCgrCv1F1w6kgdGUgaW1hZ2luw6FzIHF1ZSB2YSBhIHBhc2FyIGN1YW5kbyBhaG9yYSBjb3JyYSBlbCBzaWd1aWVudGUgY8OzZGlnbz8KYGBge3IsIGV2YWwgPSBGQUxTRX0KeCArIDIKYGBgCgo6OjoKClBvbmVybGUgbm9tYnJlIGEgbGFzIHZhcmlhYmxlcyBlcyBhIHZlY2VzIGxhIHBhcnRlIG3DoXMgZGlmw61jaWwgZGUgZXNjcmliaXIgY8OzZGlnby4gQSBSIG5vIGxlIHZpZW5lIGJpZW4gY3VhbHF1aWVyIG5vbWJyZSBkZSB2YXJpYWJsZSBzaWVtcHJlIHkgY3VhbmRvIG5vIGVtcGllY2UgY29uIHVuIG7Dum1lcm8gbyB1biAiXyIuIFBlcm8gYSBsb3Mgc2VyZXMgaHVtYW5vcyBxdWUgbGVhbiBlbCBjw7NkaWdvIHkgdGVuZ2FuIHF1ZSBpbnRlcnByZXRhcmxvcyBsZXMgdmEgYSByZXN1bHRhcyBtw6FzIGbDoWNpbCBlbnRlbmRlciBxdcOpIGhhY2UgbGEgdmFyaWFibGUgYHRlbXBlcmF0dXJhX2NvcmRvYmFgIHF1ZSBsYSB2YXJpYWJsZSBgeHh5MWAuIAoKRWwgY29uc2VqbyBlcyB0cmF0YXIgZW4gbG8gcG9zaWJsZSB1c2FyIG5vbWJyZSBkZXNjcmlwdGl2b3MgeSBjb25zaXN0ZW50ZXMuIFBvciBlamVtcGxvLCBzaWVtcHJlIHVzYXIgbWluw7pzY3VsYXMgeSBzZXBhcmFyIHBhbGFicmFzIGNvbiAiXyIuIAoKOjo6ey5hbGVydCAuYWxlcnQtc3VjY2Vzc30KKipUaXAqKjogUGFyYSBoYWNlcnNlIGxhIHZpZGEgbcOhcyBmw6FjaWwgZXhpc3RlbiAiZ3XDrWFzIGRlIGVzdGlsbyIgcGFyYSBwcm9ncmFtYXIgcXVlIGV4cGxpY2l0YW4gcmVnbGFzIGVzcGVjw61maWNhcyBwYXJhIGVzY3JpYmlyIGPDs2RpZ28uIFBvciBlamVtcGxvIFtlc3RhXShodHRwczovL3JwdWJzLmNvbS9GdkQvZ3VpYS1lc3RpbG8tcil7LmFsZXJ0LWxpbmt9IG8gW2VzdGEgb3RyYV0oaHR0cHM6Ly9naXRodWIuY29tL2VsaW9jYW1wL3Rlc2lzL2Jsb2IvbWFzdGVyL2RvY3MvZ3UlQzMlQURhX2RlX2VzdGlsby5tZCl7LmFsZXJ0LWxpbmt9LiBTZSB0cmF0YSBkZSByZWdsYXMgw7puaWNhbWVudGUgcGFyYSBsb3Mgb2pvcyBodW1hbm9zLCB5IHF1ZSBubyBhZmVjdGFuIGVuIGFic29sdXRvIGxhIGVmaWNpZW5jaWEgbyBjb3JyZWN0aXR1ZCBkZSBsYSBwcm9ncmFtYWNpw7NuLiBFbiBnZW5lcmFsLCBubyBleGlzdGVuIGd1w61hcyBidWVuYXMgbyBtYWxhcywgbGEgaWRlYSBlcyBlbGVnaXIgdW5hIHkgc2VyIGNvbnNpc3RlbnRlLiBEZSBlc3RhIG1hbmVyYSwgdmFzIGEgcG9kZXIgZW50ZW5kZXIgdHUgY8OzZGlnbyBjb24gbcOhcyBmYWNpbGlkYWQuIAo6OjoKCgojIyMgRXh0ZW5kaWVuZG8gUgoKUiBlcyB1biBsZW5ndWFqZSBjcmVhZG8gcG9yIGVzdGFkw61zdGljb3MgeSBwZW5zYWRvIHBhcmEgbGEgZXN0YWTDrXN0aWNhLCBwb3IgbG8gcXVlIHlhIHZpZW5lIGNvbiB1biBtb250w7NuIGRlIG3DqXRvZG9zIGVzdGFkw61zdGljb3MgaW5jb3Jwb3JhZG9zLCBjb21vIGBtZWFuKClgIG8gYG1lZGlhbigpYC4gUGVybyBoYXkgdGFudG9zIG3DqXRvZG9zIGVzdGFkw61zdGljb3MgY29tbyBnZW50ZSBoYWNpZW5kbyBlc3RhZMOtc3RpY2EgYXPDrSBxdWUgZXMgaW1wb3NpYmxlIHF1ZSBlc3TDqW4gdG9kb3MuIExhIHNvbHVjacOzbiBlcyBxdWUgcG9kw6lzICJhZ3JlZ2FybGUiIGEgUiBmdW5jaW9uZXMgcXVlIG5vIHZpZW5lbiBpbnN0YWxhZGFzIHBvciBkZWZlY3RvIHBlcm8gcXVlIGVzY3JpYmllcm9uIG90cmFzIHBlcnNvbmFzIGVuIGZvcm1hIGRlICJwYXF1ZXRlcyIuIEVzdGUgZXMgZWwgcG9kZXIgZGUgKipsYSBjb211bmlkYWQgZGUgUioqISAKClBhcmEgaW5zdGFsYXIgcGFxdWV0ZXMgZGUgUiwgbGEgZm9ybWEgbWFzIGbDoWNpbCBlcyBjb24gbGEgZnVuY2nDs24gYGluc3RhbGwucGFja2FnZXMoKWAuIEVudG9uY2VzLCBwb3IgZWplbXBsbywgCgpgYGB7ciwgZXZhbD1GQUxTRX0KaW5zdGFsbC5wYWNrYWdlcygicmVhZHIiKQpgYGAKCnRlIGluc3RhbGEgdW4gcGFxdWV0ZSBxdWUgY29udGllbmUgZnVuY2lvbmVzIHBhcmEgbGVlciBkYXRvcy4gTHVlZ28sIHVzYW5kbyBlbCBjb21hbmRvCgpgYGB7cn0KbGlicmFyeShyZWFkcikKYGBgCgpsZSBkZWPDrXMgYSBSIHF1ZSBjYXJndWUgbGFzIGZ1bmNpb25lcyBxdWUgdmllbmVuIGVuIGVsIHBhcXVldGUgcmVhZHIgcGFyYSB1c2FybGFzLgoKCjo6OiB7LmFsZXJ0IC5hbGVydC1pbmZvfQoqKkRlc2Fmw61vKio6IEluc3RhbMOhIGVsIHBhcXVldGUge3JlYWRyfSBjb24gZWwgY29tYW5kbyBgaW5zdGFsbC5wYWNrYWdlcygicmVhZHIiKWAKOjo6CgoKOjo6IHsuYWxlcnQgLmFsZXJ0LXN1Y2Nlc3N9CioqTm90YSoqOiBTaSBjZXJyw6FzIHkgdm9sdmXFmyBhIGFicmlyIFIsIHZhcyBhIHRlbmVyIHF1ZSB1c2FyIGBsaWJyYXJ5KHJlYWRyKWAgbnVldmFtZW50ZSBwYXJhIGFjY2VkZXIgYSBsYSBmdW5jaW9uYWxpZGFkIGRlbCBwYXF1ZXRlIHJlYWRyCjo6OgoKCiMjIyBCdXNjYW5kbyBheXVkYQoKRW50cmUgbGEgZW5vcm1lIGNhbnRpZGFkIGRlIGZ1bmNpb25lcyBxdWUgdGllbmUgUiBwb3IgZGVmZWN0byB5IGxhcyBxdWUgc2UgcHVlZGVuIGFncmVnYXIgaW5zdGFsYW5kbyBwYXF1ZXRlcyBleHRlcm5vcywgZXMgaW1wb3NpYmxlIHJlY29yZGFyIHRvZGFzIGxhcyBmdW5jaW9uZXMgeSBjw7NtbyB1c2FybGFzLiBQb3IgZXNvLCB1bmEgZ3JhbiBwcm9wb3JjacOzbiBkZWwgdGllbXBvIHF1ZSB1c2VzIFIgdmFzIGEgcGFzYXJsbyBsZXllbmRvIGRvY3VtZW50YWNpw7NuIGRlIGZ1bmNpb25lcywgeWEgc2VhIHBhcmEgYXByZW5kZXIgYSB1c2FybGFzIG8gcG9ycXVlIG5vIHRlIGFjb3Jkw6FzIGFsZ8O6biBkZXRhbGxlLiAKClBhcmEgYWNjZWRlciBhIGxhIGF5dWRhIGRlIHVuYSBmdW5jacOzbiBzaW1wbGVtZW50ZSB1c2Ftb3MgZWwgc2lnbm8gZGUgcHJlZ3VudGE6CgpgYGB7cn0KP3NpbgpgYGAKCjo6OiB7LmFsZXJ0IC5hbGVydC1zdWNjZXNzfQoqKk5vdGEqKjogT3RyYSBmb3JtYSBkZSBhY2NlZGVyIGEgbGEgYXl1ZGEgZGUgdW5hIGZ1bmNpw7NuIGVzIHBvbmllbmRvIGVsIGN1cnNvciBzb2JyZSBlbGxhIHkgYXByZXRhbmRvIEYxCjo6OgoKCkVzdG8gdmEgYSBhYnJpciBlbCBkb2N1bWVudG8gZGUgYXl1ZGEgcGFyYSBsYSBmdW5jacOzbiBgc2luKClgIHF1ZSwgY29tbyB2ZXLDoXMsIHRpZW5lIGxhIGRvY3VtZW50YWNpw7NuIGRlIGxhcyBmdW5jaW9uZXMgdHJpZ29ub23DqXRyaWNhcyBxdWUgdHJhZSBSIHBvciBkZWZlY3RvLiBUb2RhcyBsYXMgYXl1ZGFzIGRlIFIgdmllbmVuIGRpdmlkaWRhcyBlbiBzZWNjaW9uZXM6CgpEZXNjcmlwdGlvbgo6IFVuYSBkZXNjcmlwY2nDs24gYnJldmUgZGUgbGEgZnVuY2nDs24gbyBmdW5jaW9uZXMgcXVlIHNlIGRvY3VtZW50YW4uIAoKClVzYWdlCjogTm9tYnJlIGRlIGxvcyBhcmd1bWVudG9zIGRlIGxhIGZ1bmNpw7NuLiBMYSBtYXlvcsOtYSBkZSBsYXMgZnVuY2lvbmVzIHRyaWdvbm9tw6l0cmljYXMgdGllbmVuIHVuIHNvbG8gYXJndW1lbnRvLCBxdWUgc2UgbGxhbWEgYHhgLiBMYSBmdW5jacOzbiBgYXRhbjIoKWAgdGllbmUgZG9zIGFyZ3VtZW50b3MsIGxsYW1hZG9zIGB4YCBlIGB5YC4KCgpBcmd1bWVudHMKOiBVbmEgZGVzY3JpcGNpw7NuIGRlIGNhZGEgYXJndW1lbnRvLiBFbiBlc3RlIGNhc28gYHhgIGUgYHlgIHNvbiB2ZWN0b3JlcyBudW3DqXJpY29zIG8gY29tcGxlam9zLiBBdW5xdWUgdG9kYXbDrWEgbm8gc2VwYXMgcXXDqSBlcyB1biAidmVjdG9yIiwgZGUgZXN0YSBkZXNjcmlwY2nDs24geWEgcG9kw6lzIGludHVpciBxdWUgbGFzIGZ1bmNpb25lcyB0cmlnb25vbcOpdHJpY2FzIGFjZXB0YW4gbsO6bWVyb3MgY29tcGxlam9zLiAKCgpEZXRhaWxzCjogVW5hIGRlc2NyaXBjacOzbiBkZXRhbGxhZGEgZGUgbGFzIGZ1bmNpb25lcy4gUG9yIGVqZW1wbG8sIGRldGFsbGEgcXXDqSBlcyBsbyBxdWUgZGV2dWVsdmUgbGEgZnVuY2nDs24gYGF0YW4yKClgLCBkZXNjcmliZSBsYXMgdW5pZGFkZXMgZW4gbGFzIHF1ZSB0aWVuZW4gcXVlIGVzdGFyIGB4YCBlIGB5YCwgZXRjLi4gCgoKVmFsdWUKOiBEZXNjcmliZSBxdcOpIHRpcG8gZGUgdmFsb3IgZGV2dWVsdmUgbGEgZnVuY2nDs24uCgoKRXhhbXBsZXMKOiAoYWJham8gZGUgdG9kbykgRXMgbGEgc2VjY2nDs24gbcOhcyBpbXBvcnRhbnRlIHkgcHJvYmFibGVtZW50ZSBsYSBxdWUgdmFzIGEgYnVzY2FyIHByaW1lcm8gY3VhbmRvIHRlIGVuY3VlbnRyZXMgY29uIHVuYSBmdW5jacOzbiBudWV2YSBxdWUgbm8gc2Fiw6lzIGPDs21vIHVzYXIuIEFjw6EgdmFzIGEgZW5jb250cmFyIGPDs2RpZ28gZGUgUiBkZSBxdWUgZWplbXBsaWZpY2EgZWwgdXNvIHTDrXBpY28gZGUgbGEgZnVuY2nDs24uIFBvZGVzIGNvcGlhciB5IHBlZ2FyIGVsIGPDs2RpZ28gZW4gbGEgY29uc29sYSB5IHZlciBlbCByZXN1bHRhZG8gcGFyYSBlbnRlbmRlciBjb21vIGZ1bmNpb25hLiAKCgooT3RyYXMgc2VjY2lvbmVzKQo6IFB1ZWRlbiBoYWJlciBvdHJhcyBzZWNjaW9uZXMgcXVlIGRldGFsbGVuIGRpc3RpbnRhcyBwYXJ0aWN1bGFyaWRhZGVzIGRlIGxhIGZ1bmNpw7NuLCBvIHJlZmVyZW5jaWFzIGEgbG9zIG3DqXRvZG9zIGltcGxlbWVudGFkb3MuIAoKOjo6IHsuYWxlcnQgLmFsZXJ0LWluZm99CioqRGVzYWbDrW8qKgoKQWJyw60geSBsZcOpIGxhIGF5dWRhIGRlIGxhIGZ1bmNpw7NuIGBzZCgpYC4gUHVlZGUgcXVlIGhheWEgY29zYXMgcXVlIGHDum4gbm8gZW50aWVuZGFzLCBwZXJvIHRyYXTDoSBkZSBjYXB0YXIgbGEgaWRlYSBnZW5lcmFsLiDCv1F1w6kgaGFjZSBlc2EgZnVuY2nDs24/IMK/UXXDqSBhcmd1bWVudG9zIGFjZXB0YT8KOjo6CgoKCjxkaXYgY2xhc3M9ImJ0bi1ncm91cCIgcm9sZT0iZ3JvdXAiIGFyaWEtbGFiZWw9Ik5hdmVnYWNpw7NuIj4KICA8YSBocmVmPSAiaG9qYS1kZS1ydXRhLmh0bWwiIGNsYXNzID0gImJ0biBidG4tcHJpbWFyeSI+SG9qYSBkZSBydXRhPC9hPgogIDxhIGhyZWY9ICIwMi1wcm95ZWN0b3MuaHRtbCIgY2xhc3MgPSAiYnRuIGJ0bi1wcmltYXJ5Ij5TaWd1aWVudGU8L2E+CjwvZGl2Pg==