Primero la Sección de Librerías de Funciones:

# rownames(installed.packages())
list.of.packages <- c(
"arm" , 
"broom" , 
"corrplot" , 
"cowplot" , 
"datasets" , 
"datasets" , 
"dplyr" , 
"eeptools" , 
"estimatr" , 
"FinCal" , 
"formatR" , 
"ggfortify" , 
"ggpubr" , 
"haven" , 
"Hmisc" , 
"infer" , 
"knitr" , 
"lmtest" , 
"margins" , 
"nycflights13" , 
"psych" , 
"readxl" , 
"reshape2" , 
"rms" , 
"skimr" , 
"stargazer" , 
"stringr" , 
"survival" , 
"tableone" , 
"tidyr" , 
"tidyverse" , 
"TTR" , 
"wooldridge" , 
"xlsx",
# Adicionales Octubre 2021:
"sqldf", # Para SQL en R
"RODBC",  # Para Conexion SQL y R Studio
# Adicionales 9 Octubre 2021:
"readr",
"devtools",
"googledrive",
# Adicionales Domingo 10 Octubre 2021:
"lattice"
)
has   <- list.of.packages %in% rownames(installed.packages())
if(any(!has)) install.packages(list.of.packages[!has])

Llamada a LIBRERIAS:

# library(arm) 
# library(broom) 
# library(corrplot) 
# library(cowplot) 
# library(datasets) 
library(dplyr) 

Attaching package: 㤼㸱dplyr㤼㸲

The following objects are masked from 㤼㸱package:stats㤼㸲:

    filter, lag

The following objects are masked from 㤼㸱package:base㤼㸲:

    intersect, setdiff, setequal, union
# library(eeptools) 
# library(estimatr) 
library(FinCal) 
# library(formatR) 
# library(ggfortify) 
# library(ggpubr) 
 library(ggplot2) 
 library(haven) #para la lectura de archivos DTA de Stata
# library(Hmisc) 
# library(infer) 
# library(knitr) 
# library(lmtest) 
# library(margins) 
# library(nycflights13) 
# library(psych) 
library(readxl) 
library(reshape2) #para hacer ReShape (Pivot Tables)
# library(rms) 
# library(skimr) 
# library(stargazer) 
# library(stringr) 
# library(survival) 
# library(tableone) 
library(tidyr) #para hacer ReShape (Pivot Tables)

Attaching package: 㤼㸱tidyr㤼㸲

The following object is masked from 㤼㸱package:reshape2㤼㸲:

    smiths
library(tidyverse) 
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ------------------------------------------------------------------------------------------------------------------------------------ tidyverse 1.3.1 --
v tibble  3.1.4     v stringr 1.4.0
v readr   2.0.1     v forcats 0.5.1
v purrr   0.3.4     
-- Conflicts --------------------------------------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
library(TTR) #para las graficas de series de tiempo
# library(wooldridge) 
library(xlsx) #para exportar a Excel file

# Adicionales Octubre 2021:
library(sqldf) # Para SQL en R
Loading required package: gsubfn
Loading required package: proto
Loading required package: RSQLite
library(RODBC) # Para Conexion SQL y R Studio
# Adicionales 9 Octubre 2021:
library(readr)
library(devtools)
Loading required package: usethis
library(googledrive)

# Adicionales Domingo 10 Octubre 2021:
library(lattice)

A partir de aquí la Sección de Importación de Datasets:

#movies_data
(
database <- paises_001.xlsx
)

To download a Google Sheet online from Google Drive into a dataframe in R:

data_to_write <- read_sheet("https://docs.google.com/spreadsheets/d/1Cm-VRHrUDlGFke4d_wkCiL-htt0ctB_p7oPn6Pl6YEc")
Auto-refreshing stale OAuth token.
v Reading from paises_001_GoogleSheet.
v Range Sheet1.
data_to_write

To download a CSV file from Google Drive (está viendose sin UTF-8(acentos, eñe) si lo abro en Excel, debe de insertarse con llamada de datos al file CSCV):

#################################################
#- Downloading a spreadsheet file as a csv 
#################################################
#library(googledrive)
#target <- drive_get( "https://docs.google.com/spreadsheets/d/1Cm-VRHrUDlGFke4d_wkCiL-htt0ctB_p7oPn6Pl6YEc" )
#drive_download( target , 
#                type= "csv" , 
#                path = "paises_001_GoogleSheet.csv" ,
#                overwrite = TRUE )

Read data from Google Drive (the ZIP file) and attribute the table to a dataframe.

# https://docs.google.com/spreadsheets/d/1PiNq7i0cXEhvXApRCvvh3FUDrF2kGeua/edit?usp=sharing&ouid=109636307569655661315&rtpof=true&sd=true
# Read data from Google Drive (the ZIP file) and attribute the table to a dataframe.
# library(googledrive)
# library(httpuv)
# temp <- tempfile( fileext = ".zip" )
# temp
# dl <- drive_download(
#         as_id( "1AiZda_1-2nwrxI8fLD0Y6e5rTg7aocv0" ) , 
#         path = temp , overwrite = TRUE )
# dl
# out <- unzip( temp , exdir = tempdir() )
# out
# bank <- read.csv( out[14] , sep = ";" )
# str(bank)
# bank

Reading file from a CSV file:

# Read data from the TXT  file and attribute the table to a dataframe.
paises_001.csv <- read.csv("prueba_csv01.csv", header=TRUE, sep=";")
paises_001.csv

Reading file from a TXT file:

# Read data from the TXT  file and attribute the table to a dataframe.
paises_001.txt <- read_csv("paises_001.txt")
Rows: 4 Columns: 3
-- Column specification -----------------------------------------------------------------------------------------------------------------------------------------------------
Delimiter: ","
chr (1): pais
dbl (2): poblacion, anio

i Use `spec()` to retrieve the full column specification for this data.
i Specify the column types or set `show_col_types = FALSE` to quiet this message.
paises_001.txt
#library(haven)
#BaseCOVID19.sav <- read_sav("BaseCOVID-19.sav")
#BaseCOVID19.sav
#library(haven)
#enaho01.dta <- read_dta("enaho01-2020-100.dta")
#enaho01.dta

data(stackloss)
stackloss
database <-stackloss

REVISION RAPIDA DEL DATAFRAME:

#View(database)
summary(database) # Summary Estadístico.
    Air.Flow       Water.Temp     Acid.Conc.      stack.loss   
 Min.   :50.00   Min.   :17.0   Min.   :72.00   Min.   : 7.00  
 1st Qu.:56.00   1st Qu.:18.0   1st Qu.:82.00   1st Qu.:11.00  
 Median :58.00   Median :20.0   Median :87.00   Median :15.00  
 Mean   :60.43   Mean   :21.1   Mean   :86.29   Mean   :17.52  
 3rd Qu.:62.00   3rd Qu.:24.0   3rd Qu.:89.00   3rd Qu.:19.00  
 Max.   :80.00   Max.   :27.0   Max.   :93.00   Max.   :42.00  
head(database) # Primeros 6.
names(database) # Names de columnas.
[1] "Air.Flow"   "Water.Temp" "Acid.Conc." "stack.loss"
print(is.data.frame(database))
[1] TRUE
#attach(database) #only if there is only 1 dataset 
# CONTENIDO DE TABLA:
# database es la tabla con datos de películas.

ANALIZAMOS LA ESTRCUTURA DE LA TABLA:

Función str: structure Lab08-importingData


# Prints out the structure of your table.
str(database) # es la función structure
'data.frame':   21 obs. of  4 variables:
 $ Air.Flow  : num  80 80 75 62 62 62 62 62 58 58 ...
 $ Water.Temp: num  27 27 25 24 22 23 24 24 23 18 ...
 $ Acid.Conc.: num  89 88 90 87 87 87 93 93 87 80 ...
 $ stack.loss: num  42 37 37 28 18 18 19 20 15 14 ...

A partir de aquí inicia el Cuerpo del Script:

EJERCICIO FUNCIONES PROPIAS EN R

# UDF - User Defined Functions #PARA OCULTAR

sum( 111 , 222 )
[1] 333
prod( 111 , 222 )
[1] 24642
log( 8 , 2 )
[1] 3
# library(ggplot2)
# ggplot()


