Descripción del programa

¿Que es R?

  • Lenguaje de Análisis de Datos
  • Software Libre
  • Sintaxis Básica: R base
  • Sintaxis incremental1: El lenguaje se va ampliando por aportes de Universidades, investigadores y empresas privadas, organizados en librerías (o paquetes)
  • Comunidad web muy grande para realizar preguntas y despejar dudas.

El entorno más cómodo para utilizar el lenguaje R es el programa R studio

  • Rstudio es una empresa que produce productos asociados al lenguaje R, como el programa sobre el que corremos los comandos, y extensiones del lenguaje (librerías).

  • El programa es gratuito y se puede bajar de la página oficial

Pantalla Rstudio

Pantalla Rstudio

Lógica sintáctica

Definición de objetos

El operador <- sirve para definir un elemento. A la izquierda del <- debe ubicarse el nombre que tomará el elemento a crear. Del lado derecho debe ir la definición del mismo

A <- 1

Al definir un elemento, el mismo queda guardado en el ambiente del programa, y podrá ser utilizado posteriormente para observar su contenido o para realizar una operación con el mismo

A 
[1] 1

Al correr una linea con el nombre del objeto, la consola del programa nos muestra su contenido. Entre Corchetes Observamos el número de orden del elemento en cuestión

El operador = es equivalente a <-, pero en la práctica no se utiliza para la definición de objetos.

B = 2
B
[1] 2

<- es un operador Unidireccional, es decir que:
A <- B implica que A va tomar como valor el contenido del objeto B, y no al revés.

A <- B
A   #Ahora A toma el valor de B, y B continua conservando el mismo valor
[1] 2
B
[1] 2

R base

Con R base nos referimos a los comandos básicos que vienen incorporados en el R, sin necesidad de cargar librerías.

Operadores lógicos:

  • \(>\)
  • \(>=\)
  • \(<\)
  • \(<=\)
  • \(==\)
  • \(!=\)
A = 1
B = 2
A >  B
[1] FALSE
A >= B
[1] FALSE
A <  B
[1] TRUE
A <= B
[1] TRUE
A == B
[1] FALSE
A != B
[1] TRUE
C <- A != B
C
[1] TRUE

Como muestra el último ejemplo, el resultado de una operación lógica puede almacenarse como el valor de un objeto.

Operadores aritméticos:

#suma
A <- 5+6
A
[1] 11
#Resta
B <- 6-8
B
[1] -2
#cociente
C <- 6/2.5
C
[1] 2.4
#multiplicacion
D <- 6*2.5
D
[1] 15
# Modulo
E <- 7%%2
E
[1] 1

Caracteres especiales

  • R es sensible a mayúsculas y minúsculas, tanto para los nombres de las variables, como para las funciones y parámetros.
  • Los espacios en blanco y los carriage return (enter) no son considerados por el lenguaje. Los podemos aprovechar para emprolijar el código y que la lectura sea más simple2.
  • El numeral # se utiliza para hacer comentarios. Todo lo que se escribe después del # no es interpretado por R. Se debe utilizar un # por cada línea de código que se desea anular. SHORTCUT: En R-Studio se puede seleccionar todo un bloque de texto y comentarlo completo apretando CTRL+SHIFT+C

  • Los corchetes [] se utilizan para acceder a un objeto:
    • en un vector[n° orden]
    • en una matriz[fila, columna]
    • en una lista[n° elemento]
  • el signo $ también es un método de acceso, que permite llamar al elemento por su nombre, en dataframes y listas.

  • Los paréntesis() se utilizan en las funciones para definir los parámetros.

  • Las comas , se utilizan para separar los elementos.

Ejemplo: si queremos definir al elemento de la fila 2 y columna 3 de una tabla como el resultado de una funcion con parámetros A=a, B=b y C=c, diremos:

tabla[2,3] <- funcion(A=a, B=b, C=c)

Tipos de datos y estructuras de datos:

Los tipos de datos son una clase de valores que se pueden construir para representar información. Las estructuras de datos son formas de representar y guardar información

Tipos de datos

Los datos tienen distintos tipos:

  • El comando class() identifica el tipo de un objeto desde una perspectiva de programación orientada a objetos en R. Podemos redifinir la clase de un objeto
  • El comando type() identifica el tipo de un objeto según el lenguaje R. No podemos modificar el tipo de un objeto

Numeric

A <- 1
class(A)   
[1] "numeric"
typeof(A)
[1] "double"

Tratemos de cambiar la clase y el tipo de nuestro objeto

class(A) <- "nueva_clase"
class(A)
[1] "nueva_clase"
typeof(A) <- "nuevo_tipo"
Error in typeof(A) <- "nuevo_tipo" : could not find function "typeof<-"

Integer

A <- 1L
A
[1] 1
class(A)   
[1] "integer"
typeof(A)
[1] "integer"

Complex

A <- 2+2i
A
[1] 2+2i
class(A)   
[1] "complex"
typeof(A)
[1] "complex"

Character

A <-  paste('Soy', 'una', 'concatenación', 'de', 'caracteres', sep = " ")
A
[1] "Soy una concatenación de caracteres"
class(A)
[1] "character"
typeof(A)
[1] "character"

Factor

A <- factor("Soy un factor con niveles fijos")
A
[1] Soy un factor con niveles fijos
Levels: Soy un factor con niveles fijos
class(A)
[1] "factor"
typeof(A)
[1] "integer"

La diferencia entre un character y un factor es que el último tiene solo algunos valores permitidos (levels), y se le puede dar un orden

A <- factor(c("R","Weka","SPSS","SAS","R"))
A
[1] R    Weka SPSS SAS  R   
Levels: R SAS SPSS Weka
class(A)
[1] "factor"
typeof(A)
[1] "integer"
# ¿Cuáles son sus niveles?
levels(A)
[1] "R"    "SAS"  "SPSS" "Weka"
# ¿Está ordenado?
is.ordered(A)
[1] FALSE
A <- factor(c("R","Weka","SPSS","SAS","R"), ordered = TRUE)
A
[1] R    Weka SPSS SAS  R   
Levels: R < SAS < SPSS < Weka
class(A)
[1] "ordered" "factor" 
typeof(A)
[1] "integer"
# ¿Cuáles son sus niveles?
levels(A)
[1] "R"    "SAS"  "SPSS" "Weka"
# ¿Está ordenado?
is.ordered(A)
[1] TRUE
# ¿Podemos cambiar el orden de los niveles?
A <- factor(c("R","Weka","SPSS","SAS","R"), ordered = TRUE, levels = c("SPSS","SAS","Weka","R"))
A
[1] R    Weka SPSS SAS  R   
Levels: SPSS < SAS < Weka < R

Logical

A <- TRUE
class(A)
[1] "logical"
typeof(A)
[1] "logical"

Date

A <- as.Date("2017-01-01")
class(A)
[1] "Date"
typeof(A)
[1] "double"

Estructuras de datos

Vectores

Para crear un vector utilizamos el comando c(), de combinar. Puede tener variables de cualquier tipo

C <- c(1, 3, 4)
C
[1] 1 3 4
typeof(C)
[1] "double"
class(C)
[1] "numeric"
# ¿Qué longitud tiene?
length(C)
[1] 3
# ¿Cuáles son sus dimensiones?
dim(C)
NULL

sumarle 2 a cada elemento del vector anterior

C <- C + 2
C
[1] 3 5 6

sumarle 1 al primer elemento, 2 al segundo, y 3 al tercer elemento del vector anterior

D <- C + 1:3 #esto es equivalente a hacer 3+1, 5+2, 6+9 
D
[1] 4 7 9

1:3 significa que queremos todos los números enteros desde 1 hasta 3.

Reciclaje de vectores

Cuando los vectores involucrados en una operación son distinta dimensión, R recicla el vector de menor longitud para poder completar la operación.

v1 <- c(10,20,30,40,50,60)
v2 <- c(1,2,3)
v3 <- v1 + v2
v3
[1] 11 22 33 41 52 63
# ¿Qué pasa si el vector más pequeño no es multiplo del más grande?
v2 <- c(1,2,3,4)
v3 <- v1 + v2
longer object length is not a multiple of shorter object length
v3
[1] 11 22 33 44 51 62

Puede contener datos tipo “character”

E <- c("Julia","Hadley","Guido")
E
[1] "Julia"  "Hadley" "Guido" 

Para acceder a algún elemento del vector, podemos buscarlo por su número de orden, entre [ ]

elemento2 <- E[2]
elemento2
[1] "Hadley"

para borrar un objeto, utilizamos el comando rm()

rm(elemento2)
elemento2
Error: object 'elemento2' not found

También podemos cambiar el texto del segundo elemento de E, por el texto “var”

E[2] <- "Pablo"
E
[1] "Julia" "Pablo" "Guido"

Matrices

Son vectores que poseen dimensiones: número de columnas y filas. Todos sus datos deben ser de un mismo tipo

# Esta forma de construir la matriz es por columnas por default
M <- matrix(1:9, nrow = 3, ncol = 3)
M
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
typeof(M)
[1] "integer"
class(M)
[1] "matrix"
# ¿Qué longitud tiene?
length(M)
[1] 9
# ¿Cuáles son sus dimensiones?
dim(M)
[1] 3 3

También podemos reciclar vectores al construir una matriz

Otra forma de construir una matriz es uniendo dos o más vectores

v1 <- c(1,2,3)
v2 <- c(4,5,6)
# Creamos la matriz uniendo los dos vectores con cbind()
M <- cbind(v1,v2)
M
     v1 v2
[1,]  1  4
[2,]  2  5
[3,]  3  6
typeof(M)
[1] "double"
class(M)
[1] "matrix"
# ¿Qué longitud tiene?
length(M)
[1] 6
# ¿Cuáles son sus dimensiones?
dim(M)
[1] 3 2

¿Qué pasa si queremos sumar una columna con otro tipo de datos?

v3 <- c("a","b","c")
M <- cbind(M,v3)
M
     v1  v2  v3 
[1,] "1" "4" "a"
[2,] "2" "5" "b"
[3,] "3" "6" "c"
typeof(M)
[1] "character"
class(M)
[1] "matrix"

Data Frames

Un Data Frame es una tabla de datos, donde cada columna representa una variable, y cada fila una observación.

Este objeto suele ser central en el proceso de trabajo, y suele ser la forma en que se cargan datos externos, así como la mayoría de los elementos intermedios, hasta aquello que exportemos

También Se puede crear como la combinación de N vectores de igual tamaño. Por ejemplo, tomamos algunos valores del Indice de salarios

INDICE  <- c(100,   100,   100,
             101.8, 101.2, 100.73,
             102.9, 102.4, 103.2)
FECHA  <-  c("Oct-16", "Oct-16", "Oct-16",
             "Nov-16", "Nov-16", "Nov-16",
             "Dic-16", "Dic-16", "Dic-16")
GRUPO  <-  c("Privado_Registrado","Público","Privado_No_Registrado",
             "Privado_Registrado","Público","Privado_No_Registrado",
             "Privado_Registrado","Público","Privado_No_Registrado")
             
Datos <- data.frame(INDICE, FECHA, GRUPO)
Datos

Tal como en un vector se ubica a los elementos mediante [ ], en un dataframe se obtienen sus elementos de la forma [fila, columna].

Otra opción es seleccionar la columna, mediante el operador $, y luego seleccionar dentro de esa columna, por el número de orden.

Datos$FECHA
[1] Oct-16 Oct-16 Oct-16 Nov-16 Nov-16 Nov-16 Dic-16 Dic-16 Dic-16
Levels: Dic-16 Nov-16 Oct-16
Datos[3,2]
[1] Oct-16
Levels: Dic-16 Nov-16 Oct-16
Datos$FECHA[3]
[1] Oct-16
Levels: Dic-16 Nov-16 Oct-16

¿que pasa si hacemos Datos$FECHA[3,2] ?

Datos$FECHA[3,2]
Error in `[.default`(Datos$FECHA, 3, 2) : incorrect number of dimensions

Nótese que el último comando tiene un número incorrecto de dimensiones, porque estamos refiriendonos 2 veces a la columna FECHA.

Listas

Contienen una concatenación de objetos de cualquier tipo. Así como un vector contiene valores, un dataframe contiene vectores, una lista puede contener dataframes, pero también vectores, o valores, y todo ello a la vez

superlista <- list(A,B,C,D,E,FECHA, DF = Datos, INDICE, GRUPO)
superlista
[[1]]
[1] "2017-01-01"

[[2]]
[1] -2

[[3]]
[1] 3 5 6

[[4]]
[1] 4 7 9

[[5]]
[1] "Julia" "Pablo" "Guido"

[[6]]
[1] "Oct-16" "Oct-16" "Oct-16" "Nov-16" "Nov-16" "Nov-16" "Dic-16" "Dic-16" "Dic-16"

$DF

[[8]]
[1] 100.00 100.00 100.00 101.80 101.20 100.73 102.90 102.40 103.20

