1 Ejercicio 1 — Listas de vectores

1. Crear una lista llamada acciones con los precios de cierre de tres días consecutivos para Apple (120, 125, 130), Google (1800, 1850, 1900) y Amazon (3200, 3300, 3400), nombrando cada elemento según la empresa.

acciones <- list(
  apple  = c(120, 125, 130),
  google = c(1800, 1850, 1900),
  amazon = c(3200, 3300, 3400)
)

str(acciones)
#> List of 3
#>  $ apple : num [1:3] 120 125 130
#>  $ google: num [1:3] 1800 1850 1900
#>  $ amazon: num [1:3] 3200 3300 3400

La lista se puede ver también en formato tabular, ya que todos los vectores tienen la misma longitud:

tabla(
  as.data.frame(do.call(rbind, acciones)),
  col.names = c("Día 1", "Día 2", "Día 3"),
  caption   = "Precios de cierre (USD)"
)
Precios de cierre (USD)
Día 1 Día 2 Día 3
apple 120 125 130
google 1800 1850 1900
amazon 3200 3300 3400

2. Añadir a la lista un vector con los precios de cierre de Microsoft (210, 215, 220) para los mismos tres días.

acciones$microsoft <- c(210, 215, 220)

tabla(
  as.data.frame(do.call(rbind, acciones)),
  col.names = c("Día 1", "Día 2", "Día 3"),
  caption   = "Precios de cierre tras incorporar Microsoft"
)
Precios de cierre tras incorporar Microsoft
Día 1 Día 2 Día 3
apple 120 125 130
google 1800 1850 1900
amazon 3200 3300 3400
microsoft 210 215 220

3. Extraer el segundo elemento del vector google dentro de la lista acciones.

acciones$google[2]
#> [1] 1850

2 Ejercicio 2 — Listas con objetos heterogéneos

1. Crear una lista indicadores con el PIB (30000), la inflación (2.5, 3.0, 3.5), el desempleo (5.0, 5.5, 6.0, 4.5, 4.0, 3.5) en una matriz de dos filas, y la deuda desagregada en pública (60) y privada (40).

gdp <- 30000
inf <- c(2.5, 3.0, 3.5)

# matrix() LLENA POR COLUMNAS; byrow = TRUE RESPETA EL ORDEN DEL ENUNCIADO
un_emp <- matrix(
  c(5.0, 5.5, 6.0, 4.5, 4.0, 3.5),
  nrow  = 2,
  byrow = TRUE,
  dimnames = list(c("Semestre I", "Semestre II"),
                  c("T1", "T2", "T3"))
)

# DEUDA DESAGREGADA (SUBLISTA)
debt <- list(pb_debt = 60, pvt_debt = 40)

indicadores <- list(
  pib       = gdp,
  inflacion = inf,
  desempleo = un_emp,
  deuda     = debt
)

str(indicadores)
#> List of 4
#>  $ pib      : num 30000
#>  $ inflacion: num [1:3] 2.5 3 3.5
#>  $ desempleo: num [1:2, 1:3] 5 4.5 5.5 4 6 3.5
#>   ..- attr(*, "dimnames")=List of 2
#>   .. ..$ : chr [1:2] "Semestre I" "Semestre II"
#>   .. ..$ : chr [1:3] "T1" "T2" "T3"
#>  $ deuda    :List of 2
#>   ..$ pb_debt : num 60
#>   ..$ pvt_debt: num 40
tabla(un_emp, caption = "Tasa de desempleo (%)")
Tasa de desempleo (%)
T1 T2 T3
Semestre I 5.0 5.5 6.0
Semestre II 4.5 4.0 3.5

2. Calcular el promedio de los elementos del tercer elemento de la lista y aumentar la deuda pública en un 20 % adicional.

# EL RESULTADO SE GUARDA EN UN OBJETO NUEVO PARA NO DESTRUIR LA MATRIZ
prom_desempleo <- mean(indicadores[[3]])
prom_desempleo
#> [1] 4.75
# LA MATRIZ SIGUE INTACTA DENTRO DE LA LISTA
indicadores$desempleo
#>              T1  T2  T3
#> Semestre I  5.0 5.5 6.0
#> Semestre II 4.5 4.0 3.5
deuda_previa <- indicadores$deuda$pb_debt
indicadores$deuda$pb_debt <- indicadores$deuda$pb_debt * 1.20