#Incremento Porcentual
( 
Importe <- 256
)
[1] 256
(
Impuesto <- 3.2/100
)
[1] 0.032
(
Precio.de.Venta <- Importe * ( 1+Impuesto )
)
[1] 264.192
(
Variación <- Precio.de.Venta/Importe - 1
)
[1] 0.032
# Function Increase_percentaje
Increase_percentaje <- function( Importe , Prc_Impuesto ){
  Precio.de.Venta <- Importe * ( 1+Prc_Impuesto/100 )
  Precio.de.Venta <- round( Precio.de.Venta , 2 )
  
  print( paste( "Increasing ", Importe ,
                " en ", Prc_Impuesto , 
                "% resulta en: ", Precio.de.Venta , " USD.",
                sep = "" ))
  return(Precio.de.Venta)
}

#Llamar a la function
Precio.de.Venta.1 <- Increase_percentaje( 256 , 3.2 ) 
[1] "Increasing 256 en 3.2% resulta en: 264.19 USD."
Precio.de.Venta.1
[1] 264.19

OTRA FUNCION:

# Function Increase_percentaje2
Increase_percentaje2 <- function( Importe , Prc_Impuesto ){
  Precio.de.Venta <- Importe * ( 1+Prc_Impuesto/100 )
  Precio.de.Venta <- round( Precio.de.Venta , 2 )
  
  if( Importe <= 0 ){
    print("Error. Importe <= 0.")
    return(NULL)
  }else if( Prc_Impuesto <= 0 ){
    print("Error. Prc_Impuesto <= 0.")
    return(NULL)
  }else{
  
  print( paste( "Increasing ", Importe ,
                " en ", Prc_Impuesto , 
                "% resulta en: ", Precio.de.Venta , " USD.",
                sep = "" ))
  return(Precio.de.Venta)
  }
}
#Llamar a la function
Precio.de.Venta.1 <- Increase_percentaje2( 256 , 3.2 ) 
[1] "Increasing 256 en 3.2% resulta en: 264.19 USD."
str(Precio.de.Venta.1)
 num 264
#Precio.de.Venta.1
Precio.de.Venta.2 <- Increase_percentaje2( -256 , 3.2 ) 
[1] "Error. Importe <= 0."
str(Precio.de.Venta.2)
 NULL
#Precio.de.Venta.2
Precio.de.Venta.3 <- Increase_percentaje2( 256 , -3.2 ) 
[1] "Error. Prc_Impuesto <= 0."
str(Precio.de.Venta.3)
 NULL
#Precio.de.Venta.2

EJEMPLO BUCLE FOR:

for( i in 1:5){
  print( i^2 )
}
[1] 1
[1] 4
[1] 9
[1] 16
[1] 25
Vector.1a5 <- c(1:5)
#Vector.1a5
Vector.1a5^2
[1]  1  4  9 16 25
for( i in Vector.1a5 ){
  print( i^2 )
}
[1] 1
[1] 4
[1] 9
[1] 16
[1] 25
Dataframe.1a5 <- as.data.frame( c(1:5) )
#Dataframe.1a5
names(Dataframe.1a5)
[1] "c(1:5)"
Dataframe.1a5$c
[1] 1 2 3 4 5
for( i in Dataframe.1a5$c ){
  print( i^2 )
}  
[1] 1
[1] 4
[1] 9
[1] 16
[1] 25
#help("sqldf")

mtcars
#View(mtcars)
df_query <- sqldf("select * from mtcars")
df_query
#str(df_query)

df_query <- sqldf("select * from stackloss")
df_query
#str(df_query)
sqldf("SELECT cyl , count( cyl ) as Cilindros FROM mtcars GROUP BY cyl ")
NA
NA

df_pivot_sql

df_pivot_sql <- sqldf( " SELECT cyl , 
                                COUNT( cyl ) as Cilindros 
                         FROM mtcars 
                         GROUP BY cyl ")
df_pivot_sql

EJERCICIOS ADICIONALES CON mtcars:

#mtcars
tabla.1 <- table( mtcars$cyl )
#tabla.1

colores <- c( "orange" , 
              "green" , 
              "yellow" )
#colores

plot.1 <- barplot( tabla.1 , 
                   xlab = "Cilindros" , 
                   ylab = "Frequencia" , 
                   main = "Nro de Cilindros" ,
                   col = colores )

plot.1
     [,1]
[1,]  0.7
[2,]  1.9
[3,]  3.1

Con library lattice:

#mtcars
tabla.1 <- table( mtcars$cyl )
#tabla.1

colores <- c( "orange" , 
              "green" , 
              "yellow" )
#colores

plot.3 <- barchart( tabla.1 , 
                    xlab = "Cilindros" , 
                    ylab = "Número de Cilindros" , 
                    main = "Número de Cilindros", 
                    col = colores )

plot.3

CONTINUACION CON mtcars :


plot.2 <- ggplot( mtcars ,
                  aes( cyl )) +
          geom_bar( fill = colores ) + 
          labs( x= "Cilindros" , 
                y = "Frecuencias" , 
                title = "Numero de Cilindros")
plot.2  

NA

REPASO DE MATRICES:

# PARA OCULTAR
matrix.1 <- matrix( 1:10 , 
            nrow = 5 , 
            ncol = 4 )
matrix.1
     [,1] [,2] [,3] [,4]
[1,]    1    6    1    6
[2,]    2    7    2    7
[3,]    3    8    3    8
[4,]    4    9    4    9
[5,]    5   10    5   10
dim(matrix.1)
[1] 5 4
matrix.1[2,4]
[1] 7
matrix.1[2, ]
[1] 2 7 2 7
matrix.1[ ,4]
[1]  6  7  8  9 10
df_matrix.1 <- as.data.frame( matrix.1 , row.names = NULL, 
                              optional = FALSE , 
                              make.names = TRUE , 
               stringsAsFactors = default.stringsAsFactors() )
#df_matrix.1
#df_matrix.1$V4
df_matrix.1['V4']
NA

EJERCICIOS:

summary(database)
    Air.Flow       Water.Temp     Acid.Conc.      stack.loss   
 Min.   :50.00   Min.   :17.0   Min.   :72.00   Min.   : 7.00  
 1st Qu.:56.00   1st Qu.:18.0   1st Qu.:82.00   1st Qu.:11.00  
 Median :58.00   Median :20.0   Median :87.00   Median :15.00  
 Mean   :60.43   Mean   :21.1   Mean   :86.29   Mean   :17.52  
 3rd Qu.:62.00   3rd Qu.:24.0   3rd Qu.:89.00   3rd Qu.:19.00  
 Max.   :80.00   Max.   :27.0   Max.   :93.00   Max.   :42.00  
matrix_summary <- do.call(cbind, lapply(database, summary))
matrix_summary
        Air.Flow Water.Temp Acid.Conc. stack.loss
Min.    50.00000   17.00000   72.00000    7.00000
1st Qu. 56.00000   18.00000   82.00000   11.00000
Median  58.00000   20.00000   87.00000   15.00000
Mean    60.42857   21.09524   86.28571   17.52381
3rd Qu. 62.00000   24.00000   89.00000   19.00000
Max.    80.00000   27.00000   93.00000   42.00000
str(matrix_summary)
 num [1:6, 1:4] 50 56 58 60.4 62 ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:6] "Min." "1st Qu." "Median" "Mean" ...
  ..$ : chr [1:4] "Air.Flow" "Water.Temp" "Acid.Conc." "stack.loss"
df_summary <- as.data.frame(matrix_summary, row.names = NULL, optional = FALSE,
              make.names = TRUE, 
              stringsAsFactors = default.stringsAsFactors())
df_summary

summary( database$cost_millions )
Length  Class   Mode 
     0   NULL   NULL 
# Retrieve a subset_dataframe of the data frame consisting of the "genre" columns
database['PAIS']
Error in `[.data.frame`(database, "PAIS") : undefined columns selected
# Retrieve the 3rd row of the data frame. # PARA OCULTAR
database[3,]

# Retrieve the third row of the data frame, but only the "name" and "length_min" columns.
database[3, c("PAIS","CODIGO")]
Error in `[.data.frame`(database, 3, c("PAIS", "CODIGO")) : 
  undefined columns selected

summary(database)
    Air.Flow       Water.Temp     Acid.Conc.      stack.loss   
 Min.   :50.00   Min.   :17.0   Min.   :72.00   Min.   : 7.00  
 1st Qu.:56.00   1st Qu.:18.0   1st Qu.:82.00   1st Qu.:11.00  
 Median :58.00   Median :20.0   Median :87.00   Median :15.00  
 Mean   :60.43   Mean   :21.1   Mean   :86.29   Mean   :17.52  
 3rd Qu.:62.00   3rd Qu.:24.0   3rd Qu.:89.00   3rd Qu.:19.00  
 Max.   :80.00   Max.   :27.0   Max.   :93.00   Max.   :42.00  
