Contexto

El paquete nycflights13 contine información sobre todos los vuelos que partieron desde Nueva York (EWR, JFK Y LGA) a destinos en los Estados Unidos en 2013. Fueron 336776 vuelos en total. Para ayudar a comprender las causas de los retrasos, también incluye otros conjuntos de datos útiles.

Este paquete incluye las siguientes tablas:

  • flights = todos los vuelos que salieron de Nueva York en 2013
  • weather = datos meteorológicos por hora de cada aeropuerto
  • planes = informacion de construcción de cada avión
  • airports = nombres y ubicaciones de aeropuertos
  • airlines = relacion entre nombres y códigos de las aerolinea

Fuente:
Origen de los Datos

Instalar paquetes y llamar librerías

# install.packages("nycflights13")
library(nycflights13)
# install.packages("tidyverse")
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.3     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.0
## ✔ ggplot2   3.4.3     ✔ tibble    3.2.1
## ✔ lubridate 1.9.2     ✔ tidyr     1.3.0
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Guardar bases de datos

flights <- flights
weather <- weather
planes <- planes
airports <- airports
airlines <- airlines

Relacion entre las bases de datos

Funciones Básicas de Manejo de Datos

Select

La función select sirve para selecciones columnas de una tabla (data frame).

df1 <- flights %>% select(carrier, flight) # Selección de columnas específicas
df2 <- flights %>% select(carrier:distance) # Selección de rango de columnas
df3 <- flights %>% select(-carrier, -flight) # Eliminar columnas específicas
df4 <- flights %>% select(-carrier, -distance) # Eliminar rango de columnas
df5 <- flights %>% select(aerolinea = carrier) # Sirve para seleccionar una columna y cambiar de nombre
df6 <- flights %>% rename(Aerolinea = carrier) # Misma base de datos, sólo se cambia de nombre a una columna.

Filter

La función Filter sirve para seleccionar renglones de una tabla (data frame).

df7 <- flights %>% filter(dep_delay >=500) #Extrae renglones que cumplan condición
# Condicionales: Igual ==, Desigual =!=, Mayor que >, Mayor o igual que >=, Menor que <, Menor o igual que <=
# Operadores Lógicos: AND &, OR |, NOT !
df8 <- flights %>% filter(dep_delay >=500, dep_delay <600) # Extraer renglones que cumplan con dos condiciones 
df9 <- flights %>% slice(1000:1099) # Extrae los números de los renglones indicados, sin importar sus valores

Distinct

La función distinct sirve para elimianr renglones duplicados.

df10 <- distinct(flights) # Dejar sólo los renglones diferentes, borra todos los repetidos. 

Marge

La función merge sirve para juntar bases de datos.

bdgrande <- merge(flights, airlines, by="carrier")
bdgrande2 <- merge(bdgrande,planes, by="tailnum")

Mutate

bdgrande3 <- mutate(bdgrande2, dist_km = distance*1.609) # Agrega variables nuevas calculadas a partir de variables existentes en la base de datos