tabla(
  data.frame(
    Concepto = c("Deuda pública", "Deuda privada"),
    Antes    = c(deuda_previa, indicadores$deuda$pvt_debt),
    Después  = c(indicadores$deuda$pb_debt, indicadores$deuda$pvt_debt)
  ),
  row.names = FALSE,
  caption   = "Deuda antes y después del ajuste del 20 %"
)
Deuda antes y después del ajuste del 20 %
Concepto Antes Después
Deuda pública 60 72
Deuda privada 40 40

El promedio se asigna a un objeto separado (prom_desempleo). Si se escribiera indicadores$desempleo <- mean(...), la matriz original quedaría reemplazada por un escalar y se perdería la estructura de la lista.

3 Ejercicio 3 — Listas anidadas

1. Crear una lista estudiantes con los nombres (Ana, Luis, Pedro), las edades (18, 19, 20) y las notas de matemáticas (8, 7, 9), historia (6, 8, 7) e inglés (9, 10, 8).

name <- c("Ana", "Luis", "Pedro")
age  <- c(18, 19, 20)

# NOTAS POR MATERIA (SUBLISTA)
notes <- list(
  matematicas = c(8, 7, 9),
  historia    = c(6, 8, 7),
  ingles      = c(9, 10, 8)
)

estudiantes <- list(
  nombre = name,
  edad   = age,
  notas  = notes
)

str(estudiantes)
#> List of 3
#>  $ nombre: chr [1:3] "Ana" "Luis" "Pedro"
#>  $ edad  : num [1:3] 18 19 20
#>  $ notas :List of 3
#>   ..$ matematicas: num [1:3] 8 7 9
#>   ..$ historia   : num [1:3] 6 8 7
#>   ..$ ingles     : num [1:3] 9 10 8

2. Modificar el nombre del primer estudiante por “Elena”. 3. Añadir un vector con los géneros de los estudiantes (F, M, NB). 4. Cambiar la nota de inglés del tercer estudiante por nueve (9).

estudiantes$nombre[1]        <- "Elena"
estudiantes$genero           <- c("F", "M", "NB")
estudiantes$notas$ingles[3]  <- 9
tabla(
  data.frame(
    Nombre      = estudiantes$nombre,
    Edad        = estudiantes$edad,
    Género      = estudiantes$genero,
    Matemáticas = estudiantes$notas$matematicas,
    Historia    = estudiantes$notas$historia,
    Inglés      = estudiantes$notas$ingles
  ),
  row.names = FALSE,
  caption   = "Registro de estudiantes tras las modificaciones"
)
Registro de estudiantes tras las modificaciones
Nombre Edad Género Matemáticas Historia Inglés
Elena 18 F 8 6 9
Luis 19 M 7 8 10
Pedro 20 NB 9 7 9

4 Ejercicio 4 — Data frames

1. Crear un data frame ventas_tienda de \(5\times5\), donde las filas representen cinco tiendas distintas y las columnas cinco días.

ventas_tienda <- data.frame(
  dia_1 = c(12, 10, 22, 16, 30),
  dia_2 = c(15, 11, 24, 17, 32),
  dia_3 = c(14, 13, 21, 19, 31),
  dia_4 = c(18, 12, 25, 20, 35),
  dia_5 = c(20, 15, 23, 18, 33),
  row.names = c("Tienda A", "Tienda B", "Tienda C", "Tienda D", "Tienda E")
)

tabla(ventas_tienda, caption = "Ventas iniciales por tienda y día")
Ventas iniciales por tienda y día
dia_1 dia_2 dia_3 dia_4 dia_5
Tienda A 12 15 14 18 20
Tienda B 10 11 13 12 15
Tienda C 22 24 21 25 23
Tienda D 16 17 19 20 18
Tienda E 30 32 31 35 33

2. Mostrar el valor ubicado en la fila 3, columna 4. 3. Mostrar los valores de todas las tiendas para los días dos y cinco.

ventas_tienda[3, 4]
#> [1] 25
tabla(
  ventas_tienda[, c("dia_2", "dia_5")],
  col.names = c("Día 2", "Día 5"),
  caption   = "Ventas de los días 2 y 5"
)
Ventas de los días 2 y 5
Día 2 Día 5
Tienda A 15 20
Tienda B 11 15
Tienda C 24 23
Tienda D 17 18
Tienda E 32 33

4. Cambiar las ventas de la “Tienda B” en el dia_1 por un valor de 14.

# INDEXACIÓN POR NOMBRE PARA EVITAR ERRORES DE POSICIÓN
ventas_tienda["Tienda B", "dia_1"] <- 14

