Conociendo dplyr
Vamos a trabajar con los datos de las características físicas de pinguinos que están en el paquete palmerpenguins
. El paquete se puede instalar con install.packages("palmerpenguins")
. Toda la documentación sobre estos datos está acá. El paquete fue desarrollado por Allison Horst, Alison Hill, Kristen Gorman. En particular, Allison Horst es la responsable de los dibujos de los pinguinos y de hacer un gran tutorial de dplyr usando este dataset.
El objetivo de estos ejercicios es familiarizarse con las siguientes funciones de dplyr
:
filter()
: quedarse con las filas que satisfacen ciertas condiciones.
select()
: quedarse o excluir algunas columnas del dataset.
relocate
()`: mover columnas de lugar.
rename
()`: renombrar columnas.
mutate()
: crear una nueva variable (columna) operando con las demás.
group_by()
+ summarize()
: obtener medidas resumen de los datos por grupos.
across()
: aplicar una función a varias columnas.
count()
: contar rápidamente cuántas observaciones hay por grupo.
case_when()
: una forma de hacer “if-else”.
Pueden cargar la librería tidyverse
completa (library(tidyverse)
) pero por ahora sólo vamos a usar funciones del paquete dplyr
.
require(palmerpenguins)
require(dplyr)
1
Usar filter()
para crear un subconjunto de datos que contenga sólo pinguinos de la isla Biscoe y que tengan un pico de 48 mm de largo o más.
2
Crear otro dataset con la información de pinguinos Adelie machos que no hayan sido vistos en el año 2008.
3
Del dataset penguins
quedarse con todas las variables excepto year
, sex
y body_mass_g
.
4
Crear un subconjunto de los datos de penguins
sólo con las obsevaciones de pinguinos machos con aletas de más de 200 mm de largo y quedarse con todas las columnas que terminan con “mm”. (usar la función ends_with()
).
5
Empezando con penguins
, hacer un pipe
(%>%
) que:
- se quede sólo con las observaciones de la isla Dream.
- se quede con las variables
species
y todas las que empiece con bill
.
6
Mover todas las variables factor
después de las columnas integer
. Se puede usar relocate()
junto con is.integer
y is.factor
.
7
Convertir todas las variables que empiezan con bill
a mayúsculas.
penguins %>%
rename_with(____, starts_with("____"))
8
Empezando con penguins
hacer lo siguiente con un único llamado a la función mutate()
:
- Convertir la variable
species
a character
.
- Crear una nueva variable que tenga el peso en Kg.
- Convertir la variable
island
a minúscula.
9
Empezando con penguins
crear una tabla resumen que contenga para el largo mínimo y máximo de las aletas de los pinguinos chinstrap, agrupados por isla.
10
Empezando con penguins
, agrupar los datos por especie y año, luego crear una tabla de resumen que contenga el ancho del pico (llamarla bill_depth_mean
) y el largo del pico (llamarla bill_length_mean
) para cada grupo
penguins %>%
group_by(_____, _____) %>%
summarize(
_________ = mean(______, na.rm = TRUE),
_________ = mean(______, na.rm = TRUE)
)
11
Empezando con penguins
, hacer una secuencia de operaciones %>%
que:
- Agregue una nueva columna llamada
bill_ratio
que sea el cociente entre el largo y el ancho del pico.
- Quedarse sólo con las columnas
species
y bill_ratio
.
- Agrupar los datos por especie.
- Crear una tabla de resumen que contenga el promedio de la variable
bill_ratio
por especie y que el nombre de la columna en la tabla sea bill_ratio_mean
)
penguins %>%
mutate(bill_ratio = ______ / ______) %>%
select(______, ______) %>%
group_by(______) %>%
summarize(______ = mean(______, na.rm = TRUE))
12
Empezando con penguins
, agrupar los datos por isla y después usar across()
para encontrar la mediana de los grupos para todas las columnas que contengan el string “mm”. El nombre de las variables tiene que ser el nombre original seguido de un guión bajo y la palabra “median” (o sea, nombredelacolumna_median
)
penguins %>%
group_by(______) %>%
summarize(across(contains("______"),
median,
na.rm = TRUE,
.names = "_______")
)
13
Empezando con penguins
, quedarse con las observaciones correspondientes a los pinguinos Adelie y luego usar across()
para encontrar el valor máximo de todas las variables numéricas para cada isla.
penguins %>%
filter(species == "______") %>%
group_by(______) %>%
summarize(across(where(_____), _____, na.rm = TRUE))
14
Empezando con penguins
, escribir una secuencia de operaciones %>%
que:
- Excluya a los pinguinos observados en la isla Biscoe.
- Sólo se quede con las variables que están entre
species
y body_mass_g
inclusive.
- Renombrar la variable
species
a especie_pinguino
.
- Agrupar los datos por la variable
especie_pinguino
.
- Encontrar el valor medio de las variables que contienen el string “length”, separando por la especie del pinguino, y llamando a las columnas como las originales pero agregando "_mean" al final.
penguins %>%
filter(island != "_____") %>%
select(_____:_____) %>%
rename(_____ = _____) %>%
group_by(_____) %>%
summarize(across(contains("_____"), mean, na.rm = TRUE, .names = "{.col}_avg"))
15
Empezando con penguins
, contar cuántas observaciones hay por especie, isla y año.
16
Empezando con penguins
, quedarse sólo con los pinguinos Adelie y gentoo penguins. Luego contar cuántos hay por cada especie y sexo.
17
Agregar una nueva columna a la base de datos llamada campaña
que contenga:
- “c1” si el año 2007
- “c2” si el año 2008
- “c3” si el año 2009
18
Empezando con penguins
quedarse sólo con las observaciones correspondientes a pinguinos chinstrap. Luego, quedarse sólo con las variables flipper_length_mm
y body_mass_g
. Agregar una nueva columna llamada fm_ratio
que contenga el cociente entre el largo de la aleta y el peso del pinguino. Luego agregar otra columna llamada ratio_bin
que contenga la palabra “alto” si fm_ratio
es mayor o igual que 0.05, “bajo” si el cociente es menor que 0.05 y “no hay registro” en cualquier otro caso (como por ejemplo si el cociente es un NA)
penguins %>%
filter(species == "_____") %>%
select(_____, _____) %>%
mutate(fm_ratio = _____ / _____) %>%
mutate(ratio_bin = case_when(
fm_ratio >= 0.05 ~ "_____",
fm_ratio < 0.05 ~ "_____",
TRUE ~ "_____"
))
LS0tCnRpdGxlOiAiVHJhbnNmb3JtYW5kbyBkYXRvcyBjb24gZHBseXIiCmF1dGhvcjogIkd1aWxsZXJtbyBTb2xvdmV5IgpkYXRlOiAiOS8yNy8yMDIxIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogICAgdG9jOiB5ZXMKICBodG1sX25vdGVib29rOgogICAgdGhlbWU6IGx1bWVuCiAgICB0b2M6IHllcwogICAgdG9jX2Zsb2F0OiB5ZXMKc3VidGl0bGU6ICJMYWJvcmF0b3JpbyBkZSBEYXRvcyIKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIyBDb25vY2llbmRvIGRwbHlyCgpWYW1vcyBhIHRyYWJhamFyIGNvbiBsb3MgZGF0b3MgZGUgbGFzIGNhcmFjdGVyw61zdGljYXMgZsOtc2ljYXMgZGUgcGluZ3Vpbm9zIHF1ZSBlc3TDoW4gZW4gZWwgCnBhcXVldGUgYHBhbG1lcnBlbmd1aW5zYC4gRWwgcGFxdWV0ZSAgc2UgcHVlZGUgaW5zdGFsYXIgY29uIApgaW5zdGFsbC5wYWNrYWdlcygicGFsbWVycGVuZ3VpbnMiKWAuIFRvZGEgbGEgZG9jdW1lbnRhY2nDs24gc29icmUgZXN0b3MgZGF0b3MgZXN0w6EKW2Fjw6FdKGh0dHBzOi8vYWxsaXNvbmhvcnN0LmdpdGh1Yi5pby9wYWxtZXJwZW5ndWlucy8pLiBFbCBwYXF1ZXRlIGZ1ZSBkZXNhcnJvbGxhZG8gcG9yIApBbGxpc29uIEhvcnN0LCBBbGlzb24gSGlsbCwgS3Jpc3RlbiBHb3JtYW4uIEVuIHBhcnRpY3VsYXIsIEFsbGlzb24gSG9yc3QgZXMgbGEgcmVzcG9uc2FibGUKZGUgbG9zIGRpYnVqb3MgZGUgbG9zIHBpbmd1aW5vcyB5IGRlIGhhY2VyIHVuIGdyYW4gW3R1dG9yaWFsXShodHRwczovL2FsbGlzb25ob3JzdC5zaGlueWFwcHMuaW8vZHBseXItbGVhcm5yLyNzZWN0aW9uLXdlbGNvbWUpIGRlIGRwbHlyIHVzYW5kbyBlc3RlIGRhdGFzZXQuCgpFbCBvYmpldGl2byBkZSBlc3RvcyBlamVyY2ljaW9zIGVzIGZhbWlsaWFyaXphcnNlIGNvbiBsYXMgc2lndWllbnRlcyBmdW5jaW9uZXMgZGUgYGRwbHlyYDoKCiogYGZpbHRlcigpYDogcXVlZGFyc2UgY29uIGxhcyBmaWxhcyBxdWUgc2F0aXNmYWNlbiBjaWVydGFzIGNvbmRpY2lvbmVzLgoqIGBzZWxlY3QoKWA6IHF1ZWRhcnNlIG8gZXhjbHVpciBhbGd1bmFzIGNvbHVtbmFzIGRlbCBkYXRhc2V0LgoqIGByZWxvY2F0ZWAoKWA6IG1vdmVyIGNvbHVtbmFzIGRlIGx1Z2FyLgoqIGByZW5hbWVgKClgOiByZW5vbWJyYXIgY29sdW1uYXMuIAoqIGBtdXRhdGUoKWA6IGNyZWFyIHVuYSBudWV2YSB2YXJpYWJsZSAoY29sdW1uYSkgb3BlcmFuZG8gY29uIGxhcyBkZW3DoXMuCiogYGdyb3VwX2J5KClgICsgYHN1bW1hcml6ZSgpYDogb2J0ZW5lciBtZWRpZGFzIHJlc3VtZW4gZGUgbG9zIGRhdG9zIHBvciBncnVwb3MuCiogYGFjcm9zcygpYDogYXBsaWNhciB1bmEgZnVuY2nDs24gYSB2YXJpYXMgY29sdW1uYXMuCiogYGNvdW50KClgOiBjb250YXIgcsOhcGlkYW1lbnRlIGN1w6FudGFzIG9ic2VydmFjaW9uZXMgaGF5IHBvciBncnVwby4KKiBgY2FzZV93aGVuKClgOiB1bmEgZm9ybWEgZGUgaGFjZXIgImlmLWVsc2UiLgogCgpQdWVkZW4gY2FyZ2FyIGxhIGxpYnJlcsOtYSBgdGlkeXZlcnNlYCBjb21wbGV0YSAoYGxpYnJhcnkodGlkeXZlcnNlKWApIHBlcm8gcG9yIGFob3JhIHPDs2xvIAp2YW1vcyBhIHVzYXIgZnVuY2lvbmVzIGRlbCBwYXF1ZXRlIGBkcGx5cmAuCgpgYGB7ciBtZXNzYWdlPUZBTFNFfQpyZXF1aXJlKHBhbG1lcnBlbmd1aW5zKQpyZXF1aXJlKGRwbHlyKQpgYGAKCgojIyMjIyAxClVzYXIgYGZpbHRlcigpYCBwYXJhIGNyZWFyIHVuIHN1YmNvbmp1bnRvIGRlIGRhdG9zIHF1ZSBjb250ZW5nYSBzw7NsbyBwaW5ndWlub3MKZGUgbGEgaXNsYSBCaXNjb2UgeSBxdWUgdGVuZ2FuIHVuIHBpY28gZGUgNDggbW0gZGUgbGFyZ28gbyBtw6FzLgoKIyMjIyMgMgpDcmVhciBvdHJvIGRhdGFzZXQgY29uIGxhIGluZm9ybWFjacOzbiBkZSBwaW5ndWlub3MgQWRlbGllIG1hY2hvcyBxdWUgbm8gaGF5YW4Kc2lkbyB2aXN0b3MgZW4gZWwgYcOxbyAyMDA4LgoKIyMjIyMgMwpEZWwgZGF0YXNldCBgcGVuZ3VpbnNgIHF1ZWRhcnNlIGNvbiB0b2RhcyBsYXMgdmFyaWFibGVzIGV4Y2VwdG8gYHllYXJgLCBgc2V4YCB5IApgYm9keV9tYXNzX2dgLiAKCiMjIyMjIDQKQ3JlYXIgdW4gc3ViY29uanVudG8gZGUgbG9zIGRhdG9zIGRlIGBwZW5ndWluc2Agc8OzbG8gY29uIGxhcyBvYnNldmFjaW9uZXMgZGUgCnBpbmd1aW5vcyBtYWNob3MgY29uIGFsZXRhcyBkZSBtw6FzIGRlIDIwMCBtbSBkZSBsYXJnbyB5IHF1ZWRhcnNlIGNvbiB0b2RhcyBsYXMKY29sdW1uYXMgcXVlIHRlcm1pbmFuIGNvbiAibW0iLiAodXNhciBsYSBmdW5jacOzbiBgZW5kc193aXRoKClgKS4KCiMjIyMjIDUKRW1wZXphbmRvIGNvbiBgcGVuZ3VpbnNgLCBoYWNlciB1biBgcGlwZWAgKGAlPiVgKSBxdWU6CgoqIHNlIHF1ZWRlIHPDs2xvIGNvbiBsYXMgb2JzZXJ2YWNpb25lcyBkZSBsYSBpc2xhIERyZWFtLgoqIHNlIHF1ZWRlIGNvbiBsYXMgdmFyaWFibGVzIGBzcGVjaWVzYCB5IHRvZGFzIGxhcyBxdWUgZW1waWVjZSBjb24gYGJpbGxgLiAKCiMjIyMjIDYKTW92ZXIgdG9kYXMgbGFzIHZhcmlhYmxlcyBgZmFjdG9yYCBkZXNwdcOpcyBkZSBsYXMgY29sdW1uYXMgYGludGVnZXJgLgpTZSBwdWVkZSB1c2FyIGByZWxvY2F0ZSgpYCBqdW50byBjb24gYGlzLmludGVnZXJgIHkgYGlzLmZhY3RvcmAuCgojIyMjIyA3CkNvbnZlcnRpciB0b2RhcyBsYXMgdmFyaWFibGVzIHF1ZSBlbXBpZXphbiBjb24gYGJpbGxgIGEgbWF5w7pzY3VsYXMuCmBgYHtyIGV2YWw9RkFMU0V9CnBlbmd1aW5zICU+JQogIHJlbmFtZV93aXRoKF9fX18sIHN0YXJ0c193aXRoKCJfX19fIikpCmBgYAoKIyMjIyMgOApFbXBlemFuZG8gY29uIGBwZW5ndWluc2AgaGFjZXIgbG8gc2lndWllbnRlIGNvbiB1biDDum5pY28gbGxhbWFkbyBhIGxhIGZ1bmNpw7NuCmBtdXRhdGUoKWA6CgoqIENvbnZlcnRpciBsYSB2YXJpYWJsZSBgc3BlY2llc2AgYSBgY2hhcmFjdGVyYC4KKiBDcmVhciB1bmEgbnVldmEgdmFyaWFibGUgcXVlIHRlbmdhIGVsIHBlc28gZW4gS2cuCiogQ29udmVydGlyIGxhIHZhcmlhYmxlIGBpc2xhbmRgIGEgbWluw7pzY3VsYS4KCiMjIyMjIDkKRW1wZXphbmRvIGNvbiBgcGVuZ3VpbnNgIGNyZWFyIHVuYSB0YWJsYSByZXN1bWVuIHF1ZSBjb250ZW5nYSBwYXJhIGVsIApsYXJnbyBtw61uaW1vIHkgbcOheGltbyBkZSBsYXMgYWxldGFzIGRlIGxvcyBwaW5ndWlub3MgY2hpbnN0cmFwLCBhZ3J1cGFkb3MKcG9yIGlzbGEuIAoKIyMjIyMgMTAKRW1wZXphbmRvIGNvbiBgcGVuZ3VpbnNgLCBhZ3J1cGFyIGxvcyBkYXRvcyBwb3IgZXNwZWNpZSB5IGHDsW8sIGx1ZWdvIGNyZWFyIHVuYSB0YWJsYSAKZGUgcmVzdW1lbiBxdWUgY29udGVuZ2EgZWwgYW5jaG8gZGVsIHBpY28gKGxsYW1hcmxhIGBiaWxsX2RlcHRoX21lYW5gKSB5IGVsIGxhcmdvIApkZWwgcGljbyAobGxhbWFybGEgYGJpbGxfbGVuZ3RoX21lYW5gKSBwYXJhIGNhZGEgZ3J1cG8KCmBgYHtyLCBldmFsPUZBTFNFfQpwZW5ndWlucyAlPiUKICBncm91cF9ieShfX19fXywgX19fX18pICU+JQogIHN1bW1hcml6ZSgKICAgIF9fX19fX19fXyA9IG1lYW4oX19fX19fLCBuYS5ybSA9IFRSVUUpLAogICAgX19fX19fX19fID0gbWVhbihfX19fX18sIG5hLnJtID0gVFJVRSkKICApCmBgYAoKCiMjIyMjIDExCkVtcGV6YW5kbyBjb24gYHBlbmd1aW5zYCwgaGFjZXIgdW5hIHNlY3VlbmNpYSBkZSBvcGVyYWNpb25lcyBgICU+JWAgcXVlOgoKKiBBZ3JlZ3VlIHVuYSBudWV2YSBjb2x1bW5hIGxsYW1hZGEgYGJpbGxfcmF0aW9gIHF1ZSBzZWEgZWwgY29jaWVudGUgZW50cmUgZWwgbGFyZ28geSBlbCAKYW5jaG8gZGVsIHBpY28uCiogUXVlZGFyc2Ugc8OzbG8gY29uIGxhcyBjb2x1bW5hcyBgc3BlY2llc2AgeSBgYmlsbF9yYXRpb2AuCiogQWdydXBhciBsb3MgZGF0b3MgcG9yIGVzcGVjaWUuCiogQ3JlYXIgdW5hIHRhYmxhIGRlIHJlc3VtZW4gcXVlIGNvbnRlbmdhIGVsIHByb21lZGlvIGRlIGxhIHZhcmlhYmxlIGBiaWxsX3JhdGlvYCBwb3IgZXNwZWNpZQp5IHF1ZSBlbCBub21icmUgZGUgbGEgY29sdW1uYSBlbiBsYSB0YWJsYSBzZWEgYGJpbGxfcmF0aW9fbWVhbmApCgpgYGB7ciwgZXZhbD1GQUxTRX0KcGVuZ3VpbnMgJT4lCiAgbXV0YXRlKGJpbGxfcmF0aW8gPSBfX19fX18gLyBfX19fX18pICU+JQogIHNlbGVjdChfX19fX18sIF9fX19fXykgJT4lCiAgZ3JvdXBfYnkoX19fX19fKSAlPiUKICBzdW1tYXJpemUoX19fX19fID0gbWVhbihfX19fX18sIG5hLnJtID0gVFJVRSkpCmBgYAoKCiMjIyMjIDEyCkVtcGV6YW5kbyBjb24gYHBlbmd1aW5zYCwgYWdydXBhciBsb3MgZGF0b3MgcG9yIGlzbGEgeSBkZXNwdcOpcyB1c2FyIGBhY3Jvc3MoKWAgcGFyYSBlbmNvbnRyYXIKbGEgbWVkaWFuYSBkZSBsb3MgZ3J1cG9zIHBhcmEgdG9kYXMgbGFzIGNvbHVtbmFzIHF1ZSBjb250ZW5nYW4gZWwgc3RyaW5nICJtbSIuIEVsIG5vbWJyZSAKZGUgbGFzIHZhcmlhYmxlcyB0aWVuZSBxdWUgc2VyIGVsIG5vbWJyZSBvcmlnaW5hbCBzZWd1aWRvIGRlIHVuIGd1acOzbiBiYWpvIHkgbGEgcGFsYWJyYSAKIm1lZGlhbiIgKG8gc2VhLCBgbm9tYnJlZGVsYWNvbHVtbmFfbWVkaWFuYCkKYGBge3IsIGV2YWw9RkFMU0V9CnBlbmd1aW5zICU+JQogIGdyb3VwX2J5KF9fX19fXykgJT4lCiAgc3VtbWFyaXplKGFjcm9zcyhjb250YWlucygiX19fX19fIiksCiAgICAgICAgICAgICAgICAgICBtZWRpYW4sCiAgICAgICAgICAgICAgICAgICBuYS5ybSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAubmFtZXMgPSAiX19fX19fXyIpCiAgICAgICAgICAgICkKYGBgCgoKIyMjIyMgMTMKRW1wZXphbmRvIGNvbiBgcGVuZ3VpbnNgLCBxdWVkYXJzZSBjb24gbGFzIG9ic2VydmFjaW9uZXMgY29ycmVzcG9uZGllbnRlcyBhIGxvcyBwaW5ndWlub3MKQWRlbGllIHkgbHVlZ28gdXNhciBgYWNyb3NzKClgIHBhcmEgZW5jb250cmFyIGVsIHZhbG9yIG3DoXhpbW8gZGUgdG9kYXMgbGFzIHZhcmlhYmxlcyAKbnVtw6lyaWNhcyBwYXJhIGNhZGEgaXNsYS4KYGBge3IsIGV2YWw9RkFMU0V9CnBlbmd1aW5zICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJfX19fX18iKSAlPiUKICBncm91cF9ieShfX19fX18pICU+JQogIHN1bW1hcml6ZShhY3Jvc3Mod2hlcmUoX19fX18pLCBfX19fXywgbmEucm0gPSBUUlVFKSkKYGBgCgoKIyMjIyMgMTQKRW1wZXphbmRvIGNvbiBgcGVuZ3VpbnNgLCBlc2NyaWJpciB1bmEgc2VjdWVuY2lhIGRlIG9wZXJhY2lvbmVzIGAgJT4lIGAgcXVlOgoKKiBFeGNsdXlhIGEgbG9zIHBpbmd1aW5vcyBvYnNlcnZhZG9zIGVuIGxhIGlzbGEgQmlzY29lLgoqIFPDs2xvIHNlIHF1ZWRlIGNvbiBsYXMgdmFyaWFibGVzIHF1ZSBlc3TDoW4gZW50cmUgYHNwZWNpZXNgIHkgYGJvZHlfbWFzc19nYCBpbmNsdXNpdmUuCiogUmVub21icmFyIGxhIHZhcmlhYmxlIGBzcGVjaWVzYCBhIGBlc3BlY2llX3Bpbmd1aW5vYC4KKiBBZ3J1cGFyIGxvcyBkYXRvcyBwb3IgbGEgdmFyaWFibGUgYGVzcGVjaWVfcGluZ3Vpbm9gLgoqIEVuY29udHJhciBlbCB2YWxvciBtZWRpbyBkZSBsYXMgdmFyaWFibGVzIHF1ZSBjb250aWVuZW4gZWwgc3RyaW5nIOKAnGxlbmd0aOKAnSwgCnNlcGFyYW5kbyBwb3IgbGEgZXNwZWNpZSBkZWwgcGluZ3Vpbm8sIHkgbGxhbWFuZG8gYSBsYXMgY29sdW1uYXMgY29tbyBsYXMgb3JpZ2luYWxlcwpwZXJvIGFncmVnYW5kbyAiX21lYW4iIGFsIGZpbmFsLgoKYGBge3IsIGV2YWw9RkFMU0V9CnBlbmd1aW5zICU+JQogIGZpbHRlcihpc2xhbmQgIT0gIl9fX19fIikgJT4lCiAgc2VsZWN0KF9fX19fOl9fX19fKSAlPiUKICByZW5hbWUoX19fX18gPSBfX19fXykgJT4lCiAgZ3JvdXBfYnkoX19fX18pICU+JQogIHN1bW1hcml6ZShhY3Jvc3MoY29udGFpbnMoIl9fX19fIiksIG1lYW4sIG5hLnJtID0gVFJVRSwgLm5hbWVzID0gInsuY29sfV9hdmciKSkKYGBgCgoKIyMjIyMgMTUKRW1wZXphbmRvIGNvbiBgcGVuZ3VpbnNgLCBjb250YXIgY3XDoW50YXMgb2JzZXJ2YWNpb25lcyBoYXkgcG9yIGVzcGVjaWUsIGlzbGEgeSBhw7FvLgoKIyMjIyMgMTYKRW1wZXphbmRvIGNvbiBgcGVuZ3VpbnNgLCBxdWVkYXJzZSBzw7NsbyBjb24gbG9zIHBpbmd1aW5vcyBBZGVsaWUgeSBnZW50b28gcGVuZ3VpbnMuIEx1ZWdvCmNvbnRhciBjdcOhbnRvcyBoYXkgcG9yIGNhZGEgZXNwZWNpZSB5IHNleG8uCgojIyMjIyAxNwpBZ3JlZ2FyIHVuYSBudWV2YSBjb2x1bW5hIGEgbGEgYmFzZSBkZSBkYXRvcyBsbGFtYWRhIGBjYW1wYcOxYWAgcXVlIGNvbnRlbmdhOgoKKiDigJxjMeKAnSBzaSBlbCBhw7FvIDIwMDcKKiDigJxjMuKAnSBzaSBlbCBhw7FvIDIwMDgKKiDigJxjM+KAnSBzaSBlbCBhw7FvIDIwMDkKCiMjIyMjIDE4CkVtcGV6YW5kbyBjb24gYHBlbmd1aW5zYCBxdWVkYXJzZSBzw7NsbyBjb24gbGFzIG9ic2VydmFjaW9uZXMgY29ycmVzcG9uZGllbnRlcyBhIHBpbmd1aW5vcwpjaGluc3RyYXAuIEx1ZWdvLCBxdWVkYXJzZSBzw7NsbyBjb24gbGFzIHZhcmlhYmxlcyBgZmxpcHBlcl9sZW5ndGhfbW1gIHkgYGJvZHlfbWFzc19nYC4gCkFncmVnYXIgdW5hIG51ZXZhIGNvbHVtbmEgbGxhbWFkYSBgZm1fcmF0aW9gIHF1ZSBjb250ZW5nYSBlbCBjb2NpZW50ZSBlbnRyZSBlbCBsYXJnbyBkZSBsYSAKYWxldGEgeSBlbCBwZXNvIGRlbCBwaW5ndWluby4gTHVlZ28gYWdyZWdhciBvdHJhIGNvbHVtbmEgbGxhbWFkYSBgcmF0aW9fYmluYCBxdWUgY29udGVuZ2EKbGEgcGFsYWJyYSAiYWx0byIgc2kgYGZtX3JhdGlvYCBlcyBtYXlvciBvIGlndWFsIHF1ZSAwLjA1LCAiYmFqbyIgc2kgZWwgY29jaWVudGUgZXMgbWVub3IKcXVlIDAuMDUgeSAibm8gaGF5IHJlZ2lzdHJvIiBlbiBjdWFscXVpZXIgb3RybyBjYXNvIChjb21vIHBvciBlamVtcGxvIHNpIGVsIGNvY2llbnRlIGVzCnVuIE5BKQoKYGBge3IsIGV2YWw9RkFMU0V9CnBlbmd1aW5zICU+JQogIGZpbHRlcihzcGVjaWVzID09ICJfX19fXyIpICU+JQogIHNlbGVjdChfX19fXywgX19fX18pICU+JQogIG11dGF0ZShmbV9yYXRpbyA9IF9fX19fIC8gX19fX18pICU+JQogIG11dGF0ZShyYXRpb19iaW4gPSBjYXNlX3doZW4oCiAgICBmbV9yYXRpbyA+PSAwLjA1IH4gIl9fX19fIiwKICAgIGZtX3JhdGlvIDwgMC4wNSB+ICJfX19fXyIsCiAgICBUUlVFIH4gIl9fX19fIgogICkpCmBgYAoK