[[9]]
[1] "Privado_Registrado"    "Público"               "Privado_No_Registrado" "Privado_Registrado"   
[5] "Público"               "Privado_No_Registrado" "Privado_Registrado"    "Público"              
[9] "Privado_No_Registrado"

Para acceder un elemento de una lista, podemos utilizar el operador $, que se puede usar a su vez de forma iterativa

superlista$DF$FECHA[2]
[1] Oct-16
Levels: Dic-16 Nov-16 Oct-16

Loops, condicionales y funciones

Loops

Un loop es una estructura de código que nos permite recorrer iterativamente un conjunto de comandos, variando algún elemento. Por ejemplo:

for(i in 1:10){
  Cuadrados<- i^2
  print(Cuadrados)
}
[1] 1
[1] 4
[1] 9
[1] 16
[1] 25
[1] 36
[1] 49
[1] 64
[1] 81
[1] 100

esto se lee como : Para i, que toma los valores de 1 a 10:

  • Calcula el cuadrado de i y definilo como Cuadrado
  • Imprimí a Cuadrado

También se puede tomar una lista de valores cualesquiera. Por ejemplo reutilizar datos de un dataframe:

Datos
unique(Datos$GRUPO)
[1] Privado_Registrado    Público               Privado_No_Registrado
Levels: Privado_No_Registrado Privado_Registrado Público
for(variable in unique(Datos$GRUPO)){
  print(Datos[Datos$GRUPO == variable,])
}

Bonus Track: Podemos agregar una barra de progreso en nuestro loop

\ En un Rnotebook no sirve de mucho, pero en un script puede ser útil para loop largos. Sobretodo, es útil cuando tengamos loops adentro de funciones

iterator <- c(1:10)
pb <- txtProgressBar(min = 0, max = length(iterator), style = 3)  

  |                                                                                                     
  |                                                                                               |   0%
stepi =1
for(i in iterator){
  setTxtProgressBar(pb, stepi)
  stepi = stepi+1
  Cuadrados<- i^2
  print(Cuadrados)
}

  |                                                                                                     
  |==========                                                                                     |  10%[1] 1

  |                                                                                                     
  |===================                                                                            |  20%[1] 4

  |                                                                                                     
  |============================                                                                   |  30%[1] 9

  |                                                                                                     
  |======================================                                                         |  40%[1] 16

  |                                                                                                     
  |================================================                                               |  50%[1] 25

  |                                                                                                     
  |=========================================================                                      |  60%[1] 36

  |                                                                                                     
  |==================================================================                             |  70%[1] 49

  |                                                                                                     
  |============================================================================                   |  80%[1] 64

  |                                                                                                     
  |======================================================================================         |  90%[1] 81

  |                                                                                                     
  |===============================================================================================| 100%[1] 100
close(pb)

Estructuras condicionales

Las estructuras condicionales nos permiten definir flujos de ejecución del código, indicando qué se debe correr en cada circunstancia.

A <- 'Esto no es una cadena de caracteres'
B <- factor('Esto no es una cadena de caracteres')
# Condicional simple
if (class(A) == "character") {
  print("No le crean, esto es una cadena de caracteres")
} 
[1] "No le crean, esto es una cadena de caracteres"
# Condicional simple
if (class(B) == "character") {
  print("No le crean, esto es una cadena de caracteres")
} 
# Condicional exhaustivo
if (class(B) == "character") {
  print("No le crean, esto es una cadena de caracteres")
} else {print("Esta chequeado, esto NO es una cadena de caracteres")}
[1] "Esta chequeado, esto NO es una cadena de caracteres"

Una forma más sencilla y explícita es usar el comando ifelse.

ifelse(test = class(A) == "character", yes =  "Esto es un caracter",
       no = "Esto no era un caracter")
[1] "Esto es un caracter"

Funciones

Las funciones nos permiten automatizar todas aquellas partes del código que se repiten mucho. Una vez diseñadas, funcionan igual que cualquier comando. La facilidad para crear las funciones es en buena medida la explicación de que haya tantas contribuciones de usuarios a la expansión del lenguaje.

funcion_prueba <- function(a,b) {
  print(paste(a, b, sep = " "))
  
}
funcion_prueba(a = "Soy la primera parte de un string.", b = "Y yo la segunda parte")
[1] "Soy la primera parte de un string. Y yo la segunda parte"

También podemos asignar un valor por default.

funcion_prueba <- function(a = "Soy un default.",b) {
  print(paste(a, b, sep = " "))
  
}
funcion_prueba(b = " A mi me tenes que asignar")
[1] "Soy un default.  A mi me tenes que asignar"
funcion_prueba(a='Lo puedo asignar?', b='Obvio')
[1] "Lo puedo asignar? Obvio"

Las funciones que creamos nosotros viven dentro del script donde se las define. Es decir, es necesario volver a correr la definición cada vez que la queremos utilizar.

Vale mencionar que lo que ocurre en una función, queda en la función excepto que explícitamente pidamos que devuelva el resultado, con el comando print() o return()

AYUDA: En R-Studio se puede acceder a las definición de una función clickeando la función mientras apretamos CTRL

Ejercicio 1

Realicen una función que:

  • Toma como argumento una matriz compuesta por números
  • Debe imprimir las dimensiones de la matriz
  • Debe indicar si el primer elemento de la matriz es un número par
  • Para la matriz m1 debe imprimir que las dimensiones son 2,2 y que el primer elemento no es par
  • Para la matriz m2 debe imprimir que las dimensiones son 3,2 y que el primer elemento es par
m1 <- matrix(c(9,2,4,8), nrow = 2, ncol = 2)
m2 <- matrix(c(10,1,5,7,9,17), nrow = 3, ncol = 2)

Funciones anónimas

Son funciones a las cuales no les asignamos un nombre. Esto suele ser útil para hacer funciones pequeñas dentro de otras funciones o estructuras más complejas.

(function(x) x*2)(10)
[1] 20

Funciones apply

Los loops que vimos anteriormente ( for loops) suelen lentos y costosos computacionalmente para grandes conjuntos de datos.

La función apply y sus variantes brindan una alternativa más eficiente para aplicar funciones sobre un conjunto de datos.

La función apply se describe de la siguiente manera: apply(X, MARGIN, FUN, …). Sus parámetros son:

  • X: estructura de datos
  • MARGIN: parámetro que indica como se aplica la función. Con MARGIN=1 se aplica sobre filas y con MARGIN=2 se aplica sobre columnas
  • FUN: función a aplicar
# Armamos un dataframe con la recaudación en millones de dolares de la trilogía de Batman de Nolan
USA  <- c(207,   535,   448)
Mundo <- c(167,   470,   636)
pelis  <-  c("Batman Begins", "Dark Knight", "Dark Knight Rises")
batman <- data.frame(USA, Mundo, row.names = pelis)
batman
# ¿Cuanto recaudó cada película?
apply(X=batman, MARGIN =1 , FUN=sum)
    Batman Begins       Dark Knight Dark Knight Rises 
              374              1005              1084 
# ¿Cuanto recaudó en promedio la trilogía por área?
apply(X=batman, MARGIN =2 , FUN=mean)
     USA    Mundo 
396.6667 424.3333 
# ¿Cuanto recaudó cada película en pesos argentinos?
apply(X=batman, MARGIN =1 , FUN=sum*30.4)
Error in sum * 30.4 : non-numeric argument to binary operator
# Funciones anónimas al rescate
apply(X=batman, MARGIN =1 , FUN=function(x) sum(x)*30.4)
    Batman Begins       Dark Knight Dark Knight Rises 
          11369.6           30552.0           32953.6 

Ejercicio 2

  1. Crear un dataframe con el dataset de R: state.x77
  2. Responder:
  1. ¿Cuál es la población total de Estados Unidos?
  2. ¿Cuál es la media de la expectativa de vida?
  3. ¿Cual es la mediana del ingreso en pesos argentinos?
  1. Seleccionar las variables illiteracy y Murder. Crear un indice sumando ambos porcentajes y encontrar cual es el mejor y cual es el peor Estado según este índice

Lectura y escritura de archivos

R tiene formatos de archivos propios:

  • Rdata
  • RDS

RData

x <- 1:15
y <- list(a = 1, b = TRUE, c = "oops")
#Para guardar
save(x, y, file = "xy.RData")
#Para leer
load('xy.RData')

Los archivos de tipo RData permiten grabar una imagen de todos los objetos R que querramos.

RDS

x
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
saveRDS(x, "x.RDS")
Z <- readRDS("x.RDS")
Z
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15

Los archivos de tipo RDS no guardan el nombre del objeto, por lo que podemos nombrarlos cuando los cargamos (aconsejable)

Archivos de otros formatos

Hay muchas funciones para leer archivos de tipo .txt y .csv. La mayoría sólo cambia los parámetros que vienen por default.

Es importante tener en cuenta:

  • encabezado
  • delimitador (,, tab, ;)
  • separador decimal
dataframe <- read.delim(file, header = TRUE, sep = "\t", quote = "\"", dec = ".", fill = TRUE, comment.char = "", ...) 

Ejemplo. Levantar la base individual de EPH del 1er trimestre 2017

individual_t117 <- read.table('../Fuentes/usu_individual_t117.txt',sep=";", dec=",", header = TRUE, fill = TRUE)
head(individual_t117)

Excel

Para leer archivos excel debemos utilizar los comandos que vienen con la librería xlsx

# install.packages("xlsx") # por única vez
library(xlsx) #activamos la librería
#creamos una tabla cualquiera de prueba
x <- 1:10
y <- 11:20
tabla_de_R <- data.frame(x,y)
# escribimos el archivo
write.xlsx( x = tabla_de_R, file = "archivo.xlsx",sheetName = "hoja 1",row.names = FALSE)
#leemos el archivo
tabla <- read.xlsx(file = "archivo.xlsx",sheetName = "hoja 1")
tabla

SPSS, STATA, SAS

Podemos utilizar la librería haven, y los comandos:

  • read_spss()
  • read_dta()
  • read_sas()

Encoding

Tanto a la hora de leer y escribir archivos, como al trabajar un mismo script desde distintas computadoras, debemos ser cuidadosos con el encoding seteado. El encoding es la forma mediante la cual el sistema interpreta los caracteres del lenguaje natural. Hay muchos encodings diferentes, que interpretan distinto algunos caracteres, como tildes y signos de puntuación.
Por ende, si el encoding seteado no es el mismo que el de nuestro script/tabla pueden generarse errores. En medida de lo posible, al escribir nuestros scripts es recomendable evitar estos caracteres.

R tiene por default el encoding “ISO-8859-1”, sin embargo el más habitual en América Latina es “UTF-8”.

  • Lectura de archivos : Aglunas de las funciones del tipo read_table, read_xlsx permiten establecer como uno de sus parametros el encoding deseado
  • Encoding utilizado para abrir un script:File -> Reopen with Encoding
  • Encoding default con el que se guardan nuestros Scripts: Tools -> Global Options -> Code -> Saving

Directorios

Siempre que escribimos el nombre del archivo, R lo busca en el working directory. Para saber cual es el directorio de trabajo utilizamos la función getwd(). Para redefinir el directorio de trabajo, utilizamos la función setwd

No es aconsejable utilizar el directorio de trabajo, si nos olvidamos de definirlo, tiramos los archivos en cualquier lado

Lo más práctico es definir los directorios de trabajo como valores. y pegar el nombre del archivo con las carpetas.

carpeta_fuentes    <- paste("C:/Users/.../Documents/R/fuentes/")
carpeta_resultados <- paste("C:/Users/.../Documents/R/resultados/")

Es importante notar que se utiliza la barra / en lugar de \ (que sale de copiar y pegar el directorio en windows)

el nombre completo del archivo puede ser

archivo_datos      <- paste0(carpeta_fuentes, "archivo_fuentes.txt")
archivo_resultados <- paste0(carpeta_resultados, "archivo_resultados.txt")

luego, para leer un excel, se escribe:

tabla <- read.xlsx(file = archivo_datos,sheetName = "hoja 1") #como es una variable, ya no lleva comillas

Directorios autorreferenciales

Si bien excede los alcances de este curso, dejamos un chunk de código que puede resultar sumamente útil para crear un directorio de trabajo para un proyecto nuevo.

#install.packages(rstudioapi)
script.dir <- paste0(dirname(rstudioapi::getActiveDocumentContext()$path),"/")
bases.dir  <-  paste0(dirname(script.dir),"/Fuentes/")
#dir.create(bases.dir)
resultados.dir <- paste0(dirname(script.dir),"/Resultados/")
#dir.create(resultados.dir)

#chequeo
dir.exists(bases.dir)
dir.exists(resultados.dir)

La primera línea encuentra la carpeta donde esta guardado el script (si no esta guardado no funciona).
La segunda línea crea el nombre del directorio Fuentes La tercera línea (anulada) crea el directorio Fuentes La cuarta línea crea el nombre del directorio Resultados La quinta línea (anulada) crea el directorio Resultados

Organización scripts