tabla(ventas_tienda, caption = "Ventas tras corregir la Tienda B")
Ventas tras corregir la Tienda B
dia_1 dia_2 dia_3 dia_4 dia_5
Tienda A 12 15 14 18 20
Tienda B 14 11 13 12 15
Tienda C 22 24 21 25 23
Tienda D 16 17 19 20 18
Tienda E 30 32 31 35 33

5. Incrementar en un 15 % todos los valores registrados en la fila de la “Tienda E”. 6. Reemplazar toda la columna dia_3 multiplicando sus valores por dos.

ventas_tienda["Tienda E", ] <- round(ventas_tienda["Tienda E", ] * 1.15, 2)
ventas_tienda[, "dia_3"]    <- ventas_tienda[, "dia_3"] * 2

tabla(ventas_tienda, caption = "Ventas finales tras ambas transformaciones")
Ventas finales tras ambas transformaciones
dia_1 dia_2 dia_3 dia_4 dia_5
Tienda A 12.0 15.0 28.0 18.00 20.00
Tienda B 14.0 11.0 26.0 12.00 15.00
Tienda C 22.0 24.0 42.0 25.00 23.00
Tienda D 16.0 17.0 38.0 20.00 18.00
Tienda E 34.5 36.8 71.3 40.25 37.95

El orden de las operaciones importa: la Tienda E se ajusta primero en un 15 % y luego su valor de dia_3 se duplica, de modo que esa celda acumula ambas transformaciones (\(1.15 \times 2\)).

