1. Exportar el archivo y las librerias utilizadas.

#install.packages("readxl")
library(readxl)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.0     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.1     ✔ tibble    3.1.8
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.1     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(dplyr)
library(ggplot2)
#file.choose()
ruta_excel <- "/Users/crisflorespalacios/Desktop/R Studio /Business Analytics/AbarrotesVentasBA.xlsx"
excel_sheets(ruta_excel)
## [1] "Total"
Abarrotes_Ventas<-read_excel(ruta_excel)
view(Abarrotes_Ventas)

2. a) After the “Unidades” column, add another one called “Monto Total” that indicates the result of that operation (Price X Units).

Abarrotes_Ventas <- Abarrotes_Ventas %>% 
  mutate(`Monto Total` = Unidades * Precio)
Abarrotes_Ventas
## # A tibble: 200,620 × 23
##    CveTienda DescG…¹ Codig…² PLU   Fecha               Hora                Marca
##    <chr>     <chr>     <dbl> <lgl> <dttm>              <dttm>              <chr>
##  1 MX001     Abarro… 7.50e12 NA    2020-06-19 08:16:20 1899-12-31 08:16:21 NUTR…
##  2 MX001     Abarro… 7.50e12 NA    2020-06-19 08:23:32 1899-12-31 08:23:33 DAN …
##  3 MX001     Abarro… 7.50e12 NA    2020-06-19 08:24:33 1899-12-31 08:24:33 BIMBO
##  4 MX001     Abarro… 7.50e12 NA    2020-06-19 08:24:33 1899-12-31 08:24:33 PEPSI
##  5 MX001     Abarro… 7.50e12 NA    2020-06-19 08:26:28 1899-12-31 08:26:28 BLAN…
##  6 MX001     Abarro… 7.50e12 NA    2020-06-19 08:26:28 1899-12-31 08:26:28 FLASH
##  7 MX001     Abarro… 7.50e12 NA    2020-06-19 08:26:28 1899-12-31 08:26:28 VARI…
##  8 MX001     Abarro… 7.50e12 NA    2020-06-19 08:26:28 1899-12-31 08:26:28 ZOTE 
##  9 MX001     Abarro… 7.51e12 NA    2020-06-19 08:26:28 1899-12-31 08:26:28 ALWA…
## 10 MX001     Abarro… 3.22e10 NA    2020-06-19 15:24:02 1899-12-31 15:24:02 JUMEX
## # … with 200,610 more rows, 16 more variables: Fabricante <chr>,
## #   Producto <chr>, Precio <dbl>, Ult_Costo <dbl>, Unidades <dbl>,
## #   F_Ticket <dbl>, NombreDepartamento <chr>, NombreFamilia <chr>,
## #   NombreCategoria <chr>, Estado <chr>, Mts2 <dbl>, TipoUbicación <chr>,
## #   Giro <chr>, HoraInicio <dttm>, HoraCierre <dttm>, `Monto Total` <dbl>, and
## #   abbreviated variable names ¹​DescGiro, ²​CodigoBarras

3. a) How many records do not meet that parameter?. b) What do you suggest to correct these erroneous data?

