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) 
# 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)
library(tidyverse) 
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
library(RODBC) # Para Conexion SQL y R Studio
# Adicionales 9 Octubre 2021:
library(readr)
library(devtools)
library(googledrive)

# Adicionales Domingo 10 Octubre 2021:
library(lattice)

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

print("Working Directory: "); getwd() #get to show me the current Working Directory 
[1] "Working Directory: "
[1] "I:/001.7 CURSO-02 Lenguaje R Semillero/21.10.13.Mie Grupo Javier Guillen de R"
### Cargando BBDD: n5ay5qadfe7e1nnsv5s01oe1x62mq51j.csv ####
# Version de BBDD: 2021.09.24 v1
# RUTA: https://ibm.box.com/shared/static/

# XLS file,  Download datasets
# download.file( "https://ibm.box.com/shared/static/nx0ohd9sq0iz3p871zg8ehc1m39ibpx6.xls" , 
#                destfile="movies-db.xls" )

# CSV file,  Download datasets
download.file("https://ibm.box.com/shared/static/n5ay5qadfe7e1nnsv5s01oe1x62mq51j.csv", 
              destfile="movies-db.csv")
trying URL 'https://ibm.box.com/shared/static/n5ay5qadfe7e1nnsv5s01oe1x62mq51j.csv'
Content type 'text/csv' length 1424 bytes
downloaded 1424 bytes
database_csv <- read.csv("movies-db.csv", header=TRUE, sep=",")

file.exists("movies-db.xlsx")
[1] TRUE
# Read data from the XLS file and attribute the table a dataframe.
database_xlsx <- read_excel("movies-db.xlsx")
database_xlsx

#movies_data
(
database <- database_xlsx
)

# Read data from the XLS file and attribute the table to a dataframe.
paises_001.xlsx <- read_excel("paises_001.xlsx")
paises_001.xlsx
NA
#movies_data
(
database <- paises_001.xlsx
)
NA

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

#################################################
#- GoogleSheet4
#################################################
#install.packages("devtools")
library(devtools)
#devtools::install_github("tidyverse/googlesheets4")

#install.packages("gargle")
library(googlesheets4)

Attaching package: 㤼㸱googlesheets4㤼㸲

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

    request_generate, request_make
gs4_auth()
The googlesheets4 package is requesting access to your Google account.
Select a pre-authorised account or enter '0' to obtain a new token.
Press Esc/Ctrl + C to cancel.

1: ecanchor@unmsm.edu.pe
1
#help(gs4_auth)
#################################################
#- Read an existing Spreadsheet 
###############################################

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
[1] "C:\\Users\\user\\AppData\\Local\\Temp\\RtmpYDef6c\\file5c4034f4110f.zip"
dl <- drive_download(
         as_id( "1AiZda_1-2nwrxI8fLD0Y6e5rTg7aocv0" ) , 
         path = temp , overwrite = TRUE )
The googledrive package is requesting access to your Google account.
Select a pre-authorised account or enter '0' to obtain a new token.
Press Esc/Ctrl + C to cancel.

1: ecanchor@unmsm.edu.pe
1
Auto-refreshing stale OAuth token.
File downloaded:
* Archive.zip <id: 1AiZda_1-2nwrxI8fLD0Y6e5rTg7aocv0>
Saved locally as:
* C:\Users\user\AppData\Local\Temp\RtmpYDef6c\file5c4034f4110f.zip
dl
out <- unzip( temp , exdir = tempdir() )
out
 [1] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/bank/.DS_Store"                                     
 [2] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/bank/._.DS_Store"                          
 [3] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/bank/bank-full.csv"                                 
 [4] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/bank/._bank-full.csv"                      
 [5] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/bank/bank.csv"                                      
 [6] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/bank/._bank.csv"                           
 [7] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/._bank"                                    
 [8] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/bank-additional/.DS_Store"                          
 [9] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/bank-additional/._.DS_Store"               