LS0tCnRpdGxlOiAiTWFuZWpvIGRlIGVzdHJ1Y3R1cmFzIGRlIGRhdG9zIGLDoXNpY2FzIGVuIFIiCnN1YnRpdGxlOiAiQWN0aXZpZGFkIEEyMiDigJQgVGFyZWEgMiAoTE0yMzAyNykiCmF1dGhvcjogIkhhcm9sZCBTLiBMLiBNb250YW5vIgpkYXRlOiAiMjAyNi0wNy0yNCIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBmYWxzZQogICAgICBzbW9vdGhfc2Nyb2xsOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIG51bWJlcl9zZWN0aW9uczogdHJ1ZQogICAgdGhlbWU6IGZsYXRseQogICAgaGlnaGxpZ2h0OiB0YW5nbwogICAgZGZfcHJpbnQ6IHBhZ2VkCiAgICBjb2RlX2ZvbGRpbmc6IHNob3cKICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KAogIGVjaG8gICAgPSBUUlVFLAogIG1lc3NhZ2UgPSBGQUxTRSwKICB3YXJuaW5nID0gRkFMU0UsCiAgY29tbWVudCA9ICIjPiIKKQoKIyBUQUJMQVMgSFRNTCBDT05TSVNURU5URVMgU0lOIERFUEVOREVOQ0lBUyBFWFRFUk5BUwp0YWJsYSA8LSBmdW5jdGlvbih4LCAuLi4pIHsKICBrbml0cjo6a2FibGUoeCwgZm9ybWF0ID0gImh0bWwiLCB0YWJsZS5hdHRyID0gJ2NsYXNzPSJ0YWJsYSInLCAuLi4pCn0KYGBgCgpgYGB7Y3NzLCBlY2hvPUZBTFNFfQpib2R5IHsKICBmb250LXNpemU6IDE1cHg7CiAgbGluZS1oZWlnaHQ6IDEuNjU7Cn0KCmgxLnRpdGxlIHsgZm9udC13ZWlnaHQ6IDYwMDsgfQoKaDEgewogIGJvcmRlci1ib3R0b206IDJweCBzb2xpZCAjMmMzZTUwOwogIHBhZGRpbmctYm90dG9tOiAuM2VtOwogIG1hcmdpbi10b3A6IDEuOGVtOwp9CgouZW51bmNpYWRvIHsKICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjRmN2Y5OwogIGJvcmRlci1sZWZ0OiA0cHggc29saWQgIzJjM2U1MDsKICBwYWRkaW5nOiAuOWVtIDEuMWVtOwogIG1hcmdpbjogMS4yZW0gMDsKICBib3JkZXItcmFkaXVzOiAwIDRweCA0cHggMDsKfQoKLmVudW5jaWFkbyBwOmxhc3QtY2hpbGQgeyBtYXJnaW4tYm90dG9tOiAwOyB9Cgoubm90YSB7CiAgYmFja2dyb3VuZC1jb2xvcjogI2ZkZjZlMzsKICBib3JkZXItbGVmdDogNHB4IHNvbGlkICNiNTg5MDA7CiAgcGFkZGluZzogLjhlbSAxLjFlbTsKICBtYXJnaW46IDEuMmVtIDA7CiAgZm9udC1zaXplOiAuOTNlbTsKICBib3JkZXItcmFkaXVzOiAwIDRweCA0cHggMDsKfQoKdGFibGUudGFibGEgewogIGJvcmRlci1jb2xsYXBzZTogY29sbGFwc2U7CiAgbWFyZ2luOiAxZW0gMDsKICBmb250LXNpemU6IC45M2VtOwp9Cgp0YWJsZS50YWJsYSB0aCB7CiAgYmFja2dyb3VuZC1jb2xvcjogIzJjM2U1MDsKICBjb2xvcjogI2ZmZjsKICBwYWRkaW5nOiAuNWVtIC45ZW07CiAgdGV4dC1hbGlnbjogcmlnaHQ7Cn0KCnRhYmxlLnRhYmxhIHRoOmZpcnN0LWNoaWxkIHsgdGV4dC1hbGlnbjogbGVmdDsgfQoKdGFibGUudGFibGEgdGQgewogIHBhZGRpbmc6IC40NWVtIC45ZW07CiAgYm9yZGVyLWJvdHRvbTogMXB4IHNvbGlkICNlMWU1ZWE7CiAgdGV4dC1hbGlnbjogcmlnaHQ7Cn0KCnRhYmxlLnRhYmxhIHRkOmZpcnN0LWNoaWxkIHsKICB0ZXh0LWFsaWduOiBsZWZ0OwogIGZvbnQtd2VpZ2h0OiA1MDA7Cn0KCnRhYmxlLnRhYmxhIHRyOmhvdmVyIHRkIHsgYmFja2dyb3VuZC1jb2xvcjogI2Y0ZjdmOTsgfQoKcHJlIHsgYm9yZGVyLXJhZGl1czogNHB4OyB9CmBgYAoKIyBFamVyY2ljaW8gMSDigJQgTGlzdGFzIGRlIHZlY3RvcmVzIHsjZWoxfQoKOjo6IHsuZW51bmNpYWRvfQoqKjEuKiogQ3JlYXIgdW5hIGxpc3RhIGxsYW1hZGEgYGFjY2lvbmVzYCBjb24gbG9zIHByZWNpb3MgZGUgY2llcnJlIGRlIHRyZXMgZMOtYXMgY29uc2VjdXRpdm9zIHBhcmEgQXBwbGUgKDEyMCwgMTI1LCAxMzApLCBHb29nbGUgKDE4MDAsIDE4NTAsIDE5MDApIHkgQW1hem9uICgzMjAwLCAzMzAwLCAzNDAwKSwgbm9tYnJhbmRvIGNhZGEgZWxlbWVudG8gc2Vnw7puIGxhIGVtcHJlc2EuCjo6OgoKYGBge3IgYWNjaW9uZXMtbGlzdGF9CmFjY2lvbmVzIDwtIGxpc3QoCiAgYXBwbGUgID0gYygxMjAsIDEyNSwgMTMwKSwKICBnb29nbGUgPSBjKDE4MDAsIDE4NTAsIDE5MDApLAogIGFtYXpvbiA9IGMoMzIwMCwgMzMwMCwgMzQwMCkKKQoKc3RyKGFjY2lvbmVzKQpgYGAKCkxhIGxpc3RhIHNlIHB1ZWRlIHZlciB0YW1iacOpbiBlbiBmb3JtYXRvIHRhYnVsYXIsIHlhIHF1ZSB0b2RvcyBsb3MgdmVjdG9yZXMgdGllbmVuIGxhIG1pc21hIGxvbmdpdHVkOgoKYGBge3IgYWNjaW9uZXMtdGFibGF9CnRhYmxhKAogIGFzLmRhdGEuZnJhbWUoZG8uY2FsbChyYmluZCwgYWNjaW9uZXMpKSwKICBjb2wubmFtZXMgPSBjKCJEw61hIDEiLCAiRMOtYSAyIiwgIkTDrWEgMyIpLAogIGNhcHRpb24gICA9ICJQcmVjaW9zIGRlIGNpZXJyZSAoVVNEKSIKKQpgYGAKCjo6OiB7LmVudW5jaWFkb30KKioyLioqIEHDsWFkaXIgYSBsYSBsaXN0YSB1biB2ZWN0b3IgY29uIGxvcyBwcmVjaW9zIGRlIGNpZXJyZSBkZSBNaWNyb3NvZnQgKDIxMCwgMjE1LCAyMjApIHBhcmEgbG9zIG1pc21vcyB0cmVzIGTDrWFzLgo6OjoKCmBgYHtyIGFjY2lvbmVzLW1pY3Jvc29mdH0KYWNjaW9uZXMkbWljcm9zb2Z0IDwtIGMoMjEwLCAyMTUsIDIyMCkKCnRhYmxhKAogIGFzLmRhdGEuZnJhbWUoZG8uY2FsbChyYmluZCwgYWNjaW9uZXMpKSwKICBjb2wubmFtZXMgPSBjKCJEw61hIDEiLCAiRMOtYSAyIiwgIkTDrWEgMyIpLAogIGNhcHRpb24gICA9ICJQcmVjaW9zIGRlIGNpZXJyZSB0cmFzIGluY29ycG9yYXIgTWljcm9zb2Z0IgopCmBgYAoKOjo6IHsuZW51bmNpYWRvfQoqKjMuKiogRXh0cmFlciBlbCBzZWd1bmRvIGVsZW1lbnRvIGRlbCB2ZWN0b3IgYGdvb2dsZWAgZGVudHJvIGRlIGxhIGxpc3RhIGBhY2Npb25lc2AuCjo6OgoKYGBge3IgYWNjaW9uZXMtZ29vZ2xlLTJ9CmFjY2lvbmVzJGdvb2dsZVsyXQpgYGAKCiMgRWplcmNpY2lvIDIg4oCUIExpc3RhcyBjb24gb2JqZXRvcyBoZXRlcm9nw6luZW9zIHsjZWoyfQoKOjo6IHsuZW51bmNpYWRvfQoqKjEuKiogQ3JlYXIgdW5hIGxpc3RhIGBpbmRpY2Fkb3Jlc2AgY29uIGVsIFBJQiAoMzAwMDApLCBsYSBpbmZsYWNpw7NuICgyLjUsIDMuMCwgMy41KSwgZWwgZGVzZW1wbGVvICg1LjAsIDUuNSwgNi4wLCA0LjUsIDQuMCwgMy41KSBlbiB1bmEgbWF0cml6IGRlIGRvcyBmaWxhcywgeSBsYSBkZXVkYSBkZXNhZ3JlZ2FkYSBlbiBww7pibGljYSAoNjApIHkgcHJpdmFkYSAoNDApLgo6OjoKCmBgYHtyIGluZGljYWRvcmVzLWxpc3RhfQpnZHAgPC0gMzAwMDAKaW5mIDwtIGMoMi41LCAzLjAsIDMuNSkKCiMgbWF0cml4KCkgTExFTkEgUE9SIENPTFVNTkFTOyBieXJvdyA9IFRSVUUgUkVTUEVUQSBFTCBPUkRFTiBERUwgRU5VTkNJQURPCnVuX2VtcCA8LSBtYXRyaXgoCiAgYyg1LjAsIDUuNSwgNi4wLCA0LjUsIDQuMCwgMy41KSwKICBucm93ICA9IDIsCiAgYnlyb3cgPSBUUlVFLAogIGRpbW5hbWVzID0gbGlzdChjKCJTZW1lc3RyZSBJIiwgIlNlbWVzdHJlIElJIiksCiAgICAgICAgICAgICAgICAgIGMoIlQxIiwgIlQyIiwgIlQzIikpCikKCiMgREVVREEgREVTQUdSRUdBREEgKFNVQkxJU1RBKQpkZWJ0IDwtIGxpc3QocGJfZGVidCA9IDYwLCBwdnRfZGVidCA9IDQwKQoKaW5kaWNhZG9yZXMgPC0gbGlzdCgKICBwaWIgICAgICAgPSBnZHAsCiAgaW5mbGFjaW9uID0gaW5mLAogIGRlc2VtcGxlbyA9IHVuX2VtcCwKICBkZXVkYSAgICAgPSBkZWJ0CikKCnN0cihpbmRpY2Fkb3JlcykKYGBgCgpgYGB7ciBpbmRpY2Fkb3Jlcy1kZXNlbXBsZW8tdGFibGF9CnRhYmxhKHVuX2VtcCwgY2FwdGlvbiA9ICJUYXNhIGRlIGRlc2VtcGxlbyAoJSkiKQpgYGAKCjo6OiB7LmVudW5jaWFkb30KKioyLioqIENhbGN1bGFyIGVsIHByb21lZGlvIGRlIGxvcyBlbGVtZW50b3MgZGVsIHRlcmNlciBlbGVtZW50byBkZSBsYSBsaXN0YSB5IGF1bWVudGFyIGxhIGRldWRhIHDDumJsaWNhIGVuIHVuIDIwICUgYWRpY2lvbmFsLgo6OjoKCmBgYHtyIGluZGljYWRvcmVzLXByb21lZGlvfQojIEVMIFJFU1VMVEFETyBTRSBHVUFSREEgRU4gVU4gT0JKRVRPIE5VRVZPIFBBUkEgTk8gREVTVFJVSVIgTEEgTUFUUklaCnByb21fZGVzZW1wbGVvIDwtIG1lYW4oaW5kaWNhZG9yZXNbWzNdXSkKcHJvbV9kZXNlbXBsZW8KCiMgTEEgTUFUUklaIFNJR1VFIElOVEFDVEEgREVOVFJPIERFIExBIExJU1RBCmluZGljYWRvcmVzJGRlc2VtcGxlbwpgYGAKCmBgYHtyIGluZGljYWRvcmVzLWRldWRhfQpkZXVkYV9wcmV2aWEgPC0gaW5kaWNhZG9yZXMkZGV1ZGEkcGJfZGVidAppbmRpY2Fkb3JlcyRkZXVkYSRwYl9kZWJ0IDwtIGluZGljYWRvcmVzJGRldWRhJHBiX2RlYnQgKiAxLjIwCgp0YWJsYSgKICBkYXRhLmZyYW1lKAogICAgQ29uY2VwdG8gPSBjKCJEZXVkYSBww7pibGljYSIsICJEZXVkYSBwcml2YWRhIiksCiAgICBBbnRlcyAgICA9IGMoZGV1ZGFfcHJldmlhLCBpbmRpY2Fkb3JlcyRkZXVkYSRwdnRfZGVidCksCiAgICBEZXNwdcOpcyAgPSBjKGluZGljYWRvcmVzJGRldWRhJHBiX2RlYnQsIGluZGljYWRvcmVzJGRldWRhJHB2dF9kZWJ0KQogICksCiAgcm93Lm5hbWVzID0gRkFMU0UsCiAgY2FwdGlvbiAgID0gIkRldWRhIGFudGVzIHkgZGVzcHXDqXMgZGVsIGFqdXN0ZSBkZWwgMjAgJSIKKQpgYGAKCjo6OiB7Lm5vdGF9CkVsIHByb21lZGlvIHNlIGFzaWduYSBhIHVuIG9iamV0byBzZXBhcmFkbyAoYHByb21fZGVzZW1wbGVvYCkuIFNpIHNlIGVzY3JpYmllcmEgYGluZGljYWRvcmVzJGRlc2VtcGxlbyA8LSBtZWFuKC4uLilgLCBsYSBtYXRyaXogb3JpZ2luYWwgcXVlZGFyw61hIHJlZW1wbGF6YWRhIHBvciB1biBlc2NhbGFyIHkgc2UgcGVyZGVyw61hIGxhIGVzdHJ1Y3R1cmEgZGUgbGEgbGlzdGEuCjo6OgoKIyBFamVyY2ljaW8gMyDigJQgTGlzdGFzIGFuaWRhZGFzIHsjZWozfQoKOjo6IHsuZW51bmNpYWRvfQoqKjEuKiogQ3JlYXIgdW5hIGxpc3RhIGBlc3R1ZGlhbnRlc2AgY29uIGxvcyBub21icmVzIChBbmEsIEx1aXMsIFBlZHJvKSwgbGFzIGVkYWRlcyAoMTgsIDE5LCAyMCkgeSBsYXMgbm90YXMgZGUgbWF0ZW3DoXRpY2FzICg4LCA3LCA5KSwgaGlzdG9yaWEgKDYsIDgsIDcpIGUgaW5nbMOpcyAoOSwgMTAsIDgpLgo6OjoKCmBgYHtyIGVzdHVkaWFudGVzLWxpc3RhfQpuYW1lIDwtIGMoIkFuYSIsICJMdWlzIiwgIlBlZHJvIikKYWdlICA8LSBjKDE4LCAxOSwgMjApCgojIE5PVEFTIFBPUiBNQVRFUklBIChTVUJMSVNUQSkKbm90ZXMgPC0gbGlzdCgKICBtYXRlbWF0aWNhcyA9IGMoOCwgNywgOSksCiAgaGlzdG9yaWEgICAgPSBjKDYsIDgsIDcpLAogIGluZ2xlcyAgICAgID0gYyg5LCAxMCwgOCkKKQoKZXN0dWRpYW50ZXMgPC0gbGlzdCgKICBub21icmUgPSBuYW1lLAogIGVkYWQgICA9IGFnZSwKICBub3RhcyAgPSBub3RlcwopCgpzdHIoZXN0dWRpYW50ZXMpCmBgYAoKOjo6IHsuZW51bmNpYWRvfQoqKjIuKiogTW9kaWZpY2FyIGVsIG5vbWJyZSBkZWwgcHJpbWVyIGVzdHVkaWFudGUgcG9yICJFbGVuYSIuCioqMy4qKiBBw7FhZGlyIHVuIHZlY3RvciBjb24gbG9zIGfDqW5lcm9zIGRlIGxvcyBlc3R1ZGlhbnRlcyAoRiwgTSwgTkIpLgoqKjQuKiogQ2FtYmlhciBsYSBub3RhIGRlIGluZ2zDqXMgZGVsIHRlcmNlciBlc3R1ZGlhbnRlIHBvciBudWV2ZSAoOSkuCjo6OgoKYGBge3IgZXN0dWRpYW50ZXMtbW9kaWZpY2FjaW9uZXN9CmVzdHVkaWFudGVzJG5vbWJyZVsxXSAgICAgICAgPC0gIkVsZW5hIgplc3R1ZGlhbnRlcyRnZW5lcm8gICAgICAgICAgIDwtIGMoIkYiLCAiTSIsICJOQiIpCmVzdHVkaWFudGVzJG5vdGFzJGluZ2xlc1szXSAgPC0gOQpgYGAKCmBgYHtyIGVzdHVkaWFudGVzLXRhYmxhfQp0YWJsYSgKICBkYXRhLmZyYW1lKAogICAgTm9tYnJlICAgICAgPSBlc3R1ZGlhbnRlcyRub21icmUsCiAgICBFZGFkICAgICAgICA9IGVzdHVkaWFudGVzJGVkYWQsCiAgICBHw6luZXJvICAgICAgPSBlc3R1ZGlhbnRlcyRnZW5lcm8sCiAgICBNYXRlbcOhdGljYXMgPSBlc3R1ZGlhbnRlcyRub3RhcyRtYXRlbWF0aWNhcywKICAgIEhpc3RvcmlhICAgID0gZXN0dWRpYW50ZXMkbm90YXMkaGlzdG9yaWEsCiAgICBJbmdsw6lzICAgICAgPSBlc3R1ZGlhbnRlcyRub3RhcyRpbmdsZXMKICApLAogIHJvdy5uYW1lcyA9IEZBTFNFLAogIGNhcHRpb24gICA9ICJSZWdpc3RybyBkZSBlc3R1ZGlhbnRlcyB0cmFzIGxhcyBtb2RpZmljYWNpb25lcyIKKQpgYGAKCiMgRWplcmNpY2lvIDQg4oCUIERhdGEgZnJhbWVzIHsjZWo0fQoKOjo6IHsuZW51bmNpYWRvfQoqKjEuKiogQ3JlYXIgdW4gZGF0YSBmcmFtZSBgdmVudGFzX3RpZW5kYWAgZGUgJDVcdGltZXM1JCwgZG9uZGUgbGFzIGZpbGFzIHJlcHJlc2VudGVuIGNpbmNvIHRpZW5kYXMgZGlzdGludGFzIHkgbGFzIGNvbHVtbmFzIGNpbmNvIGTDrWFzLgo6OjoKCmBgYHtyIHZlbnRhcy1kZn0KdmVudGFzX3RpZW5kYSA8LSBkYXRhLmZyYW1lKAogIGRpYV8xID0gYygxMiwgMTAsIDIyLCAxNiwgMzApLAogIGRpYV8yID0gYygxNSwgMTEsIDI0LCAxNywgMzIpLAogIGRpYV8zID0gYygxNCwgMTMsIDIxLCAxOSwgMzEpLAogIGRpYV80ID0gYygxOCwgMTIsIDI1LCAyMCwgMzUpLAogIGRpYV81ID0gYygyMCwgMTUsIDIzLCAxOCwgMzMpLAogIHJvdy5uYW1lcyA9IGMoIlRpZW5kYSBBIiwgIlRpZW5kYSBCIiwgIlRpZW5kYSBDIiwgIlRpZW5kYSBEIiwgIlRpZW5kYSBFIikKKQoKdGFibGEodmVudGFzX3RpZW5kYSwgY2FwdGlvbiA9ICJWZW50YXMgaW5pY2lhbGVzIHBvciB0aWVuZGEgeSBkw61hIikKYGBgCgo6Ojogey5lbnVuY2lhZG99CioqMi4qKiBNb3N0cmFyIGVsIHZhbG9yIHViaWNhZG8gZW4gbGEgZmlsYSAzLCBjb2x1bW5hIDQuCioqMy4qKiBNb3N0cmFyIGxvcyB2YWxvcmVzIGRlIHRvZGFzIGxhcyB0aWVuZGFzIHBhcmEgbG9zIGTDrWFzIGRvcyB5IGNpbmNvLgo6OjoKCmBgYHtyIHZlbnRhcy1jb25zdWx0YXN9CnZlbnRhc190aWVuZGFbMywgNF0KYGBgCgpgYGB7ciB2ZW50YXMtZGlhcy0yLTV9CnRhYmxhKAogIHZlbnRhc190aWVuZGFbLCBjKCJkaWFfMiIsICJkaWFfNSIpXSwKICBjb2wubmFtZXMgPSBjKCJEw61hIDIiLCAiRMOtYSA1IiksCiAgY2FwdGlvbiAgID0gIlZlbnRhcyBkZSBsb3MgZMOtYXMgMiB5IDUiCikKYGBgCgo6Ojogey5lbnVuY2lhZG99CioqNC4qKiBDYW1iaWFyIGxhcyB2ZW50YXMgZGUgbGEgIlRpZW5kYSBCIiBlbiBlbCBgZGlhXzFgIHBvciB1biB2YWxvciBkZSAxNC4KOjo6CgpgYGB7ciB2ZW50YXMtdGllbmRhYi1kaWExfQojIElOREVYQUNJw5NOIFBPUiBOT01CUkUgUEFSQSBFVklUQVIgRVJST1JFUyBERSBQT1NJQ0nDk04KdmVudGFzX3RpZW5kYVsiVGllbmRhIEIiLCAiZGlhXzEiXSA8LSAxNAoKdGFibGEodmVudGFzX3RpZW5kYSwgY2FwdGlvbiA9ICJWZW50YXMgdHJhcyBjb3JyZWdpciBsYSBUaWVuZGEgQiIpCmBgYAoKOjo6IHsuZW51bmNpYWRvfQoqKjUuKiogSW5jcmVtZW50YXIgZW4gdW4gMTUgJSB0b2RvcyBsb3MgdmFsb3JlcyByZWdpc3RyYWRvcyBlbiBsYSBmaWxhIGRlIGxhICJUaWVuZGEgRSIuCioqNi4qKiBSZWVtcGxhemFyIHRvZGEgbGEgY29sdW1uYSBgZGlhXzNgIG11bHRpcGxpY2FuZG8gc3VzIHZhbG9yZXMgcG9yIGRvcy4KOjo6CgpgYGB7ciB2ZW50YXMtdHJhbnNmb3JtYWNpb25lc30KdmVudGFzX3RpZW5kYVsiVGllbmRhIEUiLCBdIDwtIHJvdW5kKHZlbnRhc190aWVuZGFbIlRpZW5kYSBFIiwgXSAqIDEuMTUsIDIpCnZlbnRhc190aWVuZGFbLCAiZGlhXzMiXSAgICA8LSB2ZW50YXNfdGllbmRhWywgImRpYV8zIl0gKiAyCgp0YWJsYSh2ZW50YXNfdGllbmRhLCBjYXB0aW9uID0gIlZlbnRhcyBmaW5hbGVzIHRyYXMgYW1iYXMgdHJhbnNmb3JtYWNpb25lcyIpCmBgYAoKOjo6IHsubm90YX0KRWwgb3JkZW4gZGUgbGFzIG9wZXJhY2lvbmVzIGltcG9ydGE6IGxhIFRpZW5kYSBFIHNlIGFqdXN0YSBwcmltZXJvIGVuIHVuIDE1ICUgeSBsdWVnbyBzdSB2YWxvciBkZSBgZGlhXzNgIHNlIGR1cGxpY2EsIGRlIG1vZG8gcXVlIGVzYSBjZWxkYSBhY3VtdWxhIGFtYmFzIHRyYW5zZm9ybWFjaW9uZXMgKCQxLjE1IFx0aW1lcyAyJCkuCjo6Ogo=