Proceso de análisis de datos
El proceso de análisis de datos en el cual nos vamos a basar se puede
ver en el siguiente diagrama:
Primero, debes importar tus datos hacia la
herramienta donde vas a procesarlos. Típicamente, esto implica tomar
datos que están guardados en un archivo o base de datos y cargarlos en
tu software para poder trabajar con ellos.
Una vez que has importado los datos, el siguiente paso es
ordenarlos para que tengan un formato adecuado para su
análisis. Este formato pensado para el análisis tiene la característica
que, en los conjuntos de datos ordenados, cada columna es una
variable y cada fila una observación. Tener datos ordenados nos
provee una estructura consistente, preparada para analizarlos y podemos
enfocar nuestros esfuerzos en las preguntas que queremos contestar con
nuestros datos y no tener que acomodarlos cada vez que la pregunta
cambie.
Cuando tus datos están ordenados, podemos necesitar
transformarlos. La transformación implica quedarte con las
observaciones que sean de interés (como todos los rendimientos de
girasol mayores a 2000 kilos por hectárea o todos los datos del último
año), crear nuevas variables que a partir de variables ya existentes
(como calcular el margen bruto de trigo a partir de los datos de precios
y el listado de actividades) y calcular una serie de estadísticos de
resumen (como obtener los rendimientos máximos y mínimos de maíz para
una región particular).
Una vez que tienes los datos ordenados con las variables que
necesitas, hay dos principales fuentes generadoras de conocimiento: la
visualización y el modelado. Ambas
tienen fortalezas y debilidades complementarias, por lo que cualquier
análisis va a utilizarlas varias veces aprovechando los resultados de
una para alimentar a la otra.
La visualización es una herramienta fundamental. Una buena
visualización te mostrará el patrón de los datos, cosas que tal vez no
esperabas o te hará surgir nuevas preguntas. También puede ayudarte a
replantear tus preguntas o darte cuenta si necesitas recolectar datos
diferentes.
Los modelos son herramientas complementarias a la visualización. Una
vez que tus preguntas son lo suficientemente precisas, puedes utilizar
un modelo para responderlas. Los modelos son herramientas estadísticas o
computacionales y tienen supuestos para poder aplicarlos, así que la
tarea de seleccionar el modelo adecuado para nuestro problema es una
parte importante de este proceso, como también lo es su implantación e
interpretación posterior.
El último paso en el proceso de la ciencia de datos es la
comunicación, una parte crítica de cualquier proyecto
de análisis de datos, porque es cuando vas a mostrar tus resultados a
otras personas y necesitas que puedan comprenderlos y encontrarlos
útiles para utilizarlos.
Alrededor de todas estas herramientas se encuentra la
programación como herramienta transversal en el
proyecto de ciencia de datos. No necesitás ser una persona experta en
programación para hacer ciencia de datos, pero aprender más sobre
programar te ayudará a automatizar tareas recurrentes, compartir tu
trabajo de forma reusable y aprovechar el trabajo de otras personas para
resolver problemas similares con mayor facilidad y rapidez.
En este curso veremos como realizar algunas de estas etapas
utilizando el software R con un enfoque en procesamiento espacial. Te
dejaremos links donde puedes aprender y profundizar más cada aspecto de
este proceso.
¿Por qué R?
Si estas trabajando con datos espaciales seguro has utilizado
diferentes software, como QGIS, Excel, ArGIS, ERDAS y Google Earth
Engine.
Cada una de estas herramientas es muy poderosa y si hace tiempo que
los venis usando, seguro conoces muchos de sus trucos y secretos.
El uso de R nos permitirá realizar algunas tareas de forma más
sencilla, especialmente las que se pueden escribir como 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.
Con R también podremos compartir estas recetas, estos programas, con
otros colaboradores de forma mas sencilla, al igual que realizar la
transición de nuestros reportes a aplicaciones web.
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:
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:
## [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:
Hablando con R
Ya viste cómo usar R como una calculadora.
## [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
^
o **
: exponenciar
Pero además conoce muchas otras operaciones. Para decirle a R que
calcule el seno de 1 hay que escribir esto:
## [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:
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 devuele el
resultado. Para verlo, ejecutamos
## [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?
Ponerle nombre a las variables es a veces la parte más difícil de
escribir código. A R 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 promedio_rendimiento
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 personas que practican la estadística 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()
. Esta función se conecta a
internet y descarga paquetes publicados en un repositorio oficial
Entonces, por ejemplo,
install.packages("rnaturalearth")
descarga e instala un paquete que contiene funciones para leer
datos.
Nota: Para instalar paquetes de esta forma es
necesario tener conexión de internet.
Luego, usando el comando
le decís a R que cargue las funciones que vienen en el paquete readr
para usarlas.
Desafío: Instalá el paquete rnaturalearth con el
comando install.packages("rnaturalearth")
en la
consola.
Nota: Si cerrás y volveś a abrir R, vas a tener que
usar library(rnaturalearth)
nuevamente para acceder a la
funcionalidad del paquete readr. Sólo hace falta correr
install.packages("rnaturalearth")
una vez por máquina.
Trabajar con proyectos en RStudio
Trabajar con proyectos de RStudio no solo hace tus análisis más
ordenados y reproducibles, también hacen tu vida más simple.
Al comienzo posiblemente tengas un script y uno o dos archivos con
datos, pero es posible que rápidamente te encuentres con una docena de
archivos con nombres parecidos pero que pertenecen a análisis totalmente
distintos. Antes de que la cosa comience a complicarse te proponemos
trabajar con proyectos.
Usando RStudio Cloud
Si estás trabajando en RStudio Cloud entonces ya estás trabajando con
un proyecto. Es la configuración por defecto de la plataforma.
¿Qué ventajas tiene?
- Te permite “cuidar” los datos que usas al ordenarnos en carpetas que
diferencien entre la versión original o cruda y los datos limpios o los
resultados finales.
- Te permite compartir tu trabajo fácilmente con otras personas. Solo
tendrías que compartir la carpeta del proyecto sabiendo que incluye todo
lo necesario para que cualquiera reproduzca tu análisis.
- Te permite publicar de manera ordenada tu código si vas a presentar
o publicar tu trabajo.
- Te permite continuar con lo que estabas haciendo hace una semana o
hace un mes como si el tiempo no hubiera pasado (tu yo futuro te lo va a
agradecer).
Desafío: Crea un nuevo proyecto en RStudio
- Hacé click en el menú “Archivo” (“File”) y luego en “Nuevo Proyecto”
(“New Project”).
- Hacé click en “Nueva Carpeta” (“New Directory”).
- Hacé click en “Nuevo Proyecto” (“New Project”).
- Escribí el nombre de la carpeta que alojará a tu proyecto, por
ejemplo “curso_analisis”
- Si aparece (y sabés usarlo), seleccioná “Crear un repositorio de
git” (“Create a git repository”).
- Hacé click en “Crear Proyecto” (“Create Project”).
Si todo salió bien, ahora deberías tener una nueva carpeta que se
llama curso_analisis. Pero si bien es una carpeta común y
corriente, le llamamos proyecto porque además contiene un archivo con el
mismo nombre curso_analisis.Rproj (o solo
curso_analisis si en tu computadora no ves la extensión de los
archivos).
Abrir un proyecto
La manera más simple de abrir un proyecto es abriendo la carpeta que
lo contiene y haciendo doble click sobre el archivo
curso_analisis.Rproj. Al hacer esto se abrirá RStudio y la
sesión de R en la misma carpeta y, por defecto, cualquier archivo que
quieras abrir o guardar lo hará en esa misma ubicación. Esto ayuda a
mantener tu trabajo ordenado y que luego sea simple retomar o compartir
lo que hiciste.
RStudio permite tener varios proyectos abiertos, y esto es posible
porque justamente cada proyecto tiene su propia carpeta. Si en algún
momento trabajas con proyectos en paralelo vas a poder hacerlo sin que
el código o los resultados de un análisis interfieran con otro.
Desafío: Abrí tu nuevo proyecto desde el explorador de
archivos
- Cerrá RStudio
- Desde el explorador de archivos, buscá la carpeta donde creaste tu
proyecto.
- Hacé doble click en el archivo que tiene el nombre de tu proyecto (y
que termina con .Rproj) que encontrarás en esa carpeta.
¿Cómo se organiza?
No existe una “mejor” forma de organizar un proyecto pero acá van
algunos principios generales que nos hacen la vida más simple::
- Tratar los datos como sólo de lectura Es posible
que la toma de los datos que querés analizar te haya costado mucho
trabajo, o te haya costado conseguirlos. Trabajar con datos de forma
interactiva (por ejemplo, en Excel) tiene la ventaja de permitirte hacer
algunos análisis rápidamente pero al mismo tiempo tiene la desventaja de
que esos datos pueden ser modificados fácilmente. Esto significa que a
veces no conozcas de la procedencia de los datos, o no recuerdes cómo
los modificaste desde que los obtuviste. Por lo tanto, es una buena idea
tratar los datos como “sólo de lectura” y nunca modificar los archivos
originales.
- Limpieza de datos En muchos casos tus datos estarán
“sucios”, necesitarán un preprocesamiento importante para organizarlos
en un formato que R (o cualquier otro lenguaje de programación) pueda
analizados fácilmente. Esta tarea se denomina a veces “amasado” o
“masticado de datos”. Es una buena costumbre guardar el código que te
permitió limpiar estos datos por si los volvieras a necesitar. También
es recomendable guardar esa versión de los datos limpios, de “sólo
lectura”, para que puedas usarlos en tu análisis sin necesidad de
repetir cada vez todo el proceso de limpieza de los datos.
- Tratar las salidas o resultados generados como
descartables Cualquier resultado (gráficos, tablas, valores)
debe poder repetirse o rehacerse a partir del código guardado. Si bien
las pruebas rápidas para ver si el código funciona se pueden
hacer en la consola, es importante guardar el código que genera los
resultados y asegurarnos de que sean reproducibles. Aún mejor, si
organizas esos resultados en distintas sub-carpetas, tendrás todo aún
más ordenado.
Borrón y cuenta nueva… todos los días!
¿Cómo nos aseguramos de que el análisis sea realmente reproducible?
Esta es una pregunta bastante amplia y hay muchas herramientas para
resolver este problema. Por ahora nos vamos a concentrar en que al menos
en tu computadora puedas repetir los cálculos o el análisis desde cero.
Y además de organizar proyectos y no modificar los datos originales,
¿cómo podés asegurarte de que guardaste todo el código que estuviste
escribiendo y usaste? La manera más directa es reiniciar la sesión de R
y correr el código de nuevo, si da error o no devuelve lo que esperabas
significa que te faltó guardar algún paso.
Tip: Podés reiniciar la sesión de R con el atajo
Ctrl+Shif+F10
Esto puede pasar si por ejemplo leés una base de datos en memoria
pero no guardás el código que lo hace. Mientras estemos trabajando, R
tendrá esa base de datos en memoria y podremos hacer cálculos y
gráficos. Por defecto además RStudio va a recordar las variables que
estés usando mañana o pasado en un archivo oculto (.RData) a menos que
le indiques lo contrario. Y si bien suena práctico volver a R al otro
día y tener el análisis tal cual lo dejamos, esto puede significar que
nunca nos demos cuenta que nos faltó guardar una línea de código clave
en nuestro análisis.
Desafío: Configurá RStudio
- Hacé click en el menú “Herramientas (”Tools”) y luego “Opciones
globales” (“Global Options”).
- Destildá la opción “Recuperar .RData al inicio de la sesión”
(“Restore .RData into workspace at startup”).
- Hacé click en “Aplicar” (“Apply”).
LS0tDQp0aXRsZTogIkZsdWpvIGRlIHRyYWJham8gcmVwcm9kdWNpYmxlIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIGhpZ2hsaWdodDogdGFuZ28NCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQotLS0NCg0KIyMgUHJvY2VzbyBkZSBhbsOhbGlzaXMgZGUgZGF0b3MNCg0KDQpFbCBwcm9jZXNvIGRlIGFuw6FsaXNpcyBkZSBkYXRvcyBlbiBlbCBjdWFsIG5vcyB2YW1vcyBhIGJhc2FyIHNlIHB1ZWRlIHZlciBlbiBlbCBzaWd1aWVudGUgZGlhZ3JhbWE6DQoNCiFbTWFwYSBjb25jZXB0dWFsIGRlbCBwcm9jZXNvIGRlIGNpZW5jaWEgZGUgZGF0b3NdKGltZy9jaWVuY2lhLWRlLWRhdG9zLnBuZykNCg0KDQpQcmltZXJvLCBkZWJlcyAqKmltcG9ydGFyKiogdHVzIGRhdG9zIGhhY2lhIGxhIGhlcnJhbWllbnRhIGRvbmRlIHZhcyBhIHByb2Nlc2FybG9zLg0KVMOtcGljYW1lbnRlLCBlc3RvIGltcGxpY2EgdG9tYXIgZGF0b3MgcXVlIGVzdMOhbiBndWFyZGFkb3MgZW4gdW4gYXJjaGl2byBvIGJhc2UgZGUgZGF0b3MgeSBjYXJnYXJsb3MgZW4gdHUgc29mdHdhcmUgcGFyYSBwb2RlciB0cmFiYWphciBjb24gZWxsb3MuDQoNClVuYSB2ZXogcXVlIGhhcyBpbXBvcnRhZG8gbG9zIGRhdG9zLCBlbCBzaWd1aWVudGUgcGFzbyBlcyAqKm9yZGVuYXJsb3MqKiBwYXJhIHF1ZSB0ZW5nYW4gdW4gZm9ybWF0byBhZGVjdWFkbyBwYXJhIHN1IGFuw6FsaXNpcy4NCkVzdGUgZm9ybWF0byBwZW5zYWRvIHBhcmEgZWwgYW7DoWxpc2lzIHRpZW5lIGxhIGNhcmFjdGVyw61zdGljYSBxdWUsIGVuIGxvcyBjb25qdW50b3MgZGUgZGF0b3Mgb3JkZW5hZG9zLCAqY2FkYSBjb2x1bW5hIGVzIHVuYSB2YXJpYWJsZSB5IGNhZGEgZmlsYSB1bmEgb2JzZXJ2YWNpw7NuKi4NClRlbmVyIGRhdG9zIG9yZGVuYWRvcyBub3MgcHJvdmVlIHVuYSBlc3RydWN0dXJhIGNvbnNpc3RlbnRlLCBwcmVwYXJhZGEgcGFyYSBhbmFsaXphcmxvcyB5IHBvZGVtb3MgZW5mb2NhciBudWVzdHJvcyBlc2Z1ZXJ6b3MgZW4gbGFzIHByZWd1bnRhcyBxdWUgcXVlcmVtb3MgY29udGVzdGFyIGNvbiBudWVzdHJvcyBkYXRvcyB5IG5vIHRlbmVyIHF1ZSBhY29tb2RhcmxvcyBjYWRhIHZleiBxdWUgbGEgcHJlZ3VudGEgY2FtYmllLg0KDQpDdWFuZG8gdHVzIGRhdG9zIGVzdMOhbiBvcmRlbmFkb3MsIHBvZGVtb3MgbmVjZXNpdGFyICp0cmFuc2Zvcm1hcmxvcyouDQpMYSB0cmFuc2Zvcm1hY2nDs24gaW1wbGljYSBxdWVkYXJ0ZSBjb24gbGFzIG9ic2VydmFjaW9uZXMgcXVlIHNlYW4gZGUgaW50ZXLDqXMgKGNvbW8gdG9kb3MgbG9zIHJlbmRpbWllbnRvcyBkZSBnaXJhc29sIG1heW9yZXMgYSAyMDAwIGtpbG9zIHBvciBoZWN0w6FyZWEgbyB0b2RvcyBsb3MgZGF0b3MgZGVsIMO6bHRpbW8gYcOxbyksIGNyZWFyIG51ZXZhcyB2YXJpYWJsZXMgcXVlIGEgcGFydGlyIGRlIHZhcmlhYmxlcyB5YSBleGlzdGVudGVzIChjb21vIGNhbGN1bGFyIGVsIG1hcmdlbiBicnV0byBkZSB0cmlnbyBhIHBhcnRpciBkZSBsb3MgZGF0b3MgZGUgcHJlY2lvcyB5IGVsIGxpc3RhZG8gZGUgYWN0aXZpZGFkZXMpIHkgY2FsY3VsYXIgdW5hIHNlcmllIGRlIGVzdGFkw61zdGljb3MgZGUgcmVzdW1lbiAoY29tbyBvYnRlbmVyIGxvcyByZW5kaW1pZW50b3MgbcOheGltb3MgeSBtw61uaW1vcyBkZSBtYcOteiBwYXJhIHVuYSByZWdpw7NuIHBhcnRpY3VsYXIpLg0KDQpVbmEgdmV6IHF1ZSB0aWVuZXMgbG9zIGRhdG9zIG9yZGVuYWRvcyBjb24gbGFzIHZhcmlhYmxlcyBxdWUgbmVjZXNpdGFzLCBoYXkgZG9zIHByaW5jaXBhbGVzIGZ1ZW50ZXMgZ2VuZXJhZG9yYXMgZGUgY29ub2NpbWllbnRvOiBsYSAqKnZpc3VhbGl6YWNpw7NuKiogeSBlbCAqKm1vZGVsYWRvKiouDQpBbWJhcyB0aWVuZW4gZm9ydGFsZXphcyB5IGRlYmlsaWRhZGVzIGNvbXBsZW1lbnRhcmlhcywgcG9yIGxvIHF1ZSBjdWFscXVpZXIgYW7DoWxpc2lzIHZhIGEgdXRpbGl6YXJsYXMgdmFyaWFzIHZlY2VzIGFwcm92ZWNoYW5kbyBsb3MgcmVzdWx0YWRvcyBkZSB1bmEgcGFyYSBhbGltZW50YXIgYSBsYSBvdHJhLg0KDQpMYSB2aXN1YWxpemFjacOzbiBlcyB1bmEgaGVycmFtaWVudGEgZnVuZGFtZW50YWwuDQpVbmEgYnVlbmEgdmlzdWFsaXphY2nDs24gdGUgbW9zdHJhcsOhIGVsIHBhdHLDs24gZGUgbG9zIGRhdG9zLCBjb3NhcyBxdWUgdGFsIHZleiBubyBlc3BlcmFiYXMgbyB0ZSBoYXLDoSBzdXJnaXIgbnVldmFzIHByZWd1bnRhcy4NClRhbWJpw6luIHB1ZWRlIGF5dWRhcnRlIGEgcmVwbGFudGVhciB0dXMgcHJlZ3VudGFzIG8gZGFydGUgY3VlbnRhIHNpIG5lY2VzaXRhcyByZWNvbGVjdGFyIGRhdG9zIGRpZmVyZW50ZXMuDQoNCkxvcyBtb2RlbG9zIHNvbiBoZXJyYW1pZW50YXMgY29tcGxlbWVudGFyaWFzIGEgbGEgdmlzdWFsaXphY2nDs24uDQpVbmEgdmV6IHF1ZSB0dXMgcHJlZ3VudGFzIHNvbiBsbyBzdWZpY2llbnRlbWVudGUgcHJlY2lzYXMsIHB1ZWRlcyB1dGlsaXphciB1biBtb2RlbG8gcGFyYSByZXNwb25kZXJsYXMuDQpMb3MgbW9kZWxvcyBzb24gaGVycmFtaWVudGFzIGVzdGFkw61zdGljYXMgbyBjb21wdXRhY2lvbmFsZXMgeSB0aWVuZW4gc3VwdWVzdG9zIHBhcmEgcG9kZXIgYXBsaWNhcmxvcywgYXPDrSBxdWUgbGEgdGFyZWEgZGUgc2VsZWNjaW9uYXIgZWwgbW9kZWxvIGFkZWN1YWRvIHBhcmEgbnVlc3RybyBwcm9ibGVtYSBlcyB1bmEgcGFydGUgaW1wb3J0YW50ZSBkZSBlc3RlIHByb2Nlc28sIGNvbW8gdGFtYmnDqW4gbG8gZXMgc3UgaW1wbGFudGFjacOzbiBlIGludGVycHJldGFjacOzbiBwb3N0ZXJpb3IuDQoNCkVsIMO6bHRpbW8gcGFzbyBlbiBlbCBwcm9jZXNvIGRlIGxhIGNpZW5jaWEgZGUgZGF0b3MgZXMgbGEgKipjb211bmljYWNpw7NuKiosIHVuYSBwYXJ0ZSBjcsOtdGljYSBkZSBjdWFscXVpZXIgcHJveWVjdG8gZGUgYW7DoWxpc2lzIGRlIGRhdG9zLCBwb3JxdWUgZXMgY3VhbmRvIHZhcyBhIG1vc3RyYXIgdHVzIHJlc3VsdGFkb3MgYSBvdHJhcyBwZXJzb25hcyB5IG5lY2VzaXRhcyBxdWUgcHVlZGFuIGNvbXByZW5kZXJsb3MgeSBlbmNvbnRyYXJsb3Mgw7p0aWxlcyBwYXJhIHV0aWxpemFybG9zLg0KDQpBbHJlZGVkb3IgZGUgdG9kYXMgZXN0YXMgaGVycmFtaWVudGFzIHNlIGVuY3VlbnRyYSBsYSAqKnByb2dyYW1hY2nDs24qKiBjb21vIGhlcnJhbWllbnRhIHRyYW5zdmVyc2FsIGVuIGVsIHByb3llY3RvIGRlIGNpZW5jaWEgZGUgZGF0b3MuDQpObyBuZWNlc2l0w6FzIHNlciB1bmEgcGVyc29uYSBleHBlcnRhIGVuIHByb2dyYW1hY2nDs24gcGFyYSBoYWNlciBjaWVuY2lhIGRlIGRhdG9zLCBwZXJvIGFwcmVuZGVyIG3DoXMgc29icmUgcHJvZ3JhbWFyIHRlIGF5dWRhcsOhIGEgYXV0b21hdGl6YXIgdGFyZWFzIHJlY3VycmVudGVzLCBjb21wYXJ0aXIgdHUgdHJhYmFqbyBkZSBmb3JtYSByZXVzYWJsZSB5IGFwcm92ZWNoYXIgZWwgdHJhYmFqbyBkZSBvdHJhcyBwZXJzb25hcyBwYXJhIHJlc29sdmVyIHByb2JsZW1hcyBzaW1pbGFyZXMgY29uIG1heW9yIGZhY2lsaWRhZCB5IHJhcGlkZXouDQoNCkVuIGVzdGUgY3Vyc28gdmVyZW1vcyBjb21vIHJlYWxpemFyIGFsZ3VuYXMgZGUgZXN0YXMgZXRhcGFzICB1dGlsaXphbmRvIGVsIHNvZnR3YXJlIFIgY29uIHVuIGVuZm9xdWUgZW4gcHJvY2VzYW1pZW50byBlc3BhY2lhbC4gVGUgZGVqYXJlbW9zIGxpbmtzIGRvbmRlIHB1ZWRlcyBhcHJlbmRlciB5IHByb2Z1bmRpemFyIG3DoXMgY2FkYSBhc3BlY3RvIGRlIGVzdGUgcHJvY2Vzby4NCg0KIyMgwr9Qb3IgcXXDqSBSPw0KDQpTaSBlc3RhcyB0cmFiYWphbmRvIGNvbiBkYXRvcyBlc3BhY2lhbGVzIHNlZ3VybyBoYXMgdXRpbGl6YWRvIGRpZmVyZW50ZXMgc29mdHdhcmUsIGNvbW8gUUdJUywgRXhjZWwsIEFyR0lTLCBFUkRBUyB5IEdvb2dsZSBFYXJ0aCBFbmdpbmUuDQoNCkNhZGEgdW5hIGRlIGVzdGFzIGhlcnJhbWllbnRhcyBlcyBtdXkgcG9kZXJvc2EgeSBzaSBoYWNlIHRpZW1wbyBxdWUgbG9zIHZlbmlzIHVzYW5kbywgc2VndXJvIGNvbm9jZXMgbXVjaG9zIGRlIHN1cyB0cnVjb3MgeSBzZWNyZXRvcy4NCg0KRWwgdXNvIGRlIFIgbm9zIHBlcm1pdGlyw6EgcmVhbGl6YXIgYWxndW5hcyB0YXJlYXMgZGUgZm9ybWEgbcOhcyBzZW5jaWxsYSwgZXNwZWNpYWxtZW50ZSBsYXMgcXVlIHNlIHB1ZWRlbiBlc2NyaWJpciBjb21vIHVuYSByZWNldGEgcGFzbyBhIHBhc28geSBxdWUgbGEgY29tcHV0YWRvcmEgY29ycmEgdG9kbyBhdXRvbcOhdGljYW1lbnRlIGNhZGEgdmV6IHF1ZSBzZSBsbyBwZWTDrXMuDQpQYXJhIHBvZGVyIGhhY2VyIGVzbywgZXNlIHBhc28gYSBwYXNvIHRpZW5lIHF1ZSBlc3RhciBlc2NyaXRvIGVuIHVuIGxlbmd1YWplIHF1ZSBsYSBjb21wdXRhZG9yYSBwdWVkYSBlbnRlbmRlciwgZXNlIGxlbmd1YWplIGVzIFIuDQoNCkNvbiBSIHRhbWJpw6luIHBvZHJlbW9zIGNvbXBhcnRpciBlc3RhcyByZWNldGFzLCBlc3RvcyBwcm9ncmFtYXMsIGNvbiBvdHJvcyBjb2xhYm9yYWRvcmVzIGRlIGZvcm1hIG1hcyBzZW5jaWxsYSwgYWwgaWd1YWwgcXVlIHJlYWxpemFyIGxhIHRyYW5zaWNpw7NuIGRlIG51ZXN0cm9zIHJlcG9ydGVzIGEgYXBsaWNhY2lvbmVzIHdlYi4NCg0KIyMgQ8OzbW8gZGVjaXJsZSBhIFIgcXXDqSBoYWNlcg0KDQojIyMgT3JpZW50w6FuZG9zZSBlbiBSU3R1ZGlvDQoNCkVuIHByaW5jaXBpbyBzZSBwb2Ryw61hIGVzY3JpYmlyIGPDs2RpZ28gZGUgUiBjb24gZWwgQmxvYyBkZSBOb3RhcyB5IGx1ZWdvIGVqZWN1dGFybG8sIHBlcm8gbm9zb3Ryb3MgdmFtb3MgYSB1c2FyIFJTdHVkaW8sIHF1ZSBicmluZGEgdW5hIGludGVyZmF6IGdyw6FmaWNhIGNvbiB1biBtb250w7NuIGRlIGhlcnJhbWllbnRhcyBleHRyYSBwYXJhIGhhY2Vybm9zIGxhIHZpZGEgbcOhcyBmw6FjaWwuDQoNCkN1YW5kbyBhYnJhcyBSU3R1ZGlvIHRlIHZhcyBhIGVuY29udHJhciBjb24gdW5hIHZlbnRhbmEgY29uIGN1YXRybyBwYW5lbGVzIGNvbW8gZXN0YToNCg0KIVtWZW50YW5hIGRlIFJTdHVkaW9dKGltZy9yc3R1ZGlvLnBuZykNCg0KTG9zIGRvcyBwYW5lbGVzIGRlIGxhIGl6cXVpZXJkYSBzb24gbGFzIGRvcyBmb3JtYXMgcHJpbmNpcGFsZXMgZGUgaW50ZXJhY3R1YXIgY29uIFIuDQpFbCBwYW5lbCBkZSBhYmFqbyBhIGxhIGl6cXVpZXJkYSBlcyAqKmxhIGNvbnNvbGEqKi4NCkVzIGVsIGx1Z2FyIHF1ZSB0ZSBwZXJtaXRlICpjb252ZXJzYXIqIGNvbiBSLg0KUG9kw6lzIGVzY3JpYmlyIGNvbWFuZG9zIHF1ZSBzZSB2YW4gYSBlamVjdXRhciBpbm1lZGnDoXRhbWVudGUgY3VhbmRvIGFwcmlldGVzIEVudGVyIHkgY3V5byByZXN1bHRhZG8gc2UgdmEgYSBtb3N0cmFyIGVuIGxhIGNvbnNvbGEuDQoNClBvciBlamVtcGxvLCBoYWPDqSBjbGljayBlbiBsYSBjb25zb2xhLCBlc2NyaWLDrSBgMiArIDJgIHkgYXByZXTDoSBFbnRlci4NClZhcyBhIHZlciBhbGdvIGNvbW8gZXN0bzoNCg0KYGBge3J9DQoyICsgMg0KYGBgDQoNCkxlIGRpamlzdGUgYSBSIHF1ZSBzdW1lIDIgeSAyIHkgUiB0ZSBkZXZvbHZpw7MgZWwgcmVzdWx0YWRvOiA0IChubyB0ZSBwcmVvY3VwZXMgZGVsIGBbMV1gIHBvciBhaG9yYSkuDQpFc28gZXN0w6EgYnVlbm8gc2kgcXVlcsOpcyBoYWNlciB1bmEgY3VlbnRhIHLDoXBpZGEgbyBjaGVxdWVhciBhbGdvIHBlcXVlw7FvLCBwZXJvIG5vIHNpcnZlIHBhcmEgaGFjZXIgdW4gYW7DoWxpc2lzIGNvbXBsZWpvIHkgcmVwcm9kdWNpYmxlLg0KDQpFbiBlbCBwYW5lbCBkZSBhcnJpYmEgYSBsYSBpenF1aWVyZGEgdGVuZW1vcyBlc2VuY2lhbG1lbnRlIHVuIGVkaXRvciBkZSB0ZXh0by4NCkFow60gZXMgZG9uZGUgdmFzIGEgZXNjcmliaXIgc2kgcXVlcsOpcyBndWFyZGFyIGluc3RydWNjaW9uZXMgcGFyYSBlamVjdXRhcmxhcyBlbiBvdHJvIG1vbWVudG8geSBkb25kZSB2YXMgYSBlc3RhciBlbCA4NyUgZGUgdHUgdGllbXBvIHVzYW5kbyBSLg0KDQpBIGxhIGRlcmVjaGEgaGF5IHBhbmVsZXMgbcOhcyBiaWVuIGluZm9ybWF0aXZvcyB5IHF1ZSB0aWVuZW4gdmFyaWFzIHNvbGFwYXMgcXVlIHZhbW9zIGEgaXIgZGVzY3VicmllbmRvIGEgc3UgdGllbXBvLg0KUGFyYSBkZXN0YWNhciwgYXJyaWJhIGEgbGEgZGVyZWNoYSBlc3TDoSBlbCAiZW52aXJvbm1lbnQiLCBxdWUgZXMgZm9ybWEgZGUgdmVyIHF1w6kgZXMgbG8gcXVlIGVzdMOhICJwZW5zYW5kbyIgUiBlbiBlc3RlIG1vbWVudG8uDQpBaMOtIHZhcyBhIHBvZGVyIHZlciB1biBsaXN0YWRvIGRlIGxvcyBkYXRvcyBxdWUgZXN0w6FuIGFiaWVydG9zIHkgb3Ryb3Mgb2JqZXRvcyBxdWUgZXN0w6FuIGNhcmdhZG9zIGVuIGxhIG1lbW9yaWEgZGUgUi4NCkFob3JhIGVzdMOhIHZhY8OtbyBwb3JxdWUgdG9kYXbDrWEgbm8gY2FyZ2FzdGUgbmkgY3JlYXN0ZSBuaW5nw7puIGRhdG8uDQpBYmFqbyBhIGxhIGRlcmVjaGEgdGllbmVuIHVuIGV4cGxvcmFkb3IgZGUgYXJjaGl2b3MgcnVkaW1lbnRhcmlvIHkgdGFtYmnDqW4gZWwgcGFuZWwgZGUgYXl1ZGEsIHF1ZSBlcyBkb25kZSB2YXMgYSBwYXNhciBlbCBvdHJvIDEzJSBkZWwgdGllbXBvIHVzYW5kbyBSLg0KDQpFbnRvbmNlcywgcGFyYSByZXN1bWlyOg0KDQohW0xhIGNvY2luYSBkZSBSU3R1ZGlvXShpbWcvcnN0dWRpby1jb2NpbmEucG5nKQ0KDQojIyMgSGFibGFuZG8gY29uIFINCg0KWWEgdmlzdGUgY8OzbW8gdXNhciBSIGNvbW8gdW5hIGNhbGN1bGFkb3JhLg0KDQpgYGB7cn0NCjIgKyAyDQpgYGANCg0KU2kgdXNhc3RlIGbDs3JtdWxhcyBlbiBFeGNlbCwgZXN0byBlcyBtdXkgcGFyZWNpZG8gYSBwb25lciBgPTIrMmAgZW4gdW5hIGNlbGRhLg0KUiBlbnRpZW5kZSB1biBtb250w7NuIGRlIG9wZXJhY2lvbmVzIGFyaXRtw6l0aWNhcyBlc2NyaXRhcyBjb21vIHNlZ3VyYW1lbnRlIHlhIHRlIGltYWdpbsOhczoNCg0KLSAgIGArYDogc3VtYXINCi0gICBgLWA6IHJlc3Rhcg0KLSAgIGAqYDogbXVsdGlwbGljYXINCi0gICBgL2A6IGRpdmlkaXINCi0gICBgXmAgbyBgKipgOiBleHBvbmVuY2lhcg0KDQpQZXJvIGFkZW3DoXMgY29ub2NlIG11Y2hhcyBvdHJhcyBvcGVyYWNpb25lcy4NClBhcmEgZGVjaXJsZSBhIFIgcXVlIGNhbGN1bGUgZWwgc2VubyBkZSAxIGhheSBxdWUgZXNjcmliaXIgZXN0bzoNCg0KYGBge3J9DQpzaW4oMSkNCmBgYA0KDQpFc3RvIGVzIHNpbWlsYXIgYSBwb25lciBgPVNJTigxKWAgZW4gRXhjZWwuDQpMYSBzaW50YXhpcyBiw6FzaWNhIHBhcmEgYXBsaWNhciBjdWFscXVpZXIgZnVuY2nDs24gZXMgYG5vbWJyZV9mdW5jaW9uKGFyZ3VtZW50b3MpYC4NCg0KOjo6IHsuYWxlcnQgLmFsZXJ0LXN1Y2Nlc3N9DQoqKk5vdGEqKjogRW4gRXhjZWwgZWwgbm9tYnJlIGRlIGxhcyBmdW5jaW9uZXMgZGVwZW5kZW4gZGVsIGlkaW9tYSBlbiBlbCBxdWUgZXN0w6EgaW5zdGFsYWRvLg0KU2kgbG8gdXPDoXMgZW4gZXNwYcOxb2wsIGxhIGZ1bmNpw7NuIHNlbm8gZXMgYFNFTigpYC4NCkVuIFIsIGxhcyBmdW5jaW9uZXMgc2llbXByZSBzZSBlc2NyaWJlbiBpZ3VhbCAocXVlIGNvaW5jaWRlIGNvbiBlbCBpbmdsw6lzKS4NCjo6Og0KDQo6Ojogey5hbGVydCAuYWxlcnQtaW5mb30NCioqRGVzYWbDrW8qKg0KDQpEZWNpbGUgYSBSIHF1ZSBjb21wdXRlIGxhcyBzaWd1aWVudGVzIG9wZXJhY2lvbmVzOg0KDQotICAgMiBtdWx0aXBsaWNhZG8gcG9yIDINCi0gICAzIGFsIGN1YWRyYWRvDQotICAgZG9zIHRlcmNpb3MNCi0gICA1IHBvciA4IG3DoXMgMQ0KOjo6DQoNCkFsIGhhY2VyIHRvZGFzIGVzdGFzIG9wZXJhY2lvbmVzLCBsbyDDum5pY28gcXVlIGhpY2lzdGUgZnVlIGRlY2lybGUgYSBSIHF1ZSBoYWdhIGVzb3MgY8OhbGN1bG9zLg0KUiB0ZSBkZXZ1ZWx2ZSBlbCByZXN1bHRhZG8sIHBlcm8gbm8gbG8gZ3VhcmRhIGVuIG5pbmfDum4gbGFkby4NClBhcmEgZGVjaXJsZSBxdWUgZ3VhcmRlIGVsIHJlc3VsdGFkbyBkZSB1bmEgb3BlcmFjacOzbiBoYXkgcXVlIGRlY2lybGUgY29uIHF1w6kgIm5vbWJyZSIgcXVlcsOpcyBndWFyZGFybG8uDQpFbCBzaWd1aWVudGUgY8OzZGlnbyBoYWNlIGVzbzoNCg0KYGBge3J9DQp4IDwtIDIgKyAyDQpgYGANCg0KTGEgImZsZWNoaXRhIiBgPC1gIGVzIGVsIG9wZXJhZG9yIGRlIGFzaWduYWNpw7NuLCBxdWUgbGUgZGljZSBhIFIgcXVlIHRvbWUgZWwgcmVzdWx0YWRvIGRlIGxhIGRlcmVjaGEgeSBsbyBndWFyZGUgZW4gdW5hIHZhcmlhYmxlIGNvbiBlbCBub21icmUgcXVlIGVzdMOhIGEgbGEgaXpxdWllcmRhLg0KVmFzIGEgdmVyIHF1ZSBubyB0ZSBkZXZ1ZWxlIGVsIHJlc3VsdGFkby4NClBhcmEgdmVybG8sIGVqZWN1dGFtb3MNCg0KYGBge3J9DQp4DQpgYGANCg0KRXN0byBsZSBkaWNlIGEgUiBxdWUgdGUgImltcHJpbWEiIGVsIGNvbnRlbmlkbyBkZSBsYSB2YXJpYWJsZSB4Lg0KDQo6Ojogey5hbGVydCAuYWxlcnQtaW5mb30NCioqRGVzYWbDrW8qKg0KDQrCv1F1w6kgdGUgaW1hZ2luw6FzIHF1ZSB2YSBhIHBhc2FyIGN1YW5kbyBhaG9yYSBjb3JyYSBlbCBzaWd1aWVudGUgY8OzZGlnbz8NCg0KYGBge3IsIGV2YWwgPSBGQUxTRX0NCnggKyAyDQpgYGANCjo6Og0KDQpQb25lcmxlIG5vbWJyZSBhIGxhcyB2YXJpYWJsZXMgZXMgYSB2ZWNlcyBsYSBwYXJ0ZSBtw6FzIGRpZsOtY2lsIGRlIGVzY3JpYmlyIGPDs2RpZ28uDQpBIFIgbGUgdmllbmUgYmllbiBjdWFscXVpZXIgbm9tYnJlIGRlIHZhcmlhYmxlIHNpZW1wcmUgeSBjdWFuZG8gbm8gZW1waWVjZSBjb24gdW4gbsO6bWVybyBvIHVuICJcXyIuDQpQZXJvIGEgbG9zIHNlcmVzIGh1bWFub3MgcXVlIGxlYW4gZWwgY8OzZGlnbyB5IHRlbmdhbiBxdWUgaW50ZXJwcmV0YXJsb3MgbGVzIHZhIGEgcmVzdWx0YXMgbcOhcyBmw6FjaWwgZW50ZW5kZXIgcXXDqSBoYWNlIGxhIHZhcmlhYmxlIGBwcm9tZWRpb19yZW5kaW1pZW50b2AgcXVlIGxhIHZhcmlhYmxlIGB4eHkxYC4NCg0KRWwgY29uc2VqbyBlcyB0cmF0YXIgZW4gbG8gcG9zaWJsZSB1c2FyIG5vbWJyZSBkZXNjcmlwdGl2b3MgeSBjb25zaXN0ZW50ZXMuDQpQb3IgZWplbXBsbywgc2llbXByZSB1c2FyIG1pbsO6c2N1bGFzIHkgc2VwYXJhciBwYWxhYnJhcyBjb24gIlxfIi4NCg0KOjo6IHsuYWxlcnQgLmFsZXJ0LXN1Y2Nlc3N9DQoqKlRpcCoqOiBQYXJhIGhhY2Vyc2UgbGEgdmlkYSBtw6FzIGbDoWNpbCBleGlzdGVuICJndcOtYXMgZGUgZXN0aWxvIiBwYXJhIHByb2dyYW1hciBxdWUgZXhwbGljaXRhbiByZWdsYXMgZXNwZWPDrWZpY2FzIHBhcmEgZXNjcmliaXIgY8OzZGlnby4NClBvciBlamVtcGxvIFtlc3RhXShodHRwczovL3JwdWJzLmNvbS9GdkQvZ3VpYS1lc3RpbG8tcil7LmFsZXJ0LWxpbmt9IG8gW2VzdGEgb3RyYV0oaHR0cHM6Ly9naXRodWIuY29tL2VsaW9jYW1wL3Rlc2lzL2Jsb2IvbWFzdGVyL2RvY3MvZ3UlQzMlQURhX2RlX2VzdGlsby5tZCl7LmFsZXJ0LWxpbmt9Lg0KU2UgdHJhdGEgZGUgcmVnbGFzIMO6bmljYW1lbnRlIHBhcmEgbG9zIG9qb3MgaHVtYW5vcywgeSBxdWUgbm8gYWZlY3RhbiBlbiBhYnNvbHV0byBsYSBlZmljaWVuY2lhIG8gY29ycmVjdGl0dWQgZGUgbGEgcHJvZ3JhbWFjacOzbi4NCkVuIGdlbmVyYWwsIG5vIGV4aXN0ZW4gZ3XDrWFzIGJ1ZW5hcyBvIG1hbGFzLCBsYSBpZGVhIGVzIGVsZWdpciB1bmEgeSBzZXIgY29uc2lzdGVudGUuDQpEZSBlc3RhIG1hbmVyYSwgdmFzIGEgcG9kZXIgZW50ZW5kZXIgdHUgY8OzZGlnbyBjb24gbcOhcyBmYWNpbGlkYWQuDQo6OjoNCg0KIyMjIEV4dGVuZGllbmRvIFINCg0KUiBlcyB1biBsZW5ndWFqZSBjcmVhZG8gcG9yIHBlcnNvbmFzIHF1ZSBwcmFjdGljYW4gbGEgZXN0YWTDrXN0aWNhIHkgcGVuc2FkbyBwYXJhIGxhIGVzdGFkw61zdGljYSwgcG9yIGxvIHF1ZSB5YSB2aWVuZSBjb24gdW4gbW9udMOzbiBkZSBtw6l0b2RvcyBlc3RhZMOtc3RpY29zIGluY29ycG9yYWRvcywgY29tbyBgbWVhbigpYCBvIGBtZWRpYW4oKWAuDQpQZXJvIGhheSB0YW50b3MgbcOpdG9kb3MgZXN0YWTDrXN0aWNvcyBjb21vIGdlbnRlIGhhY2llbmRvIGVzdGFkw61zdGljYSBhc8OtIHF1ZSBlcyBpbXBvc2libGUgcXVlIGVzdMOpbiB0b2Rvcy4NCkxhIHNvbHVjacOzbiBlcyBxdWUgcG9kw6lzICJhZ3JlZ2FybGUiIGEgUiBmdW5jaW9uZXMgcXVlIG5vIHZpZW5lbiBpbnN0YWxhZGFzIHBvciBkZWZlY3RvIHBlcm8gcXVlIGVzY3JpYmllcm9uIG90cmFzIHBlcnNvbmFzIGVuIGZvcm1hIGRlICJwYXF1ZXRlcyIuDQrCoUVzdGUgZXMgZWwgcG9kZXIgZGUgKipsYSBjb211bmlkYWQgZGUgUioqIQ0KDQpQYXJhIGluc3RhbGFyIHBhcXVldGVzIGRlIFIsIGxhIGZvcm1hIG1hcyBmw6FjaWwgZXMgY29uIGxhIGZ1bmNpw7NuIGBpbnN0YWxsLnBhY2thZ2VzKClgLg0KRXN0YSBmdW5jacOzbiBzZSBfY29uZWN0YSBhIGludGVybmV0XyB5IGRlc2NhcmdhIHBhcXVldGVzIHB1YmxpY2Fkb3MgZW4gdW4gcmVwb3NpdG9yaW8gb2ZpY2lhbCANCkVudG9uY2VzLCBwb3IgZWplbXBsbywNCg0KYGBge3IsIGV2YWw9RkFMU0V9DQppbnN0YWxsLnBhY2thZ2VzKCJybmF0dXJhbGVhcnRoIikNCmBgYA0KDQpkZXNjYXJnYSBlIGluc3RhbGEgdW4gcGFxdWV0ZSBxdWUgY29udGllbmUgZnVuY2lvbmVzIHBhcmEgbGVlciBkYXRvcy4NCg0KDQo6Ojogey5hbGVydCAuYWxlcnQtc3VjY2Vzc30NCioqTm90YSoqOiBQYXJhIGluc3RhbGFyIHBhcXVldGVzIGRlIGVzdGEgZm9ybWEgZXMgbmVjZXNhcmlvIHRlbmVyIGNvbmV4acOzbiBkZSBpbnRlcm5ldC4gDQo6OjoNCg0KTHVlZ28sIHVzYW5kbyBlbCBjb21hbmRvDQoNCmBgYHtyfQ0KbGlicmFyeShybmF0dXJhbGVhcnRoKQ0KYGBgDQoNCmxlIGRlY8OtcyBhIFIgcXVlIGNhcmd1ZSBsYXMgZnVuY2lvbmVzIHF1ZSB2aWVuZW4gZW4gZWwgcGFxdWV0ZSByZWFkciBwYXJhIHVzYXJsYXMuDQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1pbmZvfQ0KKipEZXNhZsOtbyoqOiBJbnN0YWzDoSBlbCBwYXF1ZXRlIHJuYXR1cmFsZWFydGggY29uIGVsIGNvbWFuZG8gYGluc3RhbGwucGFja2FnZXMoInJuYXR1cmFsZWFydGgiKWAgZW4gbGEgY29uc29sYS4NCjo6Og0KDQo6Ojogey5hbGVydCAuYWxlcnQtc3VjY2Vzc30NCioqTm90YSoqOiBTaSBjZXJyw6FzIHkgdm9sdmXFmyBhIGFicmlyIFIsIHZhcyBhIHRlbmVyIHF1ZSB1c2FyIGBsaWJyYXJ5KHJuYXR1cmFsZWFydGgpYCBudWV2YW1lbnRlIHBhcmEgYWNjZWRlciBhIGxhIGZ1bmNpb25hbGlkYWQgZGVsIHBhcXVldGUgcmVhZHIuDQpTw7NsbyBoYWNlIGZhbHRhIGNvcnJlciBgaW5zdGFsbC5wYWNrYWdlcygicm5hdHVyYWxlYXJ0aCIpYCB1bmEgdmV6IHBvciBtw6FxdWluYS4NCjo6Og0KDQojIyBUcmFiYWphciBjb24gcHJveWVjdG9zIGVuIFJTdHVkaW8NCg0KVHJhYmFqYXIgY29uIHByb3llY3RvcyBkZSBSU3R1ZGlvIG5vIHNvbG8gaGFjZSB0dXMgYW7DoWxpc2lzIG3DoXMgb3JkZW5hZG9zIHkgcmVwcm9kdWNpYmxlcywgdGFtYmnDqW4gaGFjZW4gdHUgdmlkYSBtw6FzIHNpbXBsZS4NCg0KQWwgY29taWVuem8gcG9zaWJsZW1lbnRlIHRlbmdhcyB1biBzY3JpcHQgeSB1bm8gbyBkb3MgYXJjaGl2b3MgY29uIGRhdG9zLCBwZXJvIGVzIHBvc2libGUgcXVlIHLDoXBpZGFtZW50ZSB0ZSBlbmN1ZW50cmVzIGNvbiB1bmEgZG9jZW5hIGRlIGFyY2hpdm9zIGNvbiBub21icmVzIHBhcmVjaWRvcyBwZXJvIHF1ZSBwZXJ0ZW5lY2VuIGEgYW7DoWxpc2lzIHRvdGFsbWVudGUgZGlzdGludG9zLg0KQW50ZXMgZGUgcXVlIGxhIGNvc2EgY29taWVuY2UgYSBjb21wbGljYXJzZSB0ZSBwcm9wb25lbW9zIHRyYWJhamFyIGNvbiBwcm95ZWN0b3MuDQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1pbmZvfQ0KKipVc2FuZG8gUlN0dWRpbyBDbG91ZCoqDQoNClNpIGVzdMOhcyB0cmFiYWphbmRvIGVuIFJTdHVkaW8gQ2xvdWQgZW50b25jZXMgeWEgZXN0w6FzIHRyYWJhamFuZG8gY29uIHVuIHByb3llY3RvLiAgRXMgbGEgY29uZmlndXJhY2nDs24gcG9yIGRlZmVjdG8gZGUgbGEgcGxhdGFmb3JtYS4NCjo6Og0KDQojIyDCv1F1w6kgdmVudGFqYXMgdGllbmU/DQoNCi0gICBUZSBwZXJtaXRlICJjdWlkYXIiIGxvcyBkYXRvcyBxdWUgdXNhcyBhbCBvcmRlbmFybm9zIGVuIGNhcnBldGFzIHF1ZSBkaWZlcmVuY2llbiBlbnRyZSBsYSB2ZXJzacOzbiBvcmlnaW5hbCBvIGNydWRhIHkgbG9zIGRhdG9zIGxpbXBpb3MgbyBsb3MgcmVzdWx0YWRvcyBmaW5hbGVzLg0KLSAgIFRlIHBlcm1pdGUgY29tcGFydGlyIHR1IHRyYWJham8gZsOhY2lsbWVudGUgY29uIG90cmFzIHBlcnNvbmFzLiBTb2xvIHRlbmRyw61hcyBxdWUgY29tcGFydGlyIGxhIGNhcnBldGEgZGVsIHByb3llY3RvIHNhYmllbmRvIHF1ZSBpbmNsdXllIHRvZG8gbG8gbmVjZXNhcmlvIHBhcmEgcXVlIGN1YWxxdWllcmEgcmVwcm9kdXpjYSB0dSBhbsOhbGlzaXMuDQotICAgVGUgcGVybWl0ZSBwdWJsaWNhciBkZSBtYW5lcmEgb3JkZW5hZGEgdHUgY8OzZGlnbyBzaSB2YXMgYSBwcmVzZW50YXIgbyBwdWJsaWNhciB0dSB0cmFiYWpvLg0KLSAgIFRlIHBlcm1pdGUgY29udGludWFyIGNvbiBsbyBxdWUgZXN0YWJhcyBoYWNpZW5kbyBoYWNlIHVuYSBzZW1hbmEgbyBoYWNlIHVuIG1lcyBjb21vIHNpIGVsIHRpZW1wbyBubyBodWJpZXJhIHBhc2FkbyAodHUgeW8gZnV0dXJvIHRlIGxvIHZhIGEgYWdyYWRlY2VyKS4NCg0KOjo6IHsuYWxlcnQgLmFsZXJ0LWluZm99DQoqKkRlc2Fmw61vOiBDcmVhIHVuIG51ZXZvIHByb3llY3RvIGVuIFJTdHVkaW8qKg0KDQoxLiAgSGFjw6kgY2xpY2sgZW4gZWwgbWVuw7ogIkFyY2hpdm8iICgiRmlsZSIpIHkgbHVlZ28gZW4gIk51ZXZvIFByb3llY3RvIiAoIk5ldyBQcm9qZWN0IikuDQoyLiAgSGFjw6kgY2xpY2sgZW4gIk51ZXZhIENhcnBldGEiICgiTmV3IERpcmVjdG9yeSIpLg0KMy4gIEhhY8OpIGNsaWNrIGVuICJOdWV2byBQcm95ZWN0byIgKCJOZXcgUHJvamVjdCIpLg0KNC4gIEVzY3JpYsOtIGVsIG5vbWJyZSBkZSBsYSBjYXJwZXRhIHF1ZSBhbG9qYXLDoSBhIHR1IHByb3llY3RvLCBwb3IgZWplbXBsbyAiY3Vyc29fYW5hbGlzaXMiDQo1LiAgU2kgYXBhcmVjZSAoeSBzYWLDqXMgdXNhcmxvKSwgc2VsZWNjaW9uw6EgIkNyZWFyIHVuIHJlcG9zaXRvcmlvIGRlIGdpdCIgKCJDcmVhdGUgYSBnaXQgcmVwb3NpdG9yeSIpLg0KNi4gIEhhY8OpIGNsaWNrIGVuICJDcmVhciBQcm95ZWN0byIgKCJDcmVhdGUgUHJvamVjdCIpLg0KOjo6DQoNClNpIHRvZG8gc2FsacOzIGJpZW4sIGFob3JhIGRlYmVyw61hcyB0ZW5lciB1bmEgbnVldmEgY2FycGV0YSBxdWUgc2UgbGxhbWEgKmN1cnNvX2FuYWxpc2lzKi4NClBlcm8gc2kgYmllbiBlcyB1bmEgY2FycGV0YSBjb23Dum4geSBjb3JyaWVudGUsIGxlIGxsYW1hbW9zIHByb3llY3RvIHBvcnF1ZSBhZGVtw6FzIGNvbnRpZW5lIHVuIGFyY2hpdm8gY29uIGVsIG1pc21vIG5vbWJyZSAqY3Vyc29fYW5hbGlzaXMuUnByb2oqIChvIHNvbG8gKmN1cnNvX2FuYWxpc2lzKiBzaSBlbiB0dSBjb21wdXRhZG9yYSBubyB2ZXMgbGEgZXh0ZW5zacOzbiBkZSBsb3MgYXJjaGl2b3MpLg0KDQojIyBBYnJpciB1biBwcm95ZWN0bw0KDQpMYSBtYW5lcmEgbcOhcyBzaW1wbGUgZGUgYWJyaXIgdW4gcHJveWVjdG8gZXMgYWJyaWVuZG8gbGEgY2FycGV0YSBxdWUgbG8gY29udGllbmUgeSBoYWNpZW5kbyBkb2JsZSBjbGljayBzb2JyZSBlbCBhcmNoaXZvICpjdXJzb19hbmFsaXNpcy5ScHJvaiouDQpBbCBoYWNlciBlc3RvIHNlIGFicmlyw6EgUlN0dWRpbyB5IGxhIHNlc2nDs24gZGUgUiBlbiBsYSBtaXNtYSBjYXJwZXRhIHksIHBvciBkZWZlY3RvLCBjdWFscXVpZXIgYXJjaGl2byBxdWUgcXVpZXJhcyBhYnJpciBvIGd1YXJkYXIgbG8gaGFyw6EgZW4gZXNhIG1pc21hIHViaWNhY2nDs24uDQpFc3RvIGF5dWRhIGEgbWFudGVuZXIgdHUgdHJhYmFqbyBvcmRlbmFkbyB5IHF1ZSBsdWVnbyBzZWEgc2ltcGxlIHJldG9tYXIgbyBjb21wYXJ0aXIgbG8gcXVlIGhpY2lzdGUuDQoNClJTdHVkaW8gcGVybWl0ZSB0ZW5lciB2YXJpb3MgcHJveWVjdG9zIGFiaWVydG9zLCB5IGVzdG8gZXMgcG9zaWJsZSBwb3JxdWUganVzdGFtZW50ZSBjYWRhIHByb3llY3RvIHRpZW5lIHN1IHByb3BpYSBjYXJwZXRhLg0KU2kgZW4gYWxnw7puIG1vbWVudG8gdHJhYmFqYXMgY29uIHByb3llY3RvcyBlbiBwYXJhbGVsbyB2YXMgYSBwb2RlciBoYWNlcmxvIHNpbiBxdWUgZWwgY8OzZGlnbyBvIGxvcyByZXN1bHRhZG9zIGRlIHVuIGFuw6FsaXNpcyBpbnRlcmZpZXJhbiBjb24gb3Ryby4NCg0KOjo6IHsuYWxlcnQgLmFsZXJ0LWluZm99DQoqKkRlc2Fmw61vOiBBYnLDrSB0dSBudWV2byBwcm95ZWN0byBkZXNkZSBlbCBleHBsb3JhZG9yIGRlIGFyY2hpdm9zKioNCg0KMS4gIENlcnLDoSBSU3R1ZGlvDQoyLiAgRGVzZGUgZWwgZXhwbG9yYWRvciBkZSBhcmNoaXZvcywgYnVzY8OhIGxhIGNhcnBldGEgZG9uZGUgY3JlYXN0ZSB0dSBwcm95ZWN0by4NCjMuICBIYWPDqSBkb2JsZSBjbGljayBlbiBlbCBhcmNoaXZvIHF1ZSB0aWVuZSBlbCBub21icmUgZGUgdHUgcHJveWVjdG8gKHkgcXVlIHRlcm1pbmEgY29uICouUnByb2oqKSBxdWUgZW5jb250cmFyw6FzIGVuIGVzYSBjYXJwZXRhLg0KOjo6DQoNCiMjIMK/Q8OzbW8gc2Ugb3JnYW5pemE/DQoNCk5vIGV4aXN0ZSB1bmEgIm1lam9yIiBmb3JtYSBkZSBvcmdhbml6YXIgdW4gcHJveWVjdG8gcGVybyBhY8OhIHZhbiBhbGd1bm9zIHByaW5jaXBpb3MgZ2VuZXJhbGVzIHF1ZSBub3MgaGFjZW4gbGEgdmlkYSBtw6FzIHNpbXBsZTo6DQoNCi0gICAqKlRyYXRhciBsb3MgZGF0b3MgY29tbyBzw7NsbyBkZSBsZWN0dXJhKiogRXMgcG9zaWJsZSBxdWUgbGEgdG9tYSBkZSBsb3MgZGF0b3MgcXVlIHF1ZXLDqXMgYW5hbGl6YXIgdGUgaGF5YSBjb3N0YWRvIG11Y2hvIHRyYWJham8sIG8gdGUgaGF5YSBjb3N0YWRvIGNvbnNlZ3Vpcmxvcy4gVHJhYmFqYXIgY29uIGRhdG9zIGRlIGZvcm1hIGludGVyYWN0aXZhIChwb3IgZWplbXBsbywgZW4gRXhjZWwpIHRpZW5lIGxhIHZlbnRhamEgZGUgcGVybWl0aXJ0ZSBoYWNlciBhbGd1bm9zIGFuw6FsaXNpcyByw6FwaWRhbWVudGUgcGVybyBhbCBtaXNtbyB0aWVtcG8gdGllbmUgbGEgZGVzdmVudGFqYSBkZSBxdWUgZXNvcyBkYXRvcyBwdWVkZW4gc2VyIG1vZGlmaWNhZG9zIGbDoWNpbG1lbnRlLiBFc3RvIHNpZ25pZmljYSBxdWUgYSB2ZWNlcyBubyBjb25vemNhcyBkZSBsYSBwcm9jZWRlbmNpYSBkZSBsb3MgZGF0b3MsIG8gbm8gcmVjdWVyZGVzIGPDs21vIGxvcyBtb2RpZmljYXN0ZSBkZXNkZSBxdWUgbG9zIG9idHV2aXN0ZS4gUG9yIGxvIHRhbnRvLCBlcyB1bmEgYnVlbmEgaWRlYSB0cmF0YXIgbG9zIGRhdG9zIGNvbW8gInPDs2xvIGRlIGxlY3R1cmEiIHkgbnVuY2EgbW9kaWZpY2FyIGxvcyBhcmNoaXZvcyBvcmlnaW5hbGVzLg0KLSAgICoqTGltcGllemEgZGUgZGF0b3MqKiBFbiBtdWNob3MgY2Fzb3MgdHVzIGRhdG9zIGVzdGFyw6FuICJzdWNpb3MiLCBuZWNlc2l0YXLDoW4gdW4gcHJlcHJvY2VzYW1pZW50byBpbXBvcnRhbnRlIHBhcmEgb3JnYW5pemFybG9zIGVuIHVuIGZvcm1hdG8gcXVlIFIgKG8gY3VhbHF1aWVyIG90cm8gbGVuZ3VhamUgZGUgcHJvZ3JhbWFjacOzbikgcHVlZGEgYW5hbGl6YWRvcyBmw6FjaWxtZW50ZS4gRXN0YSB0YXJlYSBzZSBkZW5vbWluYSBhIHZlY2VzICJhbWFzYWRvIiBvICJtYXN0aWNhZG8gZGUgZGF0b3MiLiBFcyB1bmEgYnVlbmEgY29zdHVtYnJlIGd1YXJkYXIgZWwgY8OzZGlnbyBxdWUgdGUgcGVybWl0acOzIGxpbXBpYXIgZXN0b3MgZGF0b3MgcG9yIHNpIGxvcyB2b2x2aWVyYXMgYSBuZWNlc2l0YXIuIFRhbWJpw6luIGVzIHJlY29tZW5kYWJsZSBndWFyZGFyIGVzYSB2ZXJzacOzbiBkZSBsb3MgZGF0b3MgbGltcGlvcywgZGUgInPDs2xvIGxlY3R1cmEiLCBwYXJhIHF1ZSBwdWVkYXMgdXNhcmxvcyBlbiB0dSBhbsOhbGlzaXMgc2luIG5lY2VzaWRhZCBkZSByZXBldGlyIGNhZGEgdmV6IHRvZG8gZWwgcHJvY2VzbyBkZSBsaW1waWV6YSBkZSBsb3MgZGF0b3MuDQotICAgKipUcmF0YXIgbGFzIHNhbGlkYXMgbyByZXN1bHRhZG9zIGdlbmVyYWRvcyBjb21vIGRlc2NhcnRhYmxlcyoqIEN1YWxxdWllciByZXN1bHRhZG8gKGdyw6FmaWNvcywgdGFibGFzLCB2YWxvcmVzKSBkZWJlIHBvZGVyIHJlcGV0aXJzZSBvIHJlaGFjZXJzZSBhIHBhcnRpciBkZWwgY8OzZGlnbyBndWFyZGFkby4gU2kgYmllbiBsYXMgcHJ1ZWJhcyByw6FwaWRhcyBwYXJhICp2ZXIgc2kgZWwgY8OzZGlnbyBmdW5jaW9uYSogc2UgcHVlZGVuIGhhY2VyIGVuIGxhIGNvbnNvbGEsIGVzIGltcG9ydGFudGUgZ3VhcmRhciBlbCBjw7NkaWdvIHF1ZSBnZW5lcmEgbG9zIHJlc3VsdGFkb3MgeSBhc2VndXJhcm5vcyBkZSBxdWUgc2VhbiByZXByb2R1Y2libGVzLiBBw7puIG1lam9yLCBzaSBvcmdhbml6YXMgZXNvcyByZXN1bHRhZG9zIGVuIGRpc3RpbnRhcyBzdWItY2FycGV0YXMsIHRlbmRyw6FzIHRvZG8gYcO6biBtw6FzIG9yZGVuYWRvLg0KDQoNCiMjIyBCb3Jyw7NuIHkgY3VlbnRhIG51ZXZhLi4uIHRvZG9zIGxvcyBkw61hcyENCg0Kwr9Dw7NtbyBub3MgYXNlZ3VyYW1vcyBkZSBxdWUgZWwgYW7DoWxpc2lzIHNlYSByZWFsbWVudGUgcmVwcm9kdWNpYmxlPw0KRXN0YSBlcyB1bmEgcHJlZ3VudGEgYmFzdGFudGUgYW1wbGlhIHkgaGF5IG11Y2hhcyBoZXJyYW1pZW50YXMgcGFyYSByZXNvbHZlciBlc3RlIHByb2JsZW1hLg0KUG9yIGFob3JhIG5vcyB2YW1vcyBhIGNvbmNlbnRyYXIgZW4gcXVlIGFsIG1lbm9zIGVuIHR1IGNvbXB1dGFkb3JhIHB1ZWRhcyByZXBldGlyIGxvcyBjw6FsY3Vsb3MgbyBlbCBhbsOhbGlzaXMgZGVzZGUgY2Vyby4NClkgYWRlbcOhcyBkZSBvcmdhbml6YXIgcHJveWVjdG9zIHkgbm8gbW9kaWZpY2FyIGxvcyBkYXRvcyBvcmlnaW5hbGVzLCDCv2PDs21vIHBvZMOpcyBhc2VndXJhcnRlIGRlIHF1ZSBndWFyZGFzdGUgdG9kbyBlbCBjw7NkaWdvIHF1ZSBlc3R1dmlzdGUgZXNjcmliaWVuZG8geSB1c2FzdGU/DQpMYSBtYW5lcmEgbcOhcyBkaXJlY3RhIGVzIHJlaW5pY2lhciBsYSBzZXNpw7NuIGRlIFIgeSBjb3JyZXIgZWwgY8OzZGlnbyBkZSBudWV2bywgc2kgZGEgZXJyb3IgbyBubyBkZXZ1ZWx2ZSBsbyBxdWUgZXNwZXJhYmFzIHNpZ25pZmljYSBxdWUgdGUgZmFsdMOzIGd1YXJkYXIgYWxnw7puIHBhc28uDQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1zdWNjZXNzfQ0KVGlwOiBQb2TDqXMgcmVpbmljaWFyIGxhIHNlc2nDs24gZGUgUiBjb24gZWwgYXRham8gYEN0cmwrU2hpZitGMTBgDQo6OjoNCg0KRXN0byBwdWVkZSBwYXNhciBzaSBwb3IgZWplbXBsbyBsZcOpcyB1bmEgYmFzZSBkZSBkYXRvcyBlbiBtZW1vcmlhIHBlcm8gbm8gZ3VhcmTDoXMgZWwgY8OzZGlnbyBxdWUgbG8gaGFjZS4NCk1pZW50cmFzIGVzdGVtb3MgdHJhYmFqYW5kbywgUiB0ZW5kcsOhIGVzYSBiYXNlIGRlIGRhdG9zIGVuIG1lbW9yaWEgeSBwb2RyZW1vcyBoYWNlciBjw6FsY3Vsb3MgeSBncsOhZmljb3MuDQpQb3IgZGVmZWN0byBhZGVtw6FzIFJTdHVkaW8gdmEgYSByZWNvcmRhciBsYXMgdmFyaWFibGVzIHF1ZSBlc3TDqXMgdXNhbmRvIG1hw7FhbmEgbyBwYXNhZG8gZW4gdW4gYXJjaGl2byBvY3VsdG8gKC5SRGF0YSkgYSBtZW5vcyBxdWUgbGUgaW5kaXF1ZXMgbG8gY29udHJhcmlvLg0KWSBzaSBiaWVuIHN1ZW5hIHByw6FjdGljbyB2b2x2ZXIgYSBSIGFsIG90cm8gZMOtYSB5IHRlbmVyIGVsIGFuw6FsaXNpcyB0YWwgY3VhbCBsbyBkZWphbW9zLCBlc3RvIHB1ZWRlIHNpZ25pZmljYXIgcXVlIG51bmNhIG5vcyBkZW1vcyBjdWVudGEgcXVlIG5vcyBmYWx0w7MgZ3VhcmRhciB1bmEgbMOtbmVhIGRlIGPDs2RpZ28gY2xhdmUgZW4gbnVlc3RybyBhbsOhbGlzaXMuDQoNCjo6OiB7LmFsZXJ0IC5hbGVydC1pbmZvfQ0KKipEZXNhZsOtbzogQ29uZmlndXLDoSBSU3R1ZGlvKioNCg0KMS4gIEhhY8OpIGNsaWNrIGVuIGVsIG1lbsO6ICJIZXJyYW1pZW50YXMgKCJUb29scyIpIHkgbHVlZ28gIk9wY2lvbmVzIGdsb2JhbGVzIiAoIkdsb2JhbCBPcHRpb25zIikuDQoyLiAgRGVzdGlsZMOhIGxhIG9wY2nDs24gIlJlY3VwZXJhciAuUkRhdGEgYWwgaW5pY2lvIGRlIGxhIHNlc2nDs24iICgiUmVzdG9yZSAuUkRhdGEgaW50byB3b3Jrc3BhY2UgYXQgc3RhcnR1cCIpLg0KMy4gIEhhY8OpIGNsaWNrIGVuICJBcGxpY2FyIiAoIkFwcGx5IikuDQo6OjoNCg0K