[10] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/bank-additional/.Rhistory"                          
[11] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/bank-additional/._.Rhistory"               
[12] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/bank-additional/bank-additional-full.csv"           
[13] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/bank-additional/._bank-additional-full.csv"
[14] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/bank-additional/bank-additional.csv"                
[15] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/bank-additional/._bank-additional.csv"     
[16] "C:/Users/user/AppData/Local/Temp/RtmpYDef6c/__MACOSX/._bank-additional"                         
bank <- read.csv( out[14] , sep = ";" )
str(bank)
'data.frame':   4119 obs. of  21 variables:
 $ age           : int  30 39 25 38 47 32 32 41 31 35 ...
 $ job           : chr  "blue-collar" "services" "services" "services" ...
 $ marital       : chr  "married" "single" "married" "married" ...
 $ education     : chr  "basic.9y" "high.school" "high.school" "basic.9y" ...
 $ default       : chr  "no" "no" "no" "no" ...
 $ housing       : chr  "yes" "no" "yes" "unknown" ...
 $ loan          : chr  "no" "no" "no" "unknown" ...
 $ contact       : chr  "cellular" "telephone" "telephone" "telephone" ...
 $ month         : chr  "may" "may" "jun" "jun" ...
 $ day_of_week   : chr  "fri" "fri" "wed" "fri" ...
 $ duration      : int  487 346 227 17 58 128 290 44 68 170 ...
 $ campaign      : int  2 4 1 3 1 3 4 2 1 1 ...
 $ pdays         : int  999 999 999 999 999 999 999 999 999 999 ...
 $ previous      : int  0 0 0 0 0 2 0 0 1 0 ...
 $ poutcome      : chr  "nonexistent" "nonexistent" "nonexistent" "nonexistent" ...
 $ emp.var.rate  : num  -1.8 1.1 1.4 1.4 -0.1 -1.1 -1.1 -0.1 -0.1 1.1 ...
 $ cons.price.idx: num  92.9 94 94.5 94.5 93.2 ...
 $ cons.conf.idx : num  -46.2 -36.4 -41.8 -41.8 -42 -37.5 -37.5 -42 -42 -36.4 ...
 $ euribor3m     : num  1.31 4.86 4.96 4.96 4.19 ...
 $ nr.employed   : num  5099 5191 5228 5228 5196 ...
 $ y             : chr  "no" "no" "no" "no" ...
bank
NA

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

REVISION RAPIDA DEL DATAFRAME:

#View(database)
summary(database) # Summary Estadístico.
       Nº            PAIS              CODIGO         
 Min.   : 1.00   Length:57          Length:57         
 1st Qu.:15.00   Class :character   Class :character  
 Median :30.00   Mode  :character   Mode  :character  
 Mean   :29.58                                        
 3rd Qu.:44.00                                        
 Max.   :58.00                                        
head(database) # Primeros 6.
names(database) # Names de columnas.
[1] "Nº"     "PAIS"   "CODIGO"
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
tibble [57 x 3] (S3: tbl_df/tbl/data.frame)
 $ Nº    : num [1:57] 1 2 3 4 5 6 7 8 9 10 ...
 $ PAIS  : chr [1:57] "Angola" "Argelia" "Benin" "Botswana" ...
 $ CODIGO: chr [1:57] "AGO" "DZA" "BEN" "BWA" ...

A partir de aquí inicia el Cuerpo del Script:

EJERCICIO FUNCIONES PROPIAS EN R

# UDF - User Defined Functions

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)
sqldf("SELECT cyl , count( cyl ) as Cilindros FROM mtcars GROUP BY cyl ")
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

dim(matrix.1)

matrix.1[2,4]
matrix.1[2, ]
matrix.1[ ,4]
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']

EJERCICIOS:

summary(database)
       Nº            PAIS              CODIGO         
 Min.   : 1.00   Length:57          Length:57         
 1st Qu.:15.00   Class :character   Class :character  
 Median :30.00   Mode  :character   Mode  :character  
 Mean   :29.58                                        
 3rd Qu.:44.00                                        
 Max.   :58.00                                        
matrix_summary <- do.call(cbind, lapply(database, summary))
matrix_summary
        Nº                 PAIS        CODIGO     
Min.    "1"                "57"        "57"       
1st Qu. "15"               "character" "character"
Median  "30"               "character" "character"
Mean    "29.5789473684211" "57"        "57"       
3rd Qu. "44"               "character" "character"
Max.    "58"               "character" "character"
str(matrix_summary)
 chr [1:6, 1:3] "1" "15" "30" "29.5789473684211" "44" "58" "57" "character" ...
 - attr(*, "dimnames")=List of 2
  ..$ : chr [1:6] "Min." "1st Qu." "Median" "Mean" ...
  ..$ : chr [1:3] "Nº" "PAIS" "CODIGO"
df_summary <- as.data.frame(matrix_summary, row.names = NULL, optional = FALSE,
              make.names = TRUE, 
              stringsAsFactors = default.stringsAsFactors())
df_summary

summary( database$cost_millions )
Unknown or uninitialised column: `cost_millions`.
Length  Class   Mode 
     0   NULL   NULL 
# Retrieve a subset_dataframe of the data frame consisting of the "genre" columns
database['PAIS']

# Retrieve the data for the "name" column in the data frame in a vector
database$PAIS
 [1] "Angola"                                       
 [2] "Argelia"                                      
 [3] "Benin"                                        
 [4] "Botswana"                                     
 [5] "Burkina Faso"                                 
 [6] "Burundi"                                      
 [7] "Cabo Verde"                                   
 [8] "Camerún"                                      
 [9] "Chad"                                         