registros_erroneos <- subset(Abarrotes_Ventas, nchar(as.character(CodigoBarras)) != 13)
registros_erroneos
## # A tibble: 42,486 × 23
##    CveTienda DescG…¹ Codig…² PLU   Fecha               Hora                Marca
##    <chr>     <chr>     <dbl> <lgl> <dttm>              <dttm>              <chr>
##  1 MX001     Abarro… 3.22e10 NA    2020-06-19 15:24:02 1899-12-31 15:24:02 JUMEX
##  2 MX001     Abarro… 7.50e 7 NA    2020-06-19 08:56:50 1899-12-31 08:56:50 COCA…
##  3 MX001     Abarro… 7.50e 7 NA    2020-06-19 15:44:06 1899-12-31 15:44:06 MARI…
##  4 MX001     Abarro… 7.50e 7 NA    2020-06-19 15:44:06 1899-12-31 15:44:06 COCA…
##  5 MX001     Abarro… 7.50e 7 NA    2020-06-19 09:07:17 1899-12-31 09:07:17 PERM…
##  6 MX001     Abarro… 7.50e 7 NA    2020-06-19 09:21:21 1899-12-31 09:21:21 COCA…
##  7 MX001     Abarro… 7.50e 7 NA    2020-06-19 09:21:21 1899-12-31 09:21:21 COCA…
##  8 MX001     Abarro… 7.50e 7 NA    2020-06-19 15:52:20 1899-12-31 15:52:21 CLOR…
##  9 MX001     Abarro… 7.50e 7 NA    2020-06-19 09:39:17 1899-12-31 09:39:17 COCA…
## 10 MX001     Abarro… 7.50e 7 NA    2020-06-19 16:02:00 1899-12-31 16:02:01 COCA…
## # … with 42,476 more rows, 16 more variables: Fabricante <chr>, Producto <chr>,
## #   Precio <dbl>, Ult_Costo <dbl>, Unidades <dbl>, F_Ticket <dbl>,
## #   NombreDepartamento <chr>, NombreFamilia <chr>, NombreCategoria <chr>,
## #   Estado <chr>, Mts2 <dbl>, TipoUbicación <chr>, Giro <chr>,
## #   HoraInicio <dttm>, HoraCierre <dttm>, `Monto Total` <dbl>, and abbreviated
## #   variable names ¹​DescGiro, ²​CodigoBarras
Abarrotes_Ventas$CodigoBarras <- str_pad(Abarrotes_Ventas$CodigoBarras, width = 13, pad = "0")
view(Abarrotes_Ventas$CodigoBarras)

4. a) What percentage of records have a PLU and how many do not?. b) What do you suggest doing about this variable?

con_plu <- sum(!is.na(Abarrotes_Ventas$PLU))
sin_plu <- sum(is.na(Abarrotes_Ventas$PLU))
porcentaje_con_plu <- con_plu / nrow(Abarrotes_Ventas) * 100
cat("Porcentaje de registros con PLU: ", round(porcentaje_con_plu, 2), "%\n")
## Porcentaje de registros con PLU:  0.72 %
porcentaje_sin_plu <- sin_plu / nrow(Abarrotes_Ventas) * 100
cat("Porcentaje de registros sin PLU: ", round(porcentaje_sin_plu, 2), "%\n")
## Porcentaje de registros sin PLU:  99.28 %
nueva_base <- select(Abarrotes_Ventas, -PLU)
Abarrotes_Ventas <- subset(nueva_base)

5. How many records have a negative price?. b) Correct those negative values indicating the criteria used to do so.

negative_prices <- subset(Abarrotes_Ventas, Precio < 0)
nrow(negative_prices)
## [1] 147
Abarrotes_Ventas$Precio <- ifelse(Abarrotes_Ventas$Precio < 0, 0, Abarrotes_Ventas$Precio)

6. a)The minimum number of items purchased per ticket. b) The maximum number of items purchased per ticket. c) The average number of items purchased per ticket.

Abarrotes_Ventas %>%
  group_by(CveTienda) %>% filter(Unidades >= 1) %>%
  summarize(min_items = min(Unidades), max_items = max(Unidades), avg_items = mean(Unidades))
## # A tibble: 5 × 4
##   CveTienda min_items max_items avg_items
##   <chr>         <dbl>     <dbl>     <dbl>
## 1 MX001             1        80      1.27
## 2 MX002             1         9      1.10
## 3 MX003             1        24      1.11
## 4 MX004             1        96      1.18
## 5 MX005             1        60      2.07

7. a) The product that sells the most in units. b) The product sold with the lowest unit price. c) The product sold with the highest unit price.