histograma <- hist(database$Air.Flow ,col="yellow",breaks = 10)

histograma
$breaks
[1] 50 55 60 65 70 75 80

$counts
[1] 5 7 5 1 1 2

$density
[1] 0.04761905 0.06666667 0.04761905 0.00952381 0.00952381 0.01904762

$mids
[1] 52.5 57.5 62.5 67.5 72.5 77.5

$xname
[1] "database$Air.Flow"

$equidist
[1] TRUE

attr(,"class")
[1] "histogram"
summary(database)
    Air.Flow       Water.Temp     Acid.Conc.      stack.loss   
 Min.   :50.00   Min.   :17.0   Min.   :72.00   Min.   : 7.00  
 1st Qu.:56.00   1st Qu.:18.0   1st Qu.:82.00   1st Qu.:11.00  
 Median :58.00   Median :20.0   Median :87.00   Median :15.00  
 Mean   :60.43   Mean   :21.1   Mean   :86.29   Mean   :17.52  
 3rd Qu.:62.00   3rd Qu.:24.0   3rd Qu.:89.00   3rd Qu.:19.00  
 Max.   :80.00   Max.   :27.0   Max.   :93.00   Max.   :42.00  
histograma2 <- hist(database$Nº ,col="yellow",breaks = 10)
Error in hist.default(database$Nº, col = "yellow", breaks = 10) : 
  'x' must be numeric
#MODELOS

modelo_1 <- glm( stackloss$Air.Flow ~ stackloss$stack.loss, family="poisson", data=stackloss)
modelo_1

Call:  glm(formula = stackloss$Air.Flow ~ stackloss$stack.loss, family = "poisson", 
    data = stackloss)

Coefficients:
         (Intercept)  stackloss$stack.loss  
             3.87034               0.01271  

Degrees of Freedom: 20 Total (i.e. Null);  19 Residual
Null Deviance:      26.89 
Residual Deviance: 4.555    AIC: 133.1
summary(modelo_1)

Call:
glm(formula = stackloss$Air.Flow ~ stackloss$stack.loss, family = "poisson", 
    data = stackloss)

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-0.79351  -0.33705   0.02029   0.21944   1.52116  

Coefficients:
                     Estimate Std. Error z value Pr(>|z|)    
(Intercept)          3.870336   0.056986  67.917  < 2e-16 ***
stackloss$stack.loss 0.012711   0.002627   4.838 1.31e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 26.8930  on 20  degrees of freedom
Residual deviance:  4.5552  on 19  degrees of freedom
AIC: 133.12

Number of Fisher Scoring iterations: 3
plot(modelo_1)

summary(modelo_1)

Call:
glm(formula = stackloss$Air.Flow ~ stackloss$stack.loss, family = "poisson", 
    data = stackloss)

Deviance Residuals: 
     Min        1Q    Median        3Q       Max  
-0.79351  -0.33705   0.02029   0.21944   1.52116  

Coefficients:
                     Estimate Std. Error z value Pr(>|z|)    
(Intercept)          3.870336   0.056986  67.917  < 2e-16 ***
stackloss$stack.loss 0.012711   0.002627   4.838 1.31e-06 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

(Dispersion parameter for poisson family taken to be 1)

    Null deviance: 26.8930  on 20  degrees of freedom
Residual deviance:  4.5552  on 19  degrees of freedom
AIC: 133.12

Number of Fisher Scoring iterations: 3
barplot(modelo_1)
Error in barplot.default(modelo_1) : 
  'height' must be a vector or a matrix
curve(pnorm(x, mean = mean(stackloss$stack.loss), sd = sd (stackloss$stack.loss)) , xlim = c( 50,80), col="blue", lwd=2, xlab="stackloss", ylab ="Probabilidad")


time = gsub(":", "-", Sys.time())

#- exporta en formato .csv el df df_summary al fichero "df_summary.csv". Se guardará en la subcarpeta "datos/pruebas/" del proyecto
folder_path <- "./output_databases/"
filename <- "df_summary"
filetype <-".csv"
path <- paste(folder_path,filename," ",time,filetype, sep="")
write_csv(df_summary, path)

Hay varios packages que graban datos en formato .xls. Pero el más sencillo es el package xlsx. Veámoslo:

# install.packages("xlsx")
# library(xlsx)
write.xlsx(df_summary, "./output_databases/df_summary.xlsx", sheetName = "df_summary" )

La función write.xlsx() permite añadir datos a un archivo .xlsx preexistente; para ello tenemos que usar la opción append = TRUE:

# library(xlsx)
write.xlsx(df_summary, "./output_databases/df_summary.xlsx", sheetName = "summary", append = TRUE)

DEL EJERCICIO DE EJECUTAR SQL QUERY en UN R NOTEBOOK:

write.xlsx( df_pivot_sql , 
            "./output_databases/df_pivot_sql.xlsx", 
            sheetName = "df_pivot_sql" )

GRAFICA

#**********************************************************************
#*# Publication quality graphs require 600dpi
dpi=600    #pixels per square inch
carpeta = "./output_images/"
archivo = "histograma"
time = gsub(":", "-", Sys.time())
carpeta_y_archivo = paste(carpeta,archivo," ",time,".tif", sep="")
nombre_de_tif = carpeta_y_archivo
tiff(nombre_de_tif, width=6*dpi, height=5*dpi, res=dpi)
#**********************************************************************
histograma <- hist(database$Nº ,col="yellow",breaks = 10)
histograma
$breaks
 [1]  0  5 10 15 20 25 30 35 40 45 50 55 60

$counts
 [1] 5 5 5 5 4 5 5 5 5 5 5 3

$density
 [1] 0.01754386 0.01754386 0.01754386 0.01754386 0.01403509 0.01754386 0.01754386
 [8] 0.01754386 0.01754386 0.01754386 0.01754386 0.01052632

$mids
 [1]  2.5  7.5 12.5 17.5 22.5 27.5 32.5 37.5 42.5 47.5 52.5 57.5

$xname
[1] "database$Nº"

$equidist
[1] TRUE

attr(,"class")
[1] "histogram"
#**********************************************************************
dev.off()
null device 
          1 
print(paste("Finalizado procesamiento de ",archivo," ",time, sep=""))
[1] "Finalizado procesamiento de histograma 2021-10-13 20-42-17"
#**********************************************************************
citation()

To cite R in publications use:

  R Core Team (2021). R: A language and environment for statistical computing. R Foundation for Statistical Computing, Vienna, Austria. URL
  https://www.R-project.org/.

