¿Qué es R?

R es un lenguaje de programación estadística empleado en gran variedad de disciplinas aunque también es el nombre de un software que emplea este mismo lenguaje.

Comenzando a escribir

Este cuaderno se desarrolla para la asignatura de Geomática Básica y corresponde a una breve introducción a R y sus funciones básicas. El documento fue realizado por Luisa Fernanda Carrión Ramírez.

Paquetes de R

Un paquete es un conjunto de comandos empleados para una función específica y se instalan de la siguiente manera:

install.packages("package name")

Para poder emplear el paquete es necesario ejecutarlo con el siguiente código:

library(package-name)

Como ejemplo, se instalará el paquete dplyr

install.packages("dplyr")
library(dplyr)

Directorio de trabajo

Es una carpeta donde el programa buscará los datos y documentos. Para sabe en donde está el directorio de trabajo se realiza lo siguiente:

getwd()
[1] "C:/Users/LUISA CARRION/Documents"

En caso de que se quiera cambiar el directorio de trabajo, se usa la funcion setwd()

setwd("C:/Users/LUISA CARRION/Documents")

Importar y verificar datos

Para realizar esta práctica es necesario descargar los registros entre 2000-2016 de NBN Gateway. Estos registros contienen información acerca de las especies de animales, plantas y hongos. Este archivo se guardará como edidiv.csv. Después de descargar el archivo, se importa con el comando read.csv() o empleando herramientas de la consola.

read.csv()

En el siguiente chunk se puede ver la ruta del archivo en donde se guardaron los datos:

edidiv <- read.csv("C:/Users/LUISA CARRION/Downloads/edidiv.csv")  

¿Cómo saber si se han cometido errores en los códigos?

Cometer errores en R es muy frecuente, es por ello que se recomienda ejecutar el código y verificar la salida en la consola. Sin embargo, existen otras herramientas que nos permiten tener una vista previa de unas pocas líneas.

head()

Esta opción nos permite ver las primeras filas:

head(edidiv)

tail()

Este comando muestra las últimas filas.

tail(edidiv)

str()

Esta opción indica si las variables son continuas, enteras, categóricas o caracteres.

str(edidiv)
'data.frame':   25684 obs. of  5 variables:
 $ organisationName: Factor w/ 28 levels "BATS & The Millennium Link",..: 14 14 14 8 8 28 28 28 28 28 ...
 $ gridReference   : Factor w/ 1938 levels "NT200701","NT200712",..: 1314 569 569 1412 1412 1671 1671 1671 1671 1671 ...
 $ year            : int  2000 2000 2000 2000 2000 2001 2001 2001 2001 2001 ...
 $ taxonName       : Factor w/ 1275 levels "Acarospora fuscata",..: 1126 1126 1127 192 193 1202 365 977 472 947 ...
 $ taxonGroup      : Factor w/ 11 levels "Beetle","Bird",..: 2 2 2 2 2 2 2 2 2 2 ...

Para mirar la estructura de los datos se usa el comando str(object.name). Aunque, si se quiere cambiar la estructura, se realizan los siguientes pasos: Se emplea el cógigo head(nombre del archivo$grupo) para ver las primeras filas de la columna en esta clase.

head(edidiv$taxonGroup)
[1] Bird Bird Bird Bird Bird Bird
11 Levels: Beetle Bird Butterfly Dragonfly Flowering.Plants Fungus Hymenopteran Lichen Liverwort ... Mollusc

Se usa class(nombre del archivo$grupo) para saber con que tipo de variable se está trabajando

class(edidiv$taxonGroup)
[1] "factor"

El siguiente comando, convierte cualquier valor colocado en un factor:

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

Existen otros comandos que pueden ser utiles en distintos casos. Principalmente se trabajarán:

dim()

Es otro comando que permite ver el número de columnas y filas.

dim(edidiv)
[1] 25684     5

summary

Este comando da un resumen de los datos.

