Sandra Katteryne Rodríguez Hurtado

Mayo 11 del 2020

El objetivo de este escrito es familiarse con el lenguaje de R y RStudio, dando a conocer algunas de las características y funciones que ambos brindan a quienes lo implementan en sus áreas de trabajo.

¿Qué es R?

Se dice que R es un lenguaje de programación estadística desarrollado por Ross Ihaka y Robert Gentleman, muy usado en diferentes áreas ya que es la implementación de código abierto del lenguaje de programación “S”. R no tiene una interfaz gráfica de usuario, no hay menús desplegables, algo que lo hace fácil de usar ya que no depende de un kit de herramientas para su análisis. Algunas ventajas de trabajar con R son que es gratuito y de código abierto; es un lenguaje de programación y no de una interfaz gráfica, lo que permite a quien lo esté usando guardar pequeños archivos de texto fácilmente; y tiene una comunidad en línea activa y útil.

R no tiene una interfaz gráfica, sin embargo hay personas que trabajan con R a través de plataformas gráficas que brindan funciones adicionales. Se considera a RStudio como interfaz gráfica para R, lo que quiere decir que permite a quien lo esté usando acceder a sus scripts y datos, obteniendo una vista previa de lo que está trabajando (gráficos y salidas).

Una vez descargado RStudio, se podrá apreciar una página dividida en cuatro secciones principales así: Consola, se encuentra situada en la parte inferior izquierda, donde se podrá escribir código directamente; Secuencia de Comandos se encuentra en la parte superior izquierda, donde también se puede escribir código; Ventana del entorno, la cual ofrece una visión general del espacio actual, donde se aprecian los datos que se han registrado, objetos creados, funciones introducidas, entre otros; finalmente se encuentra el último panel que tiene varias pestañas, permitiendo navegar por carpetas, y mirar los paquetes instalados recientemente.

El hecho de escribir un código en script, permite crear un registro, donde se guarda el progreso y se puede volver a acceder a este hasta donde se trabajó, permitiendo hacer cambios. Es posible también agregar comentarios al texto al insertar un un hashtag # frente a la línea de texto, permitiendo generar un texto más organizado. El hecho de introducir un hashtag #, crea un título en el texto; si se desea tener un subtítulo, se deberá introducir dos hashtag ##; si lo que se busca es tener un texto de menor tamaño pero diferente al texto normal se introducen tres hashtag ### frente al texto.

Comenzar a escribir en tu guión

Para elaborar un guión lo ideal es suministrar los datos de quién lo está redactando, tales como título, nombre, fecha y objetivo principal.

# Introducción a la Sociología Rural
# Marzo 2 del 2020
# Álvaro Rivas y Ana María Jiménez

Existe una gran variedad de comandos que permite a la persona que esté trabajando ejecutar funciones adicionales como la edición de datos o la creación de mapas. Para instalar un paquete, se deberá escribir solo una vez el siguiente comando: install.packages(“package-name”), ya que posterior a esto se puede escribir directamente en el cuadro de la consola en vez de volverlo a descargar una y otra vez.

install.packages("package-name")

Una vez se haya instalado el paquete, se carga el paquete usando el comando:

library(package-name)

Se debe también definir el directorio de trabajo. Es muy útil ya que este es una carpeta que permitirá que R busque y guarde información, además optimizar tiempo ya que permite organizar los archivos que se han trabajado por temas.Si se desea saber dónde está el directorio de trabajo, se debe ejecutar el código:

getwd() 

Si se desea cambiar el lugar del directorio se debe ejecutar el código:

setwd()

Vale aclarar que una ruta arrojada pór el computador copiada y pegada tendrá barras invertidas que separan las carpetas ( “C:”), pero la manera adecuada de introducir esto en R será con barras diagonales ( “C:/folder/data”).

Importar y verificar los datos

A manera de ejemplo para la explicación de este punto, se utilizarán unos registros de NBN Gateway, los cuyales se guardarán como edidiv.csv. Primero se debe descargar el archivo, siguiendo el enlace y dando click en “Descargar Zip”, guardarlo y descomprimir la carpeta en algún lugar de la computadora. Lo anterior se puede llevar a cabo por medio de Github.Para importar los datos guardados en la computadora a RStudio, se debe dar click en el botón “Importar conjunto de datos” y navegar hasta donde se encuentra guardado el archivo, o ejercutar el comando read.csv(). Esta es una función útil para saber de dónde proviene el conjunto de datos.

edidiv <- read.csv("C:/Users/user/Desktop/Intro_to_R/edidiv.csv")

R funciona de una mejor manera con archivos .csv (valores separados por comas), lo cual se debe tener presente a la hora de guardar archivos de excel. Si un archivo, al ser guardado por la computadora con separadores de punto y coma ;, se deberá ejecutar el comando read.csv2 en lugasr de read.csv, o también se puede utilizar el argumento de “sep” en la función: r.csv(“your-file-path”, sep = “;”). Cada obejeto es denominado como edidivobjeto. Para verificar si los datos fueron importados sin errores o que se está trabajando con los datos correctos, RStudio ofrece una función que permite obtener una vista previa dando click en el el objeto en el panel de control Entorno, donde se mostrará una página similar a una hoja de cálculo que permite visualizar los datos o la secuencia de comandos de una mejor manera.

head(edidiv) Muestra las primeras filas
tail(edidiv) Muestra las últimas filas
str(edidiv) Indica si las variables son continuas, enteras, categóricas o de caracteres. 

El comando str(object.name) es un comando que muestra la estructura de los datos con los que se está trabajando y hay algunas ocasiones en las que R puede catalogar a un conjunto de datos de un tipo que no es, es por esta razón que es de vital importancia comprobar siempre la estructura de los datos. Si se desea acceder soloa a una columna de un marco de datos se deberá agregar el nombre de la variable al nombre del objeto con un signo de dólar $. Esto permite ver, modificar y/o reasignar esta variable.

head(edidiv$taxonGroup)     Muestra solo las primeras filas de esta columna.    
class(edidiv$taxonGroup)    Indica con qué tipo de variable se está trabajando

edidiv$taxonGroup <- as.factor(edidiv$taxonGroup)      

En la última línea de código en el recuadro anterior, la función as.factor() permite convertir cualquier valor que coloque dentro en un factor.

dim(edidiv)                 Muestra el número de filas y columnas.
summary(edidiv)             Da un resumen de los datos.
summary(edidiv$taxonGroup)  Da un resumen de esa variable particular (columna) en su conjunto de datos. 

Calcular la riqueza de especies

