1. ¿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.

2. 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.

3. Paquetes de R

Un paquete es un conjunto de comandos empleados para una función específica; por este motivo, son fundamentales al momento de usar este pograma estadístico. Para instalarlos, se usa el comando install.packages().

En este primer cuaderno, se empleará el paquete “dplyr”:

install.packages("package-name")
install.packages("dplyr")

Para poder emplear el paquete es necesario ejecutarlo con el comando library():

library(dplyr)
library(package-name)

4. Directorio de trabajo

El directorio de trabajo se define como una carpeta que será consultada por el programa para identificarlos datos y documentos que pueden emplearse. La ubicación del directorio de trabajo puede conocerse a traves del comando getwd():

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")

5. Importar y verificar datos

Para realizar esta práctica es necesario descargar los registros entre 2000-2016 de NBN Gateway que contiene información acerca de las distintas especies de animales, plantas y hongos. Este archivo se guardará como edidiv.csv para posteriormente ser leído mediante el comando read.csv():

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

Otra opción para ejecutar dicha orden, es a través de las herramientas de la consola.

6. ¿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.

A continuación, se va a usar la función head() que nos permite ver las primeras filas del archivo en cuestión:

head(edidiv)

El comando tail() por otro lado, muestra las últimas filas del archivo:

tail(edidiv)

La opción str() perite conocer que tipo de variable se esta trabajando (continuas, enteras, categóricas o caracteres).

str(edidiv)
'data.frame':   25684 obs. of  5 variables:
 $ organisationName: chr  "Joint Nature Conservation Committee" "Joint Nature Conservation Committee" "Joint Nature Conservation Committee" "British Trust for Ornithology" ...
 $ gridReference   : chr  "NT265775" "NT235775" "NT235775" "NT27" ...
 $ year            : int  2000 2000 2000 2000 2000 2001 2001 2001 2001 2001 ...
 $ taxonName       : chr  "Sterna hirundo" "Sterna hirundo" "Sterna paradisaea" "Branta canadensis" ...
 $ taxonGroup      : chr  "Bird" "Bird" "Bird" "Bird" ...

Para mirar la estructura de los datos se usa el comando str(object.name). Sin embargo, es posible cambiar la estructura de una orma muy sencila que será descrita a continuación:

  1. 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"

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

class(edidiv$taxonGroup)
[1] "character"
  1. Se usa el comando as_factor() para convertir cualquier valor colocado en un factor:
edidiv$taxonGroup <- as.factor(edidiv$taxonGroup)

Existen otros comandos que pueden ser útiles en distintos casos. Por ejemplo, el comando dim() permite ver el número de columnas y filas:

dim(edidiv)
[1] 25684     5

Por otro lado, summary() nos permite obtner un resumen de los datos:

summary(edidiv)
 organisationName   gridReference           year       taxonName        
 Length:25684       Length:25684       Min.   :2000   Length:25684      
 Class :character   Class :character   1st Qu.:2006   Class :character  
 Mode  :character   Mode  :character   Median :2009   Mode  :character  
                                       Mean   :2009                     
                                       3rd Qu.:2011                     
                                       Max.   :2016                     
                                                                        
            taxonGroup  
 Butterfly       :9670  
 Bird            :7366  
 Flowering.Plants:2625  
 Mollusc         :2226  
 Hymenopteran    :1391  
 Mammal          : 960  
 (Other)         :1446  

Por último, el comando summary(-$-) nos permite tener un resumen de una variable en particular:

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

7. 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")
Dragonfly <- filter(edidiv, taxonGroup == "Dragonfly")
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 usará la función unique() para identificar las diferentes especies. A su vez, se empleará la función length() para contar las especies:

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

8. 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)

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