best_seller <- Abarrotes_Ventas %>%
  group_by(CveTienda, Producto) %>%
  summarize(total_units = sum(Unidades)) %>%
  slice_max(total_units)
## `summarise()` has grouped output by 'CveTienda'. You can override using the
## `.groups` argument.
lowest_price <- Abarrotes_Ventas %>%
  group_by(CveTienda, Producto) %>%
  summarize(unit_price = min(Precio)) %>%
  slice_head(n = 1)
## `summarise()` has grouped output by 'CveTienda'. You can override using the
## `.groups` argument.
highest_price <- Abarrotes_Ventas %>%
  group_by(CveTienda, Producto) %>%
  summarize(unit_price = max(Precio)) %>% arrange(desc(unit_price)) %>%
  slice_head(n = 1)
## `summarise()` has grouped output by 'CveTienda'. You can override using the
## `.groups` argument.
best_seller
## # A tibble: 5 × 3
## # Groups:   CveTienda [5]
##   CveTienda Producto                   total_units
##   <chr>     <chr>                            <dbl>
## 1 MX001     Cerveza Tecate Light 340Ml        7476
## 2 MX002     Coca Cola Retornable 2.5L          329
## 3 MX003     Pepsi N.R. 1.5L                    150
## 4 MX004     TECATE LIGHT LATA 340ML           1987
## 5 MX005     Cerveza Tecate Light 340Ml        7336
lowest_price
## # A tibble: 5 × 3
## # Groups:   CveTienda [5]
##   CveTienda Producto                            unit_price
##   <chr>     <chr>                                    <dbl>
## 1 MX001     9PRINGLES EXTRA HOT PAPAS BOTE 40GR         14
## 2 MX002     ACONDICIONADOR CAPRICE ESPE 800ML           27
## 3 MX003     7500435108256                               22
## 4 MX004     123 maxi efecto cn 900g                     20
## 5 MX005     AZUCAR ESTANDAR 5 ESTRELLAS 500G            13
highest_price
## # A tibble: 5 × 3
## # Groups:   CveTienda [5]
##   CveTienda Producto                 unit_price
##   <chr>     <chr>                         <dbl>
## 1 MX001     Whisky Buchanan´s 1L           1000
## 2 MX002     NIDO KINDER 1 MAS 800G          145
## 3 MX003     Tocino Fud 250Grs                72
## 4 MX004     TEQUILA CAMPO AZUL 1 LTO        197
## 5 MX005     Six Tecate Light 355ML           90

8. Make a table showing the monthly sales value in $ for each store.

ventas_mensuales <- Abarrotes_Ventas %>%
  mutate(Mes = lubridate::month(Fecha)) %>%
  group_by(CveTienda, Mes) %>%
  summarise(Ventas = sum(Unidades * Precio)) %>%
  ungroup()
## `summarise()` has grouped output by 'CveTienda'. You can override using the
## `.groups` argument.
view(ventas_mensuales)

9. Make an annex to your report that includes graphs and other tools that make it easier to visualize your findings

# Gr??fico para el producto m??s vendido por tienda
ggplot(best_seller, aes(x = total_units, y = Producto, fill = CveTienda)) +
  geom_col() +
  labs(x = "Unidades vendidas", y = "Producto", fill = "Tienda") +
  ggtitle("Producto m??s vendido por tienda")

# Gr??fico para el producto con el precio m??s bajo por tienda
ggplot(lowest_price, aes(x = unit_price, y = Producto, fill = CveTienda)) +
  geom_col() +
  labs(x = "Precio unitario", y = "Producto", fill = "Tienda") +
  ggtitle("Producto con precio m??s bajo por tienda")

# Gr??fico para el producto con el precio m??s alto por tienda
ggplot(highest_price, aes(x = unit_price, y = Producto, fill = CveTienda)) +
  geom_col() +
  labs(x = "Precio unitario", y = "Producto", fill = "Tienda") +
  ggtitle("Producto con precio m??s alto por tienda")