summary(edidiv)
                                             organisationName gridReference        year     
 Biological Records Centre                           :6744    NT2673 : 2741   Min.   :2000  
 RSPB                                                :5809    NT2773 : 2031   1st Qu.:2006  
 Butterfly Conservation                              :3000    NT2873 : 1247   Median :2009  
 Scottish Wildlife Trust                             :2070    NT2570 : 1001   Mean   :2009  
 Conchological Society of Great Britain &amp; Ireland:1998    NT27   :  888   3rd Qu.:2011  
 The Wildlife Information Centre                     :1860    NT2871 :  767   Max.   :2016  
 (Other)                                             :4203    (Other):17009                 
                 taxonName                taxonGroup  
 Maniola jurtina      : 1710   Butterfly       :9670  
 Aphantopus hyperantus: 1468   Bird            :7366  
 Turdus merula        : 1112   Flowering.Plants:2625  
 Lycaena phlaeas      :  972   Mollusc         :2226  
 Aglais urticae       :  959   Hymenopteran    :1391  
 Aglais io            :  720   Mammal          : 960  
 (Other)              :18743   (Other)         :1446  

summary(-$-)

Da un breve resumen de una variable en particular.

summary(edidiv$taxonGroup)
          Beetle             Bird        Butterfly        Dragonfly Flowering.Plants           Fungus 
             426             7366             9670              421             2625              334 
    Hymenopteran           Lichen        Liverwort           Mammal          Mollusc 
            1391              140              125              960             2226 

Calcular la riqueza en especies

La riqueza de especies es el número total de especies diferentes en un lugar. Para saber cuántas especies se tienen de mamíferos, aves, plantas, entre otros, se debe dividir la base de datos edidiv en varios grupos utilizando la función filter()

Beetle <- filter(edidiv, taxonGroup == "Beetle")
Bird <- filter(edidiv, taxonGroup == "Bird")
Butterfly <- filter(edidiv, taxonGroup == "Butterfly")
Flowering.Plants <- filter(edidiv, taxonGroup == "Flowering.Plants")
Fungus <- filter(edidiv, taxonGroup == "Fungus")
Hymenopteran <- filter(edidiv, taxonGroup == "Hymenopteran")
Lichen <- filter(edidiv, taxonGroup == "Lichen")
Liverwort <- filter(edidiv, taxonGroup == "Liverwort")
Mammal <- filter(edidiv, taxonGroup == "Mammal")
Mollusc <- filter(edidiv, taxonGroup == "Mollusc")

Ahora, se emplearán las funciones unique() que identifica las diferentes especies y length() que las cuenta.

a <- length(unique(Beetle$taxonName))
b <- length(unique(Bird$taxonName))
c <- length(unique(Butterfly$taxonName))
d <- length(unique(Flowering.Plants$taxonName))
e <- length(unique(Fungus$taxonName))
f <- length(unique(Hymenopteran$taxonName))
g <- length(unique(Lichen$taxonName))
h <- length(unique(Liverwort$taxonName))
i <- length(unique(Mammal$taxonName))
j <- length(unique(Mollusc$taxonName))

Crear un vector y trazarlo Un vector almacena valores en una única dimensión. Para crear un vector se emplea la función c()

biodiv <- c(a,b,c,d,e,f,g,h,i,j,k)
#Se están relacionando los valores en el mismo orden en el cual se escribieron anteriormente.
names(biodiv) <- c("Beetle", "Bird", "Butterfly", "Dragonfly", "Flowering.Plants", "Fungus", "Hymenopteran", "Lichen", "Liverwort", "Mammal", "Mollusc")

Ahora, se pueden visualizar la riqueza de especies con la función barplot(). Al ejecutar este código, aparece el gráfico correspondiente, sin embargo, aún falta agregarle nombres a los ejes y pulirlo. Para saber que comandos emplear se utiliza la función help().

help(barplot)
#Para obtener ayuda sólo con la función barplot.
help(par)
#Para tener ayuda con el trazado en general.

Para poder modificar el gráfico se pueden emplear distintos comandos como: -xlab y ylab que permiten nombrar los ejes -cex.names que permite modificar el tamaño de la fuente en el eje x -cex.axis que modifica el tamaño de fuente en el eje y -cex.lab que modifica el tamaño de fuente de los títulos de los ejes.

barplot(biodiv)

barplot(biodiv, xlab="Taxa", ylab="Number of species", ylim=c(0,600), cex.names= 0.45, cex.axis=0.9, cex.lab=1.0)

Crear un marco de datos y trazarlo