Continuando con el ejemplo del artículo de Getway, el edidivobjeto tiene registros de ocurrencia de varias especies en cierto país y en cierto intervalo de tiempo. Así, para explorar y conocer la biodiversidad de especies en este país, se creará un gráfico en el que se representará cuántas especies se registraron en cada grupo taxonómico. Excel permite calcular la riqueza de especies, sin embargo, cuando es un grupo extenso de datos, no se tiene registro de qué hizo, cómo se clasificaron los datos y qué copió o eliminó, lo que podría generar errores. En contraste con esto, R tiene su script, lo que permite devolverse, ver lo que hizo anteriormente verificar lo que llevó a cabo en su análisis, reduciendo el porcentaje de presentar errores. Para poder saber el total de especies de mamíferos, aves, etc, se debe dividir edidiv en varios objetos, cada uno con filas para un solo grupo taxonómico. Esto se lleva a cabo con la función filter() del dplyr paquete.

Beetle <- filter(edidiv, taxonGroup == "escarabajos") : El primer argumento de la función es el amrco de datos, el segundo es la condición que se desea filtrar. Dado que solo se quieren escarabajos, de introduce: la variable taxonGroup debe ser exactamente (==) Escarabajo: elimine todo lo demás el conjnto de datos. Se debe tener presente la ortografía ya que R tiene la capacidad de distinguir mayúsculas y minúsculas. 

Bird <- filter(edidiv, taxonGroup == "Bird")  

Si se necesita recordar nombres y ortografía, se puede escribir (edidiv$taxonGroup)

Para identificar diferentes especies se utiliza la función unique(), y length() que las puede contar.

a <- length(unique(Beetle$taxonName))
b <- length(unique(Bird$taxonName))
Se puede elegir los nombres que se desee para sus objetos, en este caso reciben el nombre de a y b, donde a estaría representando, en el ejemplo, número de especies distintas de escarabajos en el registro. 

Crear un vector y trazarlo

Siguiendo con el ejemplo, ya que se tiene la riqueza de especies, se pueden combinar esos valores en un vector, este es un objeto ed R que almacena valores. Se diferencia un marco de datos de un vector en que el primero tiene dos dimensiones (filas y columnas), mientras que el segundo solo tiene una. Esto se lleva a cabo mediante la función c() que significa concatenar o encadenar. También es posible añadir etiquetas con la función names().

biodiv <- c(a,b,c,d,e,f,g,h,i,j,k)     Se han encadenado los valores, prestar atención a la organización de estos.
names(biodiv) <- c("Beetle",
                   "Bird",
                   "Butterfly",
                   "Dragonfly",
                   "Flowering.Plants",
                   "Fungus",
                   "Hymenopteran",
                   "Lichen",
                   "Liverwort",
                   "Mammal",
                   "Mollusc")

Se deben aclarar algunas cosas: * Los espaciosdelante y atrás <-y espués de la coma, se agregan para facilitar la lectura del código. * Todas las etiquetas se han dispuesto en una nueva línea, de no ser así, sería difícil leer todo. * Sae debe verificar de hacer coincidir los valores y las etiquetas de los vectores para evitar errores y en caso de tenerlos, devolverse para verificar si la información suministrada y arrojada es la correcta. * Si se resalta un paréntesis, R mostrará el correspondiente en su código, evitando errores. Se puede ver la riqueza de especies por medio de la función barplot(), donde los gráficos aparecerán en la ventana inferior derecha.

barplot(biodiv)

Se puede usar la función help() para ver qué argumentos se necesita agregar.

help(barplot)     Para obtener ayuda con la función barplot
help(par)         Para obtener ayuda con el trazado en general

Para salvar el trabajo realizado, se puede dar click en Exportar en la ventana de gráficos. También es posible guardar el archivo envolviendo el código en las funciones png() y dev.eff().

png("barplot.png", width=1600, height=600)  buscar la ayuda para esta función permite personalizar el tamaño y resolución de la imagen. 
barplot(biodiv, xlab="Taxa", ylab="Number of species", ylim=c(0,600), cex.names= 1.5, cex.axis=1.5, cex.lab=1.5)
dev.off()
 El código cex aumenta el tamaño de fuente cuando es mayor que uno y lo disminuye cuando es menor que uno.

Crear un marco de datos y trazarlo

Los marcos de datos son tablas de valores que tienen una estructura bidimensional compuesta de filas y columnas, donde cada columna puede tener un tipo de datos diferente. La matriz es otro posible formato de datos, la cual también puede tener varias filas de datos pero las variables deben ser todas del mismo tipo. Se utilizará la función data.frame(), pero primero se deberá crear un objeto que contenga todos los nombres de los taxones (columna) y otros con todos los valores de la riqueza de especies de cada taxón (otra columna).

Crear un objeto llamado "taxón" que contenga todos los datos del taxón
taxa <- c("Beetle",
          "Bird",
          "Butterfly",
          "Dragonfly",
          "Flowering.Plants",
          "Fungus",
          "Hymenopteran",
          "Lichen",
          "Liverwort",
          "Mammal",
          "Mollusc")
Convertir ese objeto en un factor, una variable categórica.
taxa_f <- factor(taxa)

Combinando todos los valores p0ara el npumero de especies de un objeto llamado riqueza
richness <- c(a,b,c,d,e,f,g,h,i,j,k)

Crear el marco de datos a partir de los dos vectrores
biodata <- data.frame(taxa_f, richness)

Guardar la fila
write.csv(biodata, file="biodata.csv")  # it will be saved in your working directory

R y RStudio tienen la capacidad de funcionar con unos códigos, entre ello se encuentran: * Ctrl + S : Para guardar el archivo. * <- : Esta flecha en el código anterior indica que se le están asignando objetos a este.