[10] "Comoras"                                      
[11] "Congo"                                        
[12] "Côte d'Ivoire"                                
[13] "Djibouti"                                     
[14] "Egipto"                                       
[15] "Eritrea"                                      
[16] "España, territorios vinculados en Africa"     
[17] "Etiopía"                                      
[18] "Francia, territorios vinculados en Africa"    
[19] "Gabón"                                        
[20] "Gambia"                                       
[21] "Ghana"                                        
[22] "Guinea"                                       
[23] "Guinea Bissau"                                
[24] "Guinea Ecuatorial"                            
[25] "Kenya"                                        
[26] "Lesotho"                                      
[27] "Liberia"                                      
[28] "Libia"                                        
[29] "Madagascar"                                   
[30] "Malawi"                                       
[31] "Malí"                                         
[32] "Marruecos"                                    
[33] "Mauricio"                                     
[34] "Mauritania"                                   
[35] "Mozambique"                                   
[36] "Namibia"                                      
[37] "Níger"                                        
[38] "Nigeria"                                      
[39] "Reino Unido, territorios vinculados en África"
[40] "República Centroafricana"                     
[41] "República Democrática del Congo"              
[42] "Rwanda"                                       
[43] "Santo Tomé y Príncipe"                        
[44] "Senegal"                                      
[45] "Seychelles"                                   
[46] "Sierra Leona"                                 
[47] "Somalia"                                      
[48] "Sudáfrica"                                    
[49] "Sudán"                                        
[50] "Sudán del Sur"                                
[51] "Swazilandia"                                  
[52] "Tanzanía"                                     
[53] "Togo"                                         
[54] "Túnez"                                        
[55] "Uganda"                                       
[56] "Zambia"                                       
[57] "Zimbabwe"                                     
# Retrieve the 3rd row of the data frame.
database[3,]

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