9. 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()
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQojIyMgMS4gwr9RdcOpIGVzIFI/DQoNClIgZXMgdW4gbGVuZ3VhamUgZGUgcHJvZ3JhbWFjacOzbiBlc3RhZMOtc3RpY2EgZW1wbGVhZG8gZW4gZ3JhbiB2YXJpZWRhZCBkZSBkaXNjaXBsaW5hcyBhdW5xdWUgdGFtYmnDqW4gZXMgZWwgbm9tYnJlIGRlIHVuIHNvZnR3YXJlIHF1ZSBlbXBsZWEgZXN0ZSBtaXNtbyBsZW5ndWFqZS4NCg0KIyMjIDIuIENvbWVuemFuZG8gYSBlc2NyaWJpcg0KDQpFc3RlIGN1YWRlcm5vIHNlIGRlc2Fycm9sbGEgcGFyYSBsYSBhc2lnbmF0dXJhIGRlIEdlb23DoXRpY2EgQsOhc2ljYSB5IGNvcnJlc3BvbmRlIGEgdW5hIGJyZXZlIGludHJvZHVjY2nDs24gYSBSIHkgc3VzIGZ1bmNpb25lcyBiw6FzaWNhcy4gRWwgZG9jdW1lbnRvIGZ1ZSByZWFsaXphZG8gcG9yIEx1aXNhIEZlcm5hbmRhIENhcnJpw7NuIFJhbcOtcmV6Lg0KDQojIyMgMy4gUGFxdWV0ZXMgZGUgUg0KDQpVbiBwYXF1ZXRlIGVzIHVuIGNvbmp1bnRvIGRlIGNvbWFuZG9zIGVtcGxlYWRvcyBwYXJhIHVuYSBmdW5jacOzbiBlc3BlY8OtZmljYTsgcG9yIGVzdGUgbW90aXZvLCBzb24gZnVuZGFtZW50YWxlcyBhbCBtb21lbnRvIGRlIHVzYXIgZXN0ZSBwb2dyYW1hIGVzdGFkw61zdGljby4gUGFyYSBpbnN0YWxhcmxvcywgc2UgdXNhIGVsIGNvbWFuZG8gKmluc3RhbGwucGFja2FnZXMoKSouIA0KDQpFbiBlc3RlIHByaW1lciBjdWFkZXJubywgc2UgZW1wbGVhcsOhIGVsIHBhcXVldGUgImRwbHlyIjogDQoNCmBgYHtyfQ0KaW5zdGFsbC5wYWNrYWdlcygicGFja2FnZS1uYW1lIikNCmluc3RhbGwucGFja2FnZXMoImRwbHlyIikNCmBgYA0KDQpQYXJhIHBvZGVyIGVtcGxlYXIgZWwgcGFxdWV0ZSBlcyBuZWNlc2FyaW8gZWplY3V0YXJsbyBjb24gZWwgY29tYW5kbyAqbGlicmFyeSgpKjoNCg0KYGBge3J9DQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShwYWNrYWdlLW5hbWUpDQpgYGANCg0KIyMjIDQuIERpcmVjdG9yaW8gZGUgdHJhYmFqbw0KDQpFbCBkaXJlY3RvcmlvIGRlIHRyYWJham8gc2UgZGVmaW5lIGNvbW8gdW5hIGNhcnBldGEgcXVlIHNlcsOhIGNvbnN1bHRhZGEgcG9yIGVsIHByb2dyYW1hIHBhcmEgaWRlbnRpZmljYXJsb3MgZGF0b3MgeSBkb2N1bWVudG9zIHF1ZSBwdWVkZW4gZW1wbGVhcnNlLiBMYSB1YmljYWNpw7NuIGRlbCBkaXJlY3RvcmlvIGRlIHRyYWJham8gcHVlZGUgY29ub2NlcnNlIGEgdHJhdmVzIGRlbCBjb21hbmRvICpnZXR3ZCgpKjoNCg0KYGBge3J9DQpnZXR3ZCgpDQpgYGANCg0KRW4gY2FzbyBkZSBxdWUgc2UgcXVpZXJhIGNhbWJpYXIgZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvLCBzZSB1c2EgbGEgZnVuY2lvbiBzZXR3ZCgpDQoNCmBgYHtyfQ0Kc2V0d2QoIkM6L1VzZXJzL0xVSVNBIENBUlJJT04vRG9jdW1lbnRzIikNCmBgYA0KDQojIyMgNS4gSW1wb3J0YXIgeSB2ZXJpZmljYXIgZGF0b3MNCg0KUGFyYSByZWFsaXphciBlc3RhIHByw6FjdGljYSBlcyBuZWNlc2FyaW8gZGVzY2FyZ2FyIGxvcyByZWdpc3Ryb3MgZW50cmUgMjAwMC0yMDE2IGRlIE5CTiBHYXRld2F5IHF1ZSBjb250aWVuZSBpbmZvcm1hY2nDs24gYWNlcmNhIGRlIGxhcyBkaXN0aW50YXMgZXNwZWNpZXMgZGUgYW5pbWFsZXMsIHBsYW50YXMgeSBob25nb3MuIEVzdGUgYXJjaGl2byBzZSBndWFyZGFyw6EgY29tbyAqZWRpZGl2LmNzdiogcGFyYSBwb3N0ZXJpb3JtZW50ZSBzZXIgbGXDrWRvIG1lZGlhbnRlIGVsIGNvbWFuZG8gKnJlYWQuY3N2KCkqOg0KDQpgYGB7cn0NCmVkaWRpdiA8LSByZWFkLmNzdigiQzovVXNlcnMvTFVJU0EgQ0FSUklPTi9Eb3dubG9hZHMvQ0MtUkJhc2ljcy1tYXN0ZXIvQ0MtUkJhc2ljcy1tYXN0ZXIvZWRpZGl2LmNzdiIpDQpgYGANCg0KT3RyYSBvcGNpw7NuIHBhcmEgZWplY3V0YXIgZGljaGEgb3JkZW4sIGVzIGEgdHJhdsOpcyBkZSBsYXMgaGVycmFtaWVudGFzIGRlIGxhIGNvbnNvbGEuDQoNCiMjIyA2LiDCv0PDs21vIHNhYmVyIHNpIHNlIGhhbiBjb21ldGlkbyBlcnJvcmVzIGVuIGxvcyBjw7NkaWdvcz8NCg0KQ29tZXRlciBlcnJvcmVzIGVuIFIgZXMgbXV5IGZyZWN1ZW50ZSwgZXMgcG9yIGVsbG8gcXVlIHNlIHJlY29taWVuZGEgZWplY3V0YXIgZWwgY8OzZGlnbyB5IHZlcmlmaWNhciBsYSBzYWxpZGEgZW4gbGEgY29uc29sYS4gU2luIGVtYmFyZ28sIGV4aXN0ZW4gb3RyYXMgaGVycmFtaWVudGFzIHF1ZSBub3MgcGVybWl0ZW4gdGVuZXIgdW5hIHZpc3RhIHByZXZpYSBkZSB1bmFzIHBvY2FzIGzDrW5lYXMuDQoNCkEgY29udGludWFjacOzbiwgc2UgdmEgYSB1c2FyIGxhIGZ1bmNpw7NuICpoZWFkKCkqIHF1ZSBub3MgcGVybWl0ZSB2ZXIgbGFzIHByaW1lcmFzIGZpbGFzIGRlbCBhcmNoaXZvIGVuIGN1ZXN0acOzbjoNCg0KYGBge3J9DQpoZWFkKGVkaWRpdikNCmBgYA0KDQpFbCBjb21hbmRvICp0YWlsKCkqIHBvciBvdHJvIGxhZG8sIG11ZXN0cmEgbGFzIMO6bHRpbWFzIGZpbGFzIGRlbCBhcmNoaXZvOg0KDQpgYGB7cn0NCnRhaWwoZWRpZGl2KQ0KYGBgDQoNCkxhIG9wY2nDs24gKnN0cigpKiBwZXJpdGUgY29ub2NlciBxdWUgdGlwbyBkZSB2YXJpYWJsZSBzZSBlc3RhIHRyYWJhamFuZG8gKGNvbnRpbnVhcywgZW50ZXJhcywgY2F0ZWfDs3JpY2FzIG8gY2FyYWN0ZXJlcykuDQoNCmBgYHtyfQ0Kc3RyKGVkaWRpdikNCmBgYA0KUGFyYSBtaXJhciBsYSBlc3RydWN0dXJhIGRlIGxvcyBkYXRvcyBzZSB1c2EgZWwgY29tYW5kbyBzdHIob2JqZWN0Lm5hbWUpLiBTaW4gZW1iYXJnbywgZXMgcG9zaWJsZSBjYW1iaWFyIGxhIGVzdHJ1Y3R1cmEgZGUgdW5hIG9ybWEgbXV5IHNlbmNpbGEgcXVlIHNlcsOhIGRlc2NyaXRhIGEgY29udGludWFjacOzbjoNCg0KYS4gU2UgZW1wbGVhIGVsIGPDs2dpZ28gaGVhZChub21icmUgZGVsIGFyY2hpdm8kZ3J1cG8pIHBhcmEgdmVyIGxhcyBwcmltZXJhcyBmaWxhcyBkZSBsYSBjb2x1bW5hIGVuIGVzdGEgY2xhc2U6DQoNCmBgYHtyfQ0KaGVhZChlZGlkaXYkdGF4b25Hcm91cCkNCmBgYA0KIA0KYi5TZSB1c2EgY2xhc3Mobm9tYnJlIGRlbCBhcmNoaXZvJGdydXBvKSBwYXJhIHNhYmVyIGNvbiBxdWUgdGlwbyBkZSB2YXJpYWJsZSBzZSBlc3TDoSB0cmFiYWphbmRvOg0KDQpgYGB7cn0NCmNsYXNzKGVkaWRpdiR0YXhvbkdyb3VwKQ0KYGBgDQpjLiBTZSB1c2EgZWwgY29tYW5kbyAqYXNfZmFjdG9yKCkqIHBhcmEgY29udmVydGlyIGN1YWxxdWllciB2YWxvciBjb2xvY2FkbyBlbiB1biBmYWN0b3I6DQoNCmBgYHtyfQ0KZWRpZGl2JHRheG9uR3JvdXAgPC0gYXMuZmFjdG9yKGVkaWRpdiR0YXhvbkdyb3VwKQ0KYGBgDQoNCkV4aXN0ZW4gb3Ryb3MgY29tYW5kb3MgcXVlIHB1ZWRlbiBzZXIgw7p0aWxlcyBlbiBkaXN0aW50b3MgY2Fzb3MuIFBvciBlamVtcGxvLCBlbCBjb21hbmRvICpkaW0oKSogcGVybWl0ZSB2ZXIgZWwgbsO6bWVybyBkZSBjb2x1bW5hcyB5IGZpbGFzOg0KDQpgYGB7cn0NCmRpbShlZGlkaXYpDQpgYGANClBvciBvdHJvIGxhZG8sICpzdW1tYXJ5KCkqIG5vcyBwZXJtaXRlIG9idG5lciB1biByZXN1bWVuIGRlIGxvcyBkYXRvczoNCg0KYGBge3J9DQpzdW1tYXJ5KGVkaWRpdikNCmBgYA0KDQpQb3Igw7psdGltbywgZWwgY29tYW5kbyAqc3VtbWFyeSgtJC0pKiBub3MgcGVybWl0ZSB0ZW5lciB1biByZXN1bWVuIGRlIHVuYSB2YXJpYWJsZSBlbiBwYXJ0aWN1bGFyOg0KDQpgYGB7cn0NCnN1bW1hcnkoZWRpZGl2JHRheG9uR3JvdXApDQpgYGANCiMjIyA3LiBDYWxjdWxhciBsYSByaXF1ZXphIGVuIGVzcGVjaWVzDQoNCkxhIHJpcXVlemEgZGUgZXNwZWNpZXMgZXMgZWwgbsO6bWVybyB0b3RhbCBkZSBlc3BlY2llcyBkaWZlcmVudGVzIGVuIHVuIGx1Z2FyLiBQYXJhIHNhYmVyIGN1w6FudGFzIGVzcGVjaWVzIHNlIHRpZW5lbiBkZSBtYW3DrWZlcm9zLCBhdmVzLCBwbGFudGFzLCBlbnRyZSBvdHJvcywgc2UgZGViZSBkaXZpZGlyIGxhIGJhc2UgZGUgZGF0b3MgZWRpZGl2IGVuIHZhcmlvcyBncnVwb3MgdXRpbGl6YW5kbyBsYSBmdW5jacOzbiAqZmlsdGVyKCkqDQoNCmBgYHtyfQ0KQmVldGxlIDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkJlZXRsZSIpDQpCaXJkIDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkJpcmQiKQ0KQnV0dGVyZmx5IDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkJ1dHRlcmZseSIpDQpEcmFnb25mbHkgPC0gZmlsdGVyKGVkaWRpdiwgdGF4b25Hcm91cCA9PSAiRHJhZ29uZmx5IikNCkZsb3dlcmluZy5QbGFudHMgPC0gZmlsdGVyKGVkaWRpdiwgdGF4b25Hcm91cCA9PSAiRmxvd2VyaW5nLlBsYW50cyIpDQpGdW5ndXMgPC0gZmlsdGVyKGVkaWRpdiwgdGF4b25Hcm91cCA9PSAiRnVuZ3VzIikNCkh5bWVub3B0ZXJhbiA8LSBmaWx0ZXIoZWRpZGl2LCB0YXhvbkdyb3VwID09ICJIeW1lbm9wdGVyYW4iKQ0KTGljaGVuIDwtIGZpbHRlcihlZGlkaXYsIHRheG9uR3JvdXAgPT0gIkxpY2hlbiIpDQpMaXZlcndvcnQgPC0gZmlsdGVyKGVkaWRpdiwgdGF4b25Hcm91cCA9PSAiTGl2ZXJ3b3J0IikNCk1hbW1hbCA8LSBmaWx0ZXIoZWRpZGl2LCB0YXhvbkdyb3VwID09ICJNYW1tYWwiKQ0KTW9sbHVzYyA8LSBmaWx0ZXIoZWRpZGl2LCB0YXhvbkdyb3VwID09ICJNb2xsdXNjIikNCmBgYA0KDQpBaG9yYSwgc2UgdXNhcsOhIGxhIGZ1bmNpw7NuICp1bmlxdWUoKSogcGFyYSBpZGVudGlmaWNhciBsYXMgZGlmZXJlbnRlcyBlc3BlY2llcy4gQSBzdSB2ZXosIHNlIGVtcGxlYXLDoSBsYSBmdW5jacOzbiAqbGVuZ3RoKCkqIHBhcmEgY29udGFyIGxhcyBlc3BlY2llczoNCg0KYGBge3J9DQphIDwtIGxlbmd0aCh1bmlxdWUoQmVldGxlJHRheG9uTmFtZSkpDQpiIDwtIGxlbmd0aCh1bmlxdWUoQmlyZCR0YXhvbk5hbWUpKQ0KYyA8LSBsZW5ndGgodW5pcXVlKEJ1dHRlcmZseSR0YXhvbk5hbWUpKQ0KZCA8LSBsZW5ndGgodW5pcXVlKERyYWdvbmZseSR0YXhvbk5hbWUpKQ0KZSA8LSBsZW5ndGgodW5pcXVlKEZsb3dlcmluZy5QbGFudHMkdGF4b25OYW1lKSkNCmYgPC0gbGVuZ3RoKHVuaXF1ZShGdW5ndXMkdGF4b25OYW1lKSkNCmcgPC0gbGVuZ3RoKHVuaXF1ZShIeW1lbm9wdGVyYW4kdGF4b25OYW1lKSkNCmggPC0gbGVuZ3RoKHVuaXF1ZShMaWNoZW4kdGF4b25OYW1lKSkNCmkgPC0gbGVuZ3RoKHVuaXF1ZShMaXZlcndvcnQkdGF4b25OYW1lKSkNCmogPC0gbGVuZ3RoKHVuaXF1ZShNYW1tYWwkdGF4b25OYW1lKSkNCmsgPC0gbGVuZ3RoKHVuaXF1ZShNb2xsdXNjJHRheG9uTmFtZSkpDQpgYGANCg0KIyMjIDguIENyZWFyIHVuIHZlY3RvciB5IHRyYXphcmxvIA0KDQpVbiB2ZWN0b3IgYWxtYWNlbmEgdmFsb3JlcyBlbiB1bmEgw7puaWNhIGRpbWVuc2nDs24uIFBhcmEgY3JlYXIgdW4gdmVjdG9yIHNlIGVtcGxlYSBsYSBmdW5jacOzbiBjKCkNCg0KYGBge3J9DQpiaW9kaXYgPC0gYyhhLGIsYyxkLGUsZixnLGgsaSxqLGspDQojU2UgZXN0w6FuIHJlbGFjaW9uYW5kbyBsb3MgdmFsb3JlcyBlbiBlbCBtaXNtbyBvcmRlbiBlbiBlbCBjdWFsIHNlIGVzY3JpYmllcm9uIGFudGVyaW9ybWVudGUuDQpuYW1lcyhiaW9kaXYpIDwtIGMoIkJlZXRsZSIsICJCaXJkIiwgIkJ1dHRlcmZseSIsICJEcmFnb25mbHkiLCAiRmxvd2VyaW5nLlBsYW50cyIsICJGdW5ndXMiLCAiSHltZW5vcHRlcmFuIiwgIkxpY2hlbiIsICJMaXZlcndvcnQiLCAiTWFtbWFsIiwgIk1vbGx1c2MiKQ0KYGBgDQoNCkFob3JhLCBzZSBwdWVkZW4gdmlzdWFsaXphciBsYSByaXF1ZXphIGRlIGVzcGVjaWVzIGNvbiBsYSBmdW5jacOzbiBiYXJwbG90KCkuIEFsIGVqZWN1dGFyIGVzdGUgY8OzZGlnbywgYXBhcmVjZSBlbCBncsOhZmljbyBjb3JyZXNwb25kaWVudGUsIHNpbiBlbWJhcmdvLCBhw7puIGZhbHRhIGFncmVnYXJsZSBub21icmVzIGEgbG9zIGVqZXMgeSBwdWxpcmxvLiBQYXJhIHNhYmVyIHF1ZSBjb21hbmRvcyBlbXBsZWFyIHNlIHV0aWxpemEgbGEgZnVuY2nDs24gaGVscCgpLg0KDQpgYGB7cn0NCmhlbHAoYmFycGxvdCkNCiNQYXJhIG9idGVuZXIgYXl1ZGEgc8OzbG8gY29uIGxhIGZ1bmNpw7NuIGJhcnBsb3QuDQpoZWxwKHBhcikNCiNQYXJhIHRlbmVyIGF5dWRhIGNvbiBlbCB0cmF6YWRvIGVuIGdlbmVyYWwuDQpgYGANCg0KUGFyYSBwb2RlciBtb2RpZmljYXIgZWwgZ3LDoWZpY28gc2UgcHVlZGVuIGVtcGxlYXIgZGlzdGludG9zIGNvbWFuZG9zIGNvbW86IC14bGFiIHkgeWxhYiBxdWUgcGVybWl0ZW4gbm9tYnJhciBsb3MgZWplcyAtY2V4Lm5hbWVzIHF1ZSBwZXJtaXRlIG1vZGlmaWNhciBlbCB0YW1hw7FvIGRlIGxhIGZ1ZW50ZSBlbiBlbCBlamUgeCAtY2V4LmF4aXMgcXVlIG1vZGlmaWNhIGVsIHRhbWHDsW8gZGUgZnVlbnRlIGVuIGVsIGVqZSB5IC1jZXgubGFiIHF1ZSBtb2RpZmljYSBlbCB0YW1hw7FvIGRlIGZ1ZW50ZSBkZSBsb3MgdMOtdHVsb3MgZGUgbG9zIGVqZXMuDQoNCmBgYHtyfQ0KYmFycGxvdChiaW9kaXYpDQpgYGANCg0KYGBge3J9DQpiYXJwbG90KGJpb2RpdiwgeGxhYj0iVGF4YSIsIHlsYWI9Ik51bWJlciBvZiBzcGVjaWVzIiwgeWxpbT1jKDAsNjAwKSwgY2V4Lm5hbWVzPSAwLjQ1LCBjZXguYXhpcz0wLjksIGNleC5sYWI9MS4wKQ0KYGBgDQoNCmBgYHtyfQ0KYmFycGxvdChiaW9kaXYsIHhsYWI9IlRheGEiLCB5bGFiPSJOdW1iZXIgb2Ygc3BlY2llcyIsIHlsaW09YygwLDYwMCksIGNleC5uYW1lcz0gMC40NSwgY2V4LmF4aXM9MC45LCBjZXgubGFiPTEuMCwgY29sPWMoInBpbmsiLCJsaWdodGJsdWUiKSkNCmBgYA0KIyMjIDkuIENyZWFyIHVuIG1hcmNvIGRlIGRhdG9zIHkgdHJhemFybG8NCg0KRW4gZXN0YSBzZWNjaW9uc2UgY3JlYXLDoW4gdW5hIHNlcmllIGRlIHZhbG9yZXMgY29uIHN1cyByZXNwZWN0aXZhcyBldGlxdWV0YXMuIFBhcmEgZWxsbywgc2UgdXRpbGl6YXJhbiBvYmpldG9zIGRlbCBtYXJjbyBkZSBkYXRvcy4gTG9zIG1hcmNvcyBkZSBkYXRvcyBzb24gdGFibGFzIGRlIHZhbG9yZXMgY29uIGNvbHVtbmFzIHkgZmlsYXMuIFBhcmEgZWxsbywgc2UgY3JlYXLDoSB1biBvYmpldG8gcXVlIGNvbnRlbmdhIHRvZG9zIGxvcyBub21icmVzIGRlIGxvcyB0YXhvbmVzIHkgb3RybyBjb24gbG9zIHZhbG9yZXMgZGUgcmlxdWV6YSBkZSBsYXMgZXNwZWNpZXMgZGUgY2FkYSB0YXjDs24uIEx1ZWdvLCBzZSB1c2Fyw6EgbGEgZnVuY2nDs24gZGF0YS5mcmFtZSgpDQoNClBhcmEgY3JlYXIgdW4gb2JqZXRvIGxsYW1hZG8g4oCcdGF4YeKAnSBjb24gdG9kb3MgbG9zIG5vbWJyZXMgZGVsIGNvbmp1bnRvOg0KDQpgYGB7cn0NCnRheGEgPC0gYygiQmVldGxlIiwgIkJpcmQiLCAiQnV0dGVyZmx5IiwiRHJhZ29uZmx5IiwiRmxvd2VyaW5nLlBsYW50cyIsICJGdW5ndXMiLCAiSHltZW5vcHRlcmFuIiwgIkxpY2hlbiIsICJMaXZlcndvcnQiLCAiTWFtbWFsIiwgIk1vbGx1c2MiKQ0KYGBgDQoNClBhcmEgY29udmVydGlyIGVsIG9iamV0byBlbiB1biBmYWN0b3I6DQoNCmBgYHtyfQ0KdGF4YV9mIDwtIGZhY3Rvcih0YXhhKQ0KYGBgDQoNClBhcmEgY29tYmluYXIgdG9kb3MgbG9zIHZhbG9yZXMgZW4gZWwgbsO6bWVybyBkZSBlc3BlY2llcyDigJxyaWNobmVzc+KAnQ0KDQpgYGB7cn0NCnJpY2huZXNzIDwtIGMoYSxiLGMsZCxlLGYsZyxoLGksaixrKQ0KYGBgDQoNClBhcmEgY3JlYXIgdW4gbWFyY28gZGUgZGF0b3MgYSBwYXJ0aXIgZGUgZG9zIHZlY3RvcmVzOg0KDQpgYGB7cn0NCmJpb2RhdGEgPC0gZGF0YS5mcmFtZSh0YXhhX2YsIHJpY2huZXNzKQ0KYGBgDQoNClBhcmEgZ3VhcmRhciBlbCBhcmNoaXZvIGVuIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbzoNCg0KYGBge3J9DQp3cml0ZS5jc3YoYmlvZGF0YSwgZmlsZSA9ImJpb2RhdGEuY3N2IikNCmBgYA0KDQpFbiBjYXNvIGRlIHF1ZSBzZSBxdWllcmFuIGNyZWFyIHkgZ3VhcmRhciBkaWFncmFtYXMgZGUgYmFycmFzZW1wbGVhbmRvIHPDs2xvIGVsIG1hcmNvIGRlIGRhdG9zLCBzZSBuZWNlc2l0YSBjYW1iaWFyIHVuIHBvY28gZWwgY8OzZGlnby4NCg0KYGBge3J9DQpwbmcoImJhcnBsb3QyLnBuZyIsIHdpZHRoPTE2MDAsIGhlaWdodD02MDApDQpiYXJwbG90KGJpb2RhdGEkcmljaG5lc3MsIG5hbWVzLmFyZz1jKCJCZWV0bGUiLCAiQmlyZCIsICJCdXR0ZXJmbHkiLCAiRHJhZ29uZmx5IiwgIkZsb3dlcmluZy5QbGFudHMiLCAiRnVuZ3VzIiwgIkh5bWVub3B0ZXJhbiIsICJMaWNoZW4iLCAiTGl2ZXJ3b3J0IiwgIk1hbW1hbCIsICJNb2xsdXNjIiksDQp4bGFiPSJUYXhhIiwgeWxhYj0iTnVtYmVyIG9mIHNwZWNpZXMiLCB5bGltPWMoMCw2MDApKQ0KZGV2Lm9mZigpDQpgYGANCg0K