A BibTeX entry for LaTeX users is

  @Manual{,
    title = {R: A Language and Environment for Statistical Computing},
    author = {{R Core Team}},
    organization = {R Foundation for Statistical Computing},
    address = {Vienna, Austria},
    year = {2021},
    url = {https://www.R-project.org/},
  }

We have invested a lot of time and effort in creating R, please cite it when using it for data analysis. See also ‘citation("pkgname")’ for citing R
packages.
citation("readxl") 

To cite package ‘readxl’ in publications use:

  Hadley Wickham and Jennifer Bryan (2019). readxl: Read Excel Files. R package version 1.3.1. https://CRAN.R-project.org/package=readxl

A BibTeX entry for LaTeX users is

  @Manual{,
    title = {readxl: Read Excel Files},
    author = {Hadley Wickham and Jennifer Bryan},
    year = {2019},
    note = {R package version 1.3.1},
    url = {https://CRAN.R-project.org/package=readxl},
  }
# 
help("readxl") # Documentacion de la library readxl
LS0tDQp0aXRsZTogIlJlYWQgR29vZ2xlIFNoZWV0LCBHR3Bsb3QyLCBRdWVyeSBTUUwgZW4gIFIgTm90ZWJvb2sgKHBpdm90IHRhYmxlKSwgYnVjbGUgZm9yICYgZnVuY2lvbmVzLCBARUNSJ3MgTWFzdGVyIFIgTm90ZWJvb2sgVGVtcGxhdGUgMjAyMS1JSSINCmF1dGhvcjogIkluZy4gRXJuZXN0byBDYW5jaG8tUm9kcmlndWV6LCBNQkEgR2VvcmdlIFdhc2hpbmd0b24gVW5pdmVyc2l0eSINCmVtYWlsOiAiZXJuZXN0by5jYW5jaG9AdW5tc20uZWR1LnBlIg0KZGF0ZTogIjIwMjEuMTAuMTMiDQpvdXRwdXQ6DQogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQNCiAgcGRmX2RvY3VtZW50OiBkZWZhdWx0DQogIGh0bWxfZG9jdW1lbnQ6DQogICAgZGZfcHJpbnQ6IHBhZ2VkDQogIHdvcmRfZG9jdW1lbnQ6IGRlZmF1bHQNCi0tLQ0KDQpQcmltZXJvIGxhIFNlY2Npw7NuIGRlIExpYnJlcsOtYXMgZGUgRnVuY2lvbmVzOiANCg0KYGBge3IgSU5TVEFMQUNJT04gTElCUkVSSUFTIH0NCiMgcm93bmFtZXMoaW5zdGFsbGVkLnBhY2thZ2VzKCkpDQpsaXN0Lm9mLnBhY2thZ2VzIDwtIGMoDQoiYXJtIiAsIA0KImJyb29tIiAsIA0KImNvcnJwbG90IiAsIA0KImNvd3Bsb3QiICwgDQoiZGF0YXNldHMiICwgDQoiZGF0YXNldHMiICwgDQoiZHBseXIiICwgDQoiZWVwdG9vbHMiICwgDQoiZXN0aW1hdHIiICwgDQoiRmluQ2FsIiAsIA0KImZvcm1hdFIiICwgDQoiZ2dmb3J0aWZ5IiAsIA0KImdncHViciIgLCANCiJoYXZlbiIgLCANCiJIbWlzYyIgLCANCiJpbmZlciIgLCANCiJrbml0ciIgLCANCiJsbXRlc3QiICwgDQoibWFyZ2lucyIgLCANCiJueWNmbGlnaHRzMTMiICwgDQoicHN5Y2giICwgDQoicmVhZHhsIiAsIA0KInJlc2hhcGUyIiAsIA0KInJtcyIgLCANCiJza2ltciIgLCANCiJzdGFyZ2F6ZXIiICwgDQoic3RyaW5nciIgLCANCiJzdXJ2aXZhbCIgLCANCiJ0YWJsZW9uZSIgLCANCiJ0aWR5ciIgLCANCiJ0aWR5dmVyc2UiICwgDQoiVFRSIiAsIA0KIndvb2xkcmlkZ2UiICwgDQoieGxzeCIsDQojIEFkaWNpb25hbGVzIE9jdHVicmUgMjAyMToNCiJzcWxkZiIsICMgUGFyYSBTUUwgZW4gUg0KIlJPREJDIiwgICMgUGFyYSBDb25leGlvbiBTUUwgeSBSIFN0dWRpbw0KIyBBZGljaW9uYWxlcyA5IE9jdHVicmUgMjAyMToNCiJyZWFkciIsDQoiZGV2dG9vbHMiLA0KImdvb2dsZWRyaXZlIiwNCiMgQWRpY2lvbmFsZXMgRG9taW5nbyAxMCBPY3R1YnJlIDIwMjE6DQoibGF0dGljZSINCikNCmhhcyAgIDwtIGxpc3Qub2YucGFja2FnZXMgJWluJSByb3duYW1lcyhpbnN0YWxsZWQucGFja2FnZXMoKSkNCmlmKGFueSghaGFzKSkgaW5zdGFsbC5wYWNrYWdlcyhsaXN0Lm9mLnBhY2thZ2VzWyFoYXNdKQ0KDQpgYGANCg0KDQpMbGFtYWRhIGEgTElCUkVSSUFTOg0KYGBge3IgTExBTUFEQSBBIExJQlJFUklBU30NCiMgbGlicmFyeShhcm0pIA0KIyBsaWJyYXJ5KGJyb29tKSANCiMgbGlicmFyeShjb3JycGxvdCkgDQojIGxpYnJhcnkoY293cGxvdCkgDQojIGxpYnJhcnkoZGF0YXNldHMpIA0KbGlicmFyeShkcGx5cikgDQojIGxpYnJhcnkoZWVwdG9vbHMpIA0KIyBsaWJyYXJ5KGVzdGltYXRyKSANCmxpYnJhcnkoRmluQ2FsKSANCiMgbGlicmFyeShmb3JtYXRSKSANCiMgbGlicmFyeShnZ2ZvcnRpZnkpIA0KIyBsaWJyYXJ5KGdncHVicikgDQogbGlicmFyeShnZ3Bsb3QyKSANCiBsaWJyYXJ5KGhhdmVuKSAjcGFyYSBsYSBsZWN0dXJhIGRlIGFyY2hpdm9zIERUQSBkZSBTdGF0YQ0KIyBsaWJyYXJ5KEhtaXNjKSANCiMgbGlicmFyeShpbmZlcikgDQojIGxpYnJhcnkoa25pdHIpIA0KIyBsaWJyYXJ5KGxtdGVzdCkgDQojIGxpYnJhcnkobWFyZ2lucykgDQojIGxpYnJhcnkobnljZmxpZ2h0czEzKSANCiMgbGlicmFyeShwc3ljaCkgDQpsaWJyYXJ5KHJlYWR4bCkgDQpsaWJyYXJ5KHJlc2hhcGUyKSAjcGFyYSBoYWNlciBSZVNoYXBlIChQaXZvdCBUYWJsZXMpDQojIGxpYnJhcnkocm1zKSANCiMgbGlicmFyeShza2ltcikgDQojIGxpYnJhcnkoc3RhcmdhemVyKSANCiMgbGlicmFyeShzdHJpbmdyKSANCiMgbGlicmFyeShzdXJ2aXZhbCkgDQojIGxpYnJhcnkodGFibGVvbmUpIA0KbGlicmFyeSh0aWR5cikgI3BhcmEgaGFjZXIgUmVTaGFwZSAoUGl2b3QgVGFibGVzKQ0KbGlicmFyeSh0aWR5dmVyc2UpIA0KbGlicmFyeShUVFIpICNwYXJhIGxhcyBncmFmaWNhcyBkZSBzZXJpZXMgZGUgdGllbXBvDQojIGxpYnJhcnkod29vbGRyaWRnZSkgDQpsaWJyYXJ5KHhsc3gpICNwYXJhIGV4cG9ydGFyIGEgRXhjZWwgZmlsZQ0KDQojIEFkaWNpb25hbGVzIE9jdHVicmUgMjAyMToNCmxpYnJhcnkoc3FsZGYpICMgUGFyYSBTUUwgZW4gUg0KbGlicmFyeShST0RCQykgIyBQYXJhIENvbmV4aW9uIFNRTCB5IFIgU3R1ZGlvDQojIEFkaWNpb25hbGVzIDkgT2N0dWJyZSAyMDIxOg0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkoZGV2dG9vbHMpDQpsaWJyYXJ5KGdvb2dsZWRyaXZlKQ0KDQojIEFkaWNpb25hbGVzIERvbWluZ28gMTAgT2N0dWJyZSAyMDIxOg0KbGlicmFyeShsYXR0aWNlKQ0KYGBgDQoNCg0KQSBwYXJ0aXIgZGUgYXF1w60gbGEgU2VjY2nDs24gZGUgSW1wb3J0YWNpw7NuIGRlIERhdGFzZXRzOg0KYGBge3IgREFUQSB9DQpwcmludCgiV29ya2luZyBEaXJlY3Rvcnk6ICIpOyBnZXR3ZCgpICNnZXQgdG8gc2hvdyBtZSB0aGUgY3VycmVudCBXb3JraW5nIERpcmVjdG9yeSANCiMjIyBDYXJnYW5kbyBCQkREOiBuNWF5NXFhZGZlN2Uxbm5zdjVzMDFvZTF4NjJtcTUxai5jc3YgIyMjIw0KIyBWZXJzaW9uIGRlIEJCREQ6IDIwMjEuMDkuMjQgdjENCiMgUlVUQTogaHR0cHM6Ly9pYm0uYm94LmNvbS9zaGFyZWQvc3RhdGljLw0KDQojIFhMUyBmaWxlLCAgRG93bmxvYWQgZGF0YXNldHMNCiMgZG93bmxvYWQuZmlsZSggImh0dHBzOi8vaWJtLmJveC5jb20vc2hhcmVkL3N0YXRpYy9ueDBvaGQ5c3EwaXozcDg3MXpnOGVoYzFtMzlpYnB4Ni54bHMiICwgDQojICAgICAgICAgICAgICAgIGRlc3RmaWxlPSJtb3ZpZXMtZGIueGxzIiApDQoNCiMgQ1NWIGZpbGUsICBEb3dubG9hZCBkYXRhc2V0cw0KZG93bmxvYWQuZmlsZSgiaHR0cHM6Ly9pYm0uYm94LmNvbS9zaGFyZWQvc3RhdGljL241YXk1cWFkZmU3ZTFubnN2NXMwMW9lMXg2Mm1xNTFqLmNzdiIsIA0KICAgICAgICAgICAgICBkZXN0ZmlsZT0ibW92aWVzLWRiLmNzdiIpDQpkYXRhYmFzZV9jc3YgPC0gcmVhZC5jc3YoIm1vdmllcy1kYi5jc3YiLCBoZWFkZXI9VFJVRSwgc2VwPSIsIikNCg0KZmlsZS5leGlzdHMoIm1vdmllcy1kYi54bHN4IikNCiMgUmVhZCBkYXRhIGZyb20gdGhlIFhMUyBmaWxlIGFuZCBhdHRyaWJ1dGUgdGhlIHRhYmxlIGEgZGF0YWZyYW1lLg0KZGF0YWJhc2VfeGxzeCA8LSByZWFkX2V4Y2VsKCJtb3ZpZXMtZGIueGxzeCIpDQpkYXRhYmFzZV94bHN4DQoNCiNtb3ZpZXNfZGF0YQ0KKA0KZGF0YWJhc2UgPC0gZGF0YWJhc2VfeGxzeA0KKQ0KDQojIFJlYWQgZGF0YSBmcm9tIHRoZSBYTFMgZmlsZSBhbmQgYXR0cmlidXRlIHRoZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCnBhaXNlc18wMDEueGxzeCA8LSByZWFkX2V4Y2VsKCJwYWlzZXNfMDAxLnhsc3giKQ0KcGFpc2VzXzAwMS54bHN4DQoNCmBgYA0KDQoNCmBgYHtyIFNlbmQgdG8gdGhlIGRhdGFmcmFtZSBkYXRhYmFzZX0NCiNtb3ZpZXNfZGF0YQ0KKA0KZGF0YWJhc2UgPC0gcGFpc2VzXzAwMS54bHN4DQopDQoNCmBgYA0KDQpUbyBkb3dubG9hZCBhIEdvb2dsZSBTaGVldCBvbmxpbmUgZnJvbSBHb29nbGUgRHJpdmUgaW50byBhIGRhdGFmcmFtZSBpbiBSOg0KYGBge3IgUmVhZCBHb29nbGUgU2hlZXR9DQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojLSBHb29nbGVTaGVldDQNCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiNpbnN0YWxsLnBhY2thZ2VzKCJkZXZ0b29scyIpDQpsaWJyYXJ5KGRldnRvb2xzKQ0KI2RldnRvb2xzOjppbnN0YWxsX2dpdGh1YigidGlkeXZlcnNlL2dvb2dsZXNoZWV0czQiKQ0KDQojaW5zdGFsbC5wYWNrYWdlcygiZ2FyZ2xlIikNCmxpYnJhcnkoZ29vZ2xlc2hlZXRzNCkNCg0KZ3M0X2F1dGgoKQ0KI2hlbHAoZ3M0X2F1dGgpDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQojLSBSZWFkIGFuIGV4aXN0aW5nIFNwcmVhZHNoZWV0IA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KZGF0YV90b193cml0ZSA8LSByZWFkX3NoZWV0KCJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xQ20tVlJIclVEbEdGa2U0ZF93a0NpTC1odHQwY3RCX3A3b1BuNlBsNllFYyIpDQpkYXRhX3RvX3dyaXRlDQpgYGANCg0KDQpUbyBkb3dubG9hZCBhIENTViBmaWxlIGZyb20gR29vZ2xlIERyaXZlIChlc3TDoSB2aWVuZG9zZSBzaW4gVVRGLTgoYWNlbnRvcywgZcOxZSkgc2kgbG8gYWJybyBlbiBFeGNlbCwgZGViZSBkZSBpbnNlcnRhcnNlIGNvbiBsbGFtYWRhIGRlIGRhdG9zIGFsIGZpbGUgQ1NDVik6DQpgYGB7ciBSZWFkIENTViBmcm9tIERyaXZlfQ0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KIy0gRG93bmxvYWRpbmcgYSBzcHJlYWRzaGVldCBmaWxlIGFzIGEgY3N2IA0KIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KI2xpYnJhcnkoZ29vZ2xlZHJpdmUpDQojdGFyZ2V0IDwtIGRyaXZlX2dldCggImh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFDbS1WUkhyVURsR0ZrZTRkX3drQ2lMLWh0dDBjdEJfcDdvUG42UGw2WUVjIiApDQojZHJpdmVfZG93bmxvYWQoIHRhcmdldCAsIA0KIyAgICAgICAgICAgICAgICB0eXBlPSAiY3N2IiAsIA0KIyAgICAgICAgICAgICAgICBwYXRoID0gInBhaXNlc18wMDFfR29vZ2xlU2hlZXQuY3N2IiAsDQojICAgICAgICAgICAgICAgIG92ZXJ3cml0ZSA9IFRSVUUgKQ0KDQpgYGANCg0KUmVhZCBkYXRhIGZyb20gR29vZ2xlIERyaXZlICh0aGUgWklQIGZpbGUpIGFuZCBhdHRyaWJ1dGUgdGhlIHRhYmxlIHRvIGEgZGF0YWZyYW1lLg0KYGBge3IgUmVhZCBaSVAgd2l0aCBDU1YgZmlsZSBmcm9tIEdvb2dsZSBEcml2ZX0NCiMgaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVBpTnE3aTBjWEVodlhBcFJDdnZoM0ZVRHJGMmtHZXVhL2VkaXQ/dXNwPXNoYXJpbmcmb3VpZD0xMDk2MzYzMDc1Njk2NTU2NjEzMTUmcnRwb2Y9dHJ1ZSZzZD10cnVlDQojIFJlYWQgZGF0YSBmcm9tIEdvb2dsZSBEcml2ZSAodGhlIFpJUCBmaWxlKSBhbmQgYXR0cmlidXRlIHRoZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCiMgbGlicmFyeShnb29nbGVkcml2ZSkNCiMgbGlicmFyeShodHRwdXYpDQojIHRlbXAgPC0gdGVtcGZpbGUoIGZpbGVleHQgPSAiLnppcCIgKQ0KIyB0ZW1wDQojIGRsIDwtIGRyaXZlX2Rvd25sb2FkKA0KIyAgICAgICAgIGFzX2lkKCAiMUFpWmRhXzEtMm53cnhJOGZMRDBZNmU1clRnN2FvY3YwIiApICwgDQojICAgICAgICAgcGF0aCA9IHRlbXAgLCBvdmVyd3JpdGUgPSBUUlVFICkNCiMgZGwNCiMgb3V0IDwtIHVuemlwKCB0ZW1wICwgZXhkaXIgPSB0ZW1wZGlyKCkgKQ0KIyBvdXQNCiMgYmFuayA8LSByZWFkLmNzdiggb3V0WzE0XSAsIHNlcCA9ICI7IiApDQojIHN0cihiYW5rKQ0KIyBiYW5rDQoNCmBgYA0KDQoNClJlYWRpbmcgZmlsZSBmcm9tIGEgQ1NWIGZpbGU6DQpgYGB7ciBSRUFEIENTVn0NCiMgUmVhZCBkYXRhIGZyb20gdGhlIFRYVCAgZmlsZSBhbmQgYXR0cmlidXRlIHRoZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCnBhaXNlc18wMDEuY3N2IDwtIHJlYWQuY3N2KCJwcnVlYmFfY3N2MDEuY3N2IiwgaGVhZGVyPVRSVUUsIHNlcD0iOyIpDQpwYWlzZXNfMDAxLmNzdg0KYGBgDQoNClJlYWRpbmcgZmlsZSBmcm9tIGEgVFhUIGZpbGU6DQpgYGB7ciBSRUFEIFRYVH0NCiMgUmVhZCBkYXRhIGZyb20gdGhlIFRYVCAgZmlsZSBhbmQgYXR0cmlidXRlIHRoZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCnBhaXNlc18wMDEudHh0IDwtIHJlYWRfY3N2KCJwYWlzZXNfMDAxLnR4dCIpDQpwYWlzZXNfMDAxLnR4dA0KYGBgDQoNCmBgYHtyIFJlYWQgU1BTUyBmaWxlfQ0KI2xpYnJhcnkoaGF2ZW4pDQojQmFzZUNPVklEMTkuc2F2IDwtIHJlYWRfc2F2KCJCYXNlQ09WSUQtMTkuc2F2IikNCiNCYXNlQ09WSUQxOS5zYXYNCg0KYGBgDQoNCmBgYHtyIFJlYWQgU1RBVEEgZmlsZXN9DQojbGlicmFyeShoYXZlbikNCiNlbmFobzAxLmR0YSA8LSByZWFkX2R0YSgiZW5haG8wMS0yMDIwLTEwMC5kdGEiKQ0KI2VuYWhvMDEuZHRhDQoNCmBgYA0KDQpgYGB7cn0NCg0KZGF0YShzdGFja2xvc3MpDQpzdGFja2xvc3MNCmRhdGFiYXNlIDwtc3RhY2tsb3NzDQpgYGANCg0KDQpSRVZJU0lPTiBSQVBJREEgREVMIERBVEFGUkFNRToNCmBgYHtyfQ0KI1ZpZXcoZGF0YWJhc2UpDQpzdW1tYXJ5KGRhdGFiYXNlKSAjIFN1bW1hcnkgRXN0YWTDrXN0aWNvLg0KaGVhZChkYXRhYmFzZSkgIyBQcmltZXJvcyA2Lg0KbmFtZXMoZGF0YWJhc2UpICMgTmFtZXMgZGUgY29sdW1uYXMuDQpwcmludChpcy5kYXRhLmZyYW1lKGRhdGFiYXNlKSkNCiNhdHRhY2goZGF0YWJhc2UpICNvbmx5IGlmIHRoZXJlIGlzIG9ubHkgMSBkYXRhc2V0IA0KIyBDT05URU5JRE8gREUgVEFCTEE6DQojIGRhdGFiYXNlIGVzIGxhIHRhYmxhIGNvbiBkYXRvcyBkZSBwZWzDrWN1bGFzLg0KYGBgDQoNCkFOQUxJWkFNT1MgTEEgRVNUUkNVVFVSQSBERSBMQSBUQUJMQToNCg0KRnVuY2nDs24gc3RyOiBzdHJ1Y3R1cmUNCkxhYjA4LWltcG9ydGluZ0RhdGEgDQpgYGB7ciBDVUVSUE99DQoNCiMgUHJpbnRzIG91dCB0aGUgc3RydWN0dXJlIG9mIHlvdXIgdGFibGUuDQpzdHIoZGF0YWJhc2UpICMgZXMgbGEgZnVuY2nDs24gc3RydWN0dXJlDQoNCg0KYGBgDQoNCg0KQSBwYXJ0aXIgZGUgYXF1w60gaW5pY2lhIGVsIEN1ZXJwbyBkZWwgU2NyaXB0Og0KDQpFSkVSQ0lDSU8gRlVOQ0lPTkVTIFBST1BJQVMgRU4gUg0KYGBge3J9DQojIFVERiAtIFVzZXIgRGVmaW5lZCBGdW5jdGlvbnMgI1BBUkEgT0NVTFRBUg0KDQpzdW0oIDExMSAsIDIyMiApDQpwcm9kKCAxMTEgLCAyMjIgKQ0KbG9nKCA4ICwgMiApDQoNCiMgbGlicmFyeShnZ3Bsb3QyKQ0KIyBnZ3Bsb3QoKQ0KDQoNCiNJbmNyZW1lbnRvIFBvcmNlbnR1YWwNCiggDQpJbXBvcnRlIDwtIDI1Ng0KKQ0KKA0KSW1wdWVzdG8gPC0gMy4yLzEwMA0KKQ0KKA0KUHJlY2lvLmRlLlZlbnRhIDwtIEltcG9ydGUgKiAoIDErSW1wdWVzdG8gKQ0KKQ0KKA0KVmFyaWFjacOzbiA8LSBQcmVjaW8uZGUuVmVudGEvSW1wb3J0ZSAtIDENCikNCg0KIyBGdW5jdGlvbiBJbmNyZWFzZV9wZXJjZW50YWplDQpJbmNyZWFzZV9wZXJjZW50YWplIDwtIGZ1bmN0aW9uKCBJbXBvcnRlICwgUHJjX0ltcHVlc3RvICl7DQogIFByZWNpby5kZS5WZW50YSA8LSBJbXBvcnRlICogKCAxK1ByY19JbXB1ZXN0by8xMDAgKQ0KICBQcmVjaW8uZGUuVmVudGEgPC0gcm91bmQoIFByZWNpby5kZS5WZW50YSAsIDIgKQ0KICANCiAgcHJpbnQoIHBhc3RlKCAiSW5jcmVhc2luZyAiLCBJbXBvcnRlICwNCiAgICAgICAgICAgICAgICAiIGVuICIsIFByY19JbXB1ZXN0byAsIA0KICAgICAgICAgICAgICAgICIlIHJlc3VsdGEgZW46ICIsIFByZWNpby5kZS5WZW50YSAsICIgVVNELiIsDQogICAgICAgICAgICAgICAgc2VwID0gIiIgKSkNCiAgcmV0dXJuKFByZWNpby5kZS5WZW50YSkNCn0NCg0KI0xsYW1hciBhIGxhIGZ1bmN0aW9uDQpQcmVjaW8uZGUuVmVudGEuMSA8LSBJbmNyZWFzZV9wZXJjZW50YWplKCAyNTYgLCAzLjIgKSANClByZWNpby5kZS5WZW50YS4xDQoNCmBgYA0KDQpPVFJBIEZVTkNJT046DQpgYGB7cn0NCiMgRnVuY3Rpb24gSW5jcmVhc2VfcGVyY2VudGFqZTINCkluY3JlYXNlX3BlcmNlbnRhamUyIDwtIGZ1bmN0aW9uKCBJbXBvcnRlICwgUHJjX0ltcHVlc3RvICl7DQogIFByZWNpby5kZS5WZW50YSA8LSBJbXBvcnRlICogKCAxK1ByY19JbXB1ZXN0by8xMDAgKQ0KICBQcmVjaW8uZGUuVmVudGEgPC0gcm91bmQoIFByZWNpby5kZS5WZW50YSAsIDIgKQ0KICANCiAgaWYoIEltcG9ydGUgPD0gMCApew0KICAgIHByaW50KCJFcnJvci4gSW1wb3J0ZSA8PSAwLiIpDQogICAgcmV0dXJuKE5VTEwpDQogIH1lbHNlIGlmKCBQcmNfSW1wdWVzdG8gPD0gMCApew0KICAgIHByaW50KCJFcnJvci4gUHJjX0ltcHVlc3RvIDw9IDAuIikNCiAgICByZXR1cm4oTlVMTCkNCiAgfWVsc2V7DQogIA0KICBwcmludCggcGFzdGUoICJJbmNyZWFzaW5nICIsIEltcG9ydGUgLA0KICAgICAgICAgICAgICAgICIgZW4gIiwgUHJjX0ltcHVlc3RvICwgDQogICAgICAgICAgICAgICAgIiUgcmVzdWx0YSBlbjogIiwgUHJlY2lvLmRlLlZlbnRhICwgIiBVU0QuIiwNCiAgICAgICAgICAgICAgICBzZXAgPSAiIiApKQ0KICByZXR1cm4oUHJlY2lvLmRlLlZlbnRhKQ0KICB9DQp9DQojTGxhbWFyIGEgbGEgZnVuY3Rpb24NClByZWNpby5kZS5WZW50YS4xIDwtIEluY3JlYXNlX3BlcmNlbnRhamUyKCAyNTYgLCAzLjIgKSANCnN0cihQcmVjaW8uZGUuVmVudGEuMSkNCiNQcmVjaW8uZGUuVmVudGEuMQ0KUHJlY2lvLmRlLlZlbnRhLjIgPC0gSW5jcmVhc2VfcGVyY2VudGFqZTIoIC0yNTYgLCAzLjIgKSANCnN0cihQcmVjaW8uZGUuVmVudGEuMikNCiNQcmVjaW8uZGUuVmVudGEuMg0KUHJlY2lvLmRlLlZlbnRhLjMgPC0gSW5jcmVhc2VfcGVyY2VudGFqZTIoIDI1NiAsIC0zLjIgKSANCnN0cihQcmVjaW8uZGUuVmVudGEuMykNCiNQcmVjaW8uZGUuVmVudGEuMg0KYGBgDQoNCkVKRU1QTE8gQlVDTEUgRk9SOg0KYGBge3J9DQpmb3IoIGkgaW4gMTo1KXsNCiAgcHJpbnQoIGleMiApDQp9DQoNClZlY3Rvci4xYTUgPC0gYygxOjUpDQojVmVjdG9yLjFhNQ0KVmVjdG9yLjFhNV4yDQoNCmZvciggaSBpbiBWZWN0b3IuMWE1ICl7DQogIHByaW50KCBpXjIgKQ0KfQ0KDQpEYXRhZnJhbWUuMWE1IDwtIGFzLmRhdGEuZnJhbWUoIGMoMTo1KSApDQojRGF0YWZyYW1lLjFhNQ0KbmFtZXMoRGF0YWZyYW1lLjFhNSkNCkRhdGFmcmFtZS4xYTUkYw0KZm9yKCBpIGluIERhdGFmcmFtZS4xYTUkYyApew0KICBwcmludCggaV4yICkNCn0gIA0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KI2hlbHAoInNxbGRmIikNCg0KbXRjYXJzDQojVmlldyhtdGNhcnMpDQoNCmBgYA0KDQpgYGB7cn0NCmRmX3F1ZXJ5IDwtIHNxbGRmKCJzZWxlY3QgKiBmcm9tIG10Y2FycyIpDQpkZl9xdWVyeQ0KI3N0cihkZl9xdWVyeSkNCg0KZGZfcXVlcnkgPC0gc3FsZGYoInNlbGVjdCAqIGZyb20gc3RhY2tsb3NzIikNCmRmX3F1ZXJ5DQojc3RyKGRmX3F1ZXJ5KQ0KDQpgYGANCmBgYHtyfQ0Kc3FsZGYoIlNFTEVDVCBjeWwgLCBjb3VudCggY3lsICkgYXMgQ2lsaW5kcm9zIEZST00gbXRjYXJzIEdST1VQIEJZIGN5bCAiKQ0KDQoNCmBgYA0KDQpgYGB7cn0NCg0KZGZfcGl2b3Rfc3FsDQoNCmRmX3Bpdm90X3NxbCA8LSBzcWxkZiggIiBTRUxFQ1QgY3lsICwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENPVU5UKCBjeWwgKSBhcyBDaWxpbmRyb3MgDQogICAgICAgICAgICAgICAgICAgICAgICAgRlJPTSBtdGNhcnMgDQogICAgICAgICAgICAgICAgICAgICAgICAgR1JPVVAgQlkgY3lsICIpDQpkZl9waXZvdF9zcWwNCmBgYA0KDQpFSkVSQ0lDSU9TIEFESUNJT05BTEVTIENPTiBtdGNhcnM6DQoNCmBgYHtyIEJBUlBMT1QgZGUgUiBCQVNFfQ0KI210Y2Fycw0KdGFibGEuMSA8LSB0YWJsZSggbXRjYXJzJGN5bCApDQojdGFibGEuMQ0KDQpjb2xvcmVzIDwtIGMoICJvcmFuZ2UiICwgDQogICAgICAgICAgICAgICJncmVlbiIgLCANCiAgICAgICAgICAgICAgInllbGxvdyIgKQ0KI2NvbG9yZXMNCg0KcGxvdC4xIDwtIGJhcnBsb3QoIHRhYmxhLjEgLCANCiAgICAgICAgICAgICAgICAgICB4bGFiID0gIkNpbGluZHJvcyIgLCANCiAgICAgICAgICAgICAgICAgICB5bGFiID0gIkZyZXF1ZW5jaWEiICwgDQogICAgICAgICAgICAgICAgICAgbWFpbiA9ICJOcm8gZGUgQ2lsaW5kcm9zIiAsDQogICAgICAgICAgICAgICAgICAgY29sID0gY29sb3JlcyApDQpwbG90LjENCmBgYA0KDQpDb24gbGlicmFyeSBsYXR0aWNlOg0KDQoNCmBgYHtyIEJBUkNBSFJUIGRlIExBVFRJQ0V9DQojbXRjYXJzDQp0YWJsYS4xIDwtIHRhYmxlKCBtdGNhcnMkY3lsICkNCiN0YWJsYS4xDQoNCmNvbG9yZXMgPC0gYyggIm9yYW5nZSIgLCANCiAgICAgICAgICAgICAgImdyZWVuIiAsIA0KICAgICAgICAgICAgICAieWVsbG93IiApDQojY29sb3Jlcw0KDQpwbG90LjMgPC0gYmFyY2hhcnQoIHRhYmxhLjEgLCANCiAgICAgICAgICAgICAgICAgICAgeGxhYiA9ICJDaWxpbmRyb3MiICwgDQogICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiTsO6bWVybyBkZSBDaWxpbmRyb3MiICwgDQogICAgICAgICAgICAgICAgICAgIG1haW4gPSAiTsO6bWVybyBkZSBDaWxpbmRyb3MiLCANCiAgICAgICAgICAgICAgICAgICAgY29sID0gY29sb3JlcyApDQoNCnBsb3QuMw0KYGBgDQoNCkNPTlRJTlVBQ0lPTiBDT04gbXRjYXJzIDogDQoNCmBgYHtyfQ0KDQpwbG90LjIgPC0gZ2dwbG90KCBtdGNhcnMgLA0KICAgICAgICAgICAgICAgICAgYWVzKCBjeWwgKSkgKw0KICAgICAgICAgIGdlb21fYmFyKCBmaWxsID0gY29sb3JlcyApICsgDQogICAgICAgICAgbGFicyggeD0gIkNpbGluZHJvcyIgLCANCiAgICAgICAgICAgICAgICB5ID0gIkZyZWN1ZW5jaWFzIiAsIA0KICAgICAgICAgICAgICAgIHRpdGxlID0gIk51bWVybyBkZSBDaWxpbmRyb3MiKQ0KcGxvdC4yICANCiAgDQpgYGANCg0KDQoNClJFUEFTTyBERSBNQVRSSUNFUzoNCmBgYHtyfSANCiMgUEFSQSBPQ1VMVEFSDQptYXRyaXguMSA8LSBtYXRyaXgoIDE6MTAgLCANCiAgICAgICAgICAgIG5yb3cgPSA1ICwgDQogICAgICAgICAgICBuY29sID0gNCApDQptYXRyaXguMQ0KDQpkaW0obWF0cml4LjEpDQoNCm1hdHJpeC4xWzIsNF0NCm1hdHJpeC4xWzIsIF0NCm1hdHJpeC4xWyAsNF0NCmRmX21hdHJpeC4xIDwtIGFzLmRhdGEuZnJhbWUoIG1hdHJpeC4xICwgcm93Lm5hbWVzID0gTlVMTCwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25hbCA9IEZBTFNFICwgDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWtlLm5hbWVzID0gVFJVRSAsIA0KICAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IGRlZmF1bHQuc3RyaW5nc0FzRmFjdG9ycygpICkNCiNkZl9tYXRyaXguMQ0KI2RmX21hdHJpeC4xJFY0DQpkZl9tYXRyaXguMVsnVjQnXQ0KDQpgYGANCg0KDQoNCkVKRVJDSUNJT1M6DQoNCg0KYGBge3J9DQpzdW1tYXJ5KGRhdGFiYXNlKQ0KbWF0cml4X3N1bW1hcnkgPC0gZG8uY2FsbChjYmluZCwgbGFwcGx5KGRhdGFiYXNlLCBzdW1tYXJ5KSkNCm1hdHJpeF9zdW1tYXJ5DQpzdHIobWF0cml4X3N1bW1hcnkpDQpkZl9zdW1tYXJ5IDwtIGFzLmRhdGEuZnJhbWUobWF0cml4X3N1bW1hcnksIHJvdy5uYW1lcyA9IE5VTEwsIG9wdGlvbmFsID0gRkFMU0UsDQogICAgICAgICAgICAgIG1ha2UubmFtZXMgPSBUUlVFLCANCiAgICAgICAgICAgICAgc3RyaW5nc0FzRmFjdG9ycyA9IGRlZmF1bHQuc3RyaW5nc0FzRmFjdG9ycygpKQ0KZGZfc3VtbWFyeQ0KDQpzdW1tYXJ5KCBkYXRhYmFzZSRjb3N0X21pbGxpb25zICkNCg0KIyBSZXRyaWV2ZSBhIHN1YnNldF9kYXRhZnJhbWUgb2YgdGhlIGRhdGEgZnJhbWUgY29uc2lzdGluZyBvZiB0aGUgImdlbnJlIiBjb2x1bW5zDQpkYXRhYmFzZVsnUEFJUyddDQoNCiMgUmV0cmlldmUgdGhlIGRhdGEgZm9yIHRoZSAibmFtZSIgY29sdW1uIGluIHRoZSBkYXRhIGZyYW1lIGluIGEgdmVjdG9yDQpkYXRhYmFzZSRQQUlTDQoNCmBgYA0KDQpgYGB7cn0NCiMgUmV0cmlldmUgdGhlIDNyZCByb3cgb2YgdGhlIGRhdGEgZnJhbWUuICMgUEFSQSBPQ1VMVEFSDQpkYXRhYmFzZVszLF0NCg0KIyBSZXRyaWV2ZSB0aGUgdGhpcmQgcm93IG9mIHRoZSBkYXRhIGZyYW1lLCBidXQgb25seSB0aGUgIm5hbWUiIGFuZCAibGVuZ3RoX21pbiIgY29sdW1ucy4NCmRhdGFiYXNlWzMsIGMoIlBBSVMiLCJDT0RJR08iKV0NCmBgYA0KYGBge3J9DQoNCnN1bW1hcnkoZGF0YWJhc2UpDQpoaXN0b2dyYW1hIDwtIGhpc3QoZGF0YWJhc2UkQWlyLkZsb3cgLGNvbD0ieWVsbG93IixicmVha3MgPSAxMCkNCmhpc3RvZ3JhbWENCg0Kc3VtbWFyeShkYXRhYmFzZSkNCmhpc3RvZ3JhbWEyIDwtIGhpc3QoZGF0YWJhc2UkTsK6ICxjb2w9InllbGxvdyIsYnJlYWtzID0gMTApDQpoaXN0b2dyYW1hMg0KYGBgDQoNCmBgYHtyfQ0KI01PREVMT1MNCg0KbW9kZWxvXzEgPC0gZ2xtKCBzdGFja2xvc3MkQWlyLkZsb3cgfiBzdGFja2xvc3Mkc3RhY2subG9zcywgZmFtaWx5PSJwb2lzc29uIiwgZGF0YT1zdGFja2xvc3MpDQptb2RlbG9fMQ0Kc3VtbWFyeShtb2RlbG9fMSkNCnBsb3QobW9kZWxvXzEpDQpzdW1tYXJ5KG1vZGVsb18xKQ0KDQpwbG90KG1vZGVsb18xKQ0KY3VydmUocG5vcm0oeCwgbWVhbiA9IG1lYW4oc3RhY2tsb3NzJHN0YWNrLmxvc3MpLCBzZCA9IHNkIChzdGFja2xvc3Mkc3RhY2subG9zcykpICwgeGxpbSA9IGMoIDUwLDgwKSwgY29sPSJibHVlIiwgbHdkPTIsIHhsYWI9InN0YWNrbG9zcyIsIHlsYWIgPSJQcm9iYWJpbGlkYWQiKQ0KDQpgYGANCmBgYHtyfQ0KY3VydmUocG5vcm0gKHgsIG1lYW4gPSBtZWFuKHN0YWNrbG9zcyRzdGFjay5sb3NzKSwgc2QgPSBzZCAoc3RhY2tsb3NzJHN0YWNrLmxvc3MpKSAsIHhsaW0gPSBjKCA1MCw4MCksIGNvbD0iYmx1ZSIsIGx3ZD0yLCB4bGFiPSJzdGFja2xvc3MiLCB5bGFiID0iUHJvYmFiaWxpZGFkIikNCmBgYA0KDQpgYGB7cn0NCg0KdGltZSA9IGdzdWIoIjoiLCAiLSIsIFN5cy50aW1lKCkpDQoNCiMtIGV4cG9ydGEgZW4gZm9ybWF0byAuY3N2IGVsIGRmIGRmX3N1bW1hcnkgYWwgZmljaGVybyAiZGZfc3VtbWFyeS5jc3YiLiBTZSBndWFyZGFyw6EgZW4gbGEgc3ViY2FycGV0YSAiZGF0b3MvcHJ1ZWJhcy8iIGRlbCBwcm95ZWN0bw0KZm9sZGVyX3BhdGggPC0gIi4vb3V0cHV0X2RhdGFiYXNlcy8iDQpmaWxlbmFtZSA8LSAiZGZfc3VtbWFyeSINCmZpbGV0eXBlIDwtIi5jc3YiDQpwYXRoIDwtIHBhc3RlKGZvbGRlcl9wYXRoLGZpbGVuYW1lLCIgIix0aW1lLGZpbGV0eXBlLCBzZXA9IiIpDQp3cml0ZV9jc3YoZGZfc3VtbWFyeSwgcGF0aCkNCg0KDQpgYGANCkhheSB2YXJpb3MgcGFja2FnZXMgcXVlIGdyYWJhbiBkYXRvcyBlbiBmb3JtYXRvIC54bHMuIFBlcm8gZWwgbcOhcyBzZW5jaWxsbyBlcyBlbCBwYWNrYWdlIHhsc3guIFZlw6Ftb3NsbzoNCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ4bHN4IikNCiMgbGlicmFyeSh4bHN4KQ0Kd3JpdGUueGxzeChkZl9zdW1tYXJ5LCAiLi9vdXRwdXRfZGF0YWJhc2VzL2RmX3N1bW1hcnkueGxzeCIsIHNoZWV0TmFtZSA9ICJkZl9zdW1tYXJ5IiApDQoNCmBgYA0KDQpMYSBmdW5jacOzbiB3cml0ZS54bHN4KCkgcGVybWl0ZSBhw7FhZGlyIGRhdG9zIGEgdW4gYXJjaGl2byAueGxzeCBwcmVleGlzdGVudGU7IHBhcmEgZWxsbyB0ZW5lbW9zIHF1ZSB1c2FyIGxhIG9wY2nDs24gYXBwZW5kID0gVFJVRToNCmBgYHtyfQ0KIyBsaWJyYXJ5KHhsc3gpDQp3cml0ZS54bHN4KGRmX3N1bW1hcnksICIuL291dHB1dF9kYXRhYmFzZXMvZGZfc3VtbWFyeS54bHN4Iiwgc2hlZXROYW1lID0gInN1bW1hcnkiLCBhcHBlbmQgPSBUUlVFKQ0KYGBgDQoNCg0KREVMIEVKRVJDSUNJTyBERSBFSkVDVVRBUiBTUUwgUVVFUlkgZW4gVU4gUiBOT1RFQk9PSzoNCmBgYHtyfQ0Kd3JpdGUueGxzeCggZGZfcGl2b3Rfc3FsICwgDQogICAgICAgICAgICAiLi9vdXRwdXRfZGF0YWJhc2VzL2RmX3Bpdm90X3NxbC54bHN4IiwgDQogICAgICAgICAgICBzaGVldE5hbWUgPSAiZGZfcGl2b3Rfc3FsIiApDQpgYGANCg0KDQoNCg0KR1JBRklDQQ0KYGBge3J9DQojKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KIyojIFB1YmxpY2F0aW9uIHF1YWxpdHkgZ3JhcGhzIHJlcXVpcmUgNjAwZHBpDQpkcGk9NjAwICAgICNwaXhlbHMgcGVyIHNxdWFyZSBpbmNoDQpjYXJwZXRhID0gIi4vb3V0cHV0X2ltYWdlcy8iDQphcmNoaXZvID0gImhpc3RvZ3JhbWEiDQp0aW1lID0gZ3N1YigiOiIsICItIiwgU3lzLnRpbWUoKSkNCmNhcnBldGFfeV9hcmNoaXZvID0gcGFzdGUoY2FycGV0YSxhcmNoaXZvLCIgIix0aW1lLCIudGlmIiwgc2VwPSIiKQ0Kbm9tYnJlX2RlX3RpZiA9IGNhcnBldGFfeV9hcmNoaXZvDQp0aWZmKG5vbWJyZV9kZV90aWYsIHdpZHRoPTYqZHBpLCBoZWlnaHQ9NSpkcGksIHJlcz1kcGkpDQojKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KaGlzdG9ncmFtYSA8LSBoaXN0KGRhdGFiYXNlJE7CuiAsY29sPSJ5ZWxsb3ciLGJyZWFrcyA9IDEwKQ0KaGlzdG9ncmFtYQ0KIyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCmRldi5vZmYoKQ0KcHJpbnQocGFzdGUoIkZpbmFsaXphZG8gcHJvY2VzYW1pZW50byBkZSAiLGFyY2hpdm8sIiAiLHRpbWUsIHNlcD0iIikpDQojKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KYGBgDQoNCmBgYHtyfQ0KY2l0YXRpb24oKQ0KY2l0YXRpb24oInJlYWR4bCIpIA0KIyANCmhlbHAoInJlYWR4bCIpICMgRG9jdW1lbnRhY2lvbiBkZSBsYSBsaWJyYXJ5IHJlYWR4bA0KDQpgYGA=