summary(database)
       Nº            PAIS              CODIGO         
 Min.   : 1.00   Length:57          Length:57         
 1st Qu.:15.00   Class :character   Class :character  
 Median :30.00   Mode  :character   Mode  :character  
 Mean   :29.58                                        
 3rd Qu.:44.00                                        
 Max.   :58.00                                        
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"

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/dXNwPXNoYXJpbmcmb3VpZD0xMDk2MzYzMDc1Njk2NTU2NjEzMTUmcnRwb2Y9dHJ1ZSZzZD10cnVlDQojIFJlYWQgZGF0YSBmcm9tIEdvb2dsZSBEcml2ZSAodGhlIFpJUCBmaWxlKSBhbmQgYXR0cmlidXRlIHRoZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCiMgbGlicmFyeShnb29nbGVkcml2ZSkNCiMgbGlicmFyeShodHRwdXYpDQojIHRlbXAgPC0gdGVtcGZpbGUoIGZpbGVleHQgPSAiLnppcCIgKQ0KIyB0ZW1wDQojIGRsIDwtIGRyaXZlX2Rvd25sb2FkKA0KIyAgICAgICAgIGFzX2lkKCAiMUFpWmRhXzEtMm53cnhJOGZMRDBZNmU1clRnN2FvY3YwIiApICwgDQojICAgICAgICAgcGF0aCA9IHRlbXAgLCBvdmVyd3JpdGUgPSBUUlVFICkNCiMgZGwNCiMgb3V0IDwtIHVuemlwKCB0ZW1wICwgZXhkaXIgPSB0ZW1wZGlyKCkgKQ0KIyBvdXQNCiMgYmFuayA8LSByZWFkLmNzdiggb3V0WzE0XSAsIHNlcCA9ICI7IiApDQojIHN0cihiYW5rKQ0KIyBiYW5rDQoNCmBgYA0KDQoNClJlYWRpbmcgZmlsZSBmcm9tIGEgQ1NWIGZpbGU6DQpgYGB7ciBSRUFEIENTVn0NCiMgUmVhZCBkYXRhIGZyb20gdGhlIFRYVCAgZmlsZSBhbmQgYXR0cmlidXRlIHRoZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCnBhaXNlc18wMDEuY3N2IDwtIHJlYWQuY3N2KCJwcnVlYmFfY3N2MDEuY3N2IiwgaGVhZGVyPVRSVUUsIHNlcD0iOyIpDQpwYWlzZXNfMDAxLmNzdg0KYGBgDQoNClJlYWRpbmcgZmlsZSBmcm9tIGEgVFhUIGZpbGU6DQpgYGB7ciBSRUFEIFRYVH0NCiMgUmVhZCBkYXRhIGZyb20gdGhlIFRYVCAgZmlsZSBhbmQgYXR0cmlidXRlIHRoZSB0YWJsZSB0byBhIGRhdGFmcmFtZS4NCnBhaXNlc18wMDEudHh0IDwtIHJlYWRfY3N2KCJwYWlzZXNfMDAxLnR4dCIpDQpwYWlzZXNfMDAxLnR4dA0KYGBgDQoNCmBgYHtyIFJlYWQgU1BTUyBmaWxlfQ0KI2xpYnJhcnkoaGF2ZW4pDQojQmFzZUNPVklEMTkuc2F2IDwtIHJlYWRfc2F2KCJCYXNlQ09WSUQtMTkuc2F2IikNCiNCYXNlQ09WSUQxOS5zYXYNCg0KYGBgDQoNCmBgYHtyIFJlYWQgU1RBVEEgZmlsZXN9DQojbGlicmFyeShoYXZlbikNCiNlbmFobzAxLmR0YSA8LSByZWFkX2R0YSgiZW5haG8wMS0yMDIwLTEwMC5kdGEiKQ0KI2VuYWhvMDEuZHRhDQoNCmBgYA0KDQoNClJFVklTSU9OIFJBUElEQSBERUwgREFUQUZSQU1FOg0KYGBge3J9DQojVmlldyhkYXRhYmFzZSkNCnN1bW1hcnkoZGF0YWJhc2UpICMgU3VtbWFyeSBFc3RhZMOtc3RpY28uDQpoZWFkKGRhdGFiYXNlKSAjIFByaW1lcm9zIDYuDQpuYW1lcyhkYXRhYmFzZSkgIyBOYW1lcyBkZSBjb2x1bW5hcy4NCnByaW50KGlzLmRhdGEuZnJhbWUoZGF0YWJhc2UpKQ0KI2F0dGFjaChkYXRhYmFzZSkgI29ubHkgaWYgdGhlcmUgaXMgb25seSAxIGRhdGFzZXQgDQojIENPTlRFTklETyBERSBUQUJMQToNCiMgZGF0YWJhc2UgZXMgbGEgdGFibGEgY29uIGRhdG9zIGRlIHBlbMOtY3VsYXMuDQpgYGANCg0KQU5BTElaQU1PUyBMQSBFU1RSQ1VUVVJBIERFIExBIFRBQkxBOg0KDQpGdW5jacOzbiBzdHI6IHN0cnVjdHVyZQ0KTGFiMDgtaW1wb3J0aW5nRGF0YSANCmBgYHtyIENVRVJQT30NCg0KIyBQcmludHMgb3V0IHRoZSBzdHJ1Y3R1cmUgb2YgeW91ciB0YWJsZS4NCnN0cihkYXRhYmFzZSkgIyBlcyBsYSBmdW5jacOzbiBzdHJ1Y3R1cmUNCg0KDQpgYGANCg0KDQpBIHBhcnRpciBkZSBhcXXDrSBpbmljaWEgZWwgQ3VlcnBvIGRlbCBTY3JpcHQ6DQoNCkVKRVJDSUNJTyBGVU5DSU9ORVMgUFJPUElBUyBFTiBSDQpgYGB7cn0NCiMgVURGIC0gVXNlciBEZWZpbmVkIEZ1bmN0aW9ucyAjUEFSQSBPQ1VMVEFSDQoNCnN1bSggMTExICwgMjIyICkNCnByb2QoIDExMSAsIDIyMiApDQpsb2coIDggLCAyICkNCg0KIyBsaWJyYXJ5KGdncGxvdDIpDQojIGdncGxvdCgpDQoNCg0KI0luY3JlbWVudG8gUG9yY2VudHVhbA0KKCANCkltcG9ydGUgPC0gMjU2DQopDQooDQpJbXB1ZXN0byA8LSAzLjIvMTAwDQopDQooDQpQcmVjaW8uZGUuVmVudGEgPC0gSW1wb3J0ZSAqICggMStJbXB1ZXN0byApDQopDQooDQpWYXJpYWNpw7NuIDwtIFByZWNpby5kZS5WZW50YS9JbXBvcnRlIC0gMQ0KKQ0KDQojIEZ1bmN0aW9uIEluY3JlYXNlX3BlcmNlbnRhamUNCkluY3JlYXNlX3BlcmNlbnRhamUgPC0gZnVuY3Rpb24oIEltcG9ydGUgLCBQcmNfSW1wdWVzdG8gKXsNCiAgUHJlY2lvLmRlLlZlbnRhIDwtIEltcG9ydGUgKiAoIDErUHJjX0ltcHVlc3RvLzEwMCApDQogIFByZWNpby5kZS5WZW50YSA8LSByb3VuZCggUHJlY2lvLmRlLlZlbnRhICwgMiApDQogIA0KICBwcmludCggcGFzdGUoICJJbmNyZWFzaW5nICIsIEltcG9ydGUgLA0KICAgICAgICAgICAgICAgICIgZW4gIiwgUHJjX0ltcHVlc3RvICwgDQogICAgICAgICAgICAgICAgIiUgcmVzdWx0YSBlbjogIiwgUHJlY2lvLmRlLlZlbnRhICwgIiBVU0QuIiwNCiAgICAgICAgICAgICAgICBzZXAgPSAiIiApKQ0KICByZXR1cm4oUHJlY2lvLmRlLlZlbnRhKQ0KfQ0KDQojTGxhbWFyIGEgbGEgZnVuY3Rpb24NClByZWNpby5kZS5WZW50YS4xIDwtIEluY3JlYXNlX3BlcmNlbnRhamUoIDI1NiAsIDMuMiApIA0KUHJlY2lvLmRlLlZlbnRhLjENCg0KYGBgDQoNCk9UUkEgRlVOQ0lPTjoNCmBgYHtyfQ0KIyBGdW5jdGlvbiBJbmNyZWFzZV9wZXJjZW50YWplMg0KSW5jcmVhc2VfcGVyY2VudGFqZTIgPC0gZnVuY3Rpb24oIEltcG9ydGUgLCBQcmNfSW1wdWVzdG8gKXsNCiAgUHJlY2lvLmRlLlZlbnRhIDwtIEltcG9ydGUgKiAoIDErUHJjX0ltcHVlc3RvLzEwMCApDQogIFByZWNpby5kZS5WZW50YSA8LSByb3VuZCggUHJlY2lvLmRlLlZlbnRhICwgMiApDQogIA0KICBpZiggSW1wb3J0ZSA8PSAwICl7DQogICAgcHJpbnQoIkVycm9yLiBJbXBvcnRlIDw9IDAuIikNCiAgICByZXR1cm4oTlVMTCkNCiAgfWVsc2UgaWYoIFByY19JbXB1ZXN0byA8PSAwICl7DQogICAgcHJpbnQoIkVycm9yLiBQcmNfSW1wdWVzdG8gPD0gMC4iKQ0KICAgIHJldHVybihOVUxMKQ0KICB9ZWxzZXsNCiAgDQogIHByaW50KCBwYXN0ZSggIkluY3JlYXNpbmcgIiwgSW1wb3J0ZSAsDQogICAgICAgICAgICAgICAgIiBlbiAiLCBQcmNfSW1wdWVzdG8gLCANCiAgICAgICAgICAgICAgICAiJSByZXN1bHRhIGVuOiAiLCBQcmVjaW8uZGUuVmVudGEgLCAiIFVTRC4iLA0KICAgICAgICAgICAgICAgIHNlcCA9ICIiICkpDQogIHJldHVybihQcmVjaW8uZGUuVmVudGEpDQogIH0NCn0NCiNMbGFtYXIgYSBsYSBmdW5jdGlvbg0KUHJlY2lvLmRlLlZlbnRhLjEgPC0gSW5jcmVhc2VfcGVyY2VudGFqZTIoIDI1NiAsIDMuMiApIA0Kc3RyKFByZWNpby5kZS5WZW50YS4xKQ0KI1ByZWNpby5kZS5WZW50YS4xDQpQcmVjaW8uZGUuVmVudGEuMiA8LSBJbmNyZWFzZV9wZXJjZW50YWplMiggLTI1NiAsIDMuMiApIA0Kc3RyKFByZWNpby5kZS5WZW50YS4yKQ0KI1ByZWNpby5kZS5WZW50YS4yDQpQcmVjaW8uZGUuVmVudGEuMyA8LSBJbmNyZWFzZV9wZXJjZW50YWplMiggMjU2ICwgLTMuMiApIA0Kc3RyKFByZWNpby5kZS5WZW50YS4zKQ0KI1ByZWNpby5kZS5WZW50YS4yDQpgYGANCg0KRUpFTVBMTyBCVUNMRSBGT1I6DQpgYGB7cn0NCmZvciggaSBpbiAxOjUpew0KICBwcmludCggaV4yICkNCn0NCg0KVmVjdG9yLjFhNSA8LSBjKDE6NSkNCiNWZWN0b3IuMWE1DQpWZWN0b3IuMWE1XjINCg0KZm9yKCBpIGluIFZlY3Rvci4xYTUgKXsNCiAgcHJpbnQoIGleMiApDQp9DQoNCkRhdGFmcmFtZS4xYTUgPC0gYXMuZGF0YS5mcmFtZSggYygxOjUpICkNCiNEYXRhZnJhbWUuMWE1DQpuYW1lcyhEYXRhZnJhbWUuMWE1KQ0KRGF0YWZyYW1lLjFhNSRjDQpmb3IoIGkgaW4gRGF0YWZyYW1lLjFhNSRjICl7DQogIHByaW50KCBpXjIgKQ0KfSAgDQoNCmBgYA0KDQoNCg0KYGBge3J9DQojaGVscCgic3FsZGYiKQ0KDQptdGNhcnMNCiNWaWV3KG10Y2FycykNCg0KYGBgDQoNCmBgYHtyfQ0KZGZfcXVlcnkgPC0gc3FsZGYoInNlbGVjdCAqIGZyb20gbXRjYXJzIikNCmRmX3F1ZXJ5DQojc3RyKGRmX3F1ZXJ5KQ0KDQpgYGANCmBgYHtyfQ0Kc3FsZGYoIlNFTEVDVCBjeWwgLCBjb3VudCggY3lsICkgYXMgQ2lsaW5kcm9zIEZST00gbXRjYXJzIEdST1VQIEJZIGN5bCAiKQ0KYGBgDQoNCmBgYHtyfQ0KZGZfcGl2b3Rfc3FsIDwtIHNxbGRmKCAiIFNFTEVDVCBjeWwgLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ09VTlQoIGN5bCApIGFzIENpbGluZHJvcyANCiAgICAgICAgICAgICAgICAgICAgICAgICBGUk9NIG10Y2FycyANCiAgICAgICAgICAgICAgICAgICAgICAgICBHUk9VUCBCWSBjeWwgIikNCmRmX3Bpdm90X3NxbA0KYGBgDQoNCkVKRVJDSUNJT1MgQURJQ0lPTkFMRVMgQ09OIG10Y2FyczoNCg0KYGBge3IgQkFSUExPVCBkZSBSIEJBU0V9DQojbXRjYXJzDQp0YWJsYS4xIDwtIHRhYmxlKCBtdGNhcnMkY3lsICkNCiN0YWJsYS4xDQoNCmNvbG9yZXMgPC0gYyggIm9yYW5nZSIgLCANCiAgICAgICAgICAgICAgImdyZWVuIiAsIA0KICAgICAgICAgICAgICAieWVsbG93IiApDQojY29sb3Jlcw0KDQpwbG90LjEgPC0gYmFycGxvdCggdGFibGEuMSAsIA0KICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiQ2lsaW5kcm9zIiAsIA0KICAgICAgICAgICAgICAgICAgIHlsYWIgPSAiRnJlcXVlbmNpYSIgLCANCiAgICAgICAgICAgICAgICAgICBtYWluID0gIk5ybyBkZSBDaWxpbmRyb3MiICwNCiAgICAgICAgICAgICAgICAgICBjb2wgPSBjb2xvcmVzICkNCnBsb3QuMQ0KYGBgDQoNCkNvbiBsaWJyYXJ5IGxhdHRpY2U6DQpgYGB7ciBCQVJDQUhSVCBkZSBMQVRUSUNFfQ0KI210Y2Fycw0KdGFibGEuMSA8LSB0YWJsZSggbXRjYXJzJGN5bCApDQojdGFibGEuMQ0KDQpjb2xvcmVzIDwtIGMoICJvcmFuZ2UiICwgDQogICAgICAgICAgICAgICJncmVlbiIgLCANCiAgICAgICAgICAgICAgInllbGxvdyIgKQ0KI2NvbG9yZXMNCg0KcGxvdC4zIDwtIGJhcmNoYXJ0KCB0YWJsYS4xICwgDQogICAgICAgICAgICAgICAgICAgIHhsYWIgPSAiQ2lsaW5kcm9zIiAsIA0KICAgICAgICAgICAgICAgICAgICB5bGFiID0gIk7Dum1lcm8gZGUgQ2lsaW5kcm9zIiAsIA0KICAgICAgICAgICAgICAgICAgICBtYWluID0gIk7Dum1lcm8gZGUgQ2lsaW5kcm9zIiwgDQogICAgICAgICAgICAgICAgICAgIGNvbCA9IGNvbG9yZXMgKQ0KDQpwbG90LjMNCmBgYA0KDQpDT05USU5VQUNJT04gQ09OIG10Y2FycyA6IA0KDQpgYGB7cn0NCg0KcGxvdC4yIDwtIGdncGxvdCggbXRjYXJzICwNCiAgICAgICAgICAgICAgICAgIGFlcyggY3lsICkpICsNCiAgICAgICAgICBnZW9tX2JhciggZmlsbCA9IGNvbG9yZXMgKSArIA0KICAgICAgICAgIGxhYnMoIHg9ICJDaWxpbmRyb3MiICwgDQogICAgICAgICAgICAgICAgeSA9ICJGcmVjdWVuY2lhcyIgLCANCiAgICAgICAgICAgICAgICB0aXRsZSA9ICJOdW1lcm8gZGUgQ2lsaW5kcm9zIikNCnBsb3QuMiAgDQogIA0KYGBgDQoNCg0KDQpSRVBBU08gREUgTUFUUklDRVM6DQpgYGB7cn0gDQojIFBBUkEgT0NVTFRBUg0KbWF0cml4LjEgPC0gbWF0cml4KCAxOjEwICwgDQogICAgICAgICAgICBucm93ID0gNSAsIA0KICAgICAgICAgICAgbmNvbCA9IDQgKQ0KbWF0cml4LjENCg0KZGltKG1hdHJpeC4xKQ0KDQptYXRyaXguMVsyLDRdDQptYXRyaXguMVsyLCBdDQptYXRyaXguMVsgLDRdDQpkZl9tYXRyaXguMSA8LSBhcy5kYXRhLmZyYW1lKCBtYXRyaXguMSAsIHJvdy5uYW1lcyA9IE5VTEwsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uYWwgPSBGQUxTRSAsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFrZS5uYW1lcyA9IFRSVUUgLCANCiAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBkZWZhdWx0LnN0cmluZ3NBc0ZhY3RvcnMoKSApDQojZGZfbWF0cml4LjENCiNkZl9tYXRyaXguMSRWNA0KZGZfbWF0cml4LjFbJ1Y0J10NCg0KYGBgDQoNCg0KDQpFSkVSQ0lDSU9TOg0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShkYXRhYmFzZSkNCm1hdHJpeF9zdW1tYXJ5IDwtIGRvLmNhbGwoY2JpbmQsIGxhcHBseShkYXRhYmFzZSwgc3VtbWFyeSkpDQptYXRyaXhfc3VtbWFyeQ0Kc3RyKG1hdHJpeF9zdW1tYXJ5KQ0KZGZfc3VtbWFyeSA8LSBhcy5kYXRhLmZyYW1lKG1hdHJpeF9zdW1tYXJ5LCByb3cubmFtZXMgPSBOVUxMLCBvcHRpb25hbCA9IEZBTFNFLA0KICAgICAgICAgICAgICBtYWtlLm5hbWVzID0gVFJVRSwgDQogICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnMgPSBkZWZhdWx0LnN0cmluZ3NBc0ZhY3RvcnMoKSkNCmRmX3N1bW1hcnkNCg0Kc3VtbWFyeSggZGF0YWJhc2UkY29zdF9taWxsaW9ucyApDQoNCiMgUmV0cmlldmUgYSBzdWJzZXRfZGF0YWZyYW1lIG9mIHRoZSBkYXRhIGZyYW1lIGNvbnNpc3Rpbmcgb2YgdGhlICJnZW5yZSIgY29sdW1ucw0KZGF0YWJhc2VbJ1BBSVMnXQ0KDQojIFJldHJpZXZlIHRoZSBkYXRhIGZvciB0aGUgIm5hbWUiIGNvbHVtbiBpbiB0aGUgZGF0YSBmcmFtZSBpbiBhIHZlY3Rvcg0KZGF0YWJhc2UkUEFJUw0KDQpgYGANCg0KYGBge3J9DQojIFJldHJpZXZlIHRoZSAzcmQgcm93IG9mIHRoZSBkYXRhIGZyYW1lLiAjIFBBUkEgT0NVTFRBUg0KZGF0YWJhc2VbMyxdDQoNCiMgUmV0cmlldmUgdGhlIHRoaXJkIHJvdyBvZiB0aGUgZGF0YSBmcmFtZSwgYnV0IG9ubHkgdGhlICJuYW1lIiBhbmQgImxlbmd0aF9taW4iIGNvbHVtbnMuDQpkYXRhYmFzZVszLCBjKCJQQUlTIiwiQ09ESUdPIildDQpgYGANCmBgYHtyfQ0KDQpzdW1tYXJ5KGRhdGFiYXNlKQ0KaGlzdG9ncmFtYSA8LSBoaXN0KGRhdGFiYXNlJE7CuiAsY29sPSJ5ZWxsb3ciLGJyZWFrcyA9IDEwKQ0KaGlzdG9ncmFtYQ0KYGBgDQpgYGB7cn0NCg0KdGltZSA9IGdzdWIoIjoiLCAiLSIsIFN5cy50aW1lKCkpDQoNCiMtIGV4cG9ydGEgZW4gZm9ybWF0byAuY3N2IGVsIGRmIGRmX3N1bW1hcnkgYWwgZmljaGVybyAiZGZfc3VtbWFyeS5jc3YiLiBTZSBndWFyZGFyw6EgZW4gbGEgc3ViY2FycGV0YSAiZGF0b3MvcHJ1ZWJhcy8iIGRlbCBwcm95ZWN0bw0KZm9sZGVyX3BhdGggPC0gIi4vb3V0cHV0X2RhdGFiYXNlcy8iDQpmaWxlbmFtZSA8LSAiZGZfc3VtbWFyeSINCmZpbGV0eXBlIDwtIi5jc3YiDQpwYXRoIDwtIHBhc3RlKGZvbGRlcl9wYXRoLGZpbGVuYW1lLCIgIix0aW1lLGZpbGV0eXBlLCBzZXA9IiIpDQp3cml0ZV9jc3YoZGZfc3VtbWFyeSwgcGF0aCkNCg0KDQpgYGANCkhheSB2YXJpb3MgcGFja2FnZXMgcXVlIGdyYWJhbiBkYXRvcyBlbiBmb3JtYXRvIC54bHMuIFBlcm8gZWwgbcOhcyBzZW5jaWxsbyBlcyBlbCBwYWNrYWdlIHhsc3guIFZlw6Ftb3NsbzoNCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ4bHN4IikNCiMgbGlicmFyeSh4bHN4KQ0Kd3JpdGUueGxzeChkZl9zdW1tYXJ5LCAiLi9vdXRwdXRfZGF0YWJhc2VzL2RmX3N1bW1hcnkueGxzeCIsIHNoZWV0TmFtZSA9ICJkZl9zdW1tYXJ5IiApDQoNCmBgYA0KDQpMYSBmdW5jacOzbiB3cml0ZS54bHN4KCkgcGVybWl0ZSBhw7FhZGlyIGRhdG9zIGEgdW4gYXJjaGl2byAueGxzeCBwcmVleGlzdGVudGU7IHBhcmEgZWxsbyB0ZW5lbW9zIHF1ZSB1c2FyIGxhIG9wY2nDs24gYXBwZW5kID0gVFJVRToNCmBgYHtyfQ0KIyBsaWJyYXJ5KHhsc3gpDQp3cml0ZS54bHN4KGRmX3N1bW1hcnksICIuL291dHB1dF9kYXRhYmFzZXMvZGZfc3VtbWFyeS54bHN4Iiwgc2hlZXROYW1lID0gInN1bW1hcnkiLCBhcHBlbmQgPSBUUlVFKQ0KYGBgDQoNCg0KREVMIEVKRVJDSUNJTyBERSBFSkVDVVRBUiBTUUwgUVVFUlkgZW4gVU4gUiBOT1RFQk9PSzoNCmBgYHtyfQ0Kd3JpdGUueGxzeCggZGZfcGl2b3Rfc3FsICwgDQogICAgICAgICAgICAiLi9vdXRwdXRfZGF0YWJhc2VzL2RmX3Bpdm90X3NxbC54bHN4IiwgDQogICAgICAgICAgICBzaGVldE5hbWUgPSAiZGZfcGl2b3Rfc3FsIiApDQpgYGANCg0KDQoNCg0KR1JBRklDQQ0KYGBge3J9DQojKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KIyojIFB1YmxpY2F0aW9uIHF1YWxpdHkgZ3JhcGhzIHJlcXVpcmUgNjAwZHBpDQpkcGk9NjAwICAgICNwaXhlbHMgcGVyIHNxdWFyZSBpbmNoDQpjYXJwZXRhID0gIi4vb3V0cHV0X2ltYWdlcy8iDQphcmNoaXZvID0gImhpc3RvZ3JhbWEiDQp0aW1lID0gZ3N1YigiOiIsICItIiwgU3lzLnRpbWUoKSkNCmNhcnBldGFfeV9hcmNoaXZvID0gcGFzdGUoY2FycGV0YSxhcmNoaXZvLCIgIix0aW1lLCIudGlmIiwgc2VwPSIiKQ0Kbm9tYnJlX2RlX3RpZiA9IGNhcnBldGFfeV9hcmNoaXZvDQp0aWZmKG5vbWJyZV9kZV90aWYsIHdpZHRoPTYqZHBpLCBoZWlnaHQ9NSpkcGksIHJlcz1kcGkpDQojKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KaGlzdG9ncmFtYSA8LSBoaXN0KGRhdGFiYXNlJE7CuiAsY29sPSJ5ZWxsb3ciLGJyZWFrcyA9IDEwKQ0KaGlzdG9ncmFtYQ0KIyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioNCmRldi5vZmYoKQ0KcHJpbnQocGFzdGUoIkZpbmFsaXphZG8gcHJvY2VzYW1pZW50byBkZSAiLGFyY2hpdm8sIiAiLHRpbWUsIHNlcD0iIikpDQojKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg0KYGBgDQoNCmBgYHtyfQ0KY2l0YXRpb24oKQ0KY2l0YXRpb24oInJlYWR4bCIpIA0KIyANCmhlbHAoInJlYWR4bCIpICMgRG9jdW1lbnRhY2lvbiBkZSBsYSBsaWJyYXJ5IHJlYWR4bA0KDQpgYGA=