# Gr??fico de barras que muestre las ventas mensuales por tienda.
ggplot(ventas_mensuales, aes(x = Mes, y = Ventas, fill = CveTienda)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(x = "Mes", y = "Ventas ($)", fill = "Tienda") +
  theme_minimal()

Note that the echo = FALSE parameter was added to the code chunk to prevent printing of the R code that generated the plot.

LS0tCnRpdGxlOiAiRXZpZGVuY2lhMV9UZWFtMl9CQSIKYXV0aG9yOiAiQWd1c3TDrW4gR8OzbWV6IFDDqXJleiAtIEEwMTczMjg5NyAvIEthcmxhIFPDoW5jaGV6IERlbCDDgW5nZWwgLSBBMDExOTgxODQgLyBHZXJhcmRvIENlZGlsbG8gQ29yb25hIC0gQTAxNzA0MjMyIC9EYW5pZWwgQnJhdm8gUGF0acOxbyAtIEEwMTcwODY3NSAvIENyaXN0aW5hIEZsb3JlcyBQYWxhY2lvcyAtIEEwMTU2Njg4MCAvIERhbmllbCBFbWlsaWFubyBOw6FqZXJhIE90ZXJvIC0gQTAxNzA5NTc4IgpkYXRlOiAiMDUvMDUvMjAyMyIKb3V0cHV0OgogICAgaHRtbF9kb2N1bWVudDoKICAgICAgdG9jOiB0cnVlCiAgICAgIHRvY19mbG9hdDogdHJ1ZSAKICAgICAgY29kZV9kb3dubG9hZDogdHJ1ZSAKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCgojIyMgMS4gRXhwb3J0YXIgZWwgYXJjaGl2byB5IGxhcyBsaWJyZXJpYXMgdXRpbGl6YWRhcy4KCmBgYHtyfQojaW5zdGFsbC5wYWNrYWdlcygicmVhZHhsIikKbGlicmFyeShyZWFkeGwpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KGdncGxvdDIpCiNmaWxlLmNob29zZSgpCnJ1dGFfZXhjZWwgPC0gIi9Vc2Vycy9jcmlzZmxvcmVzcGFsYWNpb3MvRGVza3RvcC9SIFN0dWRpbyAvQnVzaW5lc3MgQW5hbHl0aWNzL0FiYXJyb3Rlc1ZlbnRhc0JBLnhsc3giCmV4Y2VsX3NoZWV0cyhydXRhX2V4Y2VsKQpBYmFycm90ZXNfVmVudGFzPC1yZWFkX2V4Y2VsKHJ1dGFfZXhjZWwpCnZpZXcoQWJhcnJvdGVzX1ZlbnRhcykKYGBgCgojIyMgMi4gYSkgQWZ0ZXIgdGhlICJVbmlkYWRlcyIgY29sdW1uLCBhZGQgYW5vdGhlciBvbmUgY2FsbGVkICJNb250byBUb3RhbCIgdGhhdCBpbmRpY2F0ZXMgdGhlIHJlc3VsdCBvZiB0aGF0IG9wZXJhdGlvbiAoUHJpY2UgWCBVbml0cykuCgpgYGB7cn0KQWJhcnJvdGVzX1ZlbnRhcyA8LSBBYmFycm90ZXNfVmVudGFzICU+JSAKICBtdXRhdGUoYE1vbnRvIFRvdGFsYCA9IFVuaWRhZGVzICogUHJlY2lvKQpBYmFycm90ZXNfVmVudGFzCmBgYAoKIyMjIDMuIGEpIEhvdyBtYW55IHJlY29yZHMgZG8gbm90IG1lZXQgdGhhdCBwYXJhbWV0ZXI/LiBiKSBXaGF0IGRvIHlvdSBzdWdnZXN0IHRvIGNvcnJlY3QgdGhlc2UgZXJyb25lb3VzIGRhdGE/CgpgYGB7cn0KcmVnaXN0cm9zX2Vycm9uZW9zIDwtIHN1YnNldChBYmFycm90ZXNfVmVudGFzLCBuY2hhcihhcy5jaGFyYWN0ZXIoQ29kaWdvQmFycmFzKSkgIT0gMTMpCnJlZ2lzdHJvc19lcnJvbmVvcwpBYmFycm90ZXNfVmVudGFzJENvZGlnb0JhcnJhcyA8LSBzdHJfcGFkKEFiYXJyb3Rlc19WZW50YXMkQ29kaWdvQmFycmFzLCB3aWR0aCA9IDEzLCBwYWQgPSAiMCIpCnZpZXcoQWJhcnJvdGVzX1ZlbnRhcyRDb2RpZ29CYXJyYXMpCmBgYAoKIyMjIDQuIGEpIFdoYXQgcGVyY2VudGFnZSBvZiByZWNvcmRzIGhhdmUgYSBQTFUgYW5kIGhvdyBtYW55IGRvIG5vdD8uIGIpIFdoYXQgZG8geW91IHN1Z2dlc3QgZG9pbmcgYWJvdXQgdGhpcyB2YXJpYWJsZT8KCmBgYHtyfQpjb25fcGx1IDwtIHN1bSghaXMubmEoQWJhcnJvdGVzX1ZlbnRhcyRQTFUpKQpzaW5fcGx1IDwtIHN1bShpcy5uYShBYmFycm90ZXNfVmVudGFzJFBMVSkpCnBvcmNlbnRhamVfY29uX3BsdSA8LSBjb25fcGx1IC8gbnJvdyhBYmFycm90ZXNfVmVudGFzKSAqIDEwMApjYXQoIlBvcmNlbnRhamUgZGUgcmVnaXN0cm9zIGNvbiBQTFU6ICIsIHJvdW5kKHBvcmNlbnRhamVfY29uX3BsdSwgMiksICIlXG4iKQpwb3JjZW50YWplX3Npbl9wbHUgPC0gc2luX3BsdSAvIG5yb3coQWJhcnJvdGVzX1ZlbnRhcykgKiAxMDAKY2F0KCJQb3JjZW50YWplIGRlIHJlZ2lzdHJvcyBzaW4gUExVOiAiLCByb3VuZChwb3JjZW50YWplX3Npbl9wbHUsIDIpLCAiJVxuIikKbnVldmFfYmFzZSA8LSBzZWxlY3QoQWJhcnJvdGVzX1ZlbnRhcywgLVBMVSkKQWJhcnJvdGVzX1ZlbnRhcyA8LSBzdWJzZXQobnVldmFfYmFzZSkKYGBgCgojIyMgNS4gSG93IG1hbnkgcmVjb3JkcyBoYXZlIGEgbmVnYXRpdmUgcHJpY2U/LiBiKSBDb3JyZWN0IHRob3NlIG5lZ2F0aXZlIHZhbHVlcyBpbmRpY2F0aW5nIHRoZSBjcml0ZXJpYSB1c2VkIHRvIGRvIHNvLgoKYGBge3J9Cm5lZ2F0aXZlX3ByaWNlcyA8LSBzdWJzZXQoQWJhcnJvdGVzX1ZlbnRhcywgUHJlY2lvIDwgMCkKbnJvdyhuZWdhdGl2ZV9wcmljZXMpCkFiYXJyb3Rlc19WZW50YXMkUHJlY2lvIDwtIGlmZWxzZShBYmFycm90ZXNfVmVudGFzJFByZWNpbyA8IDAsIDAsIEFiYXJyb3Rlc19WZW50YXMkUHJlY2lvKQpgYGAKCiMjIyA2LiBhKVRoZSBtaW5pbXVtIG51bWJlciBvZiBpdGVtcyBwdXJjaGFzZWQgcGVyIHRpY2tldC4gYikgVGhlIG1heGltdW0gbnVtYmVyIG9mIGl0ZW1zIHB1cmNoYXNlZCBwZXIgdGlja2V0LiBjKSBUaGUgYXZlcmFnZSBudW1iZXIgb2YgaXRlbXMgcHVyY2hhc2VkIHBlciB0aWNrZXQuCgpgYGB7cn0KQWJhcnJvdGVzX1ZlbnRhcyAlPiUKICBncm91cF9ieShDdmVUaWVuZGEpICU+JSBmaWx0ZXIoVW5pZGFkZXMgPj0gMSkgJT4lCiAgc3VtbWFyaXplKG1pbl9pdGVtcyA9IG1pbihVbmlkYWRlcyksIG1heF9pdGVtcyA9IG1heChVbmlkYWRlcyksIGF2Z19pdGVtcyA9IG1lYW4oVW5pZGFkZXMpKQpgYGAKCiMjIyA3LiBhKSBUaGUgcHJvZHVjdCB0aGF0IHNlbGxzIHRoZSBtb3N0IGluIHVuaXRzLiBiKSBUaGUgcHJvZHVjdCBzb2xkIHdpdGggdGhlIGxvd2VzdCB1bml0IHByaWNlLiBjKSBUaGUgcHJvZHVjdCBzb2xkIHdpdGggdGhlIGhpZ2hlc3QgdW5pdCBwcmljZS4KCmBgYHtyfQpiZXN0X3NlbGxlciA8LSBBYmFycm90ZXNfVmVudGFzICU+JQogIGdyb3VwX2J5KEN2ZVRpZW5kYSwgUHJvZHVjdG8pICU+JQogIHN1bW1hcml6ZSh0b3RhbF91bml0cyA9IHN1bShVbmlkYWRlcykpICU+JQogIHNsaWNlX21heCh0b3RhbF91bml0cykKCmxvd2VzdF9wcmljZSA8LSBBYmFycm90ZXNfVmVudGFzICU+JQogIGdyb3VwX2J5KEN2ZVRpZW5kYSwgUHJvZHVjdG8pICU+JQogIHN1bW1hcml6ZSh1bml0X3ByaWNlID0gbWluKFByZWNpbykpICU+JQogIHNsaWNlX2hlYWQobiA9IDEpCgpoaWdoZXN0X3ByaWNlIDwtIEFiYXJyb3Rlc19WZW50YXMgJT4lCiAgZ3JvdXBfYnkoQ3ZlVGllbmRhLCBQcm9kdWN0bykgJT4lCiAgc3VtbWFyaXplKHVuaXRfcHJpY2UgPSBtYXgoUHJlY2lvKSkgJT4lIGFycmFuZ2UoZGVzYyh1bml0X3ByaWNlKSkgJT4lCiAgc2xpY2VfaGVhZChuID0gMSkKCmJlc3Rfc2VsbGVyCmxvd2VzdF9wcmljZQpoaWdoZXN0X3ByaWNlCmBgYAoKIyMjIDguIE1ha2UgYSB0YWJsZSBzaG93aW5nIHRoZSBtb250aGx5IHNhbGVzIHZhbHVlIGluICQgZm9yIGVhY2ggc3RvcmUuCgpgYGB7cn0KdmVudGFzX21lbnN1YWxlcyA8LSBBYmFycm90ZXNfVmVudGFzICU+JQogIG11dGF0ZShNZXMgPSBsdWJyaWRhdGU6Om1vbnRoKEZlY2hhKSkgJT4lCiAgZ3JvdXBfYnkoQ3ZlVGllbmRhLCBNZXMpICU+JQogIHN1bW1hcmlzZShWZW50YXMgPSBzdW0oVW5pZGFkZXMgKiBQcmVjaW8pKSAlPiUKICB1bmdyb3VwKCkKdmlldyh2ZW50YXNfbWVuc3VhbGVzKQpgYGAKCiMjIyA5LiBNYWtlIGFuIGFubmV4IHRvIHlvdXIgcmVwb3J0IHRoYXQgaW5jbHVkZXMgZ3JhcGhzIGFuZCBvdGhlciB0b29scyB0aGF0IG1ha2UgaXQgZWFzaWVyIHRvIHZpc3VhbGl6ZSB5b3VyIGZpbmRpbmdzCgpgYGB7cn0KIyBHcj8/ZmljbyBwYXJhIGVsIHByb2R1Y3RvIG0/P3MgdmVuZGlkbyBwb3IgdGllbmRhCmdncGxvdChiZXN0X3NlbGxlciwgYWVzKHggPSB0b3RhbF91bml0cywgeSA9IFByb2R1Y3RvLCBmaWxsID0gQ3ZlVGllbmRhKSkgKwogIGdlb21fY29sKCkgKwogIGxhYnMoeCA9ICJVbmlkYWRlcyB2ZW5kaWRhcyIsIHkgPSAiUHJvZHVjdG8iLCBmaWxsID0gIlRpZW5kYSIpICsKICBnZ3RpdGxlKCJQcm9kdWN0byBtPz9zIHZlbmRpZG8gcG9yIHRpZW5kYSIpCgojIEdyPz9maWNvIHBhcmEgZWwgcHJvZHVjdG8gY29uIGVsIHByZWNpbyBtPz9zIGJham8gcG9yIHRpZW5kYQpnZ3Bsb3QobG93ZXN0X3ByaWNlLCBhZXMoeCA9IHVuaXRfcHJpY2UsIHkgPSBQcm9kdWN0bywgZmlsbCA9IEN2ZVRpZW5kYSkpICsKICBnZW9tX2NvbCgpICsKICBsYWJzKHggPSAiUHJlY2lvIHVuaXRhcmlvIiwgeSA9ICJQcm9kdWN0byIsIGZpbGwgPSAiVGllbmRhIikgKwogIGdndGl0bGUoIlByb2R1Y3RvIGNvbiBwcmVjaW8gbT8/cyBiYWpvIHBvciB0aWVuZGEiKQoKIyBHcj8/ZmljbyBwYXJhIGVsIHByb2R1Y3RvIGNvbiBlbCBwcmVjaW8gbT8/cyBhbHRvIHBvciB0aWVuZGEKZ2dwbG90KGhpZ2hlc3RfcHJpY2UsIGFlcyh4ID0gdW5pdF9wcmljZSwgeSA9IFByb2R1Y3RvLCBmaWxsID0gQ3ZlVGllbmRhKSkgKwogIGdlb21fY29sKCkgKwogIGxhYnMoeCA9ICJQcmVjaW8gdW5pdGFyaW8iLCB5ID0gIlByb2R1Y3RvIiwgZmlsbCA9ICJUaWVuZGEiKSArCiAgZ2d0aXRsZSgiUHJvZHVjdG8gY29uIHByZWNpbyBtPz9zIGFsdG8gcG9yIHRpZW5kYSIpCgojIEdyPz9maWNvIGRlIGJhcnJhcyBxdWUgbXVlc3RyZSBsYXMgdmVudGFzIG1lbnN1YWxlcyBwb3IgdGllbmRhLgpnZ3Bsb3QodmVudGFzX21lbnN1YWxlcywgYWVzKHggPSBNZXMsIHkgPSBWZW50YXMsIGZpbGwgPSBDdmVUaWVuZGEpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGxhYnMoeCA9ICJNZXMiLCB5ID0gIlZlbnRhcyAoJCkiLCBmaWxsID0gIlRpZW5kYSIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgoKTm90ZSB0aGF0IHRoZSBgZWNobyA9IEZBTFNFYCBwYXJhbWV0ZXIgd2FzIGFkZGVkIHRvIHRoZSBjb2RlIGNodW5rIHRvIHByZXZlbnQgcHJpbnRpbmcgb2YgdGhlIFIgY29kZSB0aGF0IGdlbmVyYXRlZCB0aGUgcGxvdC4K