Ejercicios

  1. Encuentra todos los vuelos que tuvieron un atraso en llegada de dos horas o más.```
ejercicio1 <- bdgrande2 %>% filter(arr_delay>= 120)
  1. Encuentra todos los vuelos que llegaron a Houston (IAH o HOU)
ejercicio2 <- bdgrande2 %>% filter(dest == "IAH" | dest == "HOU")
  1. Encuentra todos los vuelos operados por United, American o Delta
ejercicio3 <- bdgrande2 %>% filter(carrier %in% c("UA","AA","DL"))

Ejercicio 4. Encuentra todos los vuelos que despegaron en Julio, Agosto o Septiembre.

ejercicio4 <- bdgrande2 %>% filter(month %in% c(7:9))

Ejercicio 5. Encuentra todos los vuelos que arrivaron más de 2 horas tarde, pero no despegaron tarde.

ejercicio5 <- bdgrande2 %>% filter(arr_delay>120 & dep_delay<=0) 

Ejercicio 6. Encuentra todos los vuelos que se retrasaron al menos 1 hora, pero que llegaron antes 30 minutos o más.

ejercicio6 <- bdgrande2 %>% filter(dep_delay>=60 & arr_delay<=-30)

Ejercicio 7. Encuentra todos los vuelos que salieron entre la medianoche y las 6 a.m.

ejercicio7 <- bdgrande2 %>% filter(dep_time==2400 | dep_time<=600 )

Arrange

similar a filter() pero en lugar de seleccionar renglones, los ordena de menor a mayor.

df11 <- arrange(bdgrande2,year.x,month,day)

Para acomodar de mayor a menor.

df12 <- arrange(bdgrande2,year.x,desc(month),day)

Summarize

Colapsa una tabla a un sólo renglón.

# Obten el retraso promedio de despegue de todos los vuelos
summarize(bdgrande2, mean(dep_delay, na.rm=TRUE))
##   mean(dep_delay, na.rm = TRUE)
## 1                      13.17979
# Si en una tabla tenemos espacios sin información, no podemos calcular summarize, por eso hay que poner TRUE en los n.a.

Group by

Agrupa tabla basado en algunas columnas.

# Obtener el retrado promedio de despegue por dia
por_dia <- group_by(bdgrande2,year.x,month,day)
summarize(por_dia, mean(dep_delay,na.rm=TRUE))
## `summarise()` has grouped output by 'year.x', 'month'. You can override using
## the `.groups` argument.
## # A tibble: 365 × 4
## # Groups:   year.x, month [12]
##    year.x month   day `mean(dep_delay, na.rm = TRUE)`
##     <int> <int> <int>                           <dbl>
##  1   2013     1     1                           10.7 
##  2   2013     1     2                           14.4 
##  3   2013     1     3                           11.1 
##  4   2013     1     4                           10.0 
##  5   2013     1     5                            5.70
##  6   2013     1     6                            7.98
##  7   2013     1     7                            6.49
##  8   2013     1     8                            3.10
##  9   2013     1     9                            3.17
## 10   2013     1    10                            1.89
## # ℹ 355 more rows

Interrogante: Por qué llegan tarde los vuelos?

Podemos hacer ejercicios de resumenes para ver dónde está el error

LS0tDQp0aXRsZTogIkRhdGEgV3JhbmdsaW5nIChQYXJ0ZSAxKSINCmF1dGhvcjogIkZhYmlhbmEgTWVkaW5hY2VsbGkgQTAwODM1ODYiDQpkYXRlOiAiMjAyNC0wMi0xOSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHRydWUNCiAgICB0b2NfZmxvYXQ6IHRydWUNCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlDQogICAgdGhlbWU6ICJjb3NtbyINCiAgICBoaWdobGlnaHQ6ICJlc3ByZXNzbyIgICAgDQotLS0NCiFbXShDOlxcVXNlcnNcXEhQXFxEZXNrdG9wXFx2aXNpb24gYm9hcmRcXGJiZjUxNDRiMWU0MzIyYjVhNDcyNzNiYTE4YTVmNWVmLmpwZykNCg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkNvbnRleHRvPC9zcGFuPg0KDQpFbCBwYXF1ZXRlICoqbnljZmxpZ2h0czEzKiogY29udGluZSBpbmZvcm1hY2nDs24gc29icmUgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgcGFydGllcm9uIGRlc2RlIE51ZXZhIFlvcmsgKEVXUiwgSkZLIFkgTEdBKSBhIGRlc3Rpbm9zIGVuIGxvcyBFc3RhZG9zIFVuaWRvcyBlbiAyMDEzLiBGdWVyb24gMzM2Nzc2IHZ1ZWxvcyBlbiB0b3RhbC4gUGFyYSBheXVkYXIgYSBjb21wcmVuZGVyIGxhcyBjYXVzYXMgZGUgbG9zIHJldHJhc29zLCB0YW1iacOpbiBpbmNsdXllIG90cm9zIGNvbmp1bnRvcyBkZSBkYXRvcyDDunRpbGVzLiAgDQoNCkVzdGUgcGFxdWV0ZSBpbmNsdXllIGxhcyBzaWd1aWVudGVzIHRhYmxhczoNCg0KKyBmbGlnaHRzID0gdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgc2FsaWVyb24gZGUgTnVldmEgWW9yayBlbiAyMDEzICAgDQorIHdlYXRoZXIgPSBkYXRvcyBtZXRlb3JvbMOzZ2ljb3MgcG9yIGhvcmEgZGUgY2FkYSBhZXJvcHVlcnRvICAgIA0KKyBwbGFuZXMgPSBpbmZvcm1hY2lvbiBkZSBjb25zdHJ1Y2Npw7NuIGRlIGNhZGEgYXZpw7NuICANCisgYWlycG9ydHMgPSBub21icmVzIHkgdWJpY2FjaW9uZXMgZGUgYWVyb3B1ZXJ0b3MgIA0KKyBhaXJsaW5lcyA9IHJlbGFjaW9uIGVudHJlIG5vbWJyZXMgeSBjw7NkaWdvcyBkZSBsYXMgYWVyb2xpbmVhICANCg0KRnVlbnRlOiAgDQpbT3JpZ2VuIGRlIGxvcyBEYXRvc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL255Y2ZsaWdodHMxMy9ueWNmbGlnaHRzMTMucGRmKSAgDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+SW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hczwvc3Bhbj4NCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJueWNmbGlnaHRzMTMiKQ0KbGlicmFyeShueWNmbGlnaHRzMTMpDQojIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogc2t5IGJsdWU7Ij5HdWFyZGFyIGJhc2VzIGRlIGRhdG9zPC9zcGFuPg0KYGBge3J9DQpmbGlnaHRzIDwtIGZsaWdodHMNCndlYXRoZXIgPC0gd2VhdGhlcg0KcGxhbmVzIDwtIHBsYW5lcw0KYWlycG9ydHMgPC0gYWlycG9ydHMNCmFpcmxpbmVzIDwtIGFpcmxpbmVzDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+UmVsYWNpb24gZW50cmUgbGFzIGJhc2VzIGRlIGRhdG9zPC9zcGFuPg0KIVtdKEM6XFxVc2Vyc1xcSFBcXERvd25sb2Fkc1xccmVsYXRpb25hbC1ueWNmbGlnaHRzLnBuZykNCg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogc2t5IGJsdWU7Ij5GdW5jaW9uZXMgQsOhc2ljYXMgZGUgTWFuZWpvIGRlIERhdG9zPC9zcGFuPg0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPlNlbGVjdDwvc3Bhbj4NCkxhIGZ1bmNpw7NuICpzZWxlY3QqIHNpcnZlIHBhcmEgc2VsZWNjaW9uZXMgY29sdW1uYXMgZGUgdW5hIHRhYmxhICgqZGF0YSBmcmFtZSopLg0KYGBge3J9DQpkZjEgPC0gZmxpZ2h0cyAlPiUgc2VsZWN0KGNhcnJpZXIsIGZsaWdodCkgIyBTZWxlY2Npw7NuIGRlIGNvbHVtbmFzIGVzcGVjw61maWNhcw0KZGYyIDwtIGZsaWdodHMgJT4lIHNlbGVjdChjYXJyaWVyOmRpc3RhbmNlKSAjIFNlbGVjY2nDs24gZGUgcmFuZ28gZGUgY29sdW1uYXMNCmRmMyA8LSBmbGlnaHRzICU+JSBzZWxlY3QoLWNhcnJpZXIsIC1mbGlnaHQpICMgRWxpbWluYXIgY29sdW1uYXMgZXNwZWPDrWZpY2FzDQpkZjQgPC0gZmxpZ2h0cyAlPiUgc2VsZWN0KC1jYXJyaWVyLCAtZGlzdGFuY2UpICMgRWxpbWluYXIgcmFuZ28gZGUgY29sdW1uYXMNCmRmNSA8LSBmbGlnaHRzICU+JSBzZWxlY3QoYWVyb2xpbmVhID0gY2FycmllcikgIyBTaXJ2ZSBwYXJhIHNlbGVjY2lvbmFyIHVuYSBjb2x1bW5hIHkgY2FtYmlhciBkZSBub21icmUNCmRmNiA8LSBmbGlnaHRzICU+JSByZW5hbWUoQWVyb2xpbmVhID0gY2FycmllcikgIyBNaXNtYSBiYXNlIGRlIGRhdG9zLCBzw7NsbyBzZSBjYW1iaWEgZGUgbm9tYnJlIGEgdW5hIGNvbHVtbmEuDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+RmlsdGVyPC9zcGFuPg0KTGEgZnVuY2nDs24gKkZpbHRlciogc2lydmUgcGFyYSBzZWxlY2Npb25hciByZW5nbG9uZXMgZGUgdW5hIHRhYmxhICgqZGF0YSBmcmFtZSopLg0KYGBge3J9DQpkZjcgPC0gZmxpZ2h0cyAlPiUgZmlsdGVyKGRlcF9kZWxheSA+PTUwMCkgI0V4dHJhZSByZW5nbG9uZXMgcXVlIGN1bXBsYW4gY29uZGljacOzbg0KIyBDb25kaWNpb25hbGVzOiBJZ3VhbCA9PSwgRGVzaWd1YWwgPSE9LCBNYXlvciBxdWUgPiwgTWF5b3IgbyBpZ3VhbCBxdWUgPj0sIE1lbm9yIHF1ZSA8LCBNZW5vciBvIGlndWFsIHF1ZSA8PQ0KIyBPcGVyYWRvcmVzIEzDs2dpY29zOiBBTkQgJiwgT1IgfCwgTk9UICENCmRmOCA8LSBmbGlnaHRzICU+JSBmaWx0ZXIoZGVwX2RlbGF5ID49NTAwLCBkZXBfZGVsYXkgPDYwMCkgIyBFeHRyYWVyIHJlbmdsb25lcyBxdWUgY3VtcGxhbiBjb24gZG9zIGNvbmRpY2lvbmVzIA0KZGY5IDwtIGZsaWdodHMgJT4lIHNsaWNlKDEwMDA6MTA5OSkgIyBFeHRyYWUgbG9zIG7Dum1lcm9zIGRlIGxvcyByZW5nbG9uZXMgaW5kaWNhZG9zLCBzaW4gaW1wb3J0YXIgc3VzIHZhbG9yZXMNCmBgYA0KDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+RGlzdGluY3Q8L3NwYW4+DQpMYSBmdW5jacOzbiAqZGlzdGluY3QqIHNpcnZlIHBhcmEgZWxpbWlhbnIgcmVuZ2xvbmVzIGR1cGxpY2Fkb3MuDQpgYGB7cn0NCmRmMTAgPC0gZGlzdGluY3QoZmxpZ2h0cykgIyBEZWphciBzw7NsbyBsb3MgcmVuZ2xvbmVzIGRpZmVyZW50ZXMsIGJvcnJhIHRvZG9zIGxvcyByZXBldGlkb3MuIA0KYGBgDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+TWFyZ2U8L3NwYW4+DQpMYSBmdW5jacOzbiAqbWVyZ2UqIHNpcnZlIHBhcmEganVudGFyIGJhc2VzIGRlIGRhdG9zLg0KYGBge3J9DQpiZGdyYW5kZSA8LSBtZXJnZShmbGlnaHRzLCBhaXJsaW5lcywgYnk9ImNhcnJpZXIiKQ0KYmRncmFuZGUyIDwtIG1lcmdlKGJkZ3JhbmRlLHBsYW5lcywgYnk9InRhaWxudW0iKQ0KYGBgDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5NdXRhdGU8L3NwYW4+DQpgYGB7cn0NCmJkZ3JhbmRlMyA8LSBtdXRhdGUoYmRncmFuZGUyLCBkaXN0X2ttID0gZGlzdGFuY2UqMS42MDkpICMgQWdyZWdhIHZhcmlhYmxlcyBudWV2YXMgY2FsY3VsYWRhcyBhIHBhcnRpciBkZSB2YXJpYWJsZXMgZXhpc3RlbnRlcyBlbiBsYSBiYXNlIGRlIGRhdG9zDQpgYGANCg0KIyMjIEVqZXJjaWNpb3MNCjEuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSB0dXZpZXJvbiB1biBhdHJhc28gZW4gbGxlZ2FkYSBkZSBkb3MgaG9yYXMgbyBtw6FzLmBgYA0KYGBge3J9DQplamVyY2ljaW8xIDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGFycl9kZWxheT49IDEyMCkNCmBgYA0KMi4gRW5jdWVudHJhIHRvZG9zIGxvcyB2dWVsb3MgcXVlIGxsZWdhcm9uIGEgSG91c3RvbiAoSUFIIG8gSE9VKQ0KYGBge3J9DQplamVyY2ljaW8yIDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGRlc3QgPT0gIklBSCIgfCBkZXN0ID09ICJIT1UiKQ0KYGBgDQoNCjMuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIG9wZXJhZG9zIHBvciBVbml0ZWQsIEFtZXJpY2FuIG8gRGVsdGENCmBgYHtyfQ0KZWplcmNpY2lvMyA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihjYXJyaWVyICVpbiUgYygiVUEiLCJBQSIsIkRMIikpDQpgYGANCkVqZXJjaWNpbyA0LiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgZGVzcGVnYXJvbiBlbiBKdWxpbywgQWdvc3RvIG8gU2VwdGllbWJyZS4NCmBgYHtyfQ0KZWplcmNpY2lvNCA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihtb250aCAlaW4lIGMoNzo5KSkNCmBgYA0KRWplcmNpY2lvIDUuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBhcnJpdmFyb24gbcOhcyBkZSAyIGhvcmFzIHRhcmRlLCBwZXJvIG5vIGRlc3BlZ2Fyb24gdGFyZGUuDQpgYGB7cn0NCmVqZXJjaWNpbzUgPC0gYmRncmFuZGUyICU+JSBmaWx0ZXIoYXJyX2RlbGF5PjEyMCAmIGRlcF9kZWxheTw9MCkgDQpgYGANCkVqZXJjaWNpbyA2LiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgc2UgcmV0cmFzYXJvbiBhbCBtZW5vcyAxIGhvcmEsIHBlcm8gcXVlIGxsZWdhcm9uIGFudGVzIDMwIG1pbnV0b3MgbyBtw6FzLg0KYGBge3J9DQplamVyY2ljaW82IDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGRlcF9kZWxheT49NjAgJiBhcnJfZGVsYXk8PS0zMCkNCmBgYA0KRWplcmNpY2lvIDcuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzYWxpZXJvbiBlbnRyZSBsYSBtZWRpYW5vY2hlIHkgbGFzIDYgYS5tLiANCmBgYHtyfQ0KZWplcmNpY2lvNyA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihkZXBfdGltZT09MjQwMCB8IGRlcF90aW1lPD02MDAgKQ0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+QXJyYW5nZTwvc3Bhbj4NCnNpbWlsYXIgYSBmaWx0ZXIoKSBwZXJvIGVuIGx1Z2FyIGRlIHNlbGVjY2lvbmFyIHJlbmdsb25lcywgbG9zIG9yZGVuYSBkZSBtZW5vciBhIG1heW9yLg0KYGBge3J9DQpkZjExIDwtIGFycmFuZ2UoYmRncmFuZGUyLHllYXIueCxtb250aCxkYXkpDQpgYGANCg0KUGFyYSBhY29tb2RhciBkZSBtYXlvciBhIG1lbm9yLg0KYGBge3J9DQpkZjEyIDwtIGFycmFuZ2UoYmRncmFuZGUyLHllYXIueCxkZXNjKG1vbnRoKSxkYXkpDQpgYGANCg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlN1bW1hcml6ZTwvc3Bhbj4NCkNvbGFwc2EgdW5hIHRhYmxhIGEgdW4gc8OzbG8gcmVuZ2zDs24uDQpgYGB7cn0NCiMgT2J0ZW4gZWwgcmV0cmFzbyBwcm9tZWRpbyBkZSBkZXNwZWd1ZSBkZSB0b2RvcyBsb3MgdnVlbG9zDQpzdW1tYXJpemUoYmRncmFuZGUyLCBtZWFuKGRlcF9kZWxheSwgbmEucm09VFJVRSkpDQojIFNpIGVuIHVuYSB0YWJsYSB0ZW5lbW9zIGVzcGFjaW9zIHNpbiBpbmZvcm1hY2nDs24sIG5vIHBvZGVtb3MgY2FsY3VsYXIgc3VtbWFyaXplLCBwb3IgZXNvIGhheSBxdWUgcG9uZXIgVFJVRSBlbiBsb3Mgbi5hLg0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+R3JvdXAgYnk8L3NwYW4+DQpBZ3J1cGEgdGFibGEgYmFzYWRvIGVuIGFsZ3VuYXMgY29sdW1uYXMuDQpgYGB7cn0NCiMgT2J0ZW5lciBlbCByZXRyYWRvIHByb21lZGlvIGRlIGRlc3BlZ3VlIHBvciBkaWENCnBvcl9kaWEgPC0gZ3JvdXBfYnkoYmRncmFuZGUyLHllYXIueCxtb250aCxkYXkpDQpzdW1tYXJpemUocG9yX2RpYSwgbWVhbihkZXBfZGVsYXksbmEucm09VFJVRSkpDQpgYGANCiMjIyBJbnRlcnJvZ2FudGU6IFBvciBxdcOpIGxsZWdhbiB0YXJkZSBsb3MgdnVlbG9zPw0KUG9kZW1vcyBoYWNlciBlamVyY2ljaW9zIGRlIHJlc3VtZW5lcyBwYXJhIHZlciBkw7NuZGUgZXN0w6EgZWwgZXJyb3INCg0KDQo=