Por último, es aconsejable mantener en todos los script una misma estructura del tipo:

  1. Limpiar la memoria rm(list=ls())
  2. Cargar librerías
  3. Definir directorios
  4. Definir funciones
  5. Levantar archivos
    … procesamiento ….
  1. grabar resultados

También es útil organizar las partes del script en capítulos. Para eso

### escribimos el título del capitulo encerrado entre tres o más corchetes ###

Ayudas

Hay muchas ayudas, propias del programa, o de usuarios, que pueden ser de ayuda.

  • En el programa, para consultar los parámetros de una función, le escribe ?funcion()

  • Rstudio tiene unos machetes muy útiles

  • Rdocumentation

  • stack overflow conviene llegar desde google

Ejercicios para practicar

  • Crear un OBJETO llamado OBJETO definido como el resultado de la suma: 5 + 6
  • Crear un VECTOR VEC0 que contenga los números 1, 3, 4.
  • Crear 3 vectores ( VEC1, VEC2, VEC3) que sean transformaciones del anterior
  • Crear 3 vectores con la misma cantidad de elementos que VEC0, pero con variables string (texto) ( VEC4, VEC5, VEC6).
  • Crear un dataframe DFRAME como combinación de todos los vectores creados previamente
  • Crear una lista con cada uno de los elementos creados previamente

  • Para todos los valores del vector VEC0, imprimir mediante un loop el doble de dichos valores
  • Mediante un loop que itere sobre una de las columnas “string” del dataframe DFRAME, imprimir una variable que combine 3 columnas de dicho dataframe
  • Reescribir el VEC1 del DATAFRAME para que sus elementos sean:
    • El Doble de VEC_0, cuando éste sea mayor a 2
    • Iguales a VEC_0, para el resto de los casos
  • Crear una función llamada HolaMundo que imprima el texto “Hola mundo”
  • Crear una función que devuelva la sumatoria de los números enteros comprendidos entre 1 y un parámetro x a definir

  • Levantar la base Individual del 1er trimestre de 2017, de la EPH
  • Guardar la base como un archivo de extensión .RDS
  • Volver a levantar la base, pero como .RDS y asignarla con el nombre BaseRDS ¿tarda más o menos?
  • Levantar del Excel llamado CANASTAS que se encuentra en la carpeta de Fuentes, la hoja “CBT” y definirla como HojaCBT. Pueden usar la función:
    • read.xlsx de la librería xlsx
    • read_excel de la librería readxl
  • Levantar el mismo Excel, utilizando un Objeto que contenga el directorio del archivo a levantar.
    • Chequear con dir.exist() que lo creamos bien (¿no funcionó? pista: /\)

  1. Más allá de los comandos elementales, comandos más sofisticados tienen muchas versiones, y algunas quedan en desuso en el tiempo.

  2. existen ciertas excepciones con algunos paquetes más adelante.