LS0tDQp0aXRsZTogIkludHJvZHVjY2nDs24gYSBSIHkgUlN0dWRpbyINCkRhdGU6ICJNYXJ6byAxMSBkZWwgMjAyMCINCk5hbWU6ICJTYW5kcmEgS2F0dGVyeW5lIFJvZHLDrWd1ZXogSHVydGFkbyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQojIyBTYW5kcmEgS2F0dGVyeW5lIFJvZHLDrWd1ZXogSHVydGFkbw0KIyMjIE1heW8gMTEgZGVsIDIwMjANCkVsIG9iamV0aXZvIGRlIGVzdGUgZXNjcml0byBlcyBmYW1pbGlhcnNlIGNvbiBlbCBsZW5ndWFqZSBkZSBSIHkgUlN0dWRpbywgZGFuZG8gYSBjb25vY2VyIGFsZ3VuYXMgZGUgbGFzIGNhcmFjdGVyw61zdGljYXMgeSBmdW5jaW9uZXMgcXVlIGFtYm9zIGJyaW5kYW4gYSBxdWllbmVzIGxvIGltcGxlbWVudGFuIGVuIHN1cyDDoXJlYXMgZGUgdHJhYmFqby4gDQoNCiMjIyDCv1F1w6kgZXMgUj8NCg0KU2UgZGljZSBxdWUgUiBlcyB1biBsZW5ndWFqZSBkZSBwcm9ncmFtYWNpw7NuIGVzdGFkw61zdGljYSBkZXNhcnJvbGxhZG8gcG9yIFJvc3MgSWhha2EgeSBSb2JlcnQgR2VudGxlbWFuLCBtdXkgdXNhZG8gZW4gZGlmZXJlbnRlcyDDoXJlYXMgeWEgcXVlIGVzIGxhIGltcGxlbWVudGFjacOzbiBkZSBjw7NkaWdvIGFiaWVydG8gZGVsIGxlbmd1YWplIGRlIHByb2dyYW1hY2nDs24g4oCcU+KAnS4gUiBubyB0aWVuZSB1bmEgaW50ZXJmYXogZ3LDoWZpY2EgZGUgdXN1YXJpbywgbm8gaGF5IG1lbsO6cyBkZXNwbGVnYWJsZXMsIGFsZ28gcXVlIGxvIGhhY2UgZsOhY2lsIGRlIHVzYXIgeWEgcXVlIG5vIGRlcGVuZGUgZGUgdW4ga2l0IGRlIGhlcnJhbWllbnRhcyBwYXJhIHN1IGFuw6FsaXNpcy4gQWxndW5hcyB2ZW50YWphcyBkZSB0cmFiYWphciBjb24gUiBzb24gcXVlIGVzIGdyYXR1aXRvIHkgZGUgY8OzZGlnbyBhYmllcnRvOyBlcyB1biBsZW5ndWFqZSBkZSBwcm9ncmFtYWNpw7NuIHkgbm8gZGUgdW5hIGludGVyZmF6IGdyw6FmaWNhLCBsbyBxdWUgcGVybWl0ZSBhIHF1aWVuIGxvIGVzdMOpIHVzYW5kbyBndWFyZGFyIHBlcXVlw7FvcyBhcmNoaXZvcyBkZSB0ZXh0byBmw6FjaWxtZW50ZTsgeSB0aWVuZSB1bmEgY29tdW5pZGFkIGVuIGzDrW5lYSBhY3RpdmEgeSDDunRpbC4NCg0KUiBubyB0aWVuZSB1bmEgaW50ZXJmYXogZ3LDoWZpY2EsIHNpbiBlbWJhcmdvIGhheSBwZXJzb25hcyBxdWUgdHJhYmFqYW4gY29uIFIgYSB0cmF2w6lzIGRlIHBsYXRhZm9ybWFzIGdyw6FmaWNhcyBxdWUgYnJpbmRhbiBmdW5jaW9uZXMgYWRpY2lvbmFsZXMuIFNlIGNvbnNpZGVyYSBhIFJTdHVkaW8gY29tbyBpbnRlcmZheiBncsOhZmljYSBwYXJhIFIsIGxvIHF1ZSBxdWllcmUgZGVjaXIgcXVlIHBlcm1pdGUgYSBxdWllbiBsbyBlc3TDqSB1c2FuZG8gYWNjZWRlciBhIHN1cyBzY3JpcHRzIHkgZGF0b3MsIG9idGVuaWVuZG8gdW5hIHZpc3RhIHByZXZpYSBkZSBsbyBxdWUgZXN0w6EgdHJhYmFqYW5kbyAoZ3LDoWZpY29zIHkgc2FsaWRhcykuDQoNClVuYSB2ZXogZGVzY2FyZ2FkbyBSU3R1ZGlvLCBzZSBwb2Ryw6EgYXByZWNpYXIgdW5hIHDDoWdpbmEgZGl2aWRpZGEgZW4gY3VhdHJvIHNlY2Npb25lcyBwcmluY2lwYWxlcyBhc8OtOiBDb25zb2xhLCBzZSBlbmN1ZW50cmEgc2l0dWFkYSBlbiBsYSBwYXJ0ZSBpbmZlcmlvciBpenF1aWVyZGEsIGRvbmRlIHNlIHBvZHLDoSBlc2NyaWJpciBjw7NkaWdvIGRpcmVjdGFtZW50ZTsgU2VjdWVuY2lhIGRlIENvbWFuZG9zIHNlIGVuY3VlbnRyYSBlbiBsYSBwYXJ0ZSBzdXBlcmlvciBpenF1aWVyZGEsIGRvbmRlIHRhbWJpw6luIHNlIHB1ZWRlIGVzY3JpYmlyIGPDs2RpZ287IFZlbnRhbmEgZGVsIGVudG9ybm8sIGxhIGN1YWwgb2ZyZWNlIHVuYSB2aXNpw7NuIGdlbmVyYWwgZGVsIGVzcGFjaW8gYWN0dWFsLCBkb25kZSBzZSBhcHJlY2lhbiBsb3MgZGF0b3MgcXVlIHNlIGhhbiByZWdpc3RyYWRvLCBvYmpldG9zIGNyZWFkb3MsIGZ1bmNpb25lcyBpbnRyb2R1Y2lkYXMsIGVudHJlIG90cm9zOyBmaW5hbG1lbnRlIHNlIGVuY3VlbnRyYSBlbCDDumx0aW1vIHBhbmVsIHF1ZSB0aWVuZSB2YXJpYXMgcGVzdGHDsWFzLCBwZXJtaXRpZW5kbyBuYXZlZ2FyIHBvciBjYXJwZXRhcywgeSBtaXJhciBsb3MgcGFxdWV0ZXMgaW5zdGFsYWRvcyByZWNpZW50ZW1lbnRlLiANCg0KRWwgaGVjaG8gZGUgZXNjcmliaXIgdW4gY8OzZGlnbyBlbiBzY3JpcHQsIHBlcm1pdGUgY3JlYXIgdW4gcmVnaXN0cm8sIGRvbmRlIHNlIGd1YXJkYSBlbCBwcm9ncmVzbyB5IHNlIHB1ZWRlIHZvbHZlciBhIGFjY2VkZXIgYSBlc3RlIGhhc3RhIGRvbmRlIHNlIHRyYWJhasOzLCBwZXJtaXRpZW5kbyBoYWNlciBjYW1iaW9zLiBFcyBwb3NpYmxlIHRhbWJpw6luIGFncmVnYXIgY29tZW50YXJpb3MgYWwgdGV4dG8gYWwgaW5zZXJ0YXIgdW4gdW4gaGFzaHRhZyAjIGZyZW50ZSBhIGxhIGzDrW5lYSBkZSB0ZXh0bywgcGVybWl0aWVuZG8gZ2VuZXJhciB1biB0ZXh0byBtw6FzIG9yZ2FuaXphZG8uIEVsIGhlY2hvIGRlIGludHJvZHVjaXIgdW4gaGFzaHRhZyAjLCBjcmVhIHVuIHTDrXR1bG8gZW4gZWwgdGV4dG87IHNpIHNlIGRlc2VhIHRlbmVyIHVuIHN1YnTDrXR1bG8sIHNlIGRlYmVyw6EgaW50cm9kdWNpciBkb3MgaGFzaHRhZyAjIzsgc2kgbG8gcXVlIHNlIGJ1c2NhIGVzIHRlbmVyIHVuIHRleHRvIGRlIG1lbm9yIHRhbWHDsW8gcGVybyBkaWZlcmVudGUgYWwgdGV4dG8gbm9ybWFsIHNlIGludHJvZHVjZW4gdHJlcyBoYXNodGFnICMjIyBmcmVudGUgYWwgdGV4dG8uIA0KDQojIyMgQ29tZW56YXIgYSBlc2NyaWJpciBlbiB0dSBndWnDs24NCg0KUGFyYSBlbGFib3JhciB1biBndWnDs24gbG8gaWRlYWwgZXMgc3VtaW5pc3RyYXIgbG9zIGRhdG9zIGRlIHF1acOpbiBsbyBlc3TDoSByZWRhY3RhbmRvLCB0YWxlcyBjb21vIHTDrXR1bG8sIG5vbWJyZSwgZmVjaGEgeSBvYmpldGl2byBwcmluY2lwYWwuIA0KYGBge3J9DQojIEludHJvZHVjY2nDs24gYSBsYSBTb2Npb2xvZ8OtYSBSdXJhbA0KIyBNYXJ6byAyIGRlbCAyMDIwDQojIMOBbHZhcm8gUml2YXMgeSBBbmEgTWFyw61hIEppbcOpbmV6DQpgYGANCkV4aXN0ZSB1bmEgZ3JhbiB2YXJpZWRhZCBkZSBjb21hbmRvcyBxdWUgcGVybWl0ZSBhIGxhIHBlcnNvbmEgcXVlIGVzdMOpIHRyYWJhamFuZG8gZWplY3V0YXIgZnVuY2lvbmVzIGFkaWNpb25hbGVzIGNvbW8gbGEgZWRpY2nDs24gZGUgZGF0b3MgbyBsYSBjcmVhY2nDs24gZGUgbWFwYXMuIFBhcmEgaW5zdGFsYXIgdW4gcGFxdWV0ZSwgc2UgZGViZXLDoSBlc2NyaWJpciBzb2xvIHVuYSB2ZXogZWwgc2lndWllbnRlIGNvbWFuZG86IGluc3RhbGwucGFja2FnZXMoInBhY2thZ2UtbmFtZSIpLCB5YSBxdWUgcG9zdGVyaW9yIGEgZXN0byBzZSBwdWVkZSBlc2NyaWJpciBkaXJlY3RhbWVudGUgZW4gZWwgY3VhZHJvIGRlIGxhIGNvbnNvbGEgZW4gdmV6IGRlIHZvbHZlcmxvIGEgZGVzY2FyZ2FyIHVuYSB5IG90cmEgdmV6LiANCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygicGFja2FnZS1uYW1lIikNCmBgYA0KVW5hIHZleiBzZSBoYXlhIGluc3RhbGFkbyBlbCBwYXF1ZXRlLCBzZSBjYXJnYSBlbCBwYXF1ZXRlIHVzYW5kbyBlbCBjb21hbmRvOiANCmBgYHtyfQ0KbGlicmFyeShwYWNrYWdlLW5hbWUpDQpgYGANClNlIGRlYmUgdGFtYmnDqW4gZGVmaW5pciBlbCBkaXJlY3RvcmlvIGRlIHRyYWJham8uIEVzIG11eSDDunRpbCB5YSBxdWUgZXN0ZSBlcyB1bmEgY2FycGV0YSBxdWUgcGVybWl0aXLDoSBxdWUgUiBidXNxdWUgeSBndWFyZGUgaW5mb3JtYWNpw7NuLCBhZGVtw6FzIG9wdGltaXphciB0aWVtcG8geWEgcXVlIHBlcm1pdGUgb3JnYW5pemFyIGxvcyBhcmNoaXZvcyBxdWUgc2UgaGFuIHRyYWJhamFkbyBwb3IgdGVtYXMuU2kgc2UgZGVzZWEgc2FiZXIgZMOzbmRlIGVzdMOhIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbywgc2UgZGViZSBlamVjdXRhciBlbCBjw7NkaWdvOiANCmBgYHtyfQ0KZ2V0d2QoKSANCmBgYA0KU2kgc2UgZGVzZWEgY2FtYmlhciBlbCBsdWdhciBkZWwgZGlyZWN0b3JpbyBzZSBkZWJlIGVqZWN1dGFyIGVsIGPDs2RpZ286IA0KYGBge3J9DQpzZXR3ZCgpDQpgYGANClZhbGUgYWNsYXJhciBxdWUgdW5hIHJ1dGEgYXJyb2phZGEgcMOzciBlbCBjb21wdXRhZG9yIGNvcGlhZGEgeSBwZWdhZGEgdGVuZHLDoSBiYXJyYXMgaW52ZXJ0aWRhcyBxdWUgc2VwYXJhbiBsYXMgY2FycGV0YXMgKCAiQzpcZm9sZGVyXGRhdGEiKSwgcGVybyBsYSBtYW5lcmEgYWRlY3VhZGEgZGUgaW50cm9kdWNpciBlc3RvIGVuIFIgc2Vyw6EgY29uIGJhcnJhcyBkaWFnb25hbGVzICggIkM6L2ZvbGRlci9kYXRhIikuDQoNCiMjIyBJbXBvcnRhciB5IHZlcmlmaWNhciBsb3MgZGF0b3MNCg0KQSBtYW5lcmEgZGUgZWplbXBsbyBwYXJhIGxhIGV4cGxpY2FjacOzbiBkZSBlc3RlIHB1bnRvLCBzZSB1dGlsaXphcsOhbiB1bm9zIHJlZ2lzdHJvcyBkZSBOQk4gR2F0ZXdheSwgbG9zIGN1eWFsZXMgc2UgZ3VhcmRhcsOhbiBjb21vIGVkaWRpdi5jc3YuIFByaW1lcm8gc2UgZGViZSBkZXNjYXJnYXIgZWwgYXJjaGl2bywgc2lndWllbmRvIGVsIGVubGFjZSB5IGRhbmRvIGNsaWNrIGVuICJEZXNjYXJnYXIgWmlwIiwgZ3VhcmRhcmxvIHkgZGVzY29tcHJpbWlyIGxhIGNhcnBldGEgZW4gYWxnw7puIGx1Z2FyIGRlIGxhIGNvbXB1dGFkb3JhLiBMbyBhbnRlcmlvciBzZSBwdWVkZSBsbGV2YXIgYSBjYWJvIHBvciBtZWRpbyBkZSBHaXRodWIuUGFyYSBpbXBvcnRhciBsb3MgZGF0b3MgZ3VhcmRhZG9zIGVuIGxhIGNvbXB1dGFkb3JhIGEgUlN0dWRpbywgc2UgZGViZSBkYXIgY2xpY2sgZW4gZWwgYm90w7NuICJJbXBvcnRhciBjb25qdW50byBkZSBkYXRvcyIgeSBuYXZlZ2FyIGhhc3RhIGRvbmRlIHNlIGVuY3VlbnRyYSBndWFyZGFkbyBlbCBhcmNoaXZvLCBvIGVqZXJjdXRhciBlbCBjb21hbmRvIHJlYWQuY3N2KCkuIEVzdGEgZXMgdW5hIGZ1bmNpw7NuIMO6dGlsIHBhcmEgc2FiZXIgDQpkZSBkw7NuZGUgcHJvdmllbmUgZWwgY29uanVudG8gZGUgZGF0b3MuDQpgYGB7cn0NCmVkaWRpdiA8LSByZWFkLmNzdigiQzovVXNlcnMvdXNlci9EZXNrdG9wL0ludHJvX3RvX1IvZWRpZGl2LmNzdiIpDQpgYGANCg0KUiBmdW5jaW9uYSBkZSB1bmEgbWVqb3IgbWFuZXJhIGNvbiBhcmNoaXZvcyAuY3N2ICh2YWxvcmVzIHNlcGFyYWRvcyBwb3IgY29tYXMpLCBsbyBjdWFsIHNlIGRlYmUgdGVuZXIgcHJlc2VudGUgYSBsYSBob3JhIGRlIGd1YXJkYXIgYXJjaGl2b3MgZGUgZXhjZWwuIFNpIHVuIGFyY2hpdm8sIGFsIHNlciBndWFyZGFkbyBwb3IgbGEgY29tcHV0YWRvcmEgY29uIHNlcGFyYWRvcmVzIGRlIHB1bnRvIHkgY29tYSA7LCBzZSBkZWJlcsOhIGVqZWN1dGFyIGVsIGNvbWFuZG8gcmVhZC5jc3YyIGVuIGx1Z2FzciBkZSByZWFkLmNzdiwgbyB0YW1iacOpbiBzZSBwdWVkZSB1dGlsaXphciBlbCBhcmd1bWVudG8gZGUgInNlcCIgZW4gbGEgZnVuY2nDs246IHIuY3N2KCJ5b3VyLWZpbGUtcGF0aCIsIHNlcCA9ICI7IikuIENhZGEgb2JlamV0byBlcyBkZW5vbWluYWRvIGNvbW8gZWRpZGl2b2JqZXRvLiBQYXJhIHZlcmlmaWNhciBzaSBsb3MgZGF0b3MgZnVlcm9uIGltcG9ydGFkb3Mgc2luIGVycm9yZXMgbyBxdWUgc2UgZXN0w6EgdHJhYmFqYW5kbyBjb24gbG9zIGRhdG9zIGNvcnJlY3RvcywgUlN0dWRpbyBvZnJlY2UgdW5hIGZ1bmNpw7NuIHF1ZSBwZXJtaXRlIG9idGVuZXIgdW5hIHZpc3RhIHByZXZpYSBkYW5kbyBjbGljayBlbiBlbCBlbCBvYmpldG8gZW4gZWwgcGFuZWwgZGUgY29udHJvbCBFbnRvcm5vLCBkb25kZSBzZSBtb3N0cmFyw6EgdW5hIHDDoWdpbmEgc2ltaWxhciBhIHVuYSBob2phIGRlIGPDoWxjdWxvIHF1ZSBwZXJtaXRlIHZpc3VhbGl6YXIgbG9zIGRhdG9zIG8gbGEgc2VjdWVuY2lhIGRlIGNvbWFuZG9zIGRlIHVuYSBtZWpvciBtYW5lcmEuIA0KYGBge3J9DQpoZWFkKGVkaWRpdikgTXVlc3RyYSBsYXMgcHJpbWVyYXMgZmlsYXMNCnRhaWwoZWRpZGl2KSBNdWVzdHJhIGxhcyDDumx0aW1hcyBmaWxhcw0Kc3RyKGVkaWRpdikgSW5kaWNhIHNpIGxhcyB2YXJpYWJsZXMgc29uIGNvbnRpbnVhcywgZW50ZXJhcywgY2F0ZWfDs3JpY2FzIG8gZGUgY2FyYWN0ZXJlcy4gDQpgYGANCkVsIGNvbWFuZG8gc3RyKG9iamVjdC5uYW1lKSBlcyB1biBjb21hbmRvIHF1ZSBtdWVzdHJhIGxhIGVzdHJ1Y3R1cmEgZGUgbG9zIGRhdG9zIGNvbiBsb3MgcXVlIHNlIGVzdMOhIHRyYWJhamFuZG8geSBoYXkgYWxndW5hcyBvY2FzaW9uZXMgZW4gbGFzIHF1ZSBSIHB1ZWRlIGNhdGFsb2dhciBhIHVuIGNvbmp1bnRvIGRlIGRhdG9zIGRlIHVuIHRpcG8gcXVlIG5vIGVzLCBlcyBwb3IgZXN0YSByYXrDs24gcXVlIGVzIGRlIHZpdGFsIGltcG9ydGFuY2lhIGNvbXByb2JhciBzaWVtcHJlIGxhIGVzdHJ1Y3R1cmEgZGUgbG9zIGRhdG9zLiBTaSBzZSBkZXNlYSBhY2NlZGVyIHNvbG9hIGEgdW5hIGNvbHVtbmEgZGUgdW4gbWFyY28gZGUgZGF0b3Mgc2UgZGViZXLDoSBhZ3JlZ2FyIGVsIG5vbWJyZSBkZSBsYSB2YXJpYWJsZSBhbCBub21icmUgZGVsIG9iamV0byBjb24gdW4gc2lnbm8gZGUgZMOzbGFyICQuIEVzdG8gcGVybWl0ZSB2ZXIsIG1vZGlmaWNhciB5L28gcmVhc2lnbmFyIGVzdGEgdmFyaWFibGUuDQpgYGB7cn0NCmhlYWQoZWRpZGl2JHRheG9uR3JvdXApICAgICBNdWVzdHJhIHNvbG8gbGFzIHByaW1lcmFzIGZpbGFzIGRlIGVzdGEgY29sdW1uYS4gICAgDQpjbGFzcyhlZGlkaXYkdGF4b25Hcm91cCkgICAgSW5kaWNhIGNvbiBxdcOpIHRpcG8gZGUgdmFyaWFibGUgc2UgZXN0w6EgdHJhYmFqYW5kbw0KDQplZGlkaXYkdGF4b25Hcm91cCA8LSBhcy5mYWN0b3IoZWRpZGl2JHRheG9uR3JvdXApICAgICAgDQpgYGANCkVuIGxhIMO6bHRpbWEgbMOtbmVhIGRlIGPDs2RpZ28gZW4gZWwgcmVjdWFkcm8gYW50ZXJpb3IsIGxhIGZ1bmNpw7NuIGFzLmZhY3RvcigpIHBlcm1pdGUgY29udmVydGlyIGN1YWxxdWllciB2YWxvciBxdWUgY29sb3F1ZSBkZW50cm8gZW4gdW4gZmFjdG9yLg0KYGBge3J9DQpkaW0oZWRpZGl2KSAgICAgICAgICAgICAgICAgTXVlc3RyYSBlbCBuw7ptZXJvIGRlIGZpbGFzIHkgY29sdW1uYXMuDQpzdW1tYXJ5KGVkaWRpdikgICAgICAgICAgICAgRGEgdW4gcmVzdW1lbiBkZSBsb3MgZGF0b3MuDQpzdW1tYXJ5KGVkaWRpdiR0YXhvbkdyb3VwKSAgRGEgdW4gcmVzdW1lbiBkZSBlc2EgdmFyaWFibGUgcGFydGljdWxhciAoY29sdW1uYSkgZW4gc3UgY29uanVudG8gZGUgZGF0b3MuIA0KYGBgDQojIyMgQ2FsY3VsYXIgbGEgcmlxdWV6YSBkZSBlc3BlY2llcw0KQ29udGludWFuZG8gY29uIGVsIGVqZW1wbG8gZGVsIGFydMOtY3VsbyBkZSBHZXR3YXksIGVsIGVkaWRpdm9iamV0byB0aWVuZSByZWdpc3Ryb3MgZGUgb2N1cnJlbmNpYSBkZSB2YXJpYXMgZXNwZWNpZXMgZW4gY2llcnRvIHBhw61zIHkgZW4gY2llcnRvIGludGVydmFsbyBkZSB0aWVtcG8uIEFzw60sIHBhcmEgZXhwbG9yYXIgeSBjb25vY2VyIGxhIGJpb2RpdmVyc2lkYWQgZGUgZXNwZWNpZXMgZW4gZXN0ZSBwYcOtcywgc2UgY3JlYXLDoSB1biBncsOhZmljbyBlbiBlbCBxdWUgc2UgcmVwcmVzZW50YXLDoSBjdcOhbnRhcyBlc3BlY2llcyBzZSByZWdpc3RyYXJvbiBlbiBjYWRhIGdydXBvIHRheG9uw7NtaWNvLiBFeGNlbCBwZXJtaXRlIGNhbGN1bGFyIGxhIHJpcXVlemEgZGUgZXNwZWNpZXMsIHNpbiBlbWJhcmdvLCBjdWFuZG8gZXMgdW4gZ3J1cG8gZXh0ZW5zbyBkZSBkYXRvcywgbm8gc2UgdGllbmUgcmVnaXN0cm8gZGUgcXXDqSBoaXpvLCBjw7NtbyBzZSBjbGFzaWZpY2Fyb24gbG9zIGRhdG9zIHkgcXXDqSBjb3Bpw7MgbyBlbGltaW7DsywgbG8gcXVlIHBvZHLDrWEgZ2VuZXJhciBlcnJvcmVzLiBFbiBjb250cmFzdGUgY29uIGVzdG8sIFIgdGllbmUgc3Ugc2NyaXB0LCBsbyBxdWUgcGVybWl0ZSBkZXZvbHZlcnNlLCB2ZXIgbG8gcXVlIGhpem8gYW50ZXJpb3JtZW50ZSB2ZXJpZmljYXIgbG8gcXVlIGxsZXbDsyBhIGNhYm8gZW4gc3UgYW7DoWxpc2lzLCByZWR1Y2llbmRvIGVsIHBvcmNlbnRhamUgZGUgcHJlc2VudGFyIGVycm9yZXMuIA0KUGFyYSBwb2RlciBzYWJlciBlbCB0b3RhbCBkZSBlc3BlY2llcyBkZSBtYW3DrWZlcm9zLCBhdmVzLCBldGMsIHNlIGRlYmUgZGl2aWRpciBlZGlkaXYgZW4gdmFyaW9zIG9iamV0b3MsIGNhZGEgdW5vIGNvbiBmaWxhcyBwYXJhIHVuIHNvbG8gZ3J1cG8gdGF4b27Ds21pY28uIEVzdG8gc2UgbGxldmEgYSBjYWJvIGNvbiBsYSBmdW5jacOzbiBmaWx0ZXIoKSBkZWwgZHBseXIgcGFxdWV0ZS4gDQpgYGB7cn0NCkJlZXRsZSA8LSBmaWx0ZXIoZWRpZGl2LCB0YXhvbkdyb3VwID09ICJlc2NhcmFiYWpvcyIpIDogRWwgcHJpbWVyIGFyZ3VtZW50byBkZSBsYSBmdW5jacOzbiBlcyBlbCBhbXJjbyBkZSBkYXRvcywgZWwgc2VndW5kbyBlcyBsYSBjb25kaWNpw7NuIHF1ZSBzZSBkZXNlYSBmaWx0cmFyLiBEYWRvIHF1ZSBzb2xvIHNlIHF1aWVyZW4gZXNjYXJhYmFqb3MsIGRlIGludHJvZHVjZTogbGEgdmFyaWFibGUgdGF4b25Hcm91cCBkZWJlIHNlciBleGFjdGFtZW50ZSAoPT0pIEVzY2FyYWJham86IGVsaW1pbmUgdG9kbyBsbyBkZW3DoXMgZWwgY29uam50byBkZSBkYXRvcy4gU2UgZGViZSB0ZW5lciBwcmVzZW50ZSBsYSBvcnRvZ3JhZsOtYSB5YSBxdWUgUiB0aWVuZSBsYSBjYXBhY2lkYWQgZGUgZGlzdGluZ3VpciBtYXnDunNjdWxhcyB5IG1pbsO6c2N1bGFzLiANCg0KQmlyZCA8LSBmaWx0ZXIoZWRpZGl2LCB0YXhvbkdyb3VwID09ICJCaXJkIikgIA0KDQpTaSBzZSBuZWNlc2l0YSByZWNvcmRhciBub21icmVzIHkgb3J0b2dyYWbDrWEsIHNlIHB1ZWRlIGVzY3JpYmlyIChlZGlkaXYkdGF4b25Hcm91cCkNCmBgYA0KUGFyYSBpZGVudGlmaWNhciBkaWZlcmVudGVzIGVzcGVjaWVzIHNlIHV0aWxpemEgbGEgZnVuY2nDs24gdW5pcXVlKCksIHkgbGVuZ3RoKCkgcXVlIGxhcyBwdWVkZSBjb250YXIuIA0KYGBge3J9DQphIDwtIGxlbmd0aCh1bmlxdWUoQmVldGxlJHRheG9uTmFtZSkpDQpiIDwtIGxlbmd0aCh1bmlxdWUoQmlyZCR0YXhvbk5hbWUpKQ0KU2UgcHVlZGUgZWxlZ2lyIGxvcyBub21icmVzIHF1ZSBzZSBkZXNlZSBwYXJhIHN1cyBvYmpldG9zLCBlbiBlc3RlIGNhc28gcmVjaWJlbiBlbCBub21icmUgZGUgYSB5IGIsIGRvbmRlIGEgZXN0YXLDrWEgcmVwcmVzZW50YW5kbywgZW4gZWwgZWplbXBsbywgbsO6bWVybyBkZSBlc3BlY2llcyBkaXN0aW50YXMgZGUgZXNjYXJhYmFqb3MgZW4gZWwgcmVnaXN0cm8uIA0KYGBgDQojIyMgQ3JlYXIgdW4gdmVjdG9yIHkgdHJhemFybG8NClNpZ3VpZW5kbyBjb24gZWwgZWplbXBsbywgeWEgcXVlIHNlIHRpZW5lIGxhIHJpcXVlemEgZGUgZXNwZWNpZXMsIHNlIHB1ZWRlbiBjb21iaW5hciBlc29zIHZhbG9yZXMgZW4gdW4gdmVjdG9yLCBlc3RlIGVzIHVuIG9iamV0byBlZCBSIHF1ZSBhbG1hY2VuYSB2YWxvcmVzLiBTZSBkaWZlcmVuY2lhIHVuIG1hcmNvIGRlIGRhdG9zIGRlIHVuIHZlY3RvciBlbiBxdWUgZWwgcHJpbWVybyB0aWVuZSBkb3MgZGltZW5zaW9uZXMgKGZpbGFzIHkgY29sdW1uYXMpLCBtaWVudHJhcyBxdWUgZWwgc2VndW5kbyBzb2xvIHRpZW5lIHVuYS4gRXN0byBzZSBsbGV2YSBhIGNhYm8gbWVkaWFudGUgbGEgZnVuY2nDs24gYygpIHF1ZSBzaWduaWZpY2EgY29uY2F0ZW5hciBvIGVuY2FkZW5hci4gVGFtYmnDqW4gZXMgcG9zaWJsZSBhw7FhZGlyIGV0aXF1ZXRhcyBjb24gbGEgZnVuY2nDs24gbmFtZXMoKS4gDQpgYGB7cn0NCmJpb2RpdiA8LSBjKGEsYixjLGQsZSxmLGcsaCxpLGosaykgICAgIFNlIGhhbiBlbmNhZGVuYWRvIGxvcyB2YWxvcmVzLCBwcmVzdGFyIGF0ZW5jacOzbiBhIGxhIG9yZ2FuaXphY2nDs24gZGUgZXN0b3MuDQpuYW1lcyhiaW9kaXYpIDwtIGMoIkJlZXRsZSIsDQogICAgICAgICAgICAgICAgICAgIkJpcmQiLA0KICAgICAgICAgICAgICAgICAgICJCdXR0ZXJmbHkiLA0KICAgICAgICAgICAgICAgICAgICJEcmFnb25mbHkiLA0KICAgICAgICAgICAgICAgICAgICJGbG93ZXJpbmcuUGxhbnRzIiwNCiAgICAgICAgICAgICAgICAgICAiRnVuZ3VzIiwNCiAgICAgICAgICAgICAgICAgICAiSHltZW5vcHRlcmFuIiwNCiAgICAgICAgICAgICAgICAgICAiTGljaGVuIiwNCiAgICAgICAgICAgICAgICAgICAiTGl2ZXJ3b3J0IiwNCiAgICAgICAgICAgICAgICAgICAiTWFtbWFsIiwNCiAgICAgICAgICAgICAgICAgICAiTW9sbHVzYyIpDQpgYGANClNlIGRlYmVuIGFjbGFyYXIgYWxndW5hcyBjb3NhczogDQoqIExvcyBlc3BhY2lvc2RlbGFudGUgeSBhdHLDoXMgPC15IGVzcHXDqXMgZGUgbGEgY29tYSwgc2UgYWdyZWdhbiBwYXJhIGZhY2lsaXRhciBsYSBsZWN0dXJhIGRlbCBjw7NkaWdvLiANCiogVG9kYXMgbGFzIGV0aXF1ZXRhcyBzZSBoYW4gZGlzcHVlc3RvIGVuIHVuYSBudWV2YSBsw61uZWEsIGRlIG5vIHNlciBhc8OtLCBzZXLDrWEgZGlmw61jaWwgbGVlciB0b2RvLg0KKiBTYWUgZGViZSB2ZXJpZmljYXIgZGUgaGFjZXIgY29pbmNpZGlyIGxvcyB2YWxvcmVzIHkgbGFzIGV0aXF1ZXRhcyBkZSBsb3MgdmVjdG9yZXMgcGFyYSBldml0YXIgZXJyb3JlcyB5IGVuIGNhc28gZGUgdGVuZXJsb3MsIGRldm9sdmVyc2UgcGFyYSB2ZXJpZmljYXIgc2kgbGEgaW5mb3JtYWNpw7NuIHN1bWluaXN0cmFkYSB5IGFycm9qYWRhIGVzIGxhIGNvcnJlY3RhLg0KKiBTaSBzZSByZXNhbHRhIHVuIHBhcsOpbnRlc2lzLCBSIG1vc3RyYXLDoSBlbCBjb3JyZXNwb25kaWVudGUgZW4gc3UgY8OzZGlnbywgZXZpdGFuZG8gZXJyb3Jlcy4gDQpTZSBwdWVkZSB2ZXIgbGEgcmlxdWV6YSBkZSBlc3BlY2llcyBwb3IgbWVkaW8gZGUgbGEgZnVuY2nDs24gYmFycGxvdCgpLCBkb25kZSBsb3MgZ3LDoWZpY29zIGFwYXJlY2Vyw6FuIGVuIGxhIHZlbnRhbmEgaW5mZXJpb3IgZGVyZWNoYS4gDQpgYGB7cn0NCmJhcnBsb3QoYmlvZGl2KQ0KYGBgDQpTZSBwdWVkZSB1c2FyIGxhIGZ1bmNpw7NuIGhlbHAoKSBwYXJhIHZlciBxdcOpIGFyZ3VtZW50b3Mgc2UgbmVjZXNpdGEgYWdyZWdhci4NCmBgYHtyfQ0KaGVscChiYXJwbG90KSAgICAgUGFyYSBvYnRlbmVyIGF5dWRhIGNvbiBsYSBmdW5jacOzbiBiYXJwbG90DQpoZWxwKHBhcikgICAgICAgICBQYXJhIG9idGVuZXIgYXl1ZGEgY29uIGVsIHRyYXphZG8gZW4gZ2VuZXJhbA0KYGBgDQpQYXJhIHNhbHZhciBlbCB0cmFiYWpvIHJlYWxpemFkbywgc2UgcHVlZGUgZGFyIGNsaWNrIGVuIEV4cG9ydGFyIGVuIGxhIHZlbnRhbmEgZGUgZ3LDoWZpY29zLiBUYW1iacOpbiBlcyBwb3NpYmxlIGd1YXJkYXIgZWwgYXJjaGl2byBlbnZvbHZpZW5kbyBlbCBjw7NkaWdvIGVuIGxhcyBmdW5jaW9uZXMgcG5nKCkgeSBkZXYuZWZmKCkuIA0KYGBge3J9DQpwbmcoImJhcnBsb3QucG5nIiwgd2lkdGg9MTYwMCwgaGVpZ2h0PTYwMCkgIGJ1c2NhciBsYSBheXVkYSBwYXJhIGVzdGEgZnVuY2nDs24gcGVybWl0ZSBwZXJzb25hbGl6YXIgZWwgdGFtYcOxbyB5IHJlc29sdWNpw7NuIGRlIGxhIGltYWdlbi4gDQpiYXJwbG90KGJpb2RpdiwgeGxhYj0iVGF4YSIsIHlsYWI9Ik51bWJlciBvZiBzcGVjaWVzIiwgeWxpbT1jKDAsNjAwKSwgY2V4Lm5hbWVzPSAxLjUsIGNleC5heGlzPTEuNSwgY2V4LmxhYj0xLjUpDQpkZXYub2ZmKCkNCiBFbCBjw7NkaWdvIGNleCBhdW1lbnRhIGVsIHRhbWHDsW8gZGUgZnVlbnRlIGN1YW5kbyBlcyBtYXlvciBxdWUgdW5vIHkgbG8gZGlzbWludXllIGN1YW5kbyBlcyBtZW5vciBxdWUgdW5vLg0KYGBgDQojIyMgQ3JlYXIgdW4gbWFyY28gZGUgZGF0b3MgeSB0cmF6YXJsbw0KTG9zIG1hcmNvcyBkZSBkYXRvcyBzb24gdGFibGFzIGRlIHZhbG9yZXMgcXVlIHRpZW5lbiB1bmEgZXN0cnVjdHVyYSBiaWRpbWVuc2lvbmFsIGNvbXB1ZXN0YSBkZSBmaWxhcyB5IGNvbHVtbmFzLCBkb25kZSBjYWRhIGNvbHVtbmEgcHVlZGUgdGVuZXIgdW4gdGlwbyBkZSBkYXRvcyBkaWZlcmVudGUuIExhIG1hdHJpeiBlcyBvdHJvIHBvc2libGUgZm9ybWF0byBkZSBkYXRvcywgbGEgY3VhbCB0YW1iacOpbiBwdWVkZSB0ZW5lciB2YXJpYXMgZmlsYXMgZGUgZGF0b3MgcGVybyBsYXMgdmFyaWFibGVzIGRlYmVuIHNlciB0b2RhcyBkZWwgbWlzbW8gdGlwby4gDQpTZSB1dGlsaXphcsOhIGxhIGZ1bmNpw7NuIGRhdGEuZnJhbWUoKSwgcGVybyBwcmltZXJvIHNlIGRlYmVyw6EgY3JlYXIgdW4gb2JqZXRvIHF1ZSBjb250ZW5nYSB0b2RvcyBsb3Mgbm9tYnJlcyBkZSBsb3MgdGF4b25lcyAoY29sdW1uYSkgeSBvdHJvcyBjb24gdG9kb3MgbG9zIHZhbG9yZXMgZGUgbGEgcmlxdWV6YSBkZSBlc3BlY2llcyBkZSBjYWRhIHRheMOzbiAob3RyYSBjb2x1bW5hKS4gDQpgYGB7cn0NCkNyZWFyIHVuIG9iamV0byBsbGFtYWRvICJ0YXjDs24iIHF1ZSBjb250ZW5nYSB0b2RvcyBsb3MgZGF0b3MgZGVsIHRheMOzbg0KdGF4YSA8LSBjKCJCZWV0bGUiLA0KICAgICAgICAgICJCaXJkIiwNCiAgICAgICAgICAiQnV0dGVyZmx5IiwNCiAgICAgICAgICAiRHJhZ29uZmx5IiwNCiAgICAgICAgICAiRmxvd2VyaW5nLlBsYW50cyIsDQogICAgICAgICAgIkZ1bmd1cyIsDQogICAgICAgICAgIkh5bWVub3B0ZXJhbiIsDQogICAgICAgICAgIkxpY2hlbiIsDQogICAgICAgICAgIkxpdmVyd29ydCIsDQogICAgICAgICAgIk1hbW1hbCIsDQogICAgICAgICAgIk1vbGx1c2MiKQ0KQ29udmVydGlyIGVzZSBvYmpldG8gZW4gdW4gZmFjdG9yLCB1bmEgdmFyaWFibGUgY2F0ZWfDs3JpY2EuDQp0YXhhX2YgPC0gZmFjdG9yKHRheGEpDQoNCkNvbWJpbmFuZG8gdG9kb3MgbG9zIHZhbG9yZXMgcDBhcmEgZWwgbnB1bWVybyBkZSBlc3BlY2llcyBkZSB1biBvYmpldG8gbGxhbWFkbyByaXF1ZXphDQpyaWNobmVzcyA8LSBjKGEsYixjLGQsZSxmLGcsaCxpLGosaykNCg0KQ3JlYXIgZWwgbWFyY28gZGUgZGF0b3MgYSBwYXJ0aXIgZGUgbG9zIGRvcyB2ZWN0cm9yZXMNCmJpb2RhdGEgPC0gZGF0YS5mcmFtZSh0YXhhX2YsIHJpY2huZXNzKQ0KDQpHdWFyZGFyIGxhIGZpbGENCndyaXRlLmNzdihiaW9kYXRhLCBmaWxlPSJiaW9kYXRhLmNzdiIpICAjIGl0IHdpbGwgYmUgc2F2ZWQgaW4geW91ciB3b3JraW5nIGRpcmVjdG9yeQ0KYGBgDQoNCg0KUiB5IFJTdHVkaW8gdGllbmVuIGxhIGNhcGFjaWRhZCBkZSBmdW5jaW9uYXIgY29uIHVub3MgY8OzZGlnb3MsIGVudHJlIGVsbG8gc2UgZW5jdWVudHJhbjogDQogKiBDdHJsICsgUyA6IFBhcmEgZ3VhcmRhciBlbCBhcmNoaXZvLg0KICogPC0gOiBFc3RhIGZsZWNoYSBlbiBlbCBjw7NkaWdvIGFudGVyaW9yIGluZGljYSBxdWUgc2UgbGUgZXN0w6FuIGFzaWduYW5kbyBvYmpldG9zIGEgZXN0ZS4NCiANCg0KIyMjIyBSRUZFUkVOQ0lBUyBCSUJMSU9HUsOBRklDQVMNCg0KaHR0cHM6Ly9vdXJjb2RpbmdjbHViLmdpdGh1Yi5pby90dXRvcmlhbHMvaW50cm8tdG8tci8NCg0KIA0KDQpgYGB7cn0NCg0KYGBgDQo=