En esta seccionse crearán una serie de valores con sus respectivas etiquetas. Para ello, se utilizaran objetos del marco de datos. Los marcos de datos son tablas de valores con columnas y filas. Para ello, se creará un objeto que contenga todos los nombres de los taxones y otro con los valores de riqueza de las especies de cada taxón. Luego, se usará la función data.frame()

Para crear un objeto llamado “taxa” con todos los nombres del conjunto:

taxa <- c("Beetle", "Bird", "Butterfly","Dragonfly","Flowering.Plants", "Fungus", "Hymenopteran", "Lichen", "Liverwort", "Mammal", "Mollusc")

Para convertir el objeto en un factor:

taxa_f <- factor(taxa)

Para combinar todos los valores en el número de especies “richness”

richness <- c(a,b,c,d,e,f,g,h,i,j,k)

Para crear un marco de datos a partir de dos vectores:

biodata <- data.frame(taxa_f, richness)

Para guardar el archivo en el directorio de trabajo:

write.csv(biodata, file ="biodata.csv")

En caso de que se quieran crear y guardar diagramas de barrasempleando sólo el marco de datos, se necesita cambiar un poco el código.

png("barplot2.png", width=1600, height=600)
barplot(biodata$richness, names.arg=c("Beetle", "Bird", "Butterfly", "Dragonfly", "Flowering.Plants", "Fungus", "Hymenopteran", "Lichen", "Liverwort", "Mammal", "Mollusc"),
xlab="Taxa", ylab="Number of species", ylim=c(0,600))
dev.off()
LS0tDQp0aXRsZTogIkludHJvZHVjY2nDs24gYSBSJlJTdHVkaW8iDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQoqKsK/UXXDqSBlcyBSPyoqDQoNClIgZXMgdW4gbGVuZ3VhamUgZGUgcHJvZ3JhbWFjacOzbiBlc3RhZMOtc3RpY2EgZW1wbGVhZG8gZW4gZ3JhbiB2YXJpZWRhZCBkZSBkaXNjaXBsaW5hcyBhdW5xdWUgdGFtYmnDqW4gZXMgZWwgbm9tYnJlIGRlIHVuIHNvZnR3YXJlIHF1ZSBlbXBsZWEgZXN0ZSBtaXNtbyBsZW5ndWFqZS4NCg0KKipDb21lbnphbmRvIGEgZXNjcmliaXIqKg0KDQpFc3RlIGN1YWRlcm5vIHNlIGRlc2Fycm9sbGEgcGFyYSBsYSBhc2lnbmF0dXJhIGRlIEdlb23DoXRpY2EgQsOhc2ljYSB5IGNvcnJlc3BvbmRlIGEgdW5hIGJyZXZlIGludHJvZHVjY2nDs24gYSBSIHkgc3VzIGZ1bmNpb25lcyBiw6FzaWNhcy4gRWwgZG9jdW1lbnRvIGZ1ZSByZWFsaXphZG8gcG9yIEx1aXNhIEZlcm5hbmRhIENhcnJpw7NuIFJhbcOtcmV6Lg0KDQoqKlBhcXVldGVzIGRlIFIqKg0KDQpVbiBwYXF1ZXRlIGVzIHVuIGNvbmp1bnRvIGRlIGNvbWFuZG9zIGVtcGxlYWRvcyBwYXJhIHVuYSBmdW5jacOzbiBlc3BlY8OtZmljYSB5IHNlIGluc3RhbGFuIGRlIGxhIHNpZ3VpZW50ZSBtYW5lcmE6DQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoInBhY2thZ2UgbmFtZSIpDQpgYGANClBhcmEgcG9kZXIgZW1wbGVhciBlbCBwYXF1ZXRlIGVzIG5lY2VzYXJpbyBlamVjdXRhcmxvIGNvbiBlbCBzaWd1aWVudGUgY8OzZGlnbzoNCmBgYHtyfQ0KbGlicmFyeShwYWNrYWdlLW5hbWUpDQpgYGANCkNvbW8gZWplbXBsbywgc2UgaW5zdGFsYXLDoSBlbCBwYXF1ZXRlIGRwbHlyDQpgYGB7cn0NCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmxpYnJhcnkoZHBseXIpDQpgYGANCioqRGlyZWN0b3JpbyBkZSB0cmFiYWpvKioNCg0KRXMgdW5hIGNhcnBldGEgZG9uZGUgZWwgcHJvZ3JhbWEgYnVzY2Fyw6EgbG9zIGRhdG9zIHkgZG9jdW1lbnRvcy4gUGFyYSBzYWJlIGVuIGRvbmRlIGVzdMOhIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbyBzZSByZWFsaXphIGxvIHNpZ3VpZW50ZToNCg0KYGBge3J9DQpnZXR3ZCgpDQpgYGANCkVuIGNhc28gZGUgcXVlIHNlIHF1aWVyYSBjYW1iaWFyIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbywgc2UgdXNhIGxhIGZ1bmNpb24gc2V0d2QoKQ0KYGBge3J9DQpzZXR3ZCgiQzovVXNlcnMvTFVJU0EgQ0FSUklPTi9Eb2N1bWVudHMiKQ0KYGBgDQoqKkltcG9ydGFyIHkgdmVyaWZpY2FyIGRhdG9zKioNCg0KUGFyYSByZWFsaXphciBlc3RhIHByw6FjdGljYSBlcyBuZWNlc2FyaW8gZGVzY2FyZ2FyIGxvcyByZWdpc3Ryb3MgZW50cmUgMjAwMC0yMDE2IGRlIE5CTiBHYXRld2F5LiBFc3RvcyByZWdpc3Ryb3MgY29udGllbmVuIGluZm9ybWFjacOzbiBhY2VyY2EgZGUgbGFzIGVzcGVjaWVzIGRlIGFuaW1hbGVzLCBwbGFudGFzIHkgaG9uZ29zLiBFc3RlIGFyY2hpdm8gc2UgZ3VhcmRhcsOhIGNvbW8gZWRpZGl2LmNzdi4NCkRlc3B1w6lzIGRlIGRlc2NhcmdhciBlbCBhcmNoaXZvLCBzZSBpbXBvcnRhIGNvbiBlbCBjb21hbmRvIHJlYWQuY3N2KCkgbyBlbXBsZWFuZG8gaGVycmFtaWVudGFzIGRlIGxhIGNvbnNvbGEuDQpgYGB7cn0NCnJlYWQuY3N2KCkNCmBgYA0KRW4gZWwgc2lndWllbnRlIGNodW5rIHNlIHB1ZWRlIHZlciBsYSBydXRhIGRlbCBhcmNoaXZvIGVuIGRvbmRlIHNlIGd1YXJkYXJvbiBsb3MgZGF0b3M6DQpgYGB7cn0NCmVkaWRpdiA8LSByZWFkLmNzdigiQzovVXNlcnMvTFVJU0EgQ0FSUklPTi9Eb3dubG9hZHMvZWRpZGl2LmNzdiIpICANCmBgYA0KKirCv0PDs21vIHNhYmVyIHNpIHNlIGhhbiBjb21ldGlkbyBlcnJvcmVzIGVuIGxvcyBjw7NkaWdvcz8qKg0KDQpDb21ldGVyIGVycm9yZXMgZW4gUiBlcyBtdXkgZnJlY3VlbnRlLCBlcyBwb3IgZWxsbyBxdWUgc2UgcmVjb21pZW5kYSBlamVjdXRhciBlbCBjw7NkaWdvIHkgdmVyaWZpY2FyIGxhIHNhbGlkYSBlbiBsYSBjb25zb2xhLiBTaW4gZW1iYXJnbywgZXhpc3RlbiBvdHJhcyBoZXJyYW1pZW50YXMgcXVlIG5vcyBwZXJtaXRlbiB0ZW5lciB1bmEgdmlzdGEgcHJldmlhIGRlIHVuYXMgcG9jYXMgbMOtbmVhcy4NCg0KKmhlYWQoKSoNCg0KRXN0YSBvcGNpw7NuIG5vcyBwZXJtaXRlIHZlciBsYXMgcHJpbWVyYXMgZmlsYXM6DQpgYGB7cn0NCmhlYWQoZWRpZGl2KQ0KYGBgDQoqdGFpbCgpKg0KDQpFc3RlIGNvbWFuZG8gbXVlc3RyYSBsYXMgw7psdGltYXMgZmlsYXMuDQpgYGB7cn0NCnRhaWwoZWRpZGl2KQ0KYGBgDQoqc3RyKCkqDQoNCkVzdGEgb3BjacOzbiBpbmRpY2Egc2kgbGFzIHZhcmlhYmxlcyBzb24gY29udGludWFzLCBlbnRlcmFzLCBjYXRlZ8OzcmljYXMgbyBjYXJhY3RlcmVzLg0KYGBge3J9DQpzdHIoZWRpZGl2KQ0KYGBgDQpQYXJhIG1pcmFyIGxhIGVzdHJ1Y3R1cmEgZGUgbG9zIGRhdG9zIHNlIHVzYSBlbCBjb21hbmRvIHN0cihvYmplY3QubmFtZSkuIEF1bnF1ZSwgc2kgc2UgcXVpZXJlIGNhbWJpYXIgbGEgZXN0cnVjdHVyYSwgc2UgcmVhbGl6YW4gbG9zIHNpZ3VpZW50ZXMgcGFzb3M6DQpTZSBlbXBsZWEgZWwgY8OzZ2lnbyBoZWFkKG5vbWJyZSBkZWwgYXJjaGl2byRncnVwbykgcGFyYSB2ZXIgbGFzIHByaW1lcmFzIGZpbGFzIGRlIGxhIGNvbHVtbmEgZW4gZXN0YSBjbGFzZS4NCmBgYHtyfQ0KaGVhZChlZGlkaXYkdGF4b25Hcm91cCkNCmBgYA0KU2UgdXNhIGNsYXNzKG5vbWJyZSBkZWwgYXJjaGl2byRncnVwbykgcGFyYSBzYWJlciBjb24gcXVlIHRpcG8gZGUgdmFyaWFibGUgc2UgZXN0w6EgdHJhYmFqYW5kbw0KYGBge3J9DQpjbGFzcyhlZGlkaXYkdGF4b25Hcm91cCkNCmBgYA0KRWwgc2lndWllbnRlIGNvbWFuZG8sIGNvbnZpZXJ0ZSBjdWFscXVpZXIgdmFsb3IgY29sb2NhZG8gZW4gdW4gZmFjdG9yOg0KYGBge3J9DQplZGlkaXYkdGF4b25Hcm91cCA8LSBhcy5mYWN0b3IoZWRpZGl2JHRheG9uR3JvdXApDQpgYGANCkV4aXN0ZW4gb3Ryb3MgY29tYW5kb3MgcXVlIHB1ZWRlbiBzZXIgdXRpbGVzIGVuIGRpc3RpbnRvcyBjYXNvcy4gUHJpbmNpcGFsbWVudGUgc2UgdHJhYmFqYXLDoW46DQoNCipkaW0oKSoNCg0KRXMgb3RybyBjb21hbmRvIHF1ZSBwZXJtaXRlIHZlciBlbCBuw7ptZXJvIGRlIGNvbHVtbmFzIHkgZmlsYXMuDQpgYGB7cn0NCmRpbShlZGlkaXYpDQpgYGANCipzdW1tYXJ5Kg0KDQpFc3RlIGNvbWFuZG8gZGEgdW4gcmVzdW1lbiBkZSBsb3MgZGF0b3MuDQpgYGB7cn0NCnN1bW1hcnkoZWRpZGl2KQ0KYGBgDQoqc3VtbWFyeSgtJC0pKg0KDQpEYSB1biBicmV2ZSByZXN1bWVuIGRlIHVuYSB2YXJpYWJsZSBlbiBwYXJ0aWN1bGFyLg0KYGBge3J9DQpzdW1tYXJ5KGVkaWRpdiR0YXhvbkdyb3VwKQ0KYGBgDQoqKkNhbGN1bGFyIGxhIHJpcXVlemEgZW4gZXNwZWNpZXMqKg0KDQpMYSByaXF1ZXphIGRlIGVzcGVjaWVzIGVzIGVsIG7Dum1lcm8gdG90YWwgZGUgZXNwZWNpZXMgZGlmZXJlbnRlcyBlbiB1biBsdWdhci4gUGFyYSBzYWJlciBjdcOhbnRhcyBlc3BlY2llcyBzZSB0aWVuZW4gZGUgbWFtw61mZXJvcywgYXZlcywgcGxhbnRhcywgZW50cmUgb3Ryb3MsIHNlIGRlYmUgZGl2aWRpciBsYSBiYXNlIGRlIGRhdG9zIGVkaWRpdiBlbiB2YXJpb3MgZ3J1cG9zIHV0aWxpemFuZG8gbGEgZnVuY2nDs24gZmlsdGVyKCkNCmBgYHtyfQ0KQmVldGxlIDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkJlZXRsZSIpDQpCaXJkIDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkJpcmQiKQ0KQnV0dGVyZmx5IDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkJ1dHRlcmZseSIpDQpGbG93ZXJpbmcuUGxhbnRzIDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkZsb3dlcmluZy5QbGFudHMiKQ0KRnVuZ3VzIDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkZ1bmd1cyIpDQpIeW1lbm9wdGVyYW4gPC0gZmlsdGVyKGVkaWRpdiwgdGF4b25Hcm91cCA9PSAiSHltZW5vcHRlcmFuIikNCkxpY2hlbiA8LSBmaWx0ZXIoZWRpZGl2LCB0YXhvbkdyb3VwID09ICJMaWNoZW4iKQ0KTGl2ZXJ3b3J0IDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkxpdmVyd29ydCIpDQpNYW1tYWwgPC0gZmlsdGVyKGVkaWRpdiwgdGF4b25Hcm91cCA9PSAiTWFtbWFsIikNCk1vbGx1c2MgPC0gZmlsdGVyKGVkaWRpdiwgdGF4b25Hcm91cCA9PSAiTW9sbHVzYyIpDQpgYGANCkFob3JhLCBzZSBlbXBsZWFyw6FuIGxhcyBmdW5jaW9uZXMgdW5pcXVlKCkgcXVlIGlkZW50aWZpY2EgbGFzIGRpZmVyZW50ZXMgZXNwZWNpZXMgeSBsZW5ndGgoKSBxdWUgbGFzIGN1ZW50YS4NCmBgYHtyfQ0KYSA8LSBsZW5ndGgodW5pcXVlKEJlZXRsZSR0YXhvbk5hbWUpKQ0KYiA8LSBsZW5ndGgodW5pcXVlKEJpcmQkdGF4b25OYW1lKSkNCmMgPC0gbGVuZ3RoKHVuaXF1ZShCdXR0ZXJmbHkkdGF4b25OYW1lKSkNCmQgPC0gbGVuZ3RoKHVuaXF1ZShGbG93ZXJpbmcuUGxhbnRzJHRheG9uTmFtZSkpDQplIDwtIGxlbmd0aCh1bmlxdWUoRnVuZ3VzJHRheG9uTmFtZSkpDQpmIDwtIGxlbmd0aCh1bmlxdWUoSHltZW5vcHRlcmFuJHRheG9uTmFtZSkpDQpnIDwtIGxlbmd0aCh1bmlxdWUoTGljaGVuJHRheG9uTmFtZSkpDQpoIDwtIGxlbmd0aCh1bmlxdWUoTGl2ZXJ3b3J0JHRheG9uTmFtZSkpDQppIDwtIGxlbmd0aCh1bmlxdWUoTWFtbWFsJHRheG9uTmFtZSkpDQpqIDwtIGxlbmd0aCh1bmlxdWUoTW9sbHVzYyR0YXhvbk5hbWUpKQ0KYGBgDQoqKkNyZWFyIHVuIHZlY3RvciB5IHRyYXphcmxvKioNClVuIHZlY3RvciBhbG1hY2VuYSB2YWxvcmVzIGVuIHVuYSDDum5pY2EgZGltZW5zacOzbi4gUGFyYSBjcmVhciB1biB2ZWN0b3Igc2UgZW1wbGVhIGxhIGZ1bmNpw7NuIGMoKSANCmBgYHtyfQ0KYmlvZGl2IDwtIGMoYSxiLGMsZCxlLGYsZyxoLGksaixrKQ0KI1NlIGVzdMOhbiByZWxhY2lvbmFuZG8gbG9zIHZhbG9yZXMgZW4gZWwgbWlzbW8gb3JkZW4gZW4gZWwgY3VhbCBzZSBlc2NyaWJpZXJvbiBhbnRlcmlvcm1lbnRlLg0KbmFtZXMoYmlvZGl2KSA8LSBjKCJCZWV0bGUiLCAiQmlyZCIsICJCdXR0ZXJmbHkiLCAiRHJhZ29uZmx5IiwgIkZsb3dlcmluZy5QbGFudHMiLCAiRnVuZ3VzIiwgIkh5bWVub3B0ZXJhbiIsICJMaWNoZW4iLCAiTGl2ZXJ3b3J0IiwgIk1hbW1hbCIsICJNb2xsdXNjIikNCmBgYA0KQWhvcmEsIHNlIHB1ZWRlbiB2aXN1YWxpemFyIGxhIHJpcXVlemEgZGUgZXNwZWNpZXMgY29uIGxhIGZ1bmNpw7NuIGJhcnBsb3QoKS4NCkFsIGVqZWN1dGFyIGVzdGUgY8OzZGlnbywgYXBhcmVjZSBlbCBncsOhZmljbyBjb3JyZXNwb25kaWVudGUsIHNpbiBlbWJhcmdvLCBhw7puIGZhbHRhIGFncmVnYXJsZSBub21icmVzIGEgbG9zIGVqZXMgeSBwdWxpcmxvLiBQYXJhIHNhYmVyIHF1ZSBjb21hbmRvcyBlbXBsZWFyIHNlIHV0aWxpemEgbGEgZnVuY2nDs24gaGVscCgpLg0KYGBge3J9DQpoZWxwKGJhcnBsb3QpDQojUGFyYSBvYnRlbmVyIGF5dWRhIHPDs2xvIGNvbiBsYSBmdW5jacOzbiBiYXJwbG90Lg0KaGVscChwYXIpDQojUGFyYSB0ZW5lciBheXVkYSBjb24gZWwgdHJhemFkbyBlbiBnZW5lcmFsLg0KYGBgDQpQYXJhIHBvZGVyIG1vZGlmaWNhciBlbCBncsOhZmljbyBzZSBwdWVkZW4gZW1wbGVhciBkaXN0aW50b3MgY29tYW5kb3MgY29tbzoNCiAgICAgICAgLSp4bGFiKiB5ICp5bGFiKiBxdWUgcGVybWl0ZW4gbm9tYnJhciBsb3MgZWplcw0KICAgICAgICAtKmNleC5uYW1lcyogcXVlIHBlcm1pdGUgbW9kaWZpY2FyIGVsIHRhbWHDsW8gZGUgbGEgZnVlbnRlIGVuIGVsIGVqZSB4DQogICAgICAgIC0qY2V4LmF4aXMqIHF1ZSBtb2RpZmljYSBlbCB0YW1hw7FvIGRlIGZ1ZW50ZSBlbiBlbCBlamUgeQ0KICAgICAgICAtKmNleC5sYWIqIHF1ZSBtb2RpZmljYSBlbCB0YW1hw7FvIGRlIGZ1ZW50ZSBkZSBsb3MgdMOtdHVsb3MgZGUgbG9zIGVqZXMuDQpgYGB7cn0NCmJhcnBsb3QoYmlvZGl2KQ0KYmFycGxvdChiaW9kaXYsIHhsYWI9IlRheGEiLCB5bGFiPSJOdW1iZXIgb2Ygc3BlY2llcyIsIHlsaW09YygwLDYwMCksIGNleC5uYW1lcz0gMC40NSwgY2V4LmF4aXM9MC45LCBjZXgubGFiPTEuMCkNCmBgYA0KDQoqKkNyZWFyIHVuIG1hcmNvIGRlIGRhdG9zIHkgdHJhemFybG8qKg0KDQpFbiBlc3RhIHNlY2Npb25zZSBjcmVhcsOhbiB1bmEgc2VyaWUgZGUgdmFsb3JlcyBjb24gc3VzIHJlc3BlY3RpdmFzIGV0aXF1ZXRhcy4gUGFyYSBlbGxvLCBzZSB1dGlsaXphcmFuIG9iamV0b3MgZGVsIG1hcmNvIGRlIGRhdG9zLiBMb3MgbWFyY29zIGRlIGRhdG9zIHNvbiB0YWJsYXMgZGUgdmFsb3JlcyBjb24gY29sdW1uYXMgeSBmaWxhcy4NClBhcmEgZWxsbywgc2UgY3JlYXLDoSB1biBvYmpldG8gcXVlIGNvbnRlbmdhIHRvZG9zIGxvcyBub21icmVzIGRlIGxvcyB0YXhvbmVzIHkgb3RybyBjb24gbG9zIHZhbG9yZXMgZGUgcmlxdWV6YSBkZSBsYXMgZXNwZWNpZXMgZGUgY2FkYSB0YXjDs24uIEx1ZWdvLCBzZSB1c2Fyw6EgbGEgZnVuY2nDs24gZGF0YS5mcmFtZSgpDQoNClBhcmEgY3JlYXIgdW4gb2JqZXRvIGxsYW1hZG8gInRheGEiIGNvbiB0b2RvcyBsb3Mgbm9tYnJlcyBkZWwgY29uanVudG86DQoNCmBgYHtyfQ0KdGF4YSA8LSBjKCJCZWV0bGUiLCAiQmlyZCIsICJCdXR0ZXJmbHkiLCJEcmFnb25mbHkiLCJGbG93ZXJpbmcuUGxhbnRzIiwgIkZ1bmd1cyIsICJIeW1lbm9wdGVyYW4iLCAiTGljaGVuIiwgIkxpdmVyd29ydCIsICJNYW1tYWwiLCAiTW9sbHVzYyIpDQpgYGANClBhcmEgY29udmVydGlyIGVsIG9iamV0byBlbiB1biBmYWN0b3I6DQpgYGB7cn0NCnRheGFfZiA8LSBmYWN0b3IodGF4YSkNCmBgYA0KUGFyYSBjb21iaW5hciB0b2RvcyBsb3MgdmFsb3JlcyBlbiBlbCBuw7ptZXJvIGRlIGVzcGVjaWVzICJyaWNobmVzcyINCmBgYHtyfQ0KcmljaG5lc3MgPC0gYyhhLGIsYyxkLGUsZixnLGgsaSxqLGspDQpgYGANClBhcmEgY3JlYXIgdW4gbWFyY28gZGUgZGF0b3MgYSBwYXJ0aXIgZGUgZG9zIHZlY3RvcmVzOg0KYGBge3J9DQpiaW9kYXRhIDwtIGRhdGEuZnJhbWUodGF4YV9mLCByaWNobmVzcykNCmBgYA0KUGFyYSBndWFyZGFyIGVsIGFyY2hpdm8gZW4gZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvOg0KYGBge3J9DQp3cml0ZS5jc3YoYmlvZGF0YSwgZmlsZSA9ImJpb2RhdGEuY3N2IikNCmBgYA0KRW4gY2FzbyBkZSBxdWUgc2UgcXVpZXJhbiBjcmVhciB5IGd1YXJkYXIgZGlhZ3JhbWFzIGRlIGJhcnJhc2VtcGxlYW5kbyBzw7NsbyBlbCBtYXJjbyBkZSBkYXRvcywgc2UgbmVjZXNpdGEgY2FtYmlhciB1biBwb2NvIGVsIGPDs2RpZ28uDQpgYGB7cn0NCnBuZygiYmFycGxvdDIucG5nIiwgd2lkdGg9MTYwMCwgaGVpZ2h0PTYwMCkNCmJhcnBsb3QoYmlvZGF0YSRyaWNobmVzcywgbmFtZXMuYXJnPWMoIkJlZXRsZSIsICJCaXJkIiwgIkJ1dHRlcmZseSIsICJEcmFnb25mbHkiLCAiRmxvd2VyaW5nLlBsYW50cyIsICJGdW5ndXMiLCAiSHltZW5vcHRlcmFuIiwgIkxpY2hlbiIsICJMaXZlcndvcnQiLCAiTWFtbWFsIiwgIk1vbGx1c2MiKSwNCnhsYWI9IlRheGEiLCB5bGFiPSJOdW1iZXIgb2Ygc3BlY2llcyIsIHlsaW09YygwLDYwMCkpDQpkZXYub2ZmKCkNCmBgYA0KDQoNCg==