LS0tCnRpdGxlOiAiQ2xhc2UgMS4gSW50cm9kdWNjacOzbiIKYXV0aG9yOiAiRGllZ28gS296bG93c2tpIHkgSnVhbiBCYXJyaW9sYSIKZGF0ZTogIjE4IGRlIGFnb3N0byAyMDE4IgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgIHRvYzogeWVzCiAgICB0b2NfZmxvYXQ6IHllcwogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHllcwogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCi0tLQoKYGBge3IsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RiwgY29tbWVudD0iPiIsIGhpZ2hsaWdodD1ULCBpbmNsdWRlPUZBTFNFLCBzdHJpcC53aGl0ZT1UfQpybShsaXN0PWxzKCkpCmBgYAoKCiMgRGVzY3JpcGNpw7NuIGRlbCBwcm9ncmFtYSAgICAgICAgCgoKIVtodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9dKFJsb2dvLnBuZykKCiMjIMK/UXVlIGVzIFI/CgotIExlbmd1YWplIGRlIEFuw6FsaXNpcyBkZSBEYXRvcwotIFNvZnR3YXJlIExpYnJlCi0gU2ludGF4aXMgQsOhc2ljYTogUiBiYXNlIAotIFNpbnRheGlzIGluY3JlbWVudGFsW14xXTogRWwgbGVuZ3VhamUgc2UgdmEgYW1wbGlhbmRvIHBvciBhcG9ydGVzIGRlIFVuaXZlcnNpZGFkZXMsIGludmVzdGlnYWRvcmVzIHkgZW1wcmVzYXMgcHJpdmFkYXMsIG9yZ2FuaXphZG9zIGVuIGxpYnJlcsOtYXMgKG8gcGFxdWV0ZXMpCi0gX0NvbXVuaWRhZF8gd2ViIG11eSBncmFuZGUgcGFyYSByZWFsaXphciBwcmVndW50YXMgeSBkZXNwZWphciBkdWRhcy4KClteMV06IE3DoXMgYWxsw6EgZGUgbG9zIGNvbWFuZG9zIGVsZW1lbnRhbGVzLCBjb21hbmRvcyBtw6FzIHNvZmlzdGljYWRvcyB0aWVuZW4gbXVjaGFzIHZlcnNpb25lcywgeSBhbGd1bmFzIHF1ZWRhbiBlbiBkZXN1c28gZW4gZWwgdGllbXBvLgoKIVtmdWVudGU6IGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL2Rhcm9jemlnLzNjZjA2ZDZkYjRiZTJiYmUzMzY4XShudW1iZXItb2Ytc3VibWl0dGVkLXBhY2thZ2VzLXRvLUNSQU4ucG5nKQoKCiFbaHR0cHM6Ly93d3cucnN0dWRpby5jb20vXShSU3R1ZGlvbG9nby5wbmcpCgpFbCBfZW50b3Jub18gbcOhcyBjw7Ntb2RvIHBhcmEgdXRpbGl6YXIgZWwgX2xlbmd1YWplXyBfX1JfXyBlcyBlbCBfcHJvZ3JhbWFfIF9fUiBzdHVkaW9fXwoKLSBSc3R1ZGlvIGVzIHVuYSBlbXByZXNhIHF1ZSBwcm9kdWNlIHByb2R1Y3RvcyBhc29jaWFkb3MgYWwgbGVuZ3VhamUgUiwgY29tbyBlbCBwcm9ncmFtYSBzb2JyZSBlbCBxdWUgY29ycmVtb3MgbG9zIGNvbWFuZG9zLCB5IGV4dGVuc2lvbmVzIGRlbCBsZW5ndWFqZSAobGlicmVyw61hcykuCiAKLSBFbCBwcm9ncmFtYSBlcyBfZ3JhdHVpdG9fIHkgc2UgcHVlZGUgYmFqYXIgZGUgbGEgCltww6FnaW5hIG9maWNpYWxdKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tLykgCgoKIVtQYW50YWxsYSBSc3R1ZGlvXShQYW50YWxsYSBSc3R1ZGlvLnBuZykKCgohW2Z1ZW50ZTogaHR0cHM6Ly9naXRodWIuY29tL21hdHRoaWV1Z29tZXovYmVuY2htYXJrLXN0YXRhLXIvYmxvYi9tYXN0ZXIvb3V0cHV0LzFlNy5wbmddKHN0YXRhUi5wbmcpCgoKCiMgTMOzZ2ljYSBzaW50w6FjdGljYQoKIyMgRGVmaW5pY2nDs24gZGUgb2JqZXRvcwoKRWwgb3BlcmFkb3IgX19gYGA8LWBgYF9fIHNpcnZlIHBhcmEgZGVmaW5pciB1biBlbGVtZW50by4gIF9fQSBsYSBpenF1aWVyZGFfXyBkZWwgX19gYGA8LWBgYF9fIGRlYmUgdWJpY2Fyc2UgZWwgbm9tYnJlIHF1ZSB0b21hcsOhIGVsIGVsZW1lbnRvIGEgY3JlYXIuIF9fRGVsIGxhZG8gZGVyZWNob19fIGRlYmUgaXIgbGEgZGVmaW5pY2nDs24gZGVsIG1pc21vCgoKYGBge3J9CkEgPC0gMQpgYGAKCkFsIGRlZmluaXIgdW4gZWxlbWVudG8sIGVsIG1pc21vIHF1ZWRhIGd1YXJkYWRvIGVuIGVsIGFtYmllbnRlIGRlbCBwcm9ncmFtYSwgeSBwb2Ryw6Egc2VyIHV0aWxpemFkbyBwb3N0ZXJpb3JtZW50ZSBwYXJhIG9ic2VydmFyIHN1IGNvbnRlbmlkbyBvIHBhcmEgcmVhbGl6YXIgdW5hIG9wZXJhY2nDs24gY29uIGVsIG1pc21vCgpgYGB7cn0KQSAKYGBgCgpBbCBjb3JyZXIgdW5hIGxpbmVhIGNvbiBlbCBub21icmUgZGVsIG9iamV0bywgbGEgY29uc29sYSBkZWwgcHJvZ3JhbWEgbm9zIG11ZXN0cmEgc3UgY29udGVuaWRvLiBFbnRyZSBDb3JjaGV0ZXMgT2JzZXJ2YW1vcyBlbCBuw7ptZXJvIGRlIG9yZGVuIGRlbCBlbGVtZW50byBlbiBjdWVzdGnDs24KCkVsIG9wZXJhZG9yIF9fYGBgPWBgYF9fIGVzIF9fZXF1aXZhbGVudGVfXyBhIF9fYGBgPC1gYGBfXywgcGVybyBlbiBsYSBwcsOhY3RpY2Egbm8gc2UgdXRpbGl6YSBwYXJhIGxhIGRlZmluaWNpw7NuIGRlIG9iamV0b3MuICAgCgpgYGB7cn0KQiA9IDIKQgpgYGAKCl9fYGBgPC1gYGBfXyBlcyB1biBvcGVyYWRvciBfX1VuaWRpcmVjY2lvbmFsX18sIGVzIGRlY2lyIHF1ZTogICAgIApgYGBBIDwtIEJgYGAgaW1wbGljYSBxdWUgX19BX18gdmEgdG9tYXIgY29tbyB2YWxvciBlbCBjb250ZW5pZG8gZGVsIG9iamV0byBfX0JfXywgeSBubyBhbCByZXbDqXMuCmBgYHtyfQpBIDwtIEIKQSAgICNBaG9yYSBBIHRvbWEgZWwgdmFsb3IgZGUgQiwgeSBCIGNvbnRpbnVhIGNvbnNlcnZhbmRvIGVsIG1pc21vIHZhbG9yCkIKYGBgCgojIyBSIGJhc2UKCkNvbiBfUiBiYXNlXyBub3MgcmVmZXJpbW9zIGEgbG9zIGNvbWFuZG9zIGLDoXNpY29zIHF1ZSB2aWVuZW4gaW5jb3Jwb3JhZG9zIGVuIGVsIFIsIHNpbiBuZWNlc2lkYWQgZGUgY2FyZ2FyIGxpYnJlcsOtYXMuIAoKIyMgT3BlcmFkb3JlcyBsw7NnaWNvczogCgotICQ+JAotICQ+PSQKLSAkPCQKLSAkPD0kCi0gJD09JAotICQhPSQKCmBgYHtyfQpBID0gMQpCID0gMgoKQSA+ICBCCkEgPj0gQgpBIDwgIEIKQSA8PSBCCkEgPT0gQgpBICE9IEIKCkMgPC0gQSAhPSBCCkMKYGBgCgpDb21vIG11ZXN0cmEgZWwgw7psdGltbyBlamVtcGxvLCBlbCByZXN1bHRhZG8gZGUgdW5hIG9wZXJhY2nDs24gbMOzZ2ljYSBwdWVkZSBhbG1hY2VuYXJzZSBjb21vIGVsIHZhbG9yIGRlIHVuIG9iamV0by4KCiMjIE9wZXJhZG9yZXMgYXJpdG3DqXRpY29zOgoKYGBge3J9CiNzdW1hCkEgPC0gNSs2CkEKI1Jlc3RhCkIgPC0gNi04CkIKI2NvY2llbnRlCkMgPC0gNi8yLjUKQwojbXVsdGlwbGljYWNpb24KRCA8LSA2KjIuNQpECiMgTW9kdWxvCkUgPC0gNyUlMgpFCmBgYAojIyBDYXJhY3RlcmVzIGVzcGVjaWFsZXMKCi0gUiBlcyBzZW5zaWJsZSBhIG1hecO6c2N1bGFzIHkgbWluw7pzY3VsYXMsIHRhbnRvIHBhcmEgbG9zIG5vbWJyZXMgZGUgbGFzIHZhcmlhYmxlcywgY29tbyBwYXJhIGxhcyBmdW5jaW9uZXMgeSBwYXLDoW1ldHJvcy4KLSBMb3MgX19lc3BhY2lvcyBlbiBibGFuY29fXyB5IGxvcyBfX2NhcnJpYWdlIHJldHVybl9fIChfZW50ZXJfKSBubyBzb24gY29uc2lkZXJhZG9zIHBvciBlbCBsZW5ndWFqZS4gTG9zIHBvZGVtb3MgYXByb3ZlY2hhciBwYXJhIGVtcHJvbGlqYXIgZWwgY8OzZGlnbyB5IHF1ZSBsYSBsZWN0dXJhIHNlYSBtw6FzIHNpbXBsZVteMl0uCgpbXjJdOiBleGlzdGVuIGNpZXJ0YXMgZXhjZXBjaW9uZXMgY29uIGFsZ3Vub3MgcGFxdWV0ZXMgbcOhcyBhZGVsYW50ZS4gCgotIEVsIF9fbnVtZXJhbF9fIGBgYCNgYGAgc2UgdXRpbGl6YSBwYXJhIGhhY2VyIGNvbWVudGFyaW9zLiBUb2RvIGxvIHF1ZSBzZSBlc2NyaWJlIGRlc3B1w6lzIGRlbCAjIG5vIGVzIGludGVycHJldGFkbyBwb3IgUi4gU2UgZGViZSB1dGlsaXphciB1biAjIHBvciBjYWRhIGzDrW5lYSBkZSBjw7NkaWdvIHF1ZSBzZSBkZXNlYSBhbnVsYXIuCioqU0hPUlRDVVQqKjogRW4gUi1TdHVkaW8gc2UgcHVlZGUgc2VsZWNjaW9uYXIgdG9kbyB1biBibG9xdWUgZGUgdGV4dG8geSBjb21lbnRhcmxvIGNvbXBsZXRvIGFwcmV0YW5kbyBDVFJMK1NISUZUK0MKCi0gTG9zIF9fY29yY2hldGVzX18gYGBgW11gYGAgc2UgdXRpbGl6YW4gcGFyYSBhY2NlZGVyIGEgdW4gb2JqZXRvOgogICAgLSBlbiB1biB2ZWN0b3JbbsKwIG9yZGVuXQogICAgLSBlbiB1bmEgbWF0cml6W2ZpbGEsIGNvbHVtbmFdCiAgICAtIGVuIHVuYSBsaXN0YVtuwrAgZWxlbWVudG9dCi0gZWwgc2lnbm8gX18kX18gdGFtYmnDqW4gZXMgdW4gbcOpdG9kbyBkZSBhY2Nlc28sIHF1ZSBwZXJtaXRlIGxsYW1hciBhbCBlbGVtZW50byBwb3Igc3Ugbm9tYnJlLCBlbiBkYXRhZnJhbWVzIHkgbGlzdGFzLgoKLSBMb3MgX19wYXLDqW50ZXNpc19fYGBgKClgYGAgc2UgdXRpbGl6YW4gZW4gbGFzIGZ1bmNpb25lcyBwYXJhIGRlZmluaXIgbG9zIHBhcsOhbWV0cm9zLgoKLSBMYXMgX19jb21hc19fIGBgYCwgYGBgICBzZSB1dGlsaXphbiBwYXJhIHNlcGFyYXIgbG9zIGVsZW1lbnRvcy4gCgpFamVtcGxvOiBzaSBxdWVyZW1vcyBkZWZpbmlyIGFsIGVsZW1lbnRvIGRlIGxhIGZpbGEgMiB5IGNvbHVtbmEgMyBkZSB1bmEgX3RhYmxhXyAgY29tbyBlbCByZXN1bHRhZG8gZGUgdW5hIF9mdW5jaW9uXyBjb24gcGFyw6FtZXRyb3MgQT1hLCBCPWIgeSBDPWMsIGRpcmVtb3M6CgpgYGAKdGFibGFbMiwzXSA8LSBmdW5jaW9uKEE9YSwgQj1iLCBDPWMpCmBgYAoKIyBUaXBvcyBkZSBkYXRvcyB5IGVzdHJ1Y3R1cmFzIGRlIGRhdG9zOgoKTG9zIHRpcG9zIGRlIGRhdG9zIHNvbiB1bmEgY2xhc2UgZGUgdmFsb3JlcyBxdWUgc2UgcHVlZGVuIGNvbnN0cnVpciBwYXJhIHJlcHJlc2VudGFyIGluZm9ybWFjacOzbi4gTGFzIGVzdHJ1Y3R1cmFzIGRlIGRhdG9zIHNvbiBmb3JtYXMgZGUgcmVwcmVzZW50YXIgeSBndWFyZGFyIGluZm9ybWFjacOzbiAKCgojIyBUaXBvcyBkZSBkYXRvcwpMb3MgZGF0b3MgdGllbmVuIGRpc3RpbnRvcyBfdGlwb3NfOiAgIAoKKiBFbCBjb21hbmRvIGNsYXNzKCkgaWRlbnRpZmljYSBlbCB0aXBvIGRlIHVuIG9iamV0byBkZXNkZSB1bmEgcGVyc3BlY3RpdmEgZGUgcHJvZ3JhbWFjacOzbiBvcmllbnRhZGEgYSBvYmpldG9zIGVuIFIuIFBvZGVtb3MgcmVkaWZpbmlyIGxhIGNsYXNlIGRlIHVuIG9iamV0bwoqIEVsIGNvbWFuZG8gdHlwZSgpIGlkZW50aWZpY2EgZWwgdGlwbyBkZSB1biBvYmpldG8gc2Vnw7puIGVsIGxlbmd1YWplIFIuIE5vIHBvZGVtb3MgbW9kaWZpY2FyIGVsIHRpcG8gZGUgdW4gb2JqZXRvCgoKX19OdW1lcmljX18KYGBge3J9CkEgPC0gMQpjbGFzcyhBKSAgIAp0eXBlb2YoQSkKYGBgCgpUcmF0ZW1vcyBkZSBjYW1iaWFyIGxhIGNsYXNlIHkgZWwgdGlwbyBkZSBudWVzdHJvIG9iamV0bwoKYGBge3IgZXJyb3I9VFJVRX0KY2xhc3MoQSkgPC0gIm51ZXZhX2NsYXNlIgpjbGFzcyhBKQp0eXBlb2YoQSkgPC0gIm51ZXZvX3RpcG8iCmBgYAoKX19JbnRlZ2VyX18KYGBge3J9CkEgPC0gMUwKQQpjbGFzcyhBKSAgIAp0eXBlb2YoQSkKYGBgCgpfX0NvbXBsZXhfXwpgYGB7cn0KQSA8LSAyKzJpCkEKY2xhc3MoQSkgICAKdHlwZW9mKEEpCmBgYAoKX19DaGFyYWN0ZXJfXwpgYGB7cn0KQSA8LSAgcGFzdGUoJ1NveScsICd1bmEnLCAnY29uY2F0ZW5hY2nDs24nLCAnZGUnLCAnY2FyYWN0ZXJlcycsIHNlcCA9ICIgIikKQQpjbGFzcyhBKQp0eXBlb2YoQSkKYGBgCgoKX19GYWN0b3JfXwpgYGB7cn0KQSA8LSBmYWN0b3IoIlNveSB1biBmYWN0b3IgY29uIG5pdmVsZXMgZmlqb3MiKQpBCmNsYXNzKEEpCnR5cGVvZihBKQpgYGAKCkxhIGRpZmVyZW5jaWEgZW50cmUgdW4gX2NoYXJhY3Rlcl8geSB1biBfZmFjdG9yXyBlcyBxdWUgZWwgw7psdGltbyB0aWVuZSBzb2xvIGFsZ3Vub3MgdmFsb3JlcyBwZXJtaXRpZG9zIChsZXZlbHMpLCB5IHNlIGxlIHB1ZWRlIGRhciB1biBvcmRlbgoKCmBgYHtyfQpBIDwtIGZhY3RvcihjKCJSIiwiV2VrYSIsIlNQU1MiLCJTQVMiLCJSIikpCkEKY2xhc3MoQSkKdHlwZW9mKEEpCiMgwr9DdcOhbGVzIHNvbiBzdXMgbml2ZWxlcz8KbGV2ZWxzKEEpCiMgwr9Fc3TDoSBvcmRlbmFkbz8KaXMub3JkZXJlZChBKQpgYGAKCmBgYHtyfQpBIDwtIGZhY3RvcihjKCJSIiwiV2VrYSIsIlNQU1MiLCJTQVMiLCJSIiksIG9yZGVyZWQgPSBUUlVFKQpBCmNsYXNzKEEpCnR5cGVvZihBKQojIMK/Q3XDoWxlcyBzb24gc3VzIG5pdmVsZXM/CmxldmVscyhBKQojIMK/RXN0w6Egb3JkZW5hZG8/CmlzLm9yZGVyZWQoQSkKIyDCv1BvZGVtb3MgY2FtYmlhciBlbCBvcmRlbiBkZSBsb3Mgbml2ZWxlcz8KQSA8LSBmYWN0b3IoYygiUiIsIldla2EiLCJTUFNTIiwiU0FTIiwiUiIpLCBvcmRlcmVkID0gVFJVRSwgbGV2ZWxzID0gYygiU1BTUyIsIlNBUyIsIldla2EiLCJSIikpCkEKYGBgCgpfX0xvZ2ljYWxfXwpgYGB7cn0KQSA8LSBUUlVFCmNsYXNzKEEpCnR5cGVvZihBKQpgYGAKCl9fRGF0ZV9fCmBgYHtyfQpBIDwtIGFzLkRhdGUoIjIwMTctMDEtMDEiKQpjbGFzcyhBKQp0eXBlb2YoQSkKYGBgCgojIyBFc3RydWN0dXJhcyBkZSBkYXRvcwoKIyMjIFZlY3RvcmVzCgpQYXJhIGNyZWFyIHVuIF9fdmVjdG9yX18gdXRpbGl6YW1vcyBlbCBjb21hbmRvIGBgYGMoKWBgYCwgZGUgY29tYmluYXIuIFB1ZWRlIHRlbmVyIHZhcmlhYmxlcyBfX2RlIGN1YWxxdWllciB0aXBvX18KCmBgYHtyfQpDIDwtIGMoMSwgMywgNCkKQwp0eXBlb2YoQykKY2xhc3MoQykKIyDCv1F1w6kgbG9uZ2l0dWQgdGllbmU/Cmxlbmd0aChDKQojIMK/Q3XDoWxlcyBzb24gc3VzIGRpbWVuc2lvbmVzPwpkaW0oQykKYGBgCgoKc3VtYXJsZSAgMiBhIGNhZGEgZWxlbWVudG8gZGVsIF9fdmVjdG9yX18gYW50ZXJpb3IKCmBgYHtyfQpDIDwtIEMgKyAyCkMKYGBgCgpzdW1hcmxlICAxIGFsIHByaW1lciBlbGVtZW50bywgMiBhbCBzZWd1bmRvLCB5IDMgYWwgdGVyY2VyIGVsZW1lbnRvIGRlbCBfX3ZlY3Rvcl9fIGFudGVyaW9yCmBgYHtyfQpEIDwtIEMgKyAxOjMgI2VzdG8gZXMgZXF1aXZhbGVudGUgYSBoYWNlciAzKzEsIDUrMiwgNis5IApECmBgYAoKYGBgMTozYGBgIHNpZ25pZmljYSBxdWUgcXVlcmVtb3MgdG9kb3MgbG9zIG7Dum1lcm9zIGVudGVyb3MgZGVzZGUgMSBoYXN0YSAzLiAKCl9fUmVjaWNsYWplIGRlIHZlY3RvcmVzX18KCkN1YW5kbyBsb3MgdmVjdG9yZXMgaW52b2x1Y3JhZG9zIGVuIHVuYSBvcGVyYWNpw7NuIHNvbiBkaXN0aW50YSBkaW1lbnNpw7NuLCBSIHJlY2ljbGEgZWwgdmVjdG9yIGRlIG1lbm9yIGxvbmdpdHVkIHBhcmEgcG9kZXIgY29tcGxldGFyIGxhIG9wZXJhY2nDs24uCgpgYGB7cn0KdjEgPC0gYygxMCwyMCwzMCw0MCw1MCw2MCkKdjIgPC0gYygxLDIsMykKdjMgPC0gdjEgKyB2Mgp2MwojIMK/UXXDqSBwYXNhIHNpIGVsIHZlY3RvciBtw6FzIHBlcXVlw7FvIG5vIGVzIG11bHRpcGxvIGRlbCBtw6FzIGdyYW5kZT8KdjIgPC0gYygxLDIsMyw0KQp2MyA8LSB2MSArIHYyCnYzCmBgYAoKUHVlZGUgY29udGVuZXIgZGF0b3MgdGlwbyAiY2hhcmFjdGVyIgpgYGB7cn0KRSA8LSBjKCJKdWxpYSIsIkhhZGxleSIsIkd1aWRvIikKRQpgYGAKClBhcmEgYWNjZWRlciBhIGFsZ8O6biBlbGVtZW50byBkZWwgdmVjdG9yLCBwb2RlbW9zIGJ1c2NhcmxvIHBvciBzdSBuw7ptZXJvIGRlIG9yZGVuLCBlbnRyZSBgYGBbIF1gYGAKCmBgYHtyfQplbGVtZW50bzIgPC0gRVsyXQplbGVtZW50bzIKYGBgCgpwYXJhIF9fYm9ycmFyX18gdW4gb2JqZXRvLCB1dGlsaXphbW9zIGVsIGNvbWFuZG8gX2BgYHJtKClgYGBfCgpgYGB7ciBlcnJvcj1UUlVFfQpybShlbGVtZW50bzIpCmVsZW1lbnRvMgpgYGAKClRhbWJpw6luIHBvZGVtb3MgY2FtYmlhciBlbCB0ZXh0byBkZWwgc2VndW5kbyBlbGVtZW50byBkZSBFLCBwb3IgZWwgdGV4dG8gInZhciIKCmBgYHtyfQpFWzJdIDwtICJQYWJsbyIKRQpgYGAKCgojIyMgTWF0cmljZXMKU29uIHZlY3RvcmVzIHF1ZSBwb3NlZW4gZGltZW5zaW9uZXM6IG7Dum1lcm8gZGUgY29sdW1uYXMgeSBmaWxhcy4gVG9kb3Mgc3VzIGRhdG9zIGRlYmVuIHNlciBkZSB1biBtaXNtbyB0aXBvCgpgYGB7cn0KIyBFc3RhIGZvcm1hIGRlIGNvbnN0cnVpciBsYSBtYXRyaXogZXMgcG9yIGNvbHVtbmFzIHBvciBkZWZhdWx0Ck0gPC0gbWF0cml4KDE6OSwgbnJvdyA9IDMsIG5jb2wgPSAzKQpNCnR5cGVvZihNKQpjbGFzcyhNKQojIMK/UXXDqSBsb25naXR1ZCB0aWVuZT8KbGVuZ3RoKE0pCiMgwr9DdcOhbGVzIHNvbiBzdXMgZGltZW5zaW9uZXM/CmRpbShNKQpgYGAKVGFtYmnDqW4gcG9kZW1vcyByZWNpY2xhciB2ZWN0b3JlcyBhbCBjb25zdHJ1aXIgdW5hIG1hdHJpegoKT3RyYSBmb3JtYSBkZSBjb25zdHJ1aXIgdW5hIG1hdHJpeiBlcyB1bmllbmRvIGRvcyBvIG3DoXMgdmVjdG9yZXMKCmBgYHtyfQp2MSA8LSBjKDEsMiwzKQp2MiA8LSBjKDQsNSw2KQojIENyZWFtb3MgbGEgbWF0cml6IHVuaWVuZG8gbG9zIGRvcyB2ZWN0b3JlcyBjb24gY2JpbmQoKQpNIDwtIGNiaW5kKHYxLHYyKQpNCnR5cGVvZihNKQpjbGFzcyhNKQojIMK/UXXDqSBsb25naXR1ZCB0aWVuZT8KbGVuZ3RoKE0pCiMgwr9DdcOhbGVzIHNvbiBzdXMgZGltZW5zaW9uZXM/CmRpbShNKQoKYGBgCgrCv1F1w6kgcGFzYSBzaSBxdWVyZW1vcyBzdW1hciB1bmEgY29sdW1uYSBjb24gb3RybyB0aXBvIGRlIGRhdG9zPwoKYGBge3J9CnYzIDwtIGMoImEiLCJiIiwiYyIpCk0gPC0gY2JpbmQoTSx2MykKTQp0eXBlb2YoTSkKY2xhc3MoTSkKYGBgCgojIyMgRGF0YSBGcmFtZXMKClVuIERhdGEgRnJhbWUgZXMgdW5hIHRhYmxhIGRlIGRhdG9zLCBkb25kZSBjYWRhIGNvbHVtbmEgcmVwcmVzZW50YSB1bmEgdmFyaWFibGUsIHkgY2FkYSBmaWxhIHVuYSBvYnNlcnZhY2nDs24uIAoKRXN0ZSBvYmpldG8gc3VlbGUgc2VyIGNlbnRyYWwgZW4gZWwgcHJvY2VzbyBkZSB0cmFiYWpvLCB5IHN1ZWxlIHNlciBsYSBmb3JtYSBlbiBxdWUgc2UgY2FyZ2FuIGRhdG9zIGV4dGVybm9zLCBhc8OtIGNvbW8gbGEgbWF5b3LDrWEgZGUgbG9zIGVsZW1lbnRvcyBpbnRlcm1lZGlvcywgaGFzdGEgYXF1ZWxsbyBxdWUgZXhwb3J0ZW1vcyAKClRhbWJpw6luIFNlIHB1ZWRlIGNyZWFyIGNvbW8gbGEgY29tYmluYWNpw7NuIGRlIE4gdmVjdG9yZXMgZGUgaWd1YWwgdGFtYcOxby4gUG9yIGVqZW1wbG8sIHRvbWFtb3MgYWxndW5vcyB2YWxvcmVzIGRlbCBbSW5kaWNlIGRlIHNhbGFyaW9zXShodHRwOi8vd3d3LmluZGVjLmdvYi5hci9iYWphckN1YWRyb0VzdGFkaXN0aWNvLmFzcD9pZGM9NDAyMEIzMzQ0MDYwOTQ2MjY1NDU0MkJEMEJDMzIwRjE1MjNEQTBEQzUyQzM5NjIwMURCNERENTg2MUZGRURDOUFEMTQzNjY4MUFDODQxNzkpCgpgYGB7cn0KSU5ESUNFICA8LSBjKDEwMCwgICAxMDAsICAgMTAwLAogICAgICAgICAgICAgMTAxLjgsIDEwMS4yLCAxMDAuNzMsCiAgICAgICAgICAgICAxMDIuOSwgMTAyLjQsIDEwMy4yKQoKRkVDSEEgIDwtICBjKCJPY3QtMTYiLCAiT2N0LTE2IiwgIk9jdC0xNiIsCiAgICAgICAgICAgICAiTm92LTE2IiwgIk5vdi0xNiIsICJOb3YtMTYiLAogICAgICAgICAgICAgIkRpYy0xNiIsICJEaWMtMTYiLCAiRGljLTE2IikKCgpHUlVQTyAgPC0gIGMoIlByaXZhZG9fUmVnaXN0cmFkbyIsIlDDumJsaWNvIiwiUHJpdmFkb19Ob19SZWdpc3RyYWRvIiwKICAgICAgICAgICAgICJQcml2YWRvX1JlZ2lzdHJhZG8iLCJQw7pibGljbyIsIlByaXZhZG9fTm9fUmVnaXN0cmFkbyIsCiAgICAgICAgICAgICAiUHJpdmFkb19SZWdpc3RyYWRvIiwiUMO6YmxpY28iLCJQcml2YWRvX05vX1JlZ2lzdHJhZG8iKQogICAgICAgICAgICAgCgpEYXRvcyA8LSBkYXRhLmZyYW1lKElORElDRSwgRkVDSEEsIEdSVVBPKQpEYXRvcwpgYGAKClRhbCBjb21vIGVuIHVuIF9fdmVjdG9yX18gc2UgdWJpY2EgYSBsb3MgZWxlbWVudG9zIG1lZGlhbnRlIGBgYFsgXWBgYCwgZW4gdW4gX19kYXRhZnJhbWVfXyBzZSBvYnRpZW5lbiBzdXMgZWxlbWVudG9zIGRlIGxhIGZvcm1hIF9fYGBgW2ZpbGEsIGNvbHVtbmFdYGBgX18uCgpPdHJhIG9wY2nDs24gZXMgc2VsZWNjaW9uYXIgbGEgY29sdW1uYSwgbWVkaWFudGUgZWwgb3BlcmFkb3IgX19gYGAkYGBgX18sIHkgbHVlZ28gc2VsZWNjaW9uYXIgZGVudHJvIGRlIGVzYSBjb2x1bW5hLCBwb3IgZWwgbsO6bWVybyBkZSBvcmRlbi4KCmBgYHtyfQpEYXRvcyRGRUNIQQpEYXRvc1szLDJdCkRhdG9zJEZFQ0hBWzNdCmBgYAoKwr9xdWUgcGFzYSBzaSBoYWNlbW9zIGBgYERhdG9zJEZFQ0hBWzMsMl1gYGAgPwoKYGBge3IgZXJyb3I9VFJVRX0KRGF0b3MkRkVDSEFbMywyXQpgYGAKTsOzdGVzZSBxdWUgZWwgw7psdGltbyBjb21hbmRvIHRpZW5lIHVuIG7Dum1lcm8gaW5jb3JyZWN0byBkZSBkaW1lbnNpb25lcywgcG9ycXVlIGVzdGFtb3MgcmVmaXJpZW5kb25vcyAyIHZlY2VzIGEgbGEgY29sdW1uYSBGRUNIQS4KCiMjIyBMaXN0YXMKCkNvbnRpZW5lbiB1bmEgY29uY2F0ZW5hY2nDs24gZGUgb2JqZXRvcyBkZSBjdWFscXVpZXIgdGlwby4gQXPDrSBjb21vIHVuIHZlY3RvciBjb250aWVuZSB2YWxvcmVzLCB1biBkYXRhZnJhbWUgY29udGllbmUgdmVjdG9yZXMsIHVuYSBsaXN0YSBwdWVkZSBjb250ZW5lciBkYXRhZnJhbWVzLCBwZXJvIHRhbWJpw6luIHZlY3RvcmVzLCBvIHZhbG9yZXMsIHkgX3RvZG8gZWxsbyBhIGxhIHZlel8KCmBgYHtyfQpzdXBlcmxpc3RhIDwtIGxpc3QoQSxCLEMsRCxFLEZFQ0hBLCBERiA9IERhdG9zLCBJTkRJQ0UsIEdSVVBPKQpzdXBlcmxpc3RhCmBgYAoKUGFyYSBhY2NlZGVyIHVuIGVsZW1lbnRvIGRlIHVuYSBsaXN0YSwgcG9kZW1vcyB1dGlsaXphciBlbCBvcGVyYWRvciBfX2BgYCRgYGBfXywgcXVlIHNlIHB1ZWRlIHVzYXIgYSBzdSB2ZXogZGUgZm9ybWEgaXRlcmF0aXZhIAoKYGBge3J9CnN1cGVybGlzdGEkREYkRkVDSEFbMl0KYGBgCgojIExvb3BzLCBjb25kaWNpb25hbGVzIHkgZnVuY2lvbmVzCgojIyBMb29wcwoKVW4gX19sb29wX18gZXMgdW5hIGVzdHJ1Y3R1cmEgZGUgY8OzZGlnbyBxdWUgbm9zIHBlcm1pdGUgcmVjb3JyZXIgaXRlcmF0aXZhbWVudGUgdW4gY29uanVudG8gZGUgY29tYW5kb3MsIHZhcmlhbmRvIGFsZ8O6biBlbGVtZW50by4gUG9yIGVqZW1wbG86CgpgYGB7cn0KCmZvcihpIGluIDE6MTApewogIEN1YWRyYWRvczwtIGleMgogIHByaW50KEN1YWRyYWRvcykKfQoKYGBgCgplc3RvIHNlIGxlZSBjb21vIDogUGFyYSBpLCBxdWUgdG9tYSBsb3MgdmFsb3JlcyBkZSAxIGEgMTA6IAoKLSBDYWxjdWxhIGVsIGN1YWRyYWRvIGRlIGkgeSBkZWZpbmlsbyBjb21vIF9DdWFkcmFkb18KLSBJbXByaW3DrSBhIF9DdWFkcmFkb18KClRhbWJpw6luIHNlIHB1ZWRlIHRvbWFyIHVuYSBsaXN0YSBkZSB2YWxvcmVzIGN1YWxlc3F1aWVyYS4gUG9yIGVqZW1wbG8gcmV1dGlsaXphciBkYXRvcyBkZSB1biBkYXRhZnJhbWU6CgpgYGB7cn0KRGF0b3MKdW5pcXVlKERhdG9zJEdSVVBPKQpmb3IodmFyaWFibGUgaW4gdW5pcXVlKERhdG9zJEdSVVBPKSl7CiAgcHJpbnQoRGF0b3NbRGF0b3MkR1JVUE8gPT0gdmFyaWFibGUsXSkKfQoKYGBgCgpfX0JvbnVzIFRyYWNrOl9fIFBvZGVtb3MgYWdyZWdhciB1bmEgYmFycmEgZGUgcHJvZ3Jlc28gZW4gbnVlc3RybyBsb29wCgpcXCAKRW4gdW4gUm5vdGVib29rIG5vIHNpcnZlIGRlIG11Y2hvLCBwZXJvIGVuIHVuIHNjcmlwdCBwdWVkZSBzZXIgw7p0aWwgcGFyYSBsb29wIGxhcmdvcy4gU29icmV0b2RvLCBlcyDDunRpbCBjdWFuZG8gdGVuZ2Ftb3MgbG9vcHMgYWRlbnRybyBkZSBmdW5jaW9uZXMKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBwYWdlZC5wcmludD1GQUxTRX0KaXRlcmF0b3IgPC0gYygxOjEwKQpwYiA8LSB0eHRQcm9ncmVzc0JhcihtaW4gPSAwLCBtYXggPSBsZW5ndGgoaXRlcmF0b3IpLCBzdHlsZSA9IDMpICAKc3RlcGkgPTEKZm9yKGkgaW4gaXRlcmF0b3IpewogIHNldFR4dFByb2dyZXNzQmFyKHBiLCBzdGVwaSkKICBzdGVwaSA9IHN0ZXBpKzEKICBDdWFkcmFkb3M8LSBpXjIKICBwcmludChDdWFkcmFkb3MpCn0KY2xvc2UocGIpCgpgYGAKCgoKCiMjIEVzdHJ1Y3R1cmFzIGNvbmRpY2lvbmFsZXMKCkxhcyBfX2VzdHJ1Y3R1cmFzIGNvbmRpY2lvbmFsZXNfXyBub3MgcGVybWl0ZW4gZGVmaW5pciBmbHVqb3MgZGUgZWplY3VjacOzbiBkZWwgY8OzZGlnbywgaW5kaWNhbmRvIHF1w6kgc2UgZGViZSBjb3JyZXIgZW4gY2FkYSBjaXJjdW5zdGFuY2lhLgoKYGBge3J9CkEgPC0gJ0VzdG8gbm8gZXMgdW5hIGNhZGVuYSBkZSBjYXJhY3RlcmVzJwpCIDwtIGZhY3RvcignRXN0byBubyBlcyB1bmEgY2FkZW5hIGRlIGNhcmFjdGVyZXMnKQoKIyBDb25kaWNpb25hbCBzaW1wbGUKaWYgKGNsYXNzKEEpID09ICJjaGFyYWN0ZXIiKSB7CiAgcHJpbnQoIk5vIGxlIGNyZWFuLCBlc3RvIGVzIHVuYSBjYWRlbmEgZGUgY2FyYWN0ZXJlcyIpCn0gCgojIENvbmRpY2lvbmFsIHNpbXBsZQppZiAoY2xhc3MoQikgPT0gImNoYXJhY3RlciIpIHsKICBwcmludCgiTm8gbGUgY3JlYW4sIGVzdG8gZXMgdW5hIGNhZGVuYSBkZSBjYXJhY3RlcmVzIikKfSAKCiMgQ29uZGljaW9uYWwgZXhoYXVzdGl2bwppZiAoY2xhc3MoQikgPT0gImNoYXJhY3RlciIpIHsKICBwcmludCgiTm8gbGUgY3JlYW4sIGVzdG8gZXMgdW5hIGNhZGVuYSBkZSBjYXJhY3RlcmVzIikKfSBlbHNlIHtwcmludCgiRXN0YSBjaGVxdWVhZG8sIGVzdG8gTk8gZXMgdW5hIGNhZGVuYSBkZSBjYXJhY3RlcmVzIil9CmBgYAoKVW5hIGZvcm1hIG3DoXMgc2VuY2lsbGEgeSBleHBsw61jaXRhIGVzIHVzYXIgZWwgY29tYW5kbyBpZmVsc2UuIAoKYGBge3J9CmlmZWxzZSh0ZXN0ID0gY2xhc3MoQSkgPT0gImNoYXJhY3RlciIsIHllcyA9ICAiRXN0byBlcyB1biBjYXJhY3RlciIsCiAgICAgICBubyA9ICJFc3RvIG5vIGVyYSB1biBjYXJhY3RlciIpCgpgYGAKCgojIyBGdW5jaW9uZXMKCkxhcyBfX2Z1bmNpb25lc19fIG5vcyBwZXJtaXRlbiBhdXRvbWF0aXphciB0b2RhcyBhcXVlbGxhcyBwYXJ0ZXMgZGVsIGPDs2RpZ28gcXVlIHNlIHJlcGl0ZW4gbXVjaG8uIFVuYSB2ZXogZGlzZcOxYWRhcywgZnVuY2lvbmFuIGlndWFsIHF1ZSBjdWFscXVpZXIgY29tYW5kby4gTGEgZmFjaWxpZGFkIHBhcmEgY3JlYXIgbGFzIGZ1bmNpb25lcyBlcyBlbiBidWVuYSBtZWRpZGEgbGEgZXhwbGljYWNpw7NuIGRlIHF1ZSBoYXlhIHRhbnRhcyBjb250cmlidWNpb25lcyBkZSB1c3VhcmlvcyBhIGxhIGV4cGFuc2nDs24gZGVsIGxlbmd1YWplLgoKYGBge3J9CmZ1bmNpb25fcHJ1ZWJhIDwtIGZ1bmN0aW9uKGEsYikgewogIHByaW50KHBhc3RlKGEsIGIsIHNlcCA9ICIgIikpCiAgCn0KCmZ1bmNpb25fcHJ1ZWJhKGEgPSAiU295IGxhIHByaW1lcmEgcGFydGUgZGUgdW4gc3RyaW5nLiIsIGIgPSAiWSB5byBsYSBzZWd1bmRhIHBhcnRlIikKCmBgYAoKVGFtYmnDqW4gcG9kZW1vcyBhc2lnbmFyIHVuIHZhbG9yIHBvciBkZWZhdWx0LgoKYGBge3J9CmZ1bmNpb25fcHJ1ZWJhIDwtIGZ1bmN0aW9uKGEgPSAiU295IHVuIGRlZmF1bHQuIixiKSB7CiAgcHJpbnQocGFzdGUoYSwgYiwgc2VwID0gIiAiKSkKICAKfQpmdW5jaW9uX3BydWViYShiID0gIiBBIG1pIG1lIHRlbmVzIHF1ZSBhc2lnbmFyIikKCmZ1bmNpb25fcHJ1ZWJhKGE9J0xvIHB1ZWRvIGFzaWduYXI/JywgYj0nT2J2aW8nKQoKYGBgCgoKTGFzIGZ1bmNpb25lcyBxdWUgY3JlYW1vcyBub3NvdHJvcyB2aXZlbiBkZW50cm8gZGVsIHNjcmlwdCBkb25kZSBzZSBsYXMgZGVmaW5lLiBFcyBkZWNpciwgZXMgbmVjZXNhcmlvIHZvbHZlciBhIGNvcnJlciBsYSBkZWZpbmljacOzbiBjYWRhIHZleiBxdWUgbGEgcXVlcmVtb3MgdXRpbGl6YXIuIAoKVmFsZSBtZW5jaW9uYXIgcXVlIF9fbG8gcXVlIG9jdXJyZSBlbiB1bmEgZnVuY2nDs24sIHF1ZWRhIGVuIGxhIGZ1bmNpw7NuX18gZXhjZXB0byBxdWUgZXhwbMOtY2l0YW1lbnRlIHBpZGFtb3MgcXVlIGRldnVlbHZhIGVsIHJlc3VsdGFkbywgY29uIGVsIGNvbWFuZG8gYGBgcHJpbnQoKWBgYCBvIGBgYHJldHVybigpYGBgCgoqKkFZVURBKio6IEVuIFItU3R1ZGlvIHNlIHB1ZWRlIGFjY2VkZXIgYSBsYXMgZGVmaW5pY2nDs24gZGUgdW5hIGZ1bmNpw7NuIGNsaWNrZWFuZG8gbGEgZnVuY2nDs24gbWllbnRyYXMgYXByZXRhbW9zIENUUkwKCioqRWplcmNpY2lvIDEqKgoKUmVhbGljZW4gdW5hIGZ1bmNpw7NuIHF1ZToKCiogVG9tYSBjb21vIGFyZ3VtZW50byB1bmEgbWF0cml6IGNvbXB1ZXN0YSBwb3IgbsO6bWVyb3MKKiBEZWJlIGltcHJpbWlyIGxhcyBkaW1lbnNpb25lcyBkZSBsYSBtYXRyaXoKKiBEZWJlIGluZGljYXIgc2kgZWwgcHJpbWVyIGVsZW1lbnRvIGRlIGxhIG1hdHJpeiBlcyB1biBuw7ptZXJvIHBhcgoqIFBhcmEgbGEgbWF0cml6IG0xIGRlYmUgaW1wcmltaXIgcXVlIGxhcyBkaW1lbnNpb25lcyBzb24gMiwyIHkgcXVlIGVsIHByaW1lciBlbGVtZW50byBubyBlcyBwYXIKKiBQYXJhIGxhIG1hdHJpeiBtMiBkZWJlIGltcHJpbWlyIHF1ZSBsYXMgZGltZW5zaW9uZXMgc29uIDMsMiB5IHF1ZSBlbCBwcmltZXIgZWxlbWVudG8gZXMgcGFyCgpgYGB7cn0KbTEgPC0gbWF0cml4KGMoOSwyLDQsOCksIG5yb3cgPSAyLCBuY29sID0gMikKbTIgPC0gbWF0cml4KGMoMTAsMSw1LDcsOSwxNyksIG5yb3cgPSAzLCBuY29sID0gMikKYGBgCgoKKipGdW5jaW9uZXMgYW7Ds25pbWFzKioKClNvbiBmdW5jaW9uZXMgYSBsYXMgY3VhbGVzIG5vIGxlcyBhc2lnbmFtb3MgdW4gbm9tYnJlLiBFc3RvIHN1ZWxlIHNlciDDunRpbCBwYXJhIGhhY2VyIGZ1bmNpb25lcyBwZXF1ZcOxYXMgZGVudHJvIGRlIG90cmFzIGZ1bmNpb25lcyBvIGVzdHJ1Y3R1cmFzIG3DoXMgY29tcGxlamFzLgoKYGBge3J9CihmdW5jdGlvbih4KSB4KjIpKDEwKQpgYGAKCiMjIEZ1bmNpb25lcyBhcHBseQoKTG9zIGxvb3BzIHF1ZSB2aW1vcyBhbnRlcmlvcm1lbnRlICggX19mb3JfXyBsb29wcykgc3VlbGVuIGxlbnRvcyB5IGNvc3Rvc29zIGNvbXB1dGFjaW9uYWxtZW50ZSBwYXJhIGdyYW5kZXMgY29uanVudG9zIGRlIGRhdG9zLiAKCkxhIGZ1bmNpw7NuIGFwcGx5IHkgc3VzIHZhcmlhbnRlcyBicmluZGFuIHVuYSBhbHRlcm5hdGl2YSBtw6FzIGVmaWNpZW50ZSBwYXJhIGFwbGljYXIgZnVuY2lvbmVzIHNvYnJlIHVuIGNvbmp1bnRvIGRlIGRhdG9zLiAKCkxhIGZ1bmNpw7NuICoqYXBwbHkqKiBzZSBkZXNjcmliZSBkZSBsYSBzaWd1aWVudGUgbWFuZXJhOiBhcHBseShYLCBNQVJHSU4sIEZVTiwgLi4uKS4gU3VzIHBhcsOhbWV0cm9zIHNvbjoKCi0gKipYKio6IGVzdHJ1Y3R1cmEgZGUgZGF0b3MKLSAqKk1BUkdJTioqOiBwYXLDoW1ldHJvIHF1ZSBpbmRpY2EgY29tbyBzZSBhcGxpY2EgbGEgZnVuY2nDs24uIENvbiBNQVJHSU49MSBzZSBhcGxpY2Egc29icmUgZmlsYXMgeSBjb24gTUFSR0lOPTIgc2UgYXBsaWNhIHNvYnJlIGNvbHVtbmFzIAotICoqRlVOKio6IGZ1bmNpw7NuIGEgYXBsaWNhcgoKYGBge3IsIGVycm9yID0gVFJVRX0KIyBBcm1hbW9zIHVuIGRhdGFmcmFtZSBjb24gbGEgcmVjYXVkYWNpw7NuIGVuIG1pbGxvbmVzIGRlIGRvbGFyZXMgZGUgbGEgdHJpbG9nw61hIGRlIEJhdG1hbiBkZSBOb2xhbgpVU0EgIDwtIGMoMjA3LCAgIDUzNSwgICA0NDgpCk11bmRvIDwtIGMoMTY3LCAgIDQ3MCwgICA2MzYpCnBlbGlzICA8LSAgYygiQmF0bWFuIEJlZ2lucyIsICJEYXJrIEtuaWdodCIsICJEYXJrIEtuaWdodCBSaXNlcyIpCgpiYXRtYW4gPC0gZGF0YS5mcmFtZShVU0EsIE11bmRvLCByb3cubmFtZXMgPSBwZWxpcykKYmF0bWFuCgojIMK/Q3VhbnRvIHJlY2F1ZMOzIGNhZGEgcGVsw61jdWxhPwphcHBseShYPWJhdG1hbiwgTUFSR0lOID0xICwgRlVOPXN1bSkKIyDCv0N1YW50byByZWNhdWTDsyBlbiBwcm9tZWRpbyBsYSB0cmlsb2fDrWEgcG9yIMOhcmVhPwphcHBseShYPWJhdG1hbiwgTUFSR0lOID0yICwgRlVOPW1lYW4pCiMgwr9DdWFudG8gcmVjYXVkw7MgY2FkYSBwZWzDrWN1bGEgZW4gcGVzb3MgYXJnZW50aW5vcz8KYXBwbHkoWD1iYXRtYW4sIE1BUkdJTiA9MSAsIEZVTj1zdW0qMzAuNCkKIyBGdW5jaW9uZXMgYW7Ds25pbWFzIGFsIHJlc2NhdGUKYXBwbHkoWD1iYXRtYW4sIE1BUkdJTiA9MSAsIEZVTj1mdW5jdGlvbih4KSBzdW0oeCkqMzAuNCkKYGBgCgoqKkVqZXJjaWNpbyAyKioKCjEpIENyZWFyIHVuIGRhdGFmcmFtZSBjb24gZWwgZGF0YXNldCBkZSBSOiBzdGF0ZS54NzcKMikgUmVzcG9uZGVyOgphKSDCv0N1w6FsIGVzIGxhIHBvYmxhY2nDs24gdG90YWwgZGUgRXN0YWRvcyBVbmlkb3M/CmIpIMK/Q3XDoWwgZXMgbGEgbWVkaWEgZGUgbGEgZXhwZWN0YXRpdmEgZGUgdmlkYT8KYykgwr9DdWFsIGVzIGxhIG1lZGlhbmEgZGVsIGluZ3Jlc28gZW4gcGVzb3MgYXJnZW50aW5vcz8KMykgU2VsZWNjaW9uYXIgbGFzIHZhcmlhYmxlcyBpbGxpdGVyYWN5IHkgTXVyZGVyLiBDcmVhciB1biBpbmRpY2Ugc3VtYW5kbyBhbWJvcyBwb3JjZW50YWplcyB5IGVuY29udHJhciBjdWFsIGVzIGVsIG1lam9yIHkgY3VhbCBlcyBlbCBwZW9yIEVzdGFkbyBzZWfDum4gZXN0ZSDDrW5kaWNlIAoKCiMgTGVjdHVyYSB5IGVzY3JpdHVyYSBkZSBhcmNoaXZvcwoKUiB0aWVuZSBmb3JtYXRvcyBkZSBhcmNoaXZvcyBwcm9waW9zOgoKLSBSZGF0YQotIFJEUwoKIyMgUkRhdGEKYGBge3J9CnggPC0gMToxNQp5IDwtIGxpc3QoYSA9IDEsIGIgPSBUUlVFLCBjID0gIm9vcHMiKQoKI1BhcmEgZ3VhcmRhcgpzYXZlKHgsIHksIGZpbGUgPSAieHkuUkRhdGEiKQoKI1BhcmEgbGVlcgpsb2FkKCd4eS5SRGF0YScpCmBgYAoKTG9zIGFyY2hpdm9zIGRlIHRpcG8gX19SRGF0YV9fIHBlcm1pdGVuIGdyYWJhciB1bmEgX2ltYWdlbl8gZGUgdG9kb3MgbG9zIG9iamV0b3MgUiBxdWUgcXVlcnJhbW9zLgoKIyMgX19SRFNfXwpgYGB7cn0KeApzYXZlUkRTKHgsICJ4LlJEUyIpCgpaIDwtIHJlYWRSRFMoInguUkRTIikKWgpgYGAKCkxvcyBhcmNoaXZvcyBkZSB0aXBvIF9fUkRTX18gbm8gZ3VhcmRhbiBlbCBub21icmUgZGVsIG9iamV0bywgcG9yIGxvIHF1ZSBwb2RlbW9zIG5vbWJyYXJsb3MgY3VhbmRvIGxvcyBjYXJnYW1vcyAoYWNvbnNlamFibGUpCgojIyBBcmNoaXZvcyBkZSBvdHJvcyBmb3JtYXRvcwoKSGF5IF9fbXVjaGFzX18gZnVuY2lvbmVzIHBhcmEgbGVlciBhcmNoaXZvcyBkZSB0aXBvIF8udHh0XyB5IF8uY3N2Xy4gTGEgbWF5b3LDrWEgc8OzbG8gY2FtYmlhIGxvcyBwYXLDoW1ldHJvcyBxdWUgdmllbmVuIHBvciBkZWZhdWx0LiAKCkVzIGltcG9ydGFudGUgdGVuZXIgZW4gY3VlbnRhOgoKLSBlbmNhYmV6YWRvCi0gZGVsaW1pdGFkb3IgKGBgYCxgYGAsIHRhYiwgYGBgO2BgYCkKLSBzZXBhcmFkb3IgZGVjaW1hbCAKCgpgYGAgCmRhdGFmcmFtZSA8LSByZWFkLmRlbGltKGZpbGUsIGhlYWRlciA9IFRSVUUsIHNlcCA9ICJcdCIsIHF1b3RlID0gIlwiIiwgZGVjID0gIi4iLCBmaWxsID0gVFJVRSwgY29tbWVudC5jaGFyID0gIiIsIC4uLikgCmBgYApFamVtcGxvLiBMZXZhbnRhciBsYSBiYXNlIGluZGl2aWR1YWwgZGUgRVBIIGRlbCAxZXIgdHJpbWVzdHJlIDIwMTcKCmBgYHtyfQoKaW5kaXZpZHVhbF90MTE3IDwtIHJlYWQudGFibGUoJy4uL0Z1ZW50ZXMvdXN1X2luZGl2aWR1YWxfdDExNy50eHQnLHNlcD0iOyIsIGRlYz0iLCIsIGhlYWRlciA9IFRSVUUsIGZpbGwgPSBUUlVFKQpoZWFkKGluZGl2aWR1YWxfdDExNykKYGBgCgoKIyMgRXhjZWwgCgpQYXJhIGxlZXIgYXJjaGl2b3MgZXhjZWwgZGViZW1vcyB1dGlsaXphciBsb3MgY29tYW5kb3MgcXVlIHZpZW5lbiBjb24gbGEgbGlicmVyw61hIHhsc3gKCmBgYHtyfQojIGluc3RhbGwucGFja2FnZXMoInhsc3giKSAjIHBvciDDum5pY2EgdmV6CmxpYnJhcnkoeGxzeCkgI2FjdGl2YW1vcyBsYSBsaWJyZXLDrWEKCiNjcmVhbW9zIHVuYSB0YWJsYSBjdWFscXVpZXJhIGRlIHBydWViYQp4IDwtIDE6MTAKeSA8LSAxMToyMAp0YWJsYV9kZV9SIDwtIGRhdGEuZnJhbWUoeCx5KQoKIyBlc2NyaWJpbW9zIGVsIGFyY2hpdm8Kd3JpdGUueGxzeCggeCA9IHRhYmxhX2RlX1IsIGZpbGUgPSAiYXJjaGl2by54bHN4IixzaGVldE5hbWUgPSAiaG9qYSAxIixyb3cubmFtZXMgPSBGQUxTRSkKCiNsZWVtb3MgZWwgYXJjaGl2bwp0YWJsYSA8LSByZWFkLnhsc3goZmlsZSA9ICJhcmNoaXZvLnhsc3giLHNoZWV0TmFtZSA9ICJob2phIDEiKQp0YWJsYQpgYGAKCiMjIFNQU1MsIFNUQVRBLCBTQVMKClBvZGVtb3MgdXRpbGl6YXIgbGEgbGlicmVyw61hIF9oYXZlbl8sIHkgbG9zIGNvbWFuZG9zOgoKLSByZWFkX3Nwc3MoKQotIHJlYWRfZHRhKCkKLSByZWFkX3NhcygpCgojIyBFbmNvZGluZwpUYW50byBhIGxhIGhvcmEgZGUgbGVlciB5IGVzY3JpYmlyIGFyY2hpdm9zLCBjb21vIGFsIHRyYWJhamFyIHVuIG1pc21vIHNjcmlwdCBkZXNkZSBkaXN0aW50YXMgY29tcHV0YWRvcmFzLCBkZWJlbW9zIHNlciBjdWlkYWRvc29zIGNvbiBlbCBfZW5jb2RpbmdfIHNldGVhZG8uIEVsIF9lbmNvZGluZ18gZXMgbGEgZm9ybWEgbWVkaWFudGUgbGEgY3VhbCBlbCBzaXN0ZW1hIGludGVycHJldGEgbG9zIGNhcmFjdGVyZXMgZGVsIGxlbmd1YWplIG5hdHVyYWwuIEhheSBtdWNob3MgX2VuY29kaW5nc18gZGlmZXJlbnRlcywgcXVlIGludGVycHJldGFuIGRpc3RpbnRvIGFsZ3Vub3MgY2FyYWN0ZXJlcywgY29tbyB0aWxkZXMgeSBzaWdub3MgZGUgcHVudHVhY2nDs24uICAgICAKUG9yIGVuZGUsIHNpIGVsIF9lbmNvZGluZ18gc2V0ZWFkbyBubyBlcyBlbCBtaXNtbyBxdWUgZWwgZGUgbnVlc3RybyBzY3JpcHQvdGFibGEgcHVlZGVuIGdlbmVyYXJzZSBlcnJvcmVzLiBFbiBtZWRpZGEgZGUgbG8gcG9zaWJsZSwgYWwgZXNjcmliaXIgbnVlc3Ryb3Mgc2NyaXB0cyBlcyByZWNvbWVuZGFibGUgZXZpdGFyIGVzdG9zIGNhcmFjdGVyZXMuIAoKUiB0aWVuZSBwb3IgZGVmYXVsdCBlbCBlbmNvZGluZyBfXyJJU08tODg1OS0xIl9fLCBzaW4gZW1iYXJnbyBlbCBtw6FzIGhhYml0dWFsIGVuIEFtw6lyaWNhIExhdGluYSBlcyBfXyJVVEYtOCJfXy4gCgotICoqTGVjdHVyYSBkZSBhcmNoaXZvcyoqIDogQWdsdW5hcyBkZSBsYXMgZnVuY2lvbmVzIGRlbCB0aXBvIF9fcmVhZF90YWJsZV9fLCBfX3JlYWRfeGxzeF9fIHBlcm1pdGVuIGVzdGFibGVjZXIgY29tbyB1bm8gZGUgc3VzIHBhcmFtZXRyb3MgZWwgX2VuY29kaW5nXyBkZXNlYWRvIAotICoqRW5jb2RpbmcgdXRpbGl6YWRvIHBhcmEgYWJyaXIgdW4gc2NyaXB0Kio6RmlsZSAtPiBSZW9wZW4gd2l0aCBFbmNvZGluZwotICoqRW5jb2RpbmcgZGVmYXVsdCBjb24gZWwgcXVlIHNlIGd1YXJkYW4gbnVlc3Ryb3MgU2NyaXB0cyoqOiBUb29scyAtPiBHbG9iYWwgT3B0aW9ucyAtPiBDb2RlIC0+IFNhdmluZwoKIyBEaXJlY3RvcmlvcwoKU2llbXByZSBxdWUgZXNjcmliaW1vcyBlbCBub21icmUgZGVsIGFyY2hpdm8sIFIgbG8gYnVzY2EgZW4gZWwgX3dvcmtpbmcgZGlyZWN0b3J5Xy4gClBhcmEgc2FiZXIgY3VhbCBlcyBlbCBkaXJlY3RvcmlvIGRlIHRyYWJham8gdXRpbGl6YW1vcyBsYSBmdW5jacOzbiBgYGBnZXR3ZCgpYGBgLiAKUGFyYSByZWRlZmluaXIgZWwgZGlyZWN0b3JpbyBkZSB0cmFiYWpvLCB1dGlsaXphbW9zIGxhIGZ1bmNpw7NuIGBgYHNldHdkYGBgCgpfX05vIGVzIGFjb25zZWphYmxlIHV0aWxpemFyIGVsIGRpcmVjdG9yaW8gZGUgdHJhYmFqbywgc2kgbm9zIG9sdmlkYW1vcyBkZSBkZWZpbmlybG8sIHRpcmFtb3MgbG9zIGFyY2hpdm9zIGVuIGN1YWxxdWllciBsYWRvX18gCgpMbyBtw6FzIHByw6FjdGljbyBlcyBkZWZpbmlyIGxvcyBkaXJlY3RvcmlvcyBkZSB0cmFiYWpvIGNvbW8gdmFsb3Jlcy4geSBwZWdhciBlbCBub21icmUgZGVsIGFyY2hpdm8gY29uIGxhcyBjYXJwZXRhcy4KCmBgYApjYXJwZXRhX2Z1ZW50ZXMgICAgPC0gcGFzdGUoIkM6L1VzZXJzLy4uLi9Eb2N1bWVudHMvUi9mdWVudGVzLyIpCmNhcnBldGFfcmVzdWx0YWRvcyA8LSBwYXN0ZSgiQzovVXNlcnMvLi4uL0RvY3VtZW50cy9SL3Jlc3VsdGFkb3MvIikKYGBgCgpFcyBpbXBvcnRhbnRlIG5vdGFyIHF1ZSBzZSB1dGlsaXphIGxhIGJhcnJhIGBgYC9gYGAgZW4gbHVnYXIgZGUgYGBgXGBgYCAocXVlIHNhbGUgZGUgY29waWFyIHkgcGVnYXIgZWwgZGlyZWN0b3JpbyBlbiB3aW5kb3dzKQoKZWwgbm9tYnJlIGNvbXBsZXRvIGRlbCBhcmNoaXZvIHB1ZWRlIHNlciAKYGBgCmFyY2hpdm9fZGF0b3MgICAgICA8LSBwYXN0ZTAoY2FycGV0YV9mdWVudGVzLCAiYXJjaGl2b19mdWVudGVzLnR4dCIpCmFyY2hpdm9fcmVzdWx0YWRvcyA8LSBwYXN0ZTAoY2FycGV0YV9yZXN1bHRhZG9zLCAiYXJjaGl2b19yZXN1bHRhZG9zLnR4dCIpCmBgYAoKbHVlZ28sIHBhcmEgbGVlciB1biBleGNlbCwgc2UgZXNjcmliZTogCgpgYGAKdGFibGEgPC0gcmVhZC54bHN4KGZpbGUgPSBhcmNoaXZvX2RhdG9zLHNoZWV0TmFtZSA9ICJob2phIDEiKSAjY29tbyBlcyB1bmEgdmFyaWFibGUsIHlhIG5vIGxsZXZhIGNvbWlsbGFzCgpgYGAKCiMjIERpcmVjdG9yaW9zIGF1dG9ycmVmZXJlbmNpYWxlcwoKU2kgYmllbiBleGNlZGUgbG9zIGFsY2FuY2VzIGRlIGVzdGUgY3Vyc28sIGRlamFtb3MgdW4gY2h1bmsgZGUgY8OzZGlnbyBxdWUgcHVlZGUgcmVzdWx0YXIgc3VtYW1lbnRlIMO6dGlsIHBhcmEgY3JlYXIgdW4gZGlyZWN0b3JpbyBkZSB0cmFiYWpvIHBhcmEgdW4gcHJveWVjdG8gbnVldm8uCgpgYGB7ciBldmFsPUZBTFNFfQojaW5zdGFsbC5wYWNrYWdlcyhyc3R1ZGlvYXBpKQpzY3JpcHQuZGlyIDwtIHBhc3RlMChkaXJuYW1lKHJzdHVkaW9hcGk6OmdldEFjdGl2ZURvY3VtZW50Q29udGV4dCgpJHBhdGgpLCIvIikKYmFzZXMuZGlyICA8LSAgcGFzdGUwKGRpcm5hbWUoc2NyaXB0LmRpciksIi9GdWVudGVzLyIpCiNkaXIuY3JlYXRlKGJhc2VzLmRpcikKcmVzdWx0YWRvcy5kaXIgPC0gcGFzdGUwKGRpcm5hbWUoc2NyaXB0LmRpciksIi9SZXN1bHRhZG9zLyIpCiNkaXIuY3JlYXRlKHJlc3VsdGFkb3MuZGlyKQoKI2NoZXF1ZW8KZGlyLmV4aXN0cyhiYXNlcy5kaXIpCmRpci5leGlzdHMocmVzdWx0YWRvcy5kaXIpCgpgYGAKCkxhIHByaW1lcmEgbMOtbmVhIF9lbmN1ZW50cmFfIGxhIGNhcnBldGEgZG9uZGUgZXN0YSBndWFyZGFkbyBlbCBzY3JpcHQgKHNpIG5vIGVzdGEgZ3VhcmRhZG8gbm8gZnVuY2lvbmEpLiAgICAgCkxhIHNlZ3VuZGEgbMOtbmVhIGNyZWEgZWwgbm9tYnJlIGRlbCBkaXJlY3RvcmlvIEZ1ZW50ZXMKTGEgdGVyY2VyYSBsw61uZWEgKGFudWxhZGEpIGNyZWEgZWwgZGlyZWN0b3JpbyBGdWVudGVzCkxhIGN1YXJ0YSBsw61uZWEgY3JlYSBlbCBub21icmUgZGVsIGRpcmVjdG9yaW8gUmVzdWx0YWRvcwpMYSBxdWludGEgbMOtbmVhIChhbnVsYWRhKSBjcmVhIGVsIGRpcmVjdG9yaW8gUmVzdWx0YWRvcwoKIyBPcmdhbml6YWNpw7NuIHNjcmlwdHMKClBvciDDumx0aW1vLCBlcyBhY29uc2VqYWJsZSBtYW50ZW5lciBlbiB0b2RvcyBsb3Mgc2NyaXB0IHVuYSBtaXNtYSBlc3RydWN0dXJhIGRlbCB0aXBvOgoKMS4gTGltcGlhciBsYSBtZW1vcmlhIGBgYCBybShsaXN0PWxzKCkpIGBgYCAgICAKMi4gQ2FyZ2FyIGxpYnJlcsOtYXMKMy4gRGVmaW5pciBkaXJlY3Rvcmlvcwo0LiBEZWZpbmlyIGZ1bmNpb25lcwo1LiBMZXZhbnRhciBhcmNoaXZvcyAgICAgCi4uLiBwcm9jZXNhbWllbnRvIC4uLi4gICAgIApuLiBncmFiYXIgcmVzdWx0YWRvcwoKVGFtYmnDqW4gZXMgw7p0aWwgb3JnYW5pemFyIGxhcyBwYXJ0ZXMgZGVsIHNjcmlwdCBlbiBjYXDDrXR1bG9zLiBQYXJhIGVzbyAgIAoKCmBgYCMjIyBlc2NyaWJpbW9zIGVsIHTDrXR1bG8gZGVsIGNhcGl0dWxvIGVuY2VycmFkbyBlbnRyZSB0cmVzIG8gbcOhcyBjb3JjaGV0ZXMgIyMjYGBgCgoKIyBBeXVkYXMKCkhheSBtdWNoYXMgYXl1ZGFzLCBwcm9waWFzIGRlbCBwcm9ncmFtYSwgbyBkZSB1c3VhcmlvcywgcXVlIHB1ZWRlbiBzZXIgZGUgYXl1ZGEuCgotIEVuIGVsIHByb2dyYW1hLCBwYXJhIGNvbnN1bHRhciBsb3MgcGFyw6FtZXRyb3MgZGUgdW5hIGZ1bmNpw7NuLCBsZSBlc2NyaWJlIGBgYD9mdW5jaW9uKClgYGAKCi0gW1JzdHVkaW9dKGh0dHBzOi8vd3d3LnJzdHVkaW8uY29tL3Jlc291cmNlcy9jaGVhdHNoZWV0cy8pIHRpZW5lIHVub3MgbWFjaGV0ZXMgbXV5IMO6dGlsZXMKCi0gW1Jkb2N1bWVudGF0aW9uXShodHRwczovL3d3dy5yZG9jdW1lbnRhdGlvbi5vcmcvKQoKLSBbc3RhY2sgb3ZlcmZsb3ddKGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zL3RhZ2dlZC9yKSBjb252aWVuZSBsbGVnYXIgZGVzZGUgZ29vZ2xlCgoKIyBFamVyY2ljaW9zIHBhcmEgcHJhY3RpY2FyCgotIENyZWFyIHVuIE9CSkVUTyBsbGFtYWRvIF9PQkpFVE9fIGRlZmluaWRvIGNvbW8gZWwgcmVzdWx0YWRvIGRlIGxhIHN1bWE6IDUgKyA2Ci0gQ3JlYXIgdW4gVkVDVE9SIF9WRUMwXyBxdWUgY29udGVuZ2EgbG9zIG7Dum1lcm9zIDEsIDMsIDQuCi0gQ3JlYXIgMyB2ZWN0b3JlcyAoIF9WRUMxXywgX1ZFQzJfLCBfVkVDM18pIHF1ZSBzZWFuIHRyYW5zZm9ybWFjaW9uZXMgZGVsIGFudGVyaW9yCi0gQ3JlYXIgMyB2ZWN0b3JlcyBjb24gbGEgbWlzbWEgY2FudGlkYWQgZGUgZWxlbWVudG9zIHF1ZSBWRUMwLCBwZXJvIGNvbiB2YXJpYWJsZXMgc3RyaW5nICh0ZXh0bykgKCBfVkVDNF8sIF9WRUM1XywgX1ZFQzZfKS4KLSBDcmVhciB1biBkYXRhZnJhbWUgX0RGUkFNRV8gY29tbyBjb21iaW5hY2nDs24gZGUgdG9kb3MgbG9zIF9fdmVjdG9yZXNfXyBjcmVhZG9zIHByZXZpYW1lbnRlCi0gQ3JlYXIgdW5hIGxpc3RhIGNvbiBjYWRhIHVubyBkZSBsb3MgX19lbGVtZW50b3NfXyBjcmVhZG9zIHByZXZpYW1lbnRlCgotIFBhcmEgdG9kb3MgbG9zIHZhbG9yZXMgZGVsIHZlY3RvciBfVkVDMF8sIGltcHJpbWlyIG1lZGlhbnRlIHVuIGxvb3AgZWwgZG9ibGUgZGUgZGljaG9zIHZhbG9yZXMKLSBNZWRpYW50ZSB1biBsb29wIHF1ZSBpdGVyZSBzb2JyZSB1bmEgZGUgbGFzIGNvbHVtbmFzICBfXyJzdHJpbmciX18gZGVsIGRhdGFmcmFtZSBfREZSQU1FXywgaW1wcmltaXIgdW5hIHZhcmlhYmxlIHF1ZSBjb21iaW5lIDMgY29sdW1uYXMgZGUgZGljaG8gZGF0YWZyYW1lCi0gUmVlc2NyaWJpciBlbCBWRUMxIGRlbCBEQVRBRlJBTUUgcGFyYSBxdWUgc3VzIGVsZW1lbnRvcyBzZWFuOiAgICAgIAogICAgLSAgRWwgRG9ibGUgZGUgVkVDXzAsIGN1YW5kbyDDqXN0ZSBzZWEgbWF5b3IgYSAyCiAgICAtICBJZ3VhbGVzIGEgVkVDXzAsIHBhcmEgZWwgcmVzdG8gZGUgbG9zIGNhc29zIAotIENyZWFyIHVuYSBmdW5jacOzbiBsbGFtYWRhIF9Ib2xhTXVuZG9fIHF1ZSBpbXByaW1hIGVsIHRleHRvICJIb2xhIG11bmRvIgotIENyZWFyIHVuYSBmdW5jacOzbiBxdWUgZGV2dWVsdmEgbGEgc3VtYXRvcmlhIGRlIGxvcyBuw7ptZXJvcyBlbnRlcm9zIGNvbXByZW5kaWRvcyBlbnRyZSAxIHkgdW4gcGFyw6FtZXRybyBfeF8gYSBkZWZpbmlyCgotIExldmFudGFyIGxhIGJhc2UgSW5kaXZpZHVhbCBkZWwgMWVyIHRyaW1lc3RyZSBkZSAyMDE3LCBkZSBsYSBFUEgKLSBHdWFyZGFyIGxhIGJhc2UgY29tbyB1biBhcmNoaXZvIGRlIGV4dGVuc2nDs24gLlJEUwotIFZvbHZlciBhIGxldmFudGFyIGxhIGJhc2UsIHBlcm8gY29tbyAuUkRTIHkgYXNpZ25hcmxhIGNvbiBlbCBub21icmUgX0Jhc2VSRFNfIMK/dGFyZGEgbcOhcyBvIG1lbm9zPwotIExldmFudGFyIGRlbCBFeGNlbCBsbGFtYWRvIENBTkFTVEFTIHF1ZSBzZSBlbmN1ZW50cmEgZW4gbGEgY2FycGV0YSBkZSBGdWVudGVzLCBsYSBob2phICJDQlQiIHkgZGVmaW5pcmxhIGNvbW8gX0hvamFDQlRfLiAgUHVlZGVuIHVzYXIgbGEgZnVuY2nDs246CiAgICAtIHJlYWQueGxzeCAgZGUgbGEgbGlicmVyw61hIF9feGxzeF9fIAogICAgLSByZWFkX2V4Y2VsIGRlIGxhIGxpYnJlcsOtYSBfX3JlYWR4bF9fCgotIExldmFudGFyIGVsIG1pc21vIEV4Y2VsLCB1dGlsaXphbmRvIHVuIE9iamV0byBxdWUgY29udGVuZ2EgZWwgZGlyZWN0b3JpbyBkZWwgYXJjaGl2byBhIGxldmFudGFyLgogICAgLSBDaGVxdWVhciBjb24gYGBgZGlyLmV4aXN0KClgYGAgcXVlIGxvIGNyZWFtb3MgYmllbiAowr9ubyBmdW5jaW9uw7M/IHBpc3RhOiAvXFwpCg==