Data Wrangling

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

Instalar paquetes y llamar librerías

# install.packages("nycflights13")
library(nycflights13)
# install.packages("tidyverse")
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.3.3
## Warning: package 'ggplot2' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.3     ✔ readr     2.1.4
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.0     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ 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)
df2 <- flights %>% select(carrier:distance)
df3 <- flights %>% select(-carrier, -flight)
df4 <- flights %>% select(-carrier, -distance) 
df5 <- flights %>% select(aerolinea = carrier) 
df6 <- flights %>% rename(Aerolinea = carrier) 

Filter

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

df7 <- flights %>% filter(dep_delay >=500)
df8 <- flights %>% filter(dep_delay >=500, dep_delay <600)
df9 <- flights %>% slice(1000:1099)

Distinct

La función distinct sirve para elimianr renglones duplicados.

df10 <- distinct(flights)

Marge

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

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

Situación Problema 1. Actividad 1.

Tema: base de datos, sus campos, registros,tipos de datos y los resultados descriptivos de la base de datos.

Situación problema: ¿Cómo mejorar la posición competitiva de una de las aerolíneas líderes en los aeropuertos de Nueva York?

Instrucciones:

• Paquetes requeridos para la práctica: tidyverse, nyflights13 El paquete tidyverse incluye varias librerías entre ellas ggplot2, dplyr, tidyverse El paquete nyflights13 incluye varias bases de datos entre ellas flights • Librerías que deben estar instaladas: dplyr

###1. Cargar en memoria la tabla flights y mostrar su contenido

data(flights)
flights
## # A tibble: 336,776 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 336,766 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

###2. Cargar en memoria la tabla flights y mostrar su contenido. Consulta la estructura de flights, ¿Cuáles son los campos y sus tipos de datos? Identifica los diferentes tipos de datos y explica en qué consiste cada uno de ellos y cuál es la diferencia entre uno y otro, incluyendo los siguientes tipos de datos: int, dbl, chr, dttm

str(flights)
## tibble [336,776 × 19] (S3: tbl_df/tbl/data.frame)
##  $ year          : int [1:336776] 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
##  $ month         : int [1:336776] 1 1 1 1 1 1 1 1 1 1 ...
##  $ day           : int [1:336776] 1 1 1 1 1 1 1 1 1 1 ...
##  $ dep_time      : int [1:336776] 517 533 542 544 554 554 555 557 557 558 ...
##  $ sched_dep_time: int [1:336776] 515 529 540 545 600 558 600 600 600 600 ...
##  $ dep_delay     : num [1:336776] 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
##  $ arr_time      : int [1:336776] 830 850 923 1004 812 740 913 709 838 753 ...
##  $ sched_arr_time: int [1:336776] 819 830 850 1022 837 728 854 723 846 745 ...
##  $ arr_delay     : num [1:336776] 11 20 33 -18 -25 12 19 -14 -8 8 ...
##  $ carrier       : chr [1:336776] "UA" "UA" "AA" "B6" ...
##  $ flight        : int [1:336776] 1545 1714 1141 725 461 1696 507 5708 79 301 ...
##  $ tailnum       : chr [1:336776] "N14228" "N24211" "N619AA" "N804JB" ...
##  $ origin        : chr [1:336776] "EWR" "LGA" "JFK" "JFK" ...
##  $ dest          : chr [1:336776] "IAH" "IAH" "MIA" "BQN" ...
##  $ air_time      : num [1:336776] 227 227 160 183 116 150 158 53 140 138 ...
##  $ distance      : num [1:336776] 1400 1416 1089 1576 762 ...
##  $ hour          : num [1:336776] 5 5 5 5 6 5 6 6 6 6 ...
##  $ minute        : num [1:336776] 15 29 40 45 0 58 0 0 0 0 ...
##  $ time_hour     : POSIXct[1:336776], format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...

###3. ¿Cuál es la clase de flights? y ¿Qué significa?

class(flights)
## [1] "tbl_df"     "tbl"        "data.frame"

###4. ¿Cuántas columnas tiene flights?

ncol(flights)
## [1] 19

###5. ¿Cuántos renglones tiene flights?

nrow(flights)
## [1] 336776

###6. ¿Cuál es la dimensión de flights?

dim(flights)
## [1] 336776     19

###7. Consulta la tabla flights

View(flights)

###8. Genera un output de la tabla flights. Utiliza las funciones head y tail, ¿Cuántos renglones muestran por defecto cada función?

head(flights)
## # A tibble: 6 × 19
##    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
## 1  2013     1     1      517            515         2      830            819
## 2  2013     1     1      533            529         4      850            830
## 3  2013     1     1      542            540         2      923            850
## 4  2013     1     1      544            545        -1     1004           1022
## 5  2013     1     1      554            600        -6      812            837
## 6  2013     1     1      554            558        -4      740            728
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>
tail(flights)
## # A tibble: 6 × 19
##    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
## 1  2013     9    30       NA           1842        NA       NA           2019
## 2  2013     9    30       NA           1455        NA       NA           1634
## 3  2013     9    30       NA           2200        NA       NA           2312
## 4  2013     9    30       NA           1210        NA       NA           1330
## 5  2013     9    30       NA           1159        NA       NA           1344
## 6  2013     9    30       NA            840        NA       NA           1020
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

###9. Ahora muestra los primeros 50 registros y los últimos 20, ¿Cómo lo harías?

head(flights,50)
## # A tibble: 50 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 40 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>
tail(flights,20)
## # A tibble: 20 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     9    30     2150           2159        -9     2250           2306
##  2  2013     9    30     2159           1845       194     2344           2030
##  3  2013     9    30     2203           2205        -2     2339           2331
##  4  2013     9    30     2207           2140        27     2257           2250
##  5  2013     9    30     2211           2059        72     2339           2242
##  6  2013     9    30     2231           2245       -14     2335           2356
##  7  2013     9    30     2233           2113        80      112             30
##  8  2013     9    30     2235           2001       154       59           2249
##  9  2013     9    30     2237           2245        -8     2345           2353
## 10  2013     9    30     2240           2245        -5     2334           2351
## 11  2013     9    30     2240           2250       -10     2347              7
## 12  2013     9    30     2241           2246        -5     2345              1
## 13  2013     9    30     2307           2255        12     2359           2358
## 14  2013     9    30     2349           2359       -10      325            350
## 15  2013     9    30       NA           1842        NA       NA           2019
## 16  2013     9    30       NA           1455        NA       NA           1634
## 17  2013     9    30       NA           2200        NA       NA           2312
## 18  2013     9    30       NA           1210        NA       NA           1330
## 19  2013     9    30       NA           1159        NA       NA           1344
## 20  2013     9    30       NA            840        NA       NA           1020
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

###10. Encuentra los resultados descriptivos de las variables en la base de datos. Ejemplo: promedio, moda, mínimo, máximo, etc.Función: summary.

summary(flights)
##       year          month             day           dep_time    sched_dep_time
##  Min.   :2013   Min.   : 1.000   Min.   : 1.00   Min.   :   1   Min.   : 106  
##  1st Qu.:2013   1st Qu.: 4.000   1st Qu.: 8.00   1st Qu.: 907   1st Qu.: 906  
##  Median :2013   Median : 7.000   Median :16.00   Median :1401   Median :1359  
##  Mean   :2013   Mean   : 6.549   Mean   :15.71   Mean   :1349   Mean   :1344  
##  3rd Qu.:2013   3rd Qu.:10.000   3rd Qu.:23.00   3rd Qu.:1744   3rd Qu.:1729  
##  Max.   :2013   Max.   :12.000   Max.   :31.00   Max.   :2400   Max.   :2359  
##                                                  NA's   :8255                 
##    dep_delay          arr_time    sched_arr_time   arr_delay       
##  Min.   : -43.00   Min.   :   1   Min.   :   1   Min.   : -86.000  
##  1st Qu.:  -5.00   1st Qu.:1104   1st Qu.:1124   1st Qu.: -17.000  
##  Median :  -2.00   Median :1535   Median :1556   Median :  -5.000  
##  Mean   :  12.64   Mean   :1502   Mean   :1536   Mean   :   6.895  
##  3rd Qu.:  11.00   3rd Qu.:1940   3rd Qu.:1945   3rd Qu.:  14.000  
##  Max.   :1301.00   Max.   :2400   Max.   :2359   Max.   :1272.000  
##  NA's   :8255      NA's   :8713                  NA's   :9430      
##    carrier              flight       tailnum             origin         
##  Length:336776      Min.   :   1   Length:336776      Length:336776     
##  Class :character   1st Qu.: 553   Class :character   Class :character  
##  Mode  :character   Median :1496   Mode  :character   Mode  :character  
##                     Mean   :1972                                        
##                     3rd Qu.:3465                                        
##                     Max.   :8500                                        
##                                                                         
##      dest              air_time        distance         hour      
##  Length:336776      Min.   : 20.0   Min.   :  17   Min.   : 1.00  
##  Class :character   1st Qu.: 82.0   1st Qu.: 502   1st Qu.: 9.00  
##  Mode  :character   Median :129.0   Median : 872   Median :13.00  
##                     Mean   :150.7   Mean   :1040   Mean   :13.18  
##                     3rd Qu.:192.0   3rd Qu.:1389   3rd Qu.:17.00  
##                     Max.   :695.0   Max.   :4983   Max.   :23.00  
##                     NA's   :9430                                  
##      minute        time_hour                     
##  Min.   : 0.00   Min.   :2013-01-01 05:00:00.00  
##  1st Qu.: 8.00   1st Qu.:2013-04-04 13:00:00.00  
##  Median :29.00   Median :2013-07-03 10:00:00.00  
##  Mean   :26.23   Mean   :2013-07-03 05:22:54.64  
##  3rd Qu.:44.00   3rd Qu.:2013-10-01 07:00:00.00  
##  Max.   :59.00   Max.   :2013-12-31 23:00:00.00  
## 

Situación Problema 1. Actividad 2.

Funciones básicas para la manipulación de datos. Temas: Dplyr (filter, arrange, select, rename, mutate, summarize, group_by) if/else, subset, for (loops) Situación problema: ¿Cómo mejorar la posición competitiva de una de las aerolíneas líderes en los aeropuertos de Nueva York? Instrucciones: Librerías requeridas: • Paquetes requeridos para la práctica: tidyverse, nyflights13 El paquete tidyverse incluye varias librerías entre ellas ggplot2, dplyr, tidyverse El paquete nyflights13 incluye varias bases de datos entre ellas flights • Librerías que deben estar instaladas: ggplot2, dplyr, tidyverse

library(nycflights13)
library(tidyverse)
library(dplyr)
data("flights")

###1. Mostrar la base de datos flights para que conozcas su contenido

View(flights)

###2. Encuentra los datos descriptivos del data frame flights. Identifica la media de las distancias recorridas en millas.

summary(flights)
##       year          month             day           dep_time    sched_dep_time
##  Min.   :2013   Min.   : 1.000   Min.   : 1.00   Min.   :   1   Min.   : 106  
##  1st Qu.:2013   1st Qu.: 4.000   1st Qu.: 8.00   1st Qu.: 907   1st Qu.: 906  
##  Median :2013   Median : 7.000   Median :16.00   Median :1401   Median :1359  
##  Mean   :2013   Mean   : 6.549   Mean   :15.71   Mean   :1349   Mean   :1344  
##  3rd Qu.:2013   3rd Qu.:10.000   3rd Qu.:23.00   3rd Qu.:1744   3rd Qu.:1729  
##  Max.   :2013   Max.   :12.000   Max.   :31.00   Max.   :2400   Max.   :2359  
##                                                  NA's   :8255                 
##    dep_delay          arr_time    sched_arr_time   arr_delay       
##  Min.   : -43.00   Min.   :   1   Min.   :   1   Min.   : -86.000  
##  1st Qu.:  -5.00   1st Qu.:1104   1st Qu.:1124   1st Qu.: -17.000  
##  Median :  -2.00   Median :1535   Median :1556   Median :  -5.000  
##  Mean   :  12.64   Mean   :1502   Mean   :1536   Mean   :   6.895  
##  3rd Qu.:  11.00   3rd Qu.:1940   3rd Qu.:1945   3rd Qu.:  14.000  
##  Max.   :1301.00   Max.   :2400   Max.   :2359   Max.   :1272.000  
##  NA's   :8255      NA's   :8713                  NA's   :9430      
##    carrier              flight       tailnum             origin         
##  Length:336776      Min.   :   1   Length:336776      Length:336776     
##  Class :character   1st Qu.: 553   Class :character   Class :character  
##  Mode  :character   Median :1496   Mode  :character   Mode  :character  
##                     Mean   :1972                                        
##                     3rd Qu.:3465                                        
##                     Max.   :8500                                        
##                                                                         
##      dest              air_time        distance         hour      
##  Length:336776      Min.   : 20.0   Min.   :  17   Min.   : 1.00  
##  Class :character   1st Qu.: 82.0   1st Qu.: 502   1st Qu.: 9.00  
##  Mode  :character   Median :129.0   Median : 872   Median :13.00  
##                     Mean   :150.7   Mean   :1040   Mean   :13.18  
##                     3rd Qu.:192.0   3rd Qu.:1389   3rd Qu.:17.00  
##                     Max.   :695.0   Max.   :4983   Max.   :23.00  
##                     NA's   :9430                                  
##      minute        time_hour                     
##  Min.   : 0.00   Min.   :2013-01-01 05:00:00.00  
##  1st Qu.: 8.00   1st Qu.:2013-04-04 13:00:00.00  
##  Median :29.00   Median :2013-07-03 10:00:00.00  
##  Mean   :26.23   Mean   :2013-07-03 05:22:54.64  
##  3rd Qu.:44.00   3rd Qu.:2013-10-01 07:00:00.00  
##  Max.   :59.00   Max.   :2013-12-31 23:00:00.00  
## 

###3. Define un criterio para encontrar las aerolíneas que han recorrido más distancia (en millas) y crea un nuevo data frame que filtre solamente a las aeorlíneas que han recorridao una distancia superior a la media, se desea ver los campos carrier, distance, origin, dest en forma descendente por distance. Ejemplo: aerolíneas con millas recorridas superiores a la media, ordenadas en forma descendente.

#selecciona las variables carrier, distance, origin, dest de la tabla
res01 <- select(flights, carrier, distance, origin, dest)

#se filtra las aerolíneas con millas recorridas superiores a la media - 1040 
res02 <- filter(res01, distance >1040) 

#ordena en forma descendente por distancia recorrida 
res03 <- arrange(res02, desc(distance))

###4. Encuentra la suma y la media de las distancias recorridas por carrier, elimina los NA’S e interpreta que significa la suma y la media de las distancias recorridas.

#Agrupar los datos por carrier,origin, dest y obtener la suma acumulada y la media de las distancias recorridas por carrier eliminando los NA's
res04 <- res03 %>% 
  group_by(carrier,origin,dest)
sumdistance <- sum(res03$distance, n= TRUE)

###5. Ordena en forma descendente por distancia recorrida

res05 <- arrange(res04,carrier,sumdistance)

###6.Observa tus resultados de la última tabla y agrega tus interpretaciones

###7.Identifica si las aerolíneas líderes son las mismas en los tres aeropuertos cuyo origen es Nueva York ( John F. Kennedy (JFK), LaGuardia (LGA) and Newark Liberty (EWR) ).
Genera un data frame para cada aeropuerto. Funciones: filter(), arrange()

JFK = res05 %>%  
  filter(origin == "JFK")  %>%
  arrange(carrier, desc(sumdistance))
LGA = res05 %>%  
  filter(origin == "LGA")  %>%
  arrange(carrier, desc(sumdistance))
EWR = res05 %>%  
  filter(origin == "EWR")  %>%
  arrange(carrier, desc(sumdistance))

Situación Problema 1. Actividad 3.

knitr::opts_chunk$set(echo = TRUE)

R Markdown

###1. Consulta las tablas planes y weather para que conozcas su contenido.

view(planes)
view(weather)

###2. Se necesita saber de cada vuelo, la aerolínea, el aeropuerto de origen y el aeropuerto destino.

aerolineas <- flights %>% 
  select(carrier,origin,dest)

###3. En la consulta anterior se necesita conocer el nombre de la aerolínea.

aerolineas_nombre <- aerolineas %>%
  left_join(airlines, by = "carrier")

###4 Se necesita saber la cantidad de vuelos por cada destino para identificar cuáles son los destinos más buscados.

cant_vuelos <- flights %>% 
  select(carrier, dest) %>% 
  count(carrier)

###5 Agregar el nombre de la aerolínea a la tabla anterior.

cant_vuelos_nombre <- cant_vuelos %>%
  left_join(airlines, by = "carrier")

###6. Se necesita conocer las aerolíneas (clave y nombre) y destinos que vuelan por la Mañana: de 6 a 12, Tarde: de 12 a 19 , Noche: de 19 a 24 y Madrugada de 24 a 6. # Agrega un nuevo campo a la tabla con el nombre de clas_horario y agrega, mañana, tarde, noche y madrugada según sea el caso.

carrier_horario <- flights %>%
select(carrier, dest, sched_dep_time) %>%
  left_join(airlines, by = "carrier")

clasxhora<- mutate(carrier_horario, clas_horario = ifelse(sched_dep_time %in% 600:1159,"Mañana",
                                               ifelse(sched_dep_time %in% 1200:1859,"Tarde",
                                               ifelse(sched_dep_time %in% 1900:2400,"Noche", "Madrugada"))))

###7.Se necesita saber la cantidad de vuelos por aerolínea y destino que hay por la Mañana, Tarde, Noche y Madrugada.

cant_clasxhora <- clasxhora %>% 
             group_by(carrier, dest,clas_horario) %>% count()

###8 Se necesita saber a qué destinos vuela la aerolínea American Airlines Inc.-AA durante la madrugada.

destinos_aa <- clasxhora %>% 
  select(carrier,name, dest,clas_horario) %>% 
  filter(carrier == "AA" & clas_horario == "Madrugada") %>% 
  group_by(carrier,name, dest,clas_horario)

###9. ¿Qué aviones utiliza la aerolínea AA? aerolínea, tipo, motor y número de asientos y ¿Cuántos vuelos se han realizado con cada uno? elimina los NA’s

avion_aa <- flights %>%
  left_join(planes, by = "tailnum") %>%
  select(carrier, type, engine, seats) %>%
  filter(carrier == "AA", !is.na(type)) %>%
  group_by(carrier,type,engine,seats) %>% 
  count()

La aerolínea American Airlines utiliza principalmente aviones de tipo “Fixed wing multi engine”. La aerolínea American Airlines utiliza principalmente motores “turbo fan” en sus aviones. La aerolínea American Airlines utiliza aviones que tienen desde 2 asientos (463) hasta 330 asientos (450).

Evidencia 1

Te acabas de incorporar a una empresa consultora en Inteligencia de Negocios, actualmente están brindando servicios de análisis para la industria de la aviación y les interesa tener a la aerolínea American Airlines como cliente ya que es una de las aerolíneas líderes en los aeropuertos de Nueva York, motivo por el cuál te han contratado.

Instalar paquetes y llamar librerías

# install.packages("nycflights13")
library(nycflights13)
# install.packages("tidyverse")
library(tidyverse)

Guardar bases de datos

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

Relación entre las bases de datos

1. Data Frames e Identificación de tipo de datos

## Datos de Weather
weather
## # A tibble: 26,115 × 15
##    origin  year month   day  hour  temp  dewp humid wind_dir wind_speed
##    <chr>  <int> <int> <int> <int> <dbl> <dbl> <dbl>    <dbl>      <dbl>
##  1 EWR     2013     1     1     1  39.0  26.1  59.4      270      10.4 
##  2 EWR     2013     1     1     2  39.0  27.0  61.6      250       8.06
##  3 EWR     2013     1     1     3  39.0  28.0  64.4      240      11.5 
##  4 EWR     2013     1     1     4  39.9  28.0  62.2      250      12.7 
##  5 EWR     2013     1     1     5  39.0  28.0  64.4      260      12.7 
##  6 EWR     2013     1     1     6  37.9  28.0  67.2      240      11.5 
##  7 EWR     2013     1     1     7  39.0  28.0  64.4      240      15.0 
##  8 EWR     2013     1     1     8  39.9  28.0  62.2      250      10.4 
##  9 EWR     2013     1     1     9  39.9  28.0  62.2      260      15.0 
## 10 EWR     2013     1     1    10  41    28.0  59.6      260      13.8 
## # ℹ 26,105 more rows
## # ℹ 5 more variables: wind_gust <dbl>, precip <dbl>, pressure <dbl>,
## #   visib <dbl>, time_hour <dttm>
## Datos de Planes
planes
## # A tibble: 3,322 × 9
##    tailnum  year type              manufacturer model engines seats speed engine
##    <chr>   <int> <chr>             <chr>        <chr>   <int> <int> <int> <chr> 
##  1 N10156   2004 Fixed wing multi… EMBRAER      EMB-…       2    55    NA Turbo…
##  2 N102UW   1998 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
##  3 N103US   1999 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
##  4 N104UW   1999 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
##  5 N10575   2002 Fixed wing multi… EMBRAER      EMB-…       2    55    NA Turbo…
##  6 N105UW   1999 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
##  7 N107US   1999 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
##  8 N108UW   1999 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
##  9 N109UW   1999 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
## 10 N110UW   1999 Fixed wing multi… AIRBUS INDU… A320…       2   182    NA Turbo…
## # ℹ 3,312 more rows
## Datos de Airports
airports
## # A tibble: 1,458 × 8
##    faa   name                             lat    lon   alt    tz dst   tzone    
##    <chr> <chr>                          <dbl>  <dbl> <dbl> <dbl> <chr> <chr>    
##  1 04G   Lansdowne Airport               41.1  -80.6  1044    -5 A     America/…
##  2 06A   Moton Field Municipal Airport   32.5  -85.7   264    -6 A     America/…
##  3 06C   Schaumburg Regional             42.0  -88.1   801    -6 A     America/…
##  4 06N   Randall Airport                 41.4  -74.4   523    -5 A     America/…
##  5 09J   Jekyll Island Airport           31.1  -81.4    11    -5 A     America/…
##  6 0A9   Elizabethton Municipal Airport  36.4  -82.2  1593    -5 A     America/…
##  7 0G6   Williams County Airport         41.5  -84.5   730    -5 A     America/…
##  8 0G7   Finger Lakes Regional Airport   42.9  -76.8   492    -5 A     America/…
##  9 0P2   Shoestring Aviation Airfield    39.8  -76.6  1000    -5 U     America/…
## 10 0S9   Jefferson County Intl           48.1 -123.    108    -8 A     America/…
## # ℹ 1,448 more rows
## Datos de airlines
airlines
## # A tibble: 16 × 2
##    carrier name                       
##    <chr>   <chr>                      
##  1 9E      Endeavor Air Inc.          
##  2 AA      American Airlines Inc.     
##  3 AS      Alaska Airlines Inc.       
##  4 B6      JetBlue Airways            
##  5 DL      Delta Air Lines Inc.       
##  6 EV      ExpressJet Airlines Inc.   
##  7 F9      Frontier Airlines Inc.     
##  8 FL      AirTran Airways Corporation
##  9 HA      Hawaiian Airlines Inc.     
## 10 MQ      Envoy Air                  
## 11 OO      SkyWest Airlines Inc.      
## 12 UA      United Air Lines Inc.      
## 13 US      US Airways Inc.            
## 14 VX      Virgin America             
## 15 WN      Southwest Airlines Co.     
## 16 YV      Mesa Airlines Inc.

2. Cargar en memoria la tabla “flights” y mostrar su contenido

## La carga a memoria se hizo en el paso anterior
flights
## # A tibble: 336,776 × 19
##     year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1  2013     1     1      517            515         2      830            819
##  2  2013     1     1      533            529         4      850            830
##  3  2013     1     1      542            540         2      923            850
##  4  2013     1     1      544            545        -1     1004           1022
##  5  2013     1     1      554            600        -6      812            837
##  6  2013     1     1      554            558        -4      740            728
##  7  2013     1     1      555            600        -5      913            854
##  8  2013     1     1      557            600        -3      709            723
##  9  2013     1     1      557            600        -3      838            846
## 10  2013     1     1      558            600        -2      753            745
## # ℹ 336,766 more rows
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>

3. Consulta la estructura de “flights”

str(flights)
## tibble [336,776 × 19] (S3: tbl_df/tbl/data.frame)
##  $ year          : int [1:336776] 2013 2013 2013 2013 2013 2013 2013 2013 2013 2013 ...
##  $ month         : int [1:336776] 1 1 1 1 1 1 1 1 1 1 ...
##  $ day           : int [1:336776] 1 1 1 1 1 1 1 1 1 1 ...
##  $ dep_time      : int [1:336776] 517 533 542 544 554 554 555 557 557 558 ...
##  $ sched_dep_time: int [1:336776] 515 529 540 545 600 558 600 600 600 600 ...
##  $ dep_delay     : num [1:336776] 2 4 2 -1 -6 -4 -5 -3 -3 -2 ...
##  $ arr_time      : int [1:336776] 830 850 923 1004 812 740 913 709 838 753 ...
##  $ sched_arr_time: int [1:336776] 819 830 850 1022 837 728 854 723 846 745 ...
##  $ arr_delay     : num [1:336776] 11 20 33 -18 -25 12 19 -14 -8 8 ...
##  $ carrier       : chr [1:336776] "UA" "UA" "AA" "B6" ...
##  $ flight        : int [1:336776] 1545 1714 1141 725 461 1696 507 5708 79 301 ...
##  $ tailnum       : chr [1:336776] "N14228" "N24211" "N619AA" "N804JB" ...
##  $ origin        : chr [1:336776] "EWR" "LGA" "JFK" "JFK" ...
##  $ dest          : chr [1:336776] "IAH" "IAH" "MIA" "BQN" ...
##  $ air_time      : num [1:336776] 227 227 160 183 116 150 158 53 140 138 ...
##  $ distance      : num [1:336776] 1400 1416 1089 1576 762 ...
##  $ hour          : num [1:336776] 5 5 5 5 6 5 6 6 6 6 ...
##  $ minute        : num [1:336776] 15 29 40 45 0 58 0 0 0 0 ...
##  $ time_hour     : POSIXct[1:336776], format: "2013-01-01 05:00:00" "2013-01-01 05:00:00" ...
# int: entero (no tiene decimales). Se utiliza para almacenar valores numéricos sin decimales, como la cantidad de pasajeros o el número de vuelos.
# dbl: Se usa para almacenar números con decimales, como distancias o precios.
# num: numérico (tiene decimales) peso
# chr: caracter (letras). Se usa para almacenar texto, como nombres o palabras.  
# Date: fecha (en R va año-mes-día)
# POSIXct: formato fecha y hora. Es un tipo de dato que representa una fecha y hora específica. Se utiliza para almacenar información temporal, como la fecha de un vuelo o la hora de salida.

4. ¿Cuál es la clase de “flights” y qué significa?

class(flights)
## [1] "tbl_df"     "tbl"        "data.frame"
class
## function (x)  .Primitive("class")
# Las 5 clases de objetos son:
# 1. numeric: número real o decimales
# 2. integer: números enteros
# 3. complex: números complejos
# 4. character: caracteres, letras o palabras
# 5. logical: TRUE o FALSE

# Las 4 clases de objetos compuestos son: 

# 1. list: lista
# 2. matrix: matriz (es todo lo mismo)
# 3. array: colección de objetos
# 4. data.frame: base de datos (es mezclado)

5. ¿Cuántas columnas y renglones tiene “flights” ¿ Cuál es su dimensión?

# Número de columnas
ncol(flights)
## [1] 19
# Número de renglones
nrow(flights)
## [1] 336776
# Dimensión
dim(flights)
## [1] 336776     19

6. Muestra los primeros 6 renglones de “flights”, también los últimos 6.

head(flights)
## # A tibble: 6 × 19
##    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
## 1  2013     1     1      517            515         2      830            819
## 2  2013     1     1      533            529         4      850            830
## 3  2013     1     1      542            540         2      923            850
## 4  2013     1     1      544            545        -1     1004           1022
## 5  2013     1     1      554            600        -6      812            837
## 6  2013     1     1      554            558        -4      740            728
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>
tail(flights)
## # A tibble: 6 × 19
##    year month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##   <int> <int> <int>    <int>          <int>     <dbl>    <int>          <int>
## 1  2013     9    30       NA           1842        NA       NA           2019
## 2  2013     9    30       NA           1455        NA       NA           1634
## 3  2013     9    30       NA           2200        NA       NA           2312
## 4  2013     9    30       NA           1210        NA       NA           1330
## 5  2013     9    30       NA           1159        NA       NA           1344
## 6  2013     9    30       NA            840        NA       NA           1020
## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
## #   tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
## #   hour <dbl>, minute <dbl>, time_hour <dttm>
# Si quisieramos 7 renglones: head(flights)

7. Muestra los estadísticos descriptivos de “flights”

summary(flights)
##       year          month             day           dep_time    sched_dep_time
##  Min.   :2013   Min.   : 1.000   Min.   : 1.00   Min.   :   1   Min.   : 106  
##  1st Qu.:2013   1st Qu.: 4.000   1st Qu.: 8.00   1st Qu.: 907   1st Qu.: 906  
##  Median :2013   Median : 7.000   Median :16.00   Median :1401   Median :1359  
##  Mean   :2013   Mean   : 6.549   Mean   :15.71   Mean   :1349   Mean   :1344  
##  3rd Qu.:2013   3rd Qu.:10.000   3rd Qu.:23.00   3rd Qu.:1744   3rd Qu.:1729  
##  Max.   :2013   Max.   :12.000   Max.   :31.00   Max.   :2400   Max.   :2359  
##                                                  NA's   :8255                 
##    dep_delay          arr_time    sched_arr_time   arr_delay       
##  Min.   : -43.00   Min.   :   1   Min.   :   1   Min.   : -86.000  
##  1st Qu.:  -5.00   1st Qu.:1104   1st Qu.:1124   1st Qu.: -17.000  
##  Median :  -2.00   Median :1535   Median :1556   Median :  -5.000  
##  Mean   :  12.64   Mean   :1502   Mean   :1536   Mean   :   6.895  
##  3rd Qu.:  11.00   3rd Qu.:1940   3rd Qu.:1945   3rd Qu.:  14.000  
##  Max.   :1301.00   Max.   :2400   Max.   :2359   Max.   :1272.000  
##  NA's   :8255      NA's   :8713                  NA's   :9430      
##    carrier              flight       tailnum             origin         
##  Length:336776      Min.   :   1   Length:336776      Length:336776     
##  Class :character   1st Qu.: 553   Class :character   Class :character  
##  Mode  :character   Median :1496   Mode  :character   Mode  :character  
##                     Mean   :1972                                        
##                     3rd Qu.:3465                                        
##                     Max.   :8500                                        
##                                                                         
##      dest              air_time        distance         hour      
##  Length:336776      Min.   : 20.0   Min.   :  17   Min.   : 1.00  
##  Class :character   1st Qu.: 82.0   1st Qu.: 502   1st Qu.: 9.00  
##  Mode  :character   Median :129.0   Median : 872   Median :13.00  
##                     Mean   :150.7   Mean   :1040   Mean   :13.18  
##                     3rd Qu.:192.0   3rd Qu.:1389   3rd Qu.:17.00  
##                     Max.   :695.0   Max.   :4983   Max.   :23.00  
##                     NA's   :9430                                  
##      minute        time_hour                     
##  Min.   : 0.00   Min.   :2013-01-01 05:00:00.00  
##  1st Qu.: 8.00   1st Qu.:2013-04-04 13:00:00.00  
##  Median :29.00   Median :2013-07-03 10:00:00.00  
##  Mean   :26.23   Mean   :2013-07-03 05:22:54.64  
##  3rd Qu.:44.00   3rd Qu.:2013-10-01 07:00:00.00  
##  Max.   :59.00   Max.   :2013-12-31 23:00:00.00  
## 

7.1. Distancia media recorrida en millas.

summary(flights$distance)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##      17     502     872    1040    1389    4983

Podemos ver que la distancia media en millas es de 1040

7.2. Aerolíneas con millas recorridas superiores a la media, ordenadas en forma descendente.

media_distancia <- mean(flights$distance, na.rm = TRUE)
aerolineas_top <- flights %>%
  filter(distance > media_distancia) %>%
  select(carrier, distance, origin, dest) %>%
  arrange(desc(distance))
print(aerolineas_top)
## # A tibble: 127,665 × 4
##    carrier distance origin dest 
##    <chr>      <dbl> <chr>  <chr>
##  1 HA          4983 JFK    HNL  
##  2 HA          4983 JFK    HNL  
##  3 HA          4983 JFK    HNL  
##  4 HA          4983 JFK    HNL  
##  5 HA          4983 JFK    HNL  
##  6 HA          4983 JFK    HNL  
##  7 HA          4983 JFK    HNL  
##  8 HA          4983 JFK    HNL  
##  9 HA          4983 JFK    HNL  
## 10 HA          4983 JFK    HNL  
## # ℹ 127,655 more rows

7.3. Encuentra la suma y la media de las distancias recorridas por carrier

distancia_aerolinea <- flights %>%
  filter(!is.na(distance)) %>%
  group_by(carrier) %>%
  summarise(
    suma_distancia = sum(distance),
    media_distancia = mean(distance, na.rm = TRUE)
  ) %>%
  arrange(desc(suma_distancia))
print(distancia_aerolinea)
## # A tibble: 16 × 3
##    carrier suma_distancia media_distancia
##    <chr>            <dbl>           <dbl>
##  1 UA            89705524           1529.
##  2 DL            59507317           1237.
##  3 B6            58384137           1069.
##  4 AA            43864584           1340.
##  5 EV            30498951            563.
##  6 MQ            15033955            570.
##  7 VX            12902327           2499.
##  8 WN            12229203            996.
##  9 US            11365778            553.
## 10 9E             9788152            530.
## 11 FL             2167344            665.
## 12 AS             1715028           2402 
## 13 HA             1704186           4983 
## 14 F9             1109700           1620 
## 15 YV              225395            375.
## 16 OO               16026            501.

8. Identifica si las aerolíneas líderes son las mismas en los tres aeropuertos

# Función para crear un data frame para un aeropuerto
aeropuerto_df <- function(aeropuerto) {
  flights %>%
    filter(origin == aeropuerto) %>%
    filter(!is.na(distance)) %>%
    group_by(carrier) %>%
    summarise(
      suma_distancia = sum(distance),
      media_distancia = mean(distance, na.rm = TRUE)
    ) %>%
    arrange(desc(suma_distancia))
}

# Data frames para cada aeropuerto
jfk_df <- aeropuerto_df("JFK")
lga_df <- aeropuerto_df("LGA")
ewr_df <- aeropuerto_df("EWR")

# Mostrar los data frames
print(jfk_df)
## # A tibble: 10 × 3
##    carrier suma_distancia media_distancia
##    <chr>            <dbl>           <dbl>
##  1 B6            46858933           1114.
##  2 DL            34970353           1689.
##  3 AA            22891534           1661.
##  4 UA            11496375           2536.
##  5 VX             8972450           2495.
##  6 9E             7426450            507.
##  7 US             3376685           1127.
##  8 MQ             2887772            401.
##  9 HA             1704186           4983 
## 10 EV              322193            229.
print(lga_df)
## # A tibble: 13 × 3
##    carrier suma_distancia media_distancia
##    <chr>            <dbl>           <dbl>
##  1 DL            20861920            904.
##  2 AA            16100472           1041.
##  3 MQ            10509739            621.
##  4 UA             9258277           1151.
##  5 B6             6181593           1030.
##  6 WN             5517587            906.
##  7 EV             4316573            489.
##  8 US             3779472            288.
##  9 FL             2167344            665.
## 10 9E             1580071            622.
## 11 F9             1109700           1620 
## 12 YV              225395            375.
## 13 OO               11018            424.
print(ewr_df)
## # A tibble: 12 × 3
##    carrier suma_distancia media_distancia
##    <chr>            <dbl>           <dbl>
##  1 UA            68950872           1496.
##  2 EV            25860185            589.
##  3 WN             6711616           1085.
##  4 B6             5343611            815.
##  5 AA             4872578           1397.
##  6 US             4209621            956.
##  7 VX             3929877           2510.
##  8 DL             3675044            846.
##  9 AS             1715028           2402 
## 10 MQ             1636444            719 
## 11 9E              781631            616.
## 12 OO                5008            835.

Interpretación

American Airlines tiene una alta suma de distancia recorrida, lo que indica que es una aerolínea con una amplia red de rutas y un gran volumen de pasajeros. La media de la distancia recorrida por AA es superior a la media de otras aerolíneas, lo que indica que sus vuelos son generalmente más largos. Estos datos podrían ser relevantes para los inversores que buscan una aerolínea con una fuerte presencia en el mercado y un historial de rentabilidad.

Conclusión

En este trabajo pudimos utilizar las funciones más comunes del análisis explotarotio, el cual es el primer paso para cualquier trabajo de manipulación de datos, hicimos uso de distintas herramientas para analizar medias, distancias mayores y menores y así finalmente analizar los beneficios de tener a American Airlines como nuevo cliente, descubriendo su gran potencial en múltiples aeropuertos como aerolinea líder.

¿Por qué se retrasan los vuelos?

Según Destino:

  1. ANC tiene el retraso porcentual más alto con 75% y con retrado promedio de minutos de 12.88min
  2. XNA tiene de los retrasos porcentual más bajos con 25.48% y con retrado promedio de minutos de 6.4min
summary_delay <- flights %>%
  group_by(dest) %>%
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE),  
    total_flights = n(),                       
    total_delayed_flights = sum(dep_delay > 0, na.rm = TRUE),
    perc_delayed_flights = {
      total_delayed_flights / total_flights * 100
    }
  ) %>%
arrange(desc(perc_delayed_flights))
summary_delay
## # A tibble: 105 × 5
##    dest  avg_delay total_flights total_delayed_flights perc_delayed_flights
##    <chr>     <dbl>         <int>                 <int>                <dbl>
##  1 ANC        12.9             8                     6                 75  
##  2 MTJ        17.6            15                    11                 73.3
##  3 JAC        26.5            25                    16                 64  
##  4 CAE        35.6           116                    72                 62.1
##  5 HDN        12.3            15                     9                 60  
##  6 SBN        21.1            10                     6                 60  
##  7 OKC        30.6           346                   196                 56.6
##  8 MDW        18.6          4113                  2251                 54.7
##  9 TUL        34.9           315                   172                 54.6
## 10 SMF        18.7           284                   146                 51.4
## # ℹ 95 more rows
# Filtrar los 10 aeropuertos con mayor retraso
top_10_airports <- summary_delay %>%
  arrange(desc(avg_delay)) %>%
  head(10)

# Crear un gráfico de barras
ggplot(top_10_airports, aes(x = dest, y = avg_delay)) +
  geom_bar(stat = "identity") +
  labs(title = "Top 10 aeropuertos con mayor retraso promedio",
       x = "Aeropuerto de destino",
       y = "Retraso promedio (minutos)") +
  theme_minimal()

Según Hora de Partida:

  1. A la hora 17:00, el retraso promedio es de 21.10 minutos y el porcentaje de vuelos retrasados es del 49.67%.
  2. A la hora 19:00, el retraso promedio en minutos aumenta hasta 24.78 y el porcentaje a 50.55%. Sin embargo menos cantidad de vuelos se ven afectados.
  3. A la hora 6:00am, el retraso promedio es el más bajo, siendo en minutos de 1.64 y en porcentaje es de 20.92%.
retraso_horas <- flights %>%
  group_by(hour) %>%
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE),  
    total_flights = n(),                       
    total_delayed_flights = sum(dep_delay > 0, na.rm = TRUE),
    perc_delayed_flights = {
      total_delayed_flights / total_flights * 100
    }
  ) %>%
arrange(desc(total_delayed_flights))
retraso_horas
## # A tibble: 20 × 5
##     hour avg_delay total_flights total_delayed_flights perc_delayed_flights
##    <dbl>     <dbl>         <int>                 <int>                <dbl>
##  1    17    21.1           24426                 12132                 49.7
##  2    15    16.9           23888                 11364                 47.6
##  3    19    24.8           21441                 10839                 50.6
##  4    16    18.8           23002                 10699                 46.5
##  5    18    21.1           21783                 10636                 48.8
##  6    14    13.8           21706                  9257                 42.6
##  7    20    24.3           16739                  8633                 51.6
##  8    13    11.4           19956                  8183                 41.0
##  9     8     4.13          27242                  6790                 24.9
## 10    12     8.61          18181                  6408                 35.2
## 11    21    24.2           10933                  5596                 51.2
## 12     6     1.64          25951                  5430                 20.9
## 13     9     4.58          20312                  5392                 26.5
## 14    11     7.19          16033                  5034                 31.4
## 15     7     1.91          22821                  4963                 21.7
## 16    10     6.50          16708                  4942                 29.6
## 17    22    18.8            2639                  1184                 44.9
## 18     5     0.688          1953                   489                 25.0
## 19    23    14.0            1061                   461                 43.4
## 20     1   NaN                 1                     0                  0
# Crea un gráfico de barras para mostrar el número total de vuelos retrasados por hora
ggplot(retraso_horas, aes(x = hour, y = total_delayed_flights)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Total de vuelos retrasados por hora",
       x = "Hora del dia",
       y = "Total de vuelos retrasados") +
  theme_minimal()

# Crea un gráfico de líneas para mostrar el porcentaje de vuelos retrasados por hora
ggplot(retraso_horas, aes(x = hour, y = perc_delayed_flights)) +
  geom_line(color = "red") +
  labs(title = "Porcentaje de vuelos retrasados por hora",
       x = "Hora del dia",
       y = "Porcentaje de vuelos retrasados (%)") +
  theme_minimal()

Retraso según Aerolínea:

  1. WN tiene el retraso porcentual más alto de 53.42.
  2. FL tiene el segundo retraso porcentual más alto de 50.73.
  3. US y HA tienen bajos porcentajes de retrasos (10.55 y 12.58 minutos respectivamente) pero sus porcentajes de vuelos retrasados son de los más bajos (23.25% y 20.18% respectivamente).
  4. American Airlines se encuentra entre las aerolineas con menor porcentaje de retraso
top_bottom_3 <- flights %>%
  group_by(carrier) %>%
  summarise(avg_delay = mean(dep_delay, na.rm = TRUE),
            total_flights = n(),
            total_delayed_flights = sum(dep_delay > 0, na.rm = TRUE),
            perc_delayed_flights = total_delayed_flights / total_flights * 100) %>%
  arrange(desc(perc_delayed_flights))

top_bottom_3
## # A tibble: 16 × 5
##    carrier avg_delay total_flights total_delayed_flights perc_delayed_flights
##    <chr>       <dbl>         <int>                 <int>                <dbl>
##  1 WN          17.7          12275                  6558                 53.4
##  2 FL          18.7           3260                  1654                 50.7
##  3 F9          20.2            685                   341                 49.8
##  4 UA          12.1          58665                 27261                 46.5
##  5 VX          12.9           5162                  2225                 43.1
##  6 EV          20.0          54173                 23139                 42.7
##  7 B6          13.0          54635                 21445                 39.3
##  8 YV          19.0            601                   233                 38.8
##  9 9E          16.7          18460                  7063                 38.3
## 10 DL           9.26         48110                 15241                 31.7
## 11 AS           5.80           714                   226                 31.7
## 12 AA           8.59         32729                 10162                 31.0
## 13 MQ          10.6          26397                  8031                 30.4
## 14 OO          12.6             32                     9                 28.1
## 15 US           3.78         20536                  4775                 23.3
## 16 HA           4.90           342                    69                 20.2
titulo <- "Top 3 Aerolineas (Retraso Promedio)"
ggplot(top_bottom_3, aes(x = carrier, y = perc_delayed_flights)) +
  geom_bar(stat = "identity") +
  labs(title = titulo,
       x = "Aerolinea",
       y = "Retraso promedio (minutos)",
       # Rotate x-axis labels for better readability
       x.text.angle = 45
  ) +
  theme_minimal()

Retraso según Modelo de Avión:
1. Podemos ver que los modelos de avión N258JB, N228JB y N15980 son los que tienen mayor porcentaje de retraso siendo 43%, 42% y 50% respectivamente. 2. Los modelos N364NB, N37419 y N3755D son los que tienen menor cantidad de vuelos afectados siendo 46 los vuelos afectados (retrasados), sin embargo los porcentaje siguen altos.

retraso_model <- flights %>%
  group_by(tailnum) %>%
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE),  
    total_flights = n(),                       
    total_delayed_flights = sum(dep_delay > 0, na.rm = TRUE),
    perc_delayed_flights = {
      total_delayed_flights / total_flights * 100
    }
  ) %>%
arrange(desc(total_delayed_flights))
retraso_model
## # A tibble: 4,044 × 5
##    tailnum avg_delay total_flights total_delayed_flights perc_delayed_flights
##    <chr>       <dbl>         <int>                 <int>                <dbl>
##  1 N258JB      16.8            427                   186                 43.6
##  2 N228JB      19.8            388                   165                 42.5
##  3 N15980      24.7            316                   158                 50  
##  4 N190JB      14.7            362                   157                 43.4
##  5 N725MQ       6.87           575                   152                 26.4
##  6 N15910      29.3            280                   151                 53.9
##  7 N324JB      14.8            370                   151                 40.8
##  8 N327AA      11.6            387                   150                 38.8
##  9 N298JB      14.0            407                   146                 35.9
## 10 N922XJ      20.4            309                   146                 47.2
## # ℹ 4,034 more rows
top_5_modelos <- retraso_model %>%
  head(5)

# Crear un gráfico de barras
ggplot(top_5_modelos, aes(x = tailnum, y = total_delayed_flights)) +
  geom_bar(stat = "identity") +
  labs(title = titulo,
       x = "Modelo de avion (tail number)",
       y = "Cantidad de vuelos (Retrasados)") +
  theme_minimal()

Retraso según Humedad: (No tan signifacante)
Estos pueden verse afectados dependiendo de:
Tipo de aeronave: Algunos aviones son más sensibles a la humedad que otros. Los aviones más pequeños o con motores más antiguos pueden verse más afectados por la humedad alta.
Condiciones climáticas: La visibilidad, la temperatura y la velocidad del viento también influyen en la decisión de despegar o no. La humedad alta combinada con otros factores climáticos adversos aumenta la probabilidad de un retraso o cancelación.
Humedad (humid):.

-Humedad baja (menos del 40%): En general, no hay problemas para volar.
-Humedad moderada (40%-70%): La mayoría de los aviones pueden volar sin problemas. Algunas aerolíneas pueden tener restricciones para ciertos tipos de aeronaves o rutas.
-Humedad alta (más del 70%): Aumenta el riesgo de retrasos o cancelaciones. Las aerolíneas pueden tener restricciones más severas para volar en estas condiciones.

Podemos ver que la mayor cantidad de vuelos retrasados presentaban una humedad de 100, dando en promedio de minutos un retraso de 23.15min.
Y por otro lado cuando la humedad es de 60, el promedio de retraso de minutos es de 4.58minutos.

#Primero uniremos la base de datos a weather usando Merge
baseevidencia <- merge(flights,weather,by=c("origin","time_hour"))
#Ahora si vemos la correlación
retraso_humedad <- baseevidencia %>%
  group_by(humid) %>%
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE),  
    total_flights = n(),                       
    total_delayed_flights = sum(dep_delay > 0, na.rm = TRUE),
    perc_delayed_flights = {
      total_delayed_flights / total_flights * 100
    }
  ) %>%
arrange(desc(total_delayed_flights))
retraso_humedad
## # A tibble: 2,443 × 5
##    humid avg_delay total_flights total_delayed_flights perc_delayed_flights
##    <dbl>     <dbl>         <int>                 <int>                <dbl>
##  1 100       23.2           2994                  1331                 44.5
##  2  94.1     42.0            782                   422                 54.0
##  3  88.6     45.3            632                   356                 56.3
##  4  93.1     27.0            677                   350                 51.7
##  5  79.0     33.9            642                   340                 53.0
##  6  90.1     36.0            538                   299                 55.6
##  7  90.7     38.4            554                   293                 52.9
##  8  49.7     24.1            615                   285                 46.3
##  9  84.3     30.7            609                   268                 44.0
## 10  54.5      6.25           808                   260                 32.2
## # ℹ 2,433 more rows

Retraso según Meses del Año:
Podemos observar que los meses en los que se producen mayores retrasos de salida es en los meses de:

  • Julio: Con un 47.269% (porcentaje de retraso) y retraso en minutos de 21.73min.
  • Diciembre: Con un 48.16% (porcentaje de retraso) y retraso en minutos de 16.57min.
retraso_mes <- flights %>%
  group_by(month) %>%
  summarize(
    avg_delay = mean(dep_delay, na.rm = TRUE),  
    total_flights = n(),                       
    total_delayed_flights = sum(dep_delay > 0, na.rm = TRUE),
    perc_delayed_flights = {
      total_delayed_flights / total_flights * 100
    }
  ) %>%
arrange(desc(total_delayed_flights))
retraso_mes
## # A tibble: 12 × 5
##    month avg_delay total_flights total_delayed_flights perc_delayed_flights
##    <int>     <dbl>         <int>                 <int>                <dbl>
##  1     7     21.7          29425                 13909                 47.3
##  2    12     16.6          28135                 13550                 48.2
##  3     6     20.8          28243                 12655                 44.8
##  4     8     12.6          29327                 11713                 39.9
##  5     5     13.0          28796                 11291                 39.2
##  6     3     13.2          28834                 11209                 38.9
##  7     4     13.9          28330                 10543                 37.2
##  8     1     10.0          27004                  9662                 35.8
##  9     2     10.8          24951                  9124                 36.6
## 10    10      6.24         28889                  8722                 30.2
## 11    11      5.44         27268                  8239                 30.2
## 12     9      6.72         27574                  7815                 28.3
titulo <- "Meses y retrasos en promedio (minutos)"
ggplot(retraso_mes, aes(x = factor(month, levels = 1:12, labels = month.name), y = perc_delayed_flights)) +
  geom_bar(stat = "identity") +
  labs(title = titulo,
       x = "Mes",
       y = "Retraso promedio (minutos)"
  ) +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Evidencia 2.

Evidencia 2 - Analítica descriptiva (Integración de datos a través de modelo entidad-relación)
Compromiso ético y ciudadano. Se te ha solicitado hacer un estudio sobre la situación actual de la aerolínea American Airlines ya que se necesita revisar sus destinos, horarios y aviones con los que cuenta para hacer propuestas de aumento o reducción de vuelos por destino y horarios, así como la cantidad de aviones.

1. Datos Generales.

1.1 Consulta y exploración del data frame planes y weather.”

view(weather)
view(planes)

1.2. Se necesita saber de cada vuelo, la aerolínea, el aeropuerto de origen y el aeropuerto destino.”

aerolineas <- flights %>% 
  select(carrier,origin,dest)
aerolineas
## # A tibble: 336,776 × 3
##    carrier origin dest 
##    <chr>   <chr>  <chr>
##  1 UA      EWR    IAH  
##  2 UA      LGA    IAH  
##  3 AA      JFK    MIA  
##  4 B6      JFK    BQN  
##  5 DL      LGA    ATL  
##  6 UA      EWR    ORD  
##  7 B6      EWR    FLL  
##  8 EV      LGA    IAD  
##  9 B6      JFK    MCO  
## 10 AA      LGA    ORD  
## # ℹ 336,766 more rows

1.3. En la consulta anterior se necesita conocer el nombre de la aerolínea.”

aerolineas_nombre <- aerolineas %>%
  left_join(airlines, by = "carrier")
aerolineas_nombre
## # A tibble: 336,776 × 4
##    carrier origin dest  name                    
##    <chr>   <chr>  <chr> <chr>                   
##  1 UA      EWR    IAH   United Air Lines Inc.   
##  2 UA      LGA    IAH   United Air Lines Inc.   
##  3 AA      JFK    MIA   American Airlines Inc.  
##  4 B6      JFK    BQN   JetBlue Airways         
##  5 DL      LGA    ATL   Delta Air Lines Inc.    
##  6 UA      EWR    ORD   United Air Lines Inc.   
##  7 B6      EWR    FLL   JetBlue Airways         
##  8 EV      LGA    IAD   ExpressJet Airlines Inc.
##  9 B6      JFK    MCO   JetBlue Airways         
## 10 AA      LGA    ORD   American Airlines Inc.  
## # ℹ 336,766 more rows

1.4. Se necesita saber la cantidad de vuelos por cada destino para identificar cuáles son los destinos más buscados.”

cant_vuelos <- flights %>% 
  select(carrier, dest) %>% 
  count(dest)
cant_vuelos <- cant_vuelos %>%
  arrange(desc(n))
cant_vuelos
## # A tibble: 105 × 2
##    dest      n
##    <chr> <int>
##  1 ORD   17283
##  2 ATL   17215
##  3 LAX   16174
##  4 BOS   15508
##  5 MCO   14082
##  6 CLT   14064
##  7 SFO   13331
##  8 FLL   12055
##  9 MIA   11728
## 10 DCA    9705
## # ℹ 95 more rows

Los destinos más buscados son ORD (Aeropuerto Internacional O’Hare) con 17,283 vuelos, ATL (Atlanta) con 17,215 vuelos y LAX (Los Angeles) con 16,174 vuelos.

1.5. Agregar el nombre de la aerolínea a la tabla anterior.”

cant_vuelos1 <- flights %>%
  select(carrier, dest) %>%
  group_by(carrier, dest) %>%
  summarise(n = n()) %>%
  ungroup() %>%
  arrange(desc(n))
## `summarise()` has grouped output by 'carrier'. You can override using the
## `.groups` argument.
cant_vuelos1
## # A tibble: 314 × 3
##    carrier dest      n
##    <chr>   <chr> <int>
##  1 DL      ATL   10571
##  2 US      CLT    8632
##  3 AA      DFW    7257
##  4 AA      MIA    7234
##  5 UA      ORD    6984
##  6 UA      IAH    6924
##  7 UA      SFO    6819
##  8 B6      FLL    6563
##  9 B6      MCO    6472
## 10 AA      ORD    6059
## # ℹ 304 more rows

La aerolínea con mayor cantidad de vuelos es DL (DELTA AIRLINES): Delta Air Lines es una aerolínea comercial estadounidense cuya base está situada en Atlanta, Georgia. Es miembro fundador, junto con Aeroméxico, Air France y Korean Air, de SkyTeam, una alianza de aerolíneas globales que ofrece a los clientes un gran número de destinos alrededor del mundo, vuelos y otros servicios

1.6. Se necesita conocer las aerolíneas (clave y nombre) y destinos que vuelan por la Mañana: de 6 a 12, Tarde: de 12 a 19 , Noche: de 19 a 24 y Madrugada de 24 a 6.”

vuelo_porhora <- flights %>%
select(carrier, dest, sched_dep_time) %>%
  left_join(airlines, by = "carrier")

clas_hora<- mutate(vuelo_porhora, clas_horario = ifelse(sched_dep_time %in% 600:1159,"Morning",
                                               ifelse(sched_dep_time %in% 1200:1859,"Afertnoon",
                                               ifelse(sched_dep_time %in% 1900:2400,"Night", "Madrugada"))))
clas_hora
## # A tibble: 336,776 × 5
##    carrier dest  sched_dep_time name                     clas_horario
##    <chr>   <chr>          <int> <chr>                    <chr>       
##  1 UA      IAH              515 United Air Lines Inc.    Madrugada   
##  2 UA      IAH              529 United Air Lines Inc.    Madrugada   
##  3 AA      MIA              540 American Airlines Inc.   Madrugada   
##  4 B6      BQN              545 JetBlue Airways          Madrugada   
##  5 DL      ATL              600 Delta Air Lines Inc.     Morning     
##  6 UA      ORD              558 United Air Lines Inc.    Madrugada   
##  7 B6      FLL              600 JetBlue Airways          Morning     
##  8 EV      IAD              600 ExpressJet Airlines Inc. Morning     
##  9 B6      MCO              600 JetBlue Airways          Morning     
## 10 AA      ORD              600 American Airlines Inc.   Morning     
## # ℹ 336,766 more rows

1.7.Se necesita saber la cantidad de vuelos por aerolínea y destino que hay por la Mañana, Tarde, Noche y Madrugada.”

# Agrupar por aerolínea, destino y franja horaria y contar la cantidad de vuelos
vuelos_conteo <- clas_hora %>%  
  group_by(carrier, dest, clas_horario) %>% count()

# Mostrar los resultados
vuelos_conteo
## # A tibble: 741 × 4
## # Groups:   carrier, dest, clas_horario [741]
##    carrier dest  clas_horario     n
##    <chr>   <chr> <chr>        <int>
##  1 9E      ATL   Morning         59
##  2 9E      AUS   Afertnoon        2
##  3 9E      AVL   Morning         10
##  4 9E      BGR   Night            1
##  5 9E      BNA   Afertnoon      467
##  6 9E      BNA   Morning          6
##  7 9E      BNA   Night            1
##  8 9E      BOS   Afertnoon      549
##  9 9E      BOS   Morning        271
## 10 9E      BOS   Night           94
## # ℹ 731 more rows

1.8.Se necesita saber a qué destinos vuela la aerolínea American Airlines Inc.-AA durante la madrugada.”

destinos_american <- clas_hora %>% 
  select(carrier,name, dest,clas_horario) %>% 
  filter(carrier == "AA" & clas_horario == "Madrugada") %>% 
  group_by(carrier,name, dest,clas_horario)
destinos_american
## # A tibble: 365 × 4
## # Groups:   carrier, name, dest, clas_horario [1]
##    carrier name                   dest  clas_horario
##    <chr>   <chr>                  <chr> <chr>       
##  1 AA      American Airlines Inc. MIA   Madrugada   
##  2 AA      American Airlines Inc. MIA   Madrugada   
##  3 AA      American Airlines Inc. MIA   Madrugada   
##  4 AA      American Airlines Inc. MIA   Madrugada   
##  5 AA      American Airlines Inc. MIA   Madrugada   
##  6 AA      American Airlines Inc. MIA   Madrugada   
##  7 AA      American Airlines Inc. MIA   Madrugada   
##  8 AA      American Airlines Inc. MIA   Madrugada   
##  9 AA      American Airlines Inc. MIA   Madrugada   
## 10 AA      American Airlines Inc. MIA   Madrugada   
## # ℹ 355 more rows

American Airlines realiza vuelos de madrugada a únicamente el destino de Miami. #### 1.9.Qué aviones utiliza la aerolínea AA? aerolínea, tipo, motor y número de asientos y ¿Cuántos vuelos se han realizado con cada uno? (elimina los NA’s)“

avion_american <- flights %>%
  left_join(planes, by = "tailnum") %>%
  select(carrier, type, engine, seats) %>%
  filter(carrier == "AA", !is.na(type)) %>%
  group_by(carrier,type,engine,seats) %>% 
  count()
avion_american
## # A tibble: 22 × 5
## # Groups:   carrier, type, engine, seats [22]
##    carrier type                    engine        seats     n
##    <chr>   <chr>                   <chr>         <int> <int>
##  1 AA      Fixed wing multi engine Reciprocating     6    22
##  2 AA      Fixed wing multi engine Reciprocating     8    92
##  3 AA      Fixed wing multi engine Reciprocating   102    22
##  4 AA      Fixed wing multi engine Turbo-fan         8    38
##  5 AA      Fixed wing multi engine Turbo-fan        11    19
##  6 AA      Fixed wing multi engine Turbo-fan        22    13
##  7 AA      Fixed wing multi engine Turbo-fan       172  3857
##  8 AA      Fixed wing multi engine Turbo-fan       178   501
##  9 AA      Fixed wing multi engine Turbo-fan       255  4257
## 10 AA      Fixed wing multi engine Turbo-fan       330   450
## # ℹ 12 more rows

Visualización de datos

En los avances anteriores se han realizado diferentes análisis y ahora nos solicitan hacer visualizaciones de la aerolínea American Airlines para los ejecutivos con las siguientes características. Dentro de las aerolíneas el retraso tanto en la hora de partida como en la hora de llegada a su destino van generando indicadores negativos. #### Se solicita analizar para la aerolínea American Airlines si los vuelos que tienen retraso en la partida también tienen retraso en la hora de llegada.

# Filtrar los vuelos de American Airlines (AA)
american_flights <- flights %>% filter(carrier == "AA")

# Mostrar la relación entre el retraso en la partida y el retraso en la llegada
cor(american_flights$dep_delay, american_flights$arr_delay, use = "complete.obs")
## [1] 0.8917433
# Filtrar los vuelos de American Airlines (AA)
american_flights <- flights %>% filter(carrier == "AA")

# Crear un gráfico de dispersión
ggplot(american_flights, aes(x = dep_delay, y = arr_delay)) +
  geom_point(alpha = 0.5, color = "blue") +
  labs(main = "Relación entre Retraso en Salida y Llegada para American Airlines", x = "Retraso en la Partida (minutos)", y = "Retraso en la Llegada (minutos)") +
  theme_minimal()
## Warning: Removed 782 rows containing missing values or values outside the scale range
## (`geom_point()`).

El resultado de la correlación entre el retraso en la partida y el retraso en la llegada para los vuelos de American Airlines (AA) es aproximadamente 0.8917. Este valor cercano a 1 indica una fuerte correlación positiva entre ambas variables. En otras palabras, hay una tendencia a que los vuelos que experimentan retraso en la salida también tengan retraso en la llegada.

Temperatura y sus variaciones

Visualiza la tendencia de la temperatura durante los primeros 15 días del mes de Enero en los vuelos que parten del aeropuerto “Newark, EWR”, utilizar una gráfica de línea.

library(ggplot2)

# Filtrar los datos para los primeros 15 días de enero en el aeropuerto Newark
weather_january <- weather %>%
  filter(month == 1 & day <= 15 & origin == "EWR")

# Gráfico de línea para la tendencia de temperatura
ggplot(weather_january, aes(x = day, y = temp)) +
  geom_line(color = "black", size = 1) +
  labs(main="Tendencia de la Temperatura en los Primeros 15 Días de Enero (Aeropuerto Newark)",
       x=weather_january$day,
       y=weather_january$temp)
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

#### Visualiza la temperatura más frecuente en los primeros 15 días del mes de Enero, utilizar un histrograma.

# Filtrar los datos para los primeros 15 días de enero en el aeropuerto Newark
weather_january <- weather %>%
  filter(month == 1 & day <= 15 & origin == "EWR")

# Gráfico de línea para la tendencia de temperatura
ggplot(weather_january, aes(x = temp)) +
  geom_histogram(binwidth = 1, fill = "skyblue", color = "black") +
  labs(main="Tendencia de la Temperatura en los Primeros 15 Días de Enero (Aeropuerto Newark)",
       x=weather_january$day,
       y=weather_january$temp)

#### Utiliza Facets para observar cómo varía la temperatura en cada mes en el histograma del punto anterior .

weather %>%
  ggplot(aes(x = temp)) +
  geom_histogram(binwidth = 2, fill = "skyblue", color = "black") +
  labs(title = "Histograma de Temperaturas por Mes",
       x = "Temperatura (Fahrenheit)",
       y = "Frecuencia") +
  facet_wrap(~month)
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_bin()`).

#### Número de vuelos que salieron de Nueva York en 2013 por aerolínea (mostrar solamente las 10 aerolíneas con más vuelos), utilizar gráfica de barras.

flights %>%
  group_by(carrier) %>%
  summarise(num_flights = n()) %>%
  arrange(desc(num_flights)) %>%
  slice(1:10) %>%
  ggplot(aes(x = reorder(carrier, -num_flights), y = num_flights)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Numero de vuelos por aerolinea",
       x = "Aerolinea",
       y = "Numero de Vuelos") +
  theme_minimal()

Según el gráfico “Número de vuelos por aerolínea en 2013”, se observa que las aerolíneas con mayor cantidad de vuelos desde Nueva York durante ese año fueron “United Airlines” y “JetBlue Airways”. Estas dos aerolíneas lideran significativamente en términos de la cantidad de vuelos, superando a otras compañías. El gráfico proporciona una rápida visualización de la distribución de vuelos entre las aerolíneas principales, siendo útil para comprender la participación relativa de cada una en el tráfico aéreo desde Nueva York en 2013. #### Visualiza el punto anterior en una gráfica de pie.

Sys.setlocale("LC_CTYPE", "en_US.UTF-8")
## [1] "en_US.UTF-8"
# Filtramos los datos para obtener la cantidad de vuelos por aerolínea
top_airlines <- flights %>%
  group_by(carrier) %>%
  summarise(num_flights = n()) %>%
  arrange(desc(num_flights)) %>%
  slice(1:10)  # Seleccionamos las 10 aerolíneas con más vuelos
ggplot(top_airlines, aes(x = "", y = num_flights, fill = factor(carrier))) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar(theta = "y") +
  labs(title = "Distribución del Número de Vuelos por Aerolínea desde Nueva York en 2013",
       fill = "Aerolínea",
       x = NULL,
       y = NULL) +
  theme_minimal() +
  theme(legend.position = "bottom")

#### Relaciona el data frame fligths con el data frame airports a través del campo destino.

# Realiza la unión de los data frames flights y airports por el campo destino
union_fya <- left_join(flights, airports, by = c("dest" = "faa"))

Crea un nuevo data frame con el punto anterior únicamente con los 5 carriers con más vuelos por destino

# Crea un nuevo data frame con los 5 carriers con más vuelos
top_carriers <- union_fya %>%
  group_by(carrier) %>%
  summarise(num_flights = n()) %>%
  arrange(desc(num_flights)) %>%
  slice(1:5) %>%
  ungroup()

# Muestra el nuevo data frame
print(top_carriers)
## # A tibble: 5 × 2
##   carrier num_flights
##   <chr>         <int>
## 1 UA            58665
## 2 B6            54635
## 3 EV            54173
## 4 DL            48110
## 5 AA            32729
flights_top_carriers <- union_fya %>%
  filter(carrier %in% top_carriers$carrier)

Realiza una visualización del punto anterior de las siguientes tres formas.

# DataFrame con los resultados
top_carriers <- union_fya %>%
  group_by(carrier, origin) %>%
  summarise(num_flights = n()) %>%
  arrange(desc(num_flights)) %>%
  slice(1:5) %>%
  ungroup()
## `summarise()` has grouped output by 'carrier'. You can override using the
## `.groups` argument.
ggplot(top_carriers, aes(x = carrier, y = num_flights, fill = as.factor(carrier))) +
  geom_bar(stat = "identity", position = "stack") +
  labs(x = "Carrier", y = "Number of Flights", title = "Top 5 Carriers con más vuelos por aeropuerto") +
  facet_wrap(~origin, scales = "free_x") +
  theme_minimal()

ggplot(flights_top_carriers, aes(x = carrier, fill = carrier)) +
  geom_bar() +
  labs(title = "Cantidad de vuelos por aerolínea", x = "Aerolínea", y = "Cantidad de vuelos") +
  theme_minimal() +
  geom_text(stat = "count", aes(label = ..count.., group = carrier), vjust = -0.5)
## Warning: The dot-dot notation (`..count..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(count)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

ggplot(flights_top_carriers, aes(x = dest, fill = carrier)) +
  geom_bar() +
  labs(title = "Cantidad de vuelos por destino", x = "Destino", y = "Cantidad de vuelos") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

Conclusiones

  • Los vuelos que salen en meses de alta demanda tienen más retrasos debido a la mayor complejidad en las operaciones y el aumento del tráfico. Por ejemplo, en julio y diciembre, se encuentran los vuelos que tienen mayores porcentajes de retraso, teniendo porcentajes de 47.27% y de 48.16%, mientras que el mes de septiembre tiene un porcentaje de 28.34%. Esto podría hacer que empresas tipo American Airlines se enfoquen más en estos meses para abastecer la atención y operaciones

  • Las aerolíneas ejercen un impacto significativo en los retrasos de los vuelos, ya que la disponibilidad de personal y la demanda de viajes varían entre ellas. Esto se refleja en que Southwest Airlines Co. tiene un índice de retraso del 53.4% (con 12 mil vuelos totales), mientras que Hawaiian Airlines Inc. solo registra un 20.2% de retrasos (con 342 vuelos). American Airlines se encuentra entre las aerolineas con menor porcentaje de retraso, teniendo un porcentaje de 31%.

-Los datos muestran que a las 17:00 horas hay un retraso promedio de 21.10 minutos, afectando casi la mitad de los vuelos (49.67%). A las 19:00 horas, el retraso promedio aumenta ligeramente a 24.78 minutos, con menos vuelos afectados. En contraste, a las 6:00 a.m., el retraso promedio es el más bajo (1.64 minutos), con solo el 20.92% de los vuelos afectados. Estos resultados destacan cómo la hora de salida influye en la incidencia y magnitud de los retrasos en los vuelos.

-Los datos revelan disparidades significativas en los retrasos de vuelos según el destino. ANC destaca con el mayor porcentaje de retrasos, alcanzando el 75%, y un retraso promedio de 12.88 minutos, sugiriendo posibles desafíos operativos en esas rutas. Por otro lado, XNA muestra uno de los porcentajes de retraso más bajos, con solo un 25.48% de vuelos afectados y un retraso promedio de 6.4 minutos, indicando una gestión operativa más eficiente o condiciones favorables en sus rutas. Estos resultados subrayan la importancia de considerar el destino específico al evaluar los patrones de retraso en los vuelos.

-En la noche se observa la mayor proporción de retrasos en comparación con la mañana, debido a la menor disponibilidad de personal (sin que la demanda esté relacionada con esto). Se destaca que entre las horas 7 a 9 pm, se registra un 50.5% y 51.2% de retrasos, respectivamente, evidenciando un punto álgido en este período.

Compromiso ético y ciudadano (Fabiana)

En nuestro debe como analistas de datos nos comprometemos a ser justos con los datos de una empresa. Esto implica garantizar la confidencialidad de la información sensible, utilizar métodos y técnicas éticas en el análisis, y presentar los resultados de manera transparente y comprensible. Además, nos comprometemos a cuestionar cualquier práctica que pueda comprometer la integridad de los datos o el análisis, abogando siempre por la toma de decisiones éticas y responsables.

Compromiso ético y ciudadano (Salvador)

En nuestro debe como analistas de datos nos comprometemos a ser justos con los datos de una empresa. Esto implica garantizar la confidencialidad de la información sensible, utilizar métodos y técnicas éticas en el análisis, y presentar los resultados de manera transparente y comprensible. Además, nos comprometemos a cuestionar cualquier práctica que pueda comprometer la integridad de los datos o el análisis, abogando siempre por la toma de decisiones éticas y responsables.

Compromiso ético y ciudadano (Paulette)

En nuestro debe como analistas de datos nos comprometemos a ser justos con los datos de una empresa. Esto implica garantizar la confidencialidad de la información sensible, utilizar métodos y técnicas éticas en el análisis, y presentar los resultados de manera transparente y comprensible. Además, nos comprometemos a cuestionar cualquier práctica que pueda comprometer la integridad de los datos o el análisis, abogando siempre por la toma de decisiones éticas y responsables.

Compromiso ético y ciudadano ()

En nuestro debe como analistas de datos nos comprometemos a ser justos con los datos de una empresa. Esto implica garantizar la confidencialidad de la información sensible, utilizar métodos y técnicas éticas en el análisis, y presentar los resultados de manera transparente y comprensible. Además, nos comprometemos a cuestionar cualquier práctica que pueda comprometer la integridad de los datos o el análisis, abogando siempre por la toma de decisiones éticas y responsables.

Bibliografia

Johnson, R. (2018). “Ethics in Data Science: An Introduction.” O’Reilly Media.

Davenport, T., & Harris, J. (2017). “Competing on Analytics: Updated, with a New Introduction.” Harvard Business Review Press.

Diakopoulos, N. (2016). “Data Ethics and the Role of Data Science in the Fourth Industrial Revolution.” Journal of Data Science, 14(4), 553-562.

LS0tDQp0aXRsZTogIkV2aWRlbmNpYSAyIC0gTWFuaXB1bGFjacOzbiBkZSBEYXRvcyAtIEVxdWlwbyA1Ig0KYXV0aG9yOiAiRXF1aXBvIDU6DQpGYWJpYW5hIE1lZGluYWNlbGxpIC0gQTAwODM1ODk2LiANCg0KDQpTYWx2YWRvciBOYXJ2w6FleiBBbmRyYWRlIC0gQTAwNTcxODQ4Lg0KDQoNClBhdWxldHRlIE1hcnRpbmV6IC0gQTAxNzQ3NTM1LiANCg0KDQpKZXN1cyBBbGJlcnRvIE1vcmVubyBNYXJyb3F1aW4gLSBBMDExNzgwMzIuIiANCmRhdGU6ICIyMDI0LTAzLTEyIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogImNvc21vIg0KICAgIGhpZ2hsaWdodDogImVzcHJlc3NvIiAgICANCi0tLQ0KIVtdKEM6XFxVc2Vyc1xcSFBcXERlc2t0b3BcXHZpc2lvbiBib2FyZFxcYmJmNTE0NGIxZTQzMjJiNWE0NzI3M2JhMThhNWY1ZWYuanBnKQ0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkRhdGEgV3JhbmdsaW5nPC9zcGFuPg0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+Q29udGV4dG88L3NwYW4+DQoNCkVsIHBhcXVldGUgKipueWNmbGlnaHRzMTMqKiBjb250aW5lIGluZm9ybWFjacOzbiBzb2JyZSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBwYXJ0aWVyb24gZGVzZGUgTnVldmEgWW9yayAoRVdSLCBKRksgWSBMR0EpIGEgZGVzdGlub3MgZW4gbG9zIEVzdGFkb3MgVW5pZG9zIGVuIDIwMTMuIEZ1ZXJvbiAzMzY3NzYgdnVlbG9zIGVuIHRvdGFsLiBQYXJhIGF5dWRhciBhIGNvbXByZW5kZXIgbGFzIGNhdXNhcyBkZSBsb3MgcmV0cmFzb3MsIHRhbWJpw6luIGluY2x1eWUgb3Ryb3MgY29uanVudG9zIGRlIGRhdG9zIMO6dGlsZXMuICANCg0KRXN0ZSBwYXF1ZXRlIGluY2x1eWUgbGFzIHNpZ3VpZW50ZXMgdGFibGFzOg0KDQorIGZsaWdodHMgPSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzYWxpZXJvbiBkZSBOdWV2YSBZb3JrIGVuIDIwMTMgICANCisgd2VhdGhlciA9IGRhdG9zIG1ldGVvcm9sw7NnaWNvcyBwb3IgaG9yYSBkZSBjYWRhIGFlcm9wdWVydG8gICAgDQorIHBsYW5lcyA9IGluZm9ybWFjaW9uIGRlIGNvbnN0cnVjY2nDs24gZGUgY2FkYSBhdmnDs24gIA0KKyBhaXJwb3J0cyA9IG5vbWJyZXMgeSB1YmljYWNpb25lcyBkZSBhZXJvcHVlcnRvcyAgDQorIGFpcmxpbmVzID0gcmVsYWNpb24gZW50cmUgbm9tYnJlcyB5IGPDs2RpZ29zIGRlIGxhcyBhZXJvbGluZWEgIA0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPkluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcsOtYXM8L3NwYW4+DQpgYGB7cn0NCiMgaW5zdGFsbC5wYWNrYWdlcygibnljZmxpZ2h0czEzIikNCmxpYnJhcnkobnljZmxpZ2h0czEzKQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+R3VhcmRhciBiYXNlcyBkZSBkYXRvczwvc3Bhbj4NCmBgYHtyfQ0KZmxpZ2h0cyA8LSBmbGlnaHRzDQp3ZWF0aGVyIDwtIHdlYXRoZXINCnBsYW5lcyA8LSBwbGFuZXMNCmFpcnBvcnRzIDwtIGFpcnBvcnRzDQphaXJsaW5lcyA8LSBhaXJsaW5lcw0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPlJlbGFjaW9uIGVudHJlIGxhcyBiYXNlcyBkZSBkYXRvczwvc3Bhbj4NCiFbXShDOlxcVXNlcnNcXEhQXFxEb3dubG9hZHNcXHJlbGF0aW9uYWwtbnljZmxpZ2h0cy5wbmcpDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+RnVuY2lvbmVzIELDoXNpY2FzIGRlIE1hbmVqbyBkZSBEYXRvczwvc3Bhbj4NCg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogc2t5IGJsdWU7Ij5TZWxlY3Q8L3NwYW4+DQpMYSBmdW5jacOzbiAqc2VsZWN0KiBzaXJ2ZSBwYXJhIHNlbGVjY2lvbmVzIGNvbHVtbmFzIGRlIHVuYSB0YWJsYSAoKmRhdGEgZnJhbWUqKS4NCmBgYHtyfQ0KZGYxIDwtIGZsaWdodHMgJT4lIHNlbGVjdChjYXJyaWVyLCBmbGlnaHQpDQpkZjIgPC0gZmxpZ2h0cyAlPiUgc2VsZWN0KGNhcnJpZXI6ZGlzdGFuY2UpDQpkZjMgPC0gZmxpZ2h0cyAlPiUgc2VsZWN0KC1jYXJyaWVyLCAtZmxpZ2h0KQ0KZGY0IDwtIGZsaWdodHMgJT4lIHNlbGVjdCgtY2FycmllciwgLWRpc3RhbmNlKSANCmRmNSA8LSBmbGlnaHRzICU+JSBzZWxlY3QoYWVyb2xpbmVhID0gY2FycmllcikgDQpkZjYgPC0gZmxpZ2h0cyAlPiUgcmVuYW1lKEFlcm9saW5lYSA9IGNhcnJpZXIpIA0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPkZpbHRlcjwvc3Bhbj4NCkxhIGZ1bmNpw7NuICpGaWx0ZXIqIHNpcnZlIHBhcmEgc2VsZWNjaW9uYXIgcmVuZ2xvbmVzIGRlIHVuYSB0YWJsYSAoKmRhdGEgZnJhbWUqKS4NCmBgYHtyfQ0KZGY3IDwtIGZsaWdodHMgJT4lIGZpbHRlcihkZXBfZGVsYXkgPj01MDApDQpkZjggPC0gZmxpZ2h0cyAlPiUgZmlsdGVyKGRlcF9kZWxheSA+PTUwMCwgZGVwX2RlbGF5IDw2MDApDQpkZjkgPC0gZmxpZ2h0cyAlPiUgc2xpY2UoMTAwMDoxMDk5KQ0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPkRpc3RpbmN0PC9zcGFuPg0KTGEgZnVuY2nDs24gKmRpc3RpbmN0KiBzaXJ2ZSBwYXJhIGVsaW1pYW5yIHJlbmdsb25lcyBkdXBsaWNhZG9zLg0KYGBge3J9DQpkZjEwIDwtIGRpc3RpbmN0KGZsaWdodHMpDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+TWFyZ2U8L3NwYW4+DQpMYSBmdW5jacOzbiAqbWVyZ2UqIHNpcnZlIHBhcmEganVudGFyIGJhc2VzIGRlIGRhdG9zLg0KYGBge3J9DQpiZGdyYW5kZSA8LSBtZXJnZShmbGlnaHRzLCBhaXJsaW5lcywgYnk9ImNhcnJpZXIiKQ0KYmRncmFuZGUgPC0gbWVyZ2UoYmRncmFuZGUscGxhbmVzLCBieT0idGFpbG51bSIpDQpgYGANCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5TaXR1YWNpw7NuIFByb2JsZW1hIDEuIEFjdGl2aWRhZCAxLiA8L3NwYW4+DQpUZW1hOiBiYXNlIGRlIGRhdG9zLCBzdXMgY2FtcG9zLCByZWdpc3Ryb3MsdGlwb3MgZGUgZGF0b3MgeSBsb3MgcmVzdWx0YWRvcyBkZXNjcmlwdGl2b3MgZGUgbGEgYmFzZSBkZSBkYXRvcy4NCg0KU2l0dWFjacOzbiBwcm9ibGVtYTogDQrCv0PDs21vIG1lam9yYXIgbGEgcG9zaWNpw7NuIGNvbXBldGl0aXZhIGRlIHVuYSBkZSBsYXMgYWVyb2zDrW5lYXMgbMOtZGVyZXMgZW4gbG9zIGFlcm9wdWVydG9zIGRlIE51ZXZhIFlvcms/DQoNCkluc3RydWNjaW9uZXM6DQoNCuKAoglQYXF1ZXRlcyAgcmVxdWVyaWRvcyBwYXJhIGxhIHByw6FjdGljYTogIHRpZHl2ZXJzZSwgbnlmbGlnaHRzMTMgDQogIEVsIHBhcXVldGUgdGlkeXZlcnNlIGluY2x1eWUgdmFyaWFzIGxpYnJlcsOtYXMgZW50cmUgZWxsYXMgZ2dwbG90MiwgZHBseXIsIHRpZHl2ZXJzZQ0KICBFbCBwYXF1ZXRlIG55ZmxpZ2h0czEzIGluY2x1eWUgdmFyaWFzIGJhc2VzIGRlIGRhdG9zIGVudHJlIGVsbGFzIGZsaWdodHMgDQrigKIgTGlicmVyw61hcyBxdWUgZGViZW4gZXN0YXIgaW5zdGFsYWRhczogZHBseXINCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQojTGxhbWFyIGEgbGFzIGxpYnJlcsOtYXMgcmVxdWVyaWRhcw0KbGlicmFyeShkcGx5cikNCiNMbGFtYXIgYSBsYSBsaWJyZXLDrWEgcXVlIHRpZW5lIGVsIGFyY2hpdm8gcmVxdWVyaWRvIHBhcmEgbGEgcHLDoWN0aWNhLg0KbGlicmFyeShueWNmbGlnaHRzMTMpDQojRWwgYXJjaGl2byB0aWVuZSA0IGJhc2VzIGRlIGRhdG9zLCBzb2xvIGxsYW1hciBhIGxvcyBkYXRvcyBmbGlnaHRzLg0KYGBgDQoNCiMjIzEuIENhcmdhciBlbiBtZW1vcmlhIGxhIHRhYmxhIGZsaWdodHMgeSBtb3N0cmFyIHN1IGNvbnRlbmlkbw0KYGBge3J9DQpkYXRhKGZsaWdodHMpDQpmbGlnaHRzDQpgYGANCg0KIyMjMi4JQ2FyZ2FyIGVuIG1lbW9yaWEgbGEgdGFibGEgZmxpZ2h0cyB5IG1vc3RyYXIgc3UgY29udGVuaWRvLiBDb25zdWx0YSBsYSBlc3RydWN0dXJhIGRlIGZsaWdodHMsIMK/Q3XDoWxlcyBzb24gbG9zIGNhbXBvcyB5IHN1cyB0aXBvcyBkZSBkYXRvcz8gIElkZW50aWZpY2EgbG9zIGRpZmVyZW50ZXMgdGlwb3MgZGUgZGF0b3MgeSBleHBsaWNhIGVuIHF1w6kgY29uc2lzdGUgY2FkYSB1bm8gZGUgZWxsb3MgIHkgY3XDoWwgZXMgbGEgZGlmZXJlbmNpYSBlbnRyZSB1bm8geSBvdHJvLCBpbmNsdXllbmRvIGxvcyBzaWd1aWVudGVzIHRpcG9zIGRlIGRhdG9zOiBpbnQsIGRibCwgY2hyLCBkdHRtDQoNCmBgYHtyfQ0Kc3RyKGZsaWdodHMpDQpgYGANCg0KIyMjMy4gwr9DdcOhbCBlcyBsYSBjbGFzZSBkZSBmbGlnaHRzPyB5IMK/UXXDqSBzaWduaWZpY2E/DQpgYGB7cn0NCmNsYXNzKGZsaWdodHMpDQpgYGANCiMjIzQuIMK/Q3XDoW50YXMgY29sdW1uYXMgdGllbmUgZmxpZ2h0cz8NCmBgYHtyfQ0KbmNvbChmbGlnaHRzKQ0KYGBgDQojIyM1LiDCv0N1w6FudG9zIHJlbmdsb25lcyB0aWVuZSBmbGlnaHRzPw0KDQpgYGB7cn0NCm5yb3coZmxpZ2h0cykNCmBgYA0KIyMjNi4gwr9DdcOhbCBlcyBsYSBkaW1lbnNpw7NuIGRlIGZsaWdodHM/DQoNCmBgYHtyfQ0KZGltKGZsaWdodHMpDQpgYGANCiMjIzcuIENvbnN1bHRhIGxhIHRhYmxhIGZsaWdodHMNCmBgYHtyfQ0KVmlldyhmbGlnaHRzKQ0KDQpgYGANCiMjIzguIEdlbmVyYSB1biBvdXRwdXQgZGUgbGEgdGFibGEgZmxpZ2h0cy4gVXRpbGl6YSBsYXMgZnVuY2lvbmVzIGhlYWQgeSB0YWlsLCDCv0N1w6FudG9zIHJlbmdsb25lcyBtdWVzdHJhbiBwb3IgZGVmZWN0byBjYWRhIGZ1bmNpw7NuPw0KYGBge3J9DQpoZWFkKGZsaWdodHMpDQp0YWlsKGZsaWdodHMpDQpgYGANCg0KIyMjOS4gQWhvcmEgbXVlc3RyYSBsb3MgcHJpbWVyb3MgNTAgcmVnaXN0cm9zIHkgbG9zIMO6bHRpbW9zIDIwLCDCv0PDs21vIGxvIGhhcsOtYXM/IA0KDQpgYGB7cn0NCmhlYWQoZmxpZ2h0cyw1MCkNCnRhaWwoZmxpZ2h0cywyMCkNCmBgYA0KDQojIyMxMC4gRW5jdWVudHJhIGxvcyByZXN1bHRhZG9zIGRlc2NyaXB0aXZvcyBkZSBsYXMgdmFyaWFibGVzIGVuIGxhIGJhc2UgZGUgZGF0b3MuIEVqZW1wbG86IHByb21lZGlvLCBtb2RhLCBtw61uaW1vLCBtw6F4aW1vLCBldGMuRnVuY2nDs246IHN1bW1hcnkuIA0KDQpgYGB7cn0NCnN1bW1hcnkoZmxpZ2h0cykNCmBgYA0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5TaXR1YWNpw7NuIFByb2JsZW1hIDEuIEFjdGl2aWRhZCAyLiA8L3NwYW4+DQoNCkZ1bmNpb25lcyBiw6FzaWNhcyBwYXJhIGxhIG1hbmlwdWxhY2nDs24gZGUgZGF0b3MuDQpUZW1hczogIERwbHlyIChmaWx0ZXIsIGFycmFuZ2UsIHNlbGVjdCwgcmVuYW1lLCAgbXV0YXRlLCBzdW1tYXJpemUsIGdyb3VwX2J5KSBpZi9lbHNlLCBzdWJzZXQsIGZvciAobG9vcHMpDQpTaXR1YWNpw7NuIHByb2JsZW1hOiDCv0PDs21vIG1lam9yYXIgbGEgcG9zaWNpw7NuIGNvbXBldGl0aXZhIGRlIHVuYSBkZSBsYXMgYWVyb2zDrW5lYXMgbMOtZGVyZXMgZW4gbG9zIGFlcm9wdWVydG9zIGRlIE51ZXZhIFlvcms/DQpJbnN0cnVjY2lvbmVzOg0KTGlicmVyw61hcyByZXF1ZXJpZGFzOiANCuKAoglQYXF1ZXRlcyAgcmVxdWVyaWRvcyBwYXJhIGxhIHByw6FjdGljYTogIHRpZHl2ZXJzZSwgbnlmbGlnaHRzMTMgDQogIEVsIHBhcXVldGUgdGlkeXZlcnNlIGluY2x1eWUgdmFyaWFzIGxpYnJlcsOtYXMgZW50cmUgZWxsYXMgZ2dwbG90MiwgZHBseXIsIHRpZHl2ZXJzZQ0KICBFbCBwYXF1ZXRlIG55ZmxpZ2h0czEzIGluY2x1eWUgdmFyaWFzIGJhc2VzIGRlIGRhdG9zIGVudHJlIGVsbGFzIGZsaWdodHMgDQrigKIgTGlicmVyw61hcyBxdWUgZGViZW4gZXN0YXIgaW5zdGFsYWRhczogIGdncGxvdDIsICBkcGx5ciwgdGlkeXZlcnNlDQoNCmBgYHtyfQ0KbGlicmFyeShueWNmbGlnaHRzMTMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoZHBseXIpDQpkYXRhKCJmbGlnaHRzIikNCmBgYA0KDQojIyMxLiBNb3N0cmFyIGxhIGJhc2UgZGUgZGF0b3MgZmxpZ2h0cyBwYXJhIHF1ZSBjb25vemNhcyBzdSBjb250ZW5pZG8NCg0KYGBge3J9DQpWaWV3KGZsaWdodHMpDQpgYGANCg0KDQojIyMyLglFbmN1ZW50cmEgbG9zIGRhdG9zIGRlc2NyaXB0aXZvcyBkZWwgZGF0YSBmcmFtZSBmbGlnaHRzLiBJZGVudGlmaWNhIGxhIG1lZGlhIGRlIGxhcyBkaXN0YW5jaWFzIHJlY29ycmlkYXMgZW4gbWlsbGFzLg0KYGBge3J9DQpzdW1tYXJ5KGZsaWdodHMpDQpgYGANCg0KDQojIyMzLglEZWZpbmUgdW4gY3JpdGVyaW8gcGFyYSBlbmNvbnRyYXIgbGFzIGFlcm9sw61uZWFzIHF1ZSBoYW4gcmVjb3JyaWRvIG3DoXMgZGlzdGFuY2lhIChlbiBtaWxsYXMpIHkgY3JlYSB1biBudWV2byBkYXRhIGZyYW1lIHF1ZSBmaWx0cmUgc29sYW1lbnRlIGEgbGFzIGFlb3Jsw61uZWFzIHF1ZSBoYW4gcmVjb3JyaWRhbyB1bmEgZGlzdGFuY2lhIHN1cGVyaW9yIGEgbGEgbWVkaWEsIHNlIGRlc2VhIHZlciBsb3MgY2FtcG9zIGNhcnJpZXIsIGRpc3RhbmNlLCBvcmlnaW4sIGRlc3QgZW4gZm9ybWEgZGVzY2VuZGVudGUgcG9yIGRpc3RhbmNlLg0KRWplbXBsbzogIGFlcm9sw61uZWFzIGNvbiBtaWxsYXMgcmVjb3JyaWRhcyBzdXBlcmlvcmVzIGEgbGEgbWVkaWEsIG9yZGVuYWRhcyBlbiBmb3JtYSBkZXNjZW5kZW50ZS4NCg0KDQpgYGB7cn0NCiNzZWxlY2Npb25hIGxhcyB2YXJpYWJsZXMgY2FycmllciwgZGlzdGFuY2UsIG9yaWdpbiwgZGVzdCBkZSBsYSB0YWJsYQ0KcmVzMDEgPC0gc2VsZWN0KGZsaWdodHMsIGNhcnJpZXIsIGRpc3RhbmNlLCBvcmlnaW4sIGRlc3QpDQoNCiNzZSBmaWx0cmEgbGFzIGFlcm9sw61uZWFzIGNvbiBtaWxsYXMgcmVjb3JyaWRhcyBzdXBlcmlvcmVzIGEgbGEgbWVkaWEgLSAxMDQwIA0KcmVzMDIgPC0gZmlsdGVyKHJlczAxLCBkaXN0YW5jZSA+MTA0MCkgDQoNCiNvcmRlbmEgZW4gZm9ybWEgZGVzY2VuZGVudGUgcG9yIGRpc3RhbmNpYSByZWNvcnJpZGEgDQpyZXMwMyA8LSBhcnJhbmdlKHJlczAyLCBkZXNjKGRpc3RhbmNlKSkNCmBgYA0KDQojIyM0LiBFbmN1ZW50cmEgbGEgc3VtYSB5IGxhIG1lZGlhIGRlIGxhcyBkaXN0YW5jaWFzIHJlY29ycmlkYXMgcG9yIGNhcnJpZXIsIGVsaW1pbmEgbG9zIE5B4oCZUyAgZSBpbnRlcnByZXRhIHF1ZSBzaWduaWZpY2EgbGEgc3VtYSB5IGxhIG1lZGlhIGRlIGxhcyBkaXN0YW5jaWFzIHJlY29ycmlkYXMuDQoNCmBgYHtyfQ0KI0FncnVwYXIgbG9zIGRhdG9zIHBvciBjYXJyaWVyLG9yaWdpbiwgZGVzdCB5IG9idGVuZXIgbGEgc3VtYSBhY3VtdWxhZGEgeSBsYSBtZWRpYSBkZSBsYXMgZGlzdGFuY2lhcyByZWNvcnJpZGFzIHBvciBjYXJyaWVyIGVsaW1pbmFuZG8gbG9zIE5BJ3MNCnJlczA0IDwtIHJlczAzICU+JSANCiAgZ3JvdXBfYnkoY2FycmllcixvcmlnaW4sZGVzdCkNCnN1bWRpc3RhbmNlIDwtIHN1bShyZXMwMyRkaXN0YW5jZSwgbj0gVFJVRSkNCmBgYA0KIyMjNS4gT3JkZW5hIGVuIGZvcm1hIGRlc2NlbmRlbnRlIHBvciBkaXN0YW5jaWEgcmVjb3JyaWRhDQpgYGB7cn0NCnJlczA1IDwtIGFycmFuZ2UocmVzMDQsY2FycmllcixzdW1kaXN0YW5jZSkNCmBgYA0KDQoNCiMjIzYuT2JzZXJ2YSB0dXMgcmVzdWx0YWRvcyBkZSBsYSDDumx0aW1hIHRhYmxhIHkgYWdyZWdhIHR1cyBpbnRlcnByZXRhY2lvbmVzIA0KDQojIyM3LklkZW50aWZpY2Egc2kgbGFzIGFlcm9sw61uZWFzIGzDrWRlcmVzIHNvbiBsYXMgbWlzbWFzIGVuIGxvcyB0cmVzIGFlcm9wdWVydG9zIGN1eW8gb3JpZ2VuIGVzIE51ZXZhIFlvcmsgKCBKb2huIEYuIEtlbm5lZHkgKEpGSyksIExhR3VhcmRpYSAoTEdBKSBhbmQgTmV3YXJrIExpYmVydHkgIChFV1IpICkuICANCkdlbmVyYSB1biBkYXRhIGZyYW1lICBwYXJhIGNhZGEgYWVyb3B1ZXJ0by4gDQpGdW5jaW9uZXM6IGZpbHRlcigpLCBhcnJhbmdlKCkgDQoNCmBgYHtyfQ0KSkZLID0gcmVzMDUgJT4lICANCiAgZmlsdGVyKG9yaWdpbiA9PSAiSkZLIikgICU+JQ0KICBhcnJhbmdlKGNhcnJpZXIsIGRlc2Moc3VtZGlzdGFuY2UpKQ0KTEdBID0gcmVzMDUgJT4lICANCiAgZmlsdGVyKG9yaWdpbiA9PSAiTEdBIikgICU+JQ0KICBhcnJhbmdlKGNhcnJpZXIsIGRlc2Moc3VtZGlzdGFuY2UpKQ0KRVdSID0gcmVzMDUgJT4lICANCiAgZmlsdGVyKG9yaWdpbiA9PSAiRVdSIikgICU+JQ0KICBhcnJhbmdlKGNhcnJpZXIsIGRlc2Moc3VtZGlzdGFuY2UpKQ0KYGBgDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlNpdHVhY2nDs24gUHJvYmxlbWEgMS4gQWN0aXZpZGFkIDMuIDwvc3Bhbj4NCg0KYGBge3J9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyMjIFIgTWFya2Rvd24NCg0KIyMjMS4JQ29uc3VsdGEgbGFzIHRhYmxhcyBwbGFuZXMgeSB3ZWF0aGVyIHBhcmEgcXVlIGNvbm96Y2FzIHN1IGNvbnRlbmlkby4NCmBgYHtyfQ0KdmlldyhwbGFuZXMpDQp2aWV3KHdlYXRoZXIpDQpgYGANCg0KIyMjMi4JU2UgbmVjZXNpdGEgc2FiZXIgZGUgY2FkYSB2dWVsbywgbGEgYWVyb2zDrW5lYSwgZWwgYWVyb3B1ZXJ0byBkZSBvcmlnZW4geSBlbCBhZXJvcHVlcnRvIGRlc3Rpbm8uDQpgYGB7cn0NCmFlcm9saW5lYXMgPC0gZmxpZ2h0cyAlPiUgDQogIHNlbGVjdChjYXJyaWVyLG9yaWdpbixkZXN0KQ0KYGBgDQoNCiMjIzMuCUVuIGxhIGNvbnN1bHRhIGFudGVyaW9yIHNlIG5lY2VzaXRhIGNvbm9jZXIgZWwgbm9tYnJlIGRlIGxhIGFlcm9sw61uZWEuDQpgYGB7cn0NCmFlcm9saW5lYXNfbm9tYnJlIDwtIGFlcm9saW5lYXMgJT4lDQogIGxlZnRfam9pbihhaXJsaW5lcywgYnkgPSAiY2FycmllciIpDQpgYGANCg0KIyMjNCBTZSBuZWNlc2l0YSBzYWJlciBsYSBjYW50aWRhZCBkZSB2dWVsb3MgcG9yIGNhZGEgZGVzdGlubyBwYXJhIGlkZW50aWZpY2FyIGN1w6FsZXMgc29uIGxvcyBkZXN0aW5vcyBtw6FzIGJ1c2NhZG9zLg0KYGBge3J9DQpjYW50X3Z1ZWxvcyA8LSBmbGlnaHRzICU+JSANCiAgc2VsZWN0KGNhcnJpZXIsIGRlc3QpICU+JSANCiAgY291bnQoY2FycmllcikNCiAgDQpgYGANCg0KIyMjNSBBZ3JlZ2FyIGVsIG5vbWJyZSBkZSBsYSBhZXJvbMOtbmVhIGEgbGEgdGFibGEgYW50ZXJpb3IuDQpgYGB7cn0NCmNhbnRfdnVlbG9zX25vbWJyZSA8LSBjYW50X3Z1ZWxvcyAlPiUNCiAgbGVmdF9qb2luKGFpcmxpbmVzLCBieSA9ICJjYXJyaWVyIikNCmBgYA0KDQojIyM2LiBTZSBuZWNlc2l0YSBjb25vY2VyIGxhcyBhZXJvbMOtbmVhcyAoY2xhdmUgeSBub21icmUpIHkgZGVzdGlub3MgcXVlIHZ1ZWxhbiBwb3IgbGEgTWHDsWFuYTogZGUgNiBhIDEyLCBUYXJkZTogZGUgMTIgYSAxOSAsIE5vY2hlOiBkZSAxOSBhIDI0IHkgTWFkcnVnYWRhIGRlIDI0IGEgNi4NCiMgQWdyZWdhIHVuIG51ZXZvIGNhbXBvIGEgbGEgdGFibGEgY29uIGVsIG5vbWJyZSBkZSBjbGFzX2hvcmFyaW8geSBhZ3JlZ2EsIG1hw7FhbmEsIHRhcmRlLCBub2NoZSB5IG1hZHJ1Z2FkYSBzZWfDum4gc2VhIGVsIGNhc28uDQpgYGB7cn0NCmNhcnJpZXJfaG9yYXJpbyA8LSBmbGlnaHRzICU+JQ0Kc2VsZWN0KGNhcnJpZXIsIGRlc3QsIHNjaGVkX2RlcF90aW1lKSAlPiUNCiAgbGVmdF9qb2luKGFpcmxpbmVzLCBieSA9ICJjYXJyaWVyIikNCg0KY2xhc3hob3JhPC0gbXV0YXRlKGNhcnJpZXJfaG9yYXJpbywgY2xhc19ob3JhcmlvID0gaWZlbHNlKHNjaGVkX2RlcF90aW1lICVpbiUgNjAwOjExNTksIk1hw7FhbmEiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc2NoZWRfZGVwX3RpbWUgJWluJSAxMjAwOjE4NTksIlRhcmRlIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNjaGVkX2RlcF90aW1lICVpbiUgMTkwMDoyNDAwLCJOb2NoZSIsICJNYWRydWdhZGEiKSkpKQ0KYGBgDQoNCiMjIzcuU2UgbmVjZXNpdGEgc2FiZXIgbGEgY2FudGlkYWQgZGUgdnVlbG9zIHBvciBhZXJvbMOtbmVhIHkgZGVzdGlubyBxdWUgaGF5IHBvciBsYSBNYcOxYW5hLCBUYXJkZSwgTm9jaGUgeSBNYWRydWdhZGEuDQpgYGB7cn0NCmNhbnRfY2xhc3hob3JhIDwtIGNsYXN4aG9yYSAlPiUgDQogICAgICAgICAgICAgZ3JvdXBfYnkoY2FycmllciwgZGVzdCxjbGFzX2hvcmFyaW8pICU+JSBjb3VudCgpDQoNCmBgYCAgICAgICAgICAgICAgICAgICAgICAgDQogDQojIyM4IFNlIG5lY2VzaXRhIHNhYmVyIGEgcXXDqSBkZXN0aW5vcyB2dWVsYSBsYSBhZXJvbMOtbmVhIEFtZXJpY2FuIEFpcmxpbmVzIEluYy4tQUEgIGR1cmFudGUgbGEgbWFkcnVnYWRhLiAgDQpgYGB7cn0NCmRlc3Rpbm9zX2FhIDwtIGNsYXN4aG9yYSAlPiUgDQogIHNlbGVjdChjYXJyaWVyLG5hbWUsIGRlc3QsY2xhc19ob3JhcmlvKSAlPiUgDQogIGZpbHRlcihjYXJyaWVyID09ICJBQSIgJiBjbGFzX2hvcmFyaW8gPT0gIk1hZHJ1Z2FkYSIpICU+JSANCiAgZ3JvdXBfYnkoY2FycmllcixuYW1lLCBkZXN0LGNsYXNfaG9yYXJpbykNCmBgYA0KDQojIyM5LiDCv1F1w6kgYXZpb25lcyB1dGlsaXphIGxhIGFlcm9sw61uZWEgQUE/IGFlcm9sw61uZWEsIHRpcG8sIG1vdG9yIHkgbsO6bWVybyBkZSBhc2llbnRvcyB5IMK/Q3XDoW50b3MgdnVlbG9zIHNlIGhhbiByZWFsaXphZG8gY29uIGNhZGEgdW5vPyBlbGltaW5hIGxvcyBOQSdzDQpgYGB7cn0NCmF2aW9uX2FhIDwtIGZsaWdodHMgJT4lDQogIGxlZnRfam9pbihwbGFuZXMsIGJ5ID0gInRhaWxudW0iKSAlPiUNCiAgc2VsZWN0KGNhcnJpZXIsIHR5cGUsIGVuZ2luZSwgc2VhdHMpICU+JQ0KICBmaWx0ZXIoY2FycmllciA9PSAiQUEiLCAhaXMubmEodHlwZSkpICU+JQ0KICBncm91cF9ieShjYXJyaWVyLHR5cGUsZW5naW5lLHNlYXRzKSAlPiUgDQogIGNvdW50KCkNCmBgYA0KTGEgYWVyb2zDrW5lYSBBbWVyaWNhbiBBaXJsaW5lcyAgdXRpbGl6YSBwcmluY2lwYWxtZW50ZSBhdmlvbmVzIGRlIHRpcG8gIkZpeGVkIHdpbmcgbXVsdGkgZW5naW5lIi4NCkxhIGFlcm9sw61uZWEgQW1lcmljYW4gQWlybGluZXMgdXRpbGl6YSBwcmluY2lwYWxtZW50ZSBtb3RvcmVzICJ0dXJibyBmYW4iIGVuIHN1cyBhdmlvbmVzLg0KTGEgYWVyb2zDrW5lYSBBbWVyaWNhbiBBaXJsaW5lcyB1dGlsaXphIGF2aW9uZXMgcXVlIHRpZW5lbiBkZXNkZSAyIGFzaWVudG9zICg0NjMpIGhhc3RhIDMzMCBhc2llbnRvcyAoNDUwKS4gIA0KDQojIEV2aWRlbmNpYSAxICANCg0KVGUgYWNhYmFzIGRlIGluY29ycG9yYXIgYSB1bmEgZW1wcmVzYSBjb25zdWx0b3JhIGVuIEludGVsaWdlbmNpYSBkZSBOZWdvY2lvcywNCmFjdHVhbG1lbnRlIGVzdMOhbiBicmluZGFuZG8gc2VydmljaW9zIGRlIGFuw6FsaXNpcyBwYXJhIGxhIGluZHVzdHJpYSBkZSBsYSBhdmlhY2nDs24geSBsZXMNCmludGVyZXNhIHRlbmVyIGEgbGEgYWVyb2zDrW5lYSBBbWVyaWNhbiBBaXJsaW5lcyBjb21vIGNsaWVudGUgeWEgcXVlIGVzIHVuYSBkZSBsYXMNCmFlcm9sw61uZWFzIGzDrWRlcmVzIGVuIGxvcyBhZXJvcHVlcnRvcyBkZSBOdWV2YSBZb3JrLCBtb3Rpdm8gcG9yIGVsIGN1w6FsIHRlIGhhbg0KY29udHJhdGFkby4gIA0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPkluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcsOtYXM8L3NwYW4+DQpgYGB7cn0NCiMgaW5zdGFsbC5wYWNrYWdlcygibnljZmxpZ2h0czEzIikNCmxpYnJhcnkobnljZmxpZ2h0czEzKQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+R3VhcmRhciBiYXNlcyBkZSBkYXRvczwvc3Bhbj4NCmBgYHtyfQ0KZmxpZ2h0cyA8LSBmbGlnaHRzDQp3ZWF0aGVyIDwtIHdlYXRoZXINCnBsYW5lcyA8LSBwbGFuZXMNCmFpcnBvcnRzIDwtIGFpcnBvcnRzDQphaXJsaW5lcyA8LSBhaXJsaW5lcw0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPlJlbGFjacOzbiBlbnRyZSBsYXMgYmFzZXMgZGUgZGF0b3M8L3NwYW4+DQohW10oQzpcXFVzZXJzXFxIUFxcRG93bmxvYWRzXFxyZWxhdGlvbmFsLW55Y2ZsaWdodHMucG5nKSAgDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+MS4gRGF0YSBGcmFtZXMgZSBJZGVudGlmaWNhY2nDs24gZGUgdGlwbyBkZSBkYXRvczwvc3Bhbj4NCmBgYHtyfQ0KIyMgRGF0b3MgZGUgV2VhdGhlcg0Kd2VhdGhlcg0KIyMgRGF0b3MgZGUgUGxhbmVzDQpwbGFuZXMNCiMjIERhdG9zIGRlIEFpcnBvcnRzDQphaXJwb3J0cw0KIyMgRGF0b3MgZGUgYWlybGluZXMNCmFpcmxpbmVzDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+Mi4gQ2FyZ2FyIGVuIG1lbW9yaWEgbGEgdGFibGEgImZsaWdodHMiIHkgbW9zdHJhciBzdSBjb250ZW5pZG88L3NwYW4+DQpgYGB7cn0NCiMjIExhIGNhcmdhIGEgbWVtb3JpYSBzZSBoaXpvIGVuIGVsIHBhc28gYW50ZXJpb3INCmZsaWdodHMNCmBgYA0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPjMuIENvbnN1bHRhIGxhIGVzdHJ1Y3R1cmEgZGUgImZsaWdodHMiPC9zcGFuPg0KYGBge3J9DQpzdHIoZmxpZ2h0cykNCiMgaW50OiBlbnRlcm8gKG5vIHRpZW5lIGRlY2ltYWxlcykuIFNlIHV0aWxpemEgcGFyYSBhbG1hY2VuYXIgdmFsb3JlcyBudW3DqXJpY29zIHNpbiBkZWNpbWFsZXMsIGNvbW8gbGEgY2FudGlkYWQgZGUgcGFzYWplcm9zIG8gZWwgbsO6bWVybyBkZSB2dWVsb3MuDQojIGRibDogU2UgdXNhIHBhcmEgYWxtYWNlbmFyIG7Dum1lcm9zIGNvbiBkZWNpbWFsZXMsIGNvbW8gZGlzdGFuY2lhcyBvIHByZWNpb3MuDQojIG51bTogbnVtw6lyaWNvICh0aWVuZSBkZWNpbWFsZXMpIHBlc28NCiMgY2hyOiBjYXJhY3RlciAobGV0cmFzKS4gU2UgdXNhIHBhcmEgYWxtYWNlbmFyIHRleHRvLCBjb21vIG5vbWJyZXMgbyBwYWxhYnJhcy4gIA0KIyBEYXRlOiBmZWNoYSAoZW4gUiB2YSBhw7FvLW1lcy1kw61hKQ0KIyBQT1NJWGN0OiBmb3JtYXRvIGZlY2hhIHkgaG9yYS4gRXMgdW4gdGlwbyBkZSBkYXRvIHF1ZSByZXByZXNlbnRhIHVuYSBmZWNoYSB5IGhvcmEgZXNwZWPDrWZpY2EuIFNlIHV0aWxpemEgcGFyYSBhbG1hY2VuYXIgaW5mb3JtYWNpw7NuIHRlbXBvcmFsLCBjb21vIGxhIGZlY2hhIGRlIHVuIHZ1ZWxvIG8gbGEgaG9yYSBkZSBzYWxpZGEuDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+NC4gwr9DdcOhbCBlcyBsYSBjbGFzZSBkZSAiZmxpZ2h0cyIgeSBxdcOpIHNpZ25pZmljYT88L3NwYW4+DQpgYGB7cn0NCmNsYXNzKGZsaWdodHMpDQpjbGFzcw0KDQojIExhcyA1IGNsYXNlcyBkZSBvYmpldG9zIHNvbjoNCiMgMS4gbnVtZXJpYzogbsO6bWVybyByZWFsIG8gZGVjaW1hbGVzDQojIDIuIGludGVnZXI6IG7Dum1lcm9zIGVudGVyb3MNCiMgMy4gY29tcGxleDogbsO6bWVyb3MgY29tcGxlam9zDQojIDQuIGNoYXJhY3RlcjogY2FyYWN0ZXJlcywgbGV0cmFzIG8gcGFsYWJyYXMNCiMgNS4gbG9naWNhbDogVFJVRSBvIEZBTFNFDQoNCiMgTGFzIDQgY2xhc2VzIGRlIG9iamV0b3MgY29tcHVlc3RvcyBzb246IA0KDQojIDEuIGxpc3Q6IGxpc3RhDQojIDIuIG1hdHJpeDogbWF0cml6IChlcyB0b2RvIGxvIG1pc21vKQ0KIyAzLiBhcnJheTogY29sZWNjacOzbiBkZSBvYmpldG9zDQojIDQuIGRhdGEuZnJhbWU6IGJhc2UgZGUgZGF0b3MgKGVzIG1lemNsYWRvKQ0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPjUuIMK/Q3XDoW50YXMgY29sdW1uYXMgeSByZW5nbG9uZXMgdGllbmUgImZsaWdodHMiIMK/IEN1w6FsIGVzIHN1IGRpbWVuc2nDs24/IDwvc3Bhbj4NCmBgYHtyfQ0KIyBOw7ptZXJvIGRlIGNvbHVtbmFzDQpuY29sKGZsaWdodHMpDQojIE7Dum1lcm8gZGUgcmVuZ2xvbmVzDQpucm93KGZsaWdodHMpDQojIERpbWVuc2nDs24NCmRpbShmbGlnaHRzKQ0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPjYuIE11ZXN0cmEgbG9zIHByaW1lcm9zIDYgcmVuZ2xvbmVzIGRlICJmbGlnaHRzIiwgdGFtYmnDqW4gbG9zIMO6bHRpbW9zIDYuIDwvc3Bhbj4NCmBgYHtyfQ0KaGVhZChmbGlnaHRzKQ0KdGFpbChmbGlnaHRzKQ0KIyBTaSBxdWlzaWVyYW1vcyA3IHJlbmdsb25lczogaGVhZChmbGlnaHRzKQ0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPjcuIE11ZXN0cmEgbG9zIGVzdGFkw61zdGljb3MgZGVzY3JpcHRpdm9zIGRlICJmbGlnaHRzIjwvc3Bhbj4NCmBgYHtyfQ0Kc3VtbWFyeShmbGlnaHRzKQ0KYGBgICANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+Ny4xLiBEaXN0YW5jaWEgbWVkaWEgcmVjb3JyaWRhIGVuIG1pbGxhcy48L3NwYW4+ICANCmBgYHtyfQ0Kc3VtbWFyeShmbGlnaHRzJGRpc3RhbmNlKQ0KYGBgICANClBvZGVtb3MgdmVyIHF1ZSBsYSBkaXN0YW5jaWEgbWVkaWEgZW4gbWlsbGFzIGVzIGRlIDEwNDAgIA0KDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPjcuMi4gQWVyb2zDrW5lYXMgY29uIG1pbGxhcyByZWNvcnJpZGFzIHN1cGVyaW9yZXMgYSBsYSBtZWRpYSwgb3JkZW5hZGFzIGVuIGZvcm1hIGRlc2NlbmRlbnRlLjwvc3Bhbj4gIA0KDQpgYGB7cn0NCm1lZGlhX2Rpc3RhbmNpYSA8LSBtZWFuKGZsaWdodHMkZGlzdGFuY2UsIG5hLnJtID0gVFJVRSkNCmFlcm9saW5lYXNfdG9wIDwtIGZsaWdodHMgJT4lDQogIGZpbHRlcihkaXN0YW5jZSA+IG1lZGlhX2Rpc3RhbmNpYSkgJT4lDQogIHNlbGVjdChjYXJyaWVyLCBkaXN0YW5jZSwgb3JpZ2luLCBkZXN0KSAlPiUNCiAgYXJyYW5nZShkZXNjKGRpc3RhbmNlKSkNCnByaW50KGFlcm9saW5lYXNfdG9wKQ0KYGBgDQojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBza3kgYmx1ZTsiPjcuMy4gRW5jdWVudHJhIGxhIHN1bWEgeSBsYSBtZWRpYSBkZSBsYXMgZGlzdGFuY2lhcyByZWNvcnJpZGFzIHBvciBjYXJyaWVyPC9zcGFuPiAgDQpgYGB7cn0NCmRpc3RhbmNpYV9hZXJvbGluZWEgPC0gZmxpZ2h0cyAlPiUNCiAgZmlsdGVyKCFpcy5uYShkaXN0YW5jZSkpICU+JQ0KICBncm91cF9ieShjYXJyaWVyKSAlPiUNCiAgc3VtbWFyaXNlKA0KICAgIHN1bWFfZGlzdGFuY2lhID0gc3VtKGRpc3RhbmNlKSwNCiAgICBtZWRpYV9kaXN0YW5jaWEgPSBtZWFuKGRpc3RhbmNlLCBuYS5ybSA9IFRSVUUpDQogICkgJT4lDQogIGFycmFuZ2UoZGVzYyhzdW1hX2Rpc3RhbmNpYSkpDQpwcmludChkaXN0YW5jaWFfYWVyb2xpbmVhKQ0KYGBgDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+OC4gSWRlbnRpZmljYSBzaSBsYXMgYWVyb2zDrW5lYXMgbMOtZGVyZXMgc29uIGxhcyBtaXNtYXMgZW4gbG9zIHRyZXMgYWVyb3B1ZXJ0b3M8L3NwYW4+DQpgYGB7cn0NCiMgRnVuY2nDs24gcGFyYSBjcmVhciB1biBkYXRhIGZyYW1lIHBhcmEgdW4gYWVyb3B1ZXJ0bw0KYWVyb3B1ZXJ0b19kZiA8LSBmdW5jdGlvbihhZXJvcHVlcnRvKSB7DQogIGZsaWdodHMgJT4lDQogICAgZmlsdGVyKG9yaWdpbiA9PSBhZXJvcHVlcnRvKSAlPiUNCiAgICBmaWx0ZXIoIWlzLm5hKGRpc3RhbmNlKSkgJT4lDQogICAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogICAgc3VtbWFyaXNlKA0KICAgICAgc3VtYV9kaXN0YW5jaWEgPSBzdW0oZGlzdGFuY2UpLA0KICAgICAgbWVkaWFfZGlzdGFuY2lhID0gbWVhbihkaXN0YW5jZSwgbmEucm0gPSBUUlVFKQ0KICAgICkgJT4lDQogICAgYXJyYW5nZShkZXNjKHN1bWFfZGlzdGFuY2lhKSkNCn0NCg0KIyBEYXRhIGZyYW1lcyBwYXJhIGNhZGEgYWVyb3B1ZXJ0bw0KamZrX2RmIDwtIGFlcm9wdWVydG9fZGYoIkpGSyIpDQpsZ2FfZGYgPC0gYWVyb3B1ZXJ0b19kZigiTEdBIikNCmV3cl9kZiA8LSBhZXJvcHVlcnRvX2RmKCJFV1IiKQ0KDQojIE1vc3RyYXIgbG9zIGRhdGEgZnJhbWVzDQpwcmludChqZmtfZGYpDQpwcmludChsZ2FfZGYpDQpwcmludChld3JfZGYpDQpgYGANCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IHNreSBibHVlOyI+SW50ZXJwcmV0YWNpw7NuPC9zcGFuPiANCkFtZXJpY2FuIEFpcmxpbmVzIHRpZW5lIHVuYSBhbHRhIHN1bWEgZGUgZGlzdGFuY2lhIHJlY29ycmlkYSwgbG8gcXVlIGluZGljYSBxdWUgZXMgdW5hIGFlcm9sw61uZWEgY29uIHVuYSBhbXBsaWEgcmVkIGRlIHJ1dGFzIHkgdW4gZ3JhbiB2b2x1bWVuIGRlIHBhc2FqZXJvcy4NCkxhIG1lZGlhIGRlIGxhIGRpc3RhbmNpYSByZWNvcnJpZGEgcG9yIEFBIGVzIHN1cGVyaW9yIGEgbGEgbWVkaWEgZGUgb3RyYXMgYWVyb2zDrW5lYXMsIGxvIHF1ZSBpbmRpY2EgcXVlIHN1cyB2dWVsb3Mgc29uIGdlbmVyYWxtZW50ZSBtw6FzIGxhcmdvcy4NCkVzdG9zIGRhdG9zIHBvZHLDrWFuIHNlciByZWxldmFudGVzIHBhcmEgbG9zIGludmVyc29yZXMgcXVlIGJ1c2NhbiB1bmEgYWVyb2zDrW5lYSBjb24gdW5hIGZ1ZXJ0ZSBwcmVzZW5jaWEgZW4gZWwgbWVyY2FkbyB5IHVuIGhpc3RvcmlhbCBkZSByZW50YWJpbGlkYWQuICAgIA0KIVtdKEM6XFxVc2Vyc1xcSFBcXERlc2t0b3BcXEJMT1FVRVxcQWlycGxhbmUtMS5wbmcpICANCg0KIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogc2t5IGJsdWU7Ij5Db25jbHVzacOzbjwvc3Bhbj4NCkVuIGVzdGUgdHJhYmFqbyBwdWRpbW9zIHV0aWxpemFyIGxhcyBmdW5jaW9uZXMgbcOhcyBjb211bmVzIGRlbCBhbsOhbGlzaXMgZXhwbG90YXJvdGlvLCBlbCBjdWFsIGVzIGVsIHByaW1lciBwYXNvIHBhcmEgY3VhbHF1aWVyIHRyYWJham8gZGUgbWFuaXB1bGFjacOzbiBkZSBkYXRvcywgaGljaW1vcyB1c28gZGUgZGlzdGludGFzIGhlcnJhbWllbnRhcyBwYXJhIGFuYWxpemFyIG1lZGlhcywgZGlzdGFuY2lhcyBtYXlvcmVzIHkgbWVub3JlcyB5IGFzw60gZmluYWxtZW50ZSBhbmFsaXphciBsb3MgYmVuZWZpY2lvcyBkZSB0ZW5lciBhIEFtZXJpY2FuIEFpcmxpbmVzIGNvbW8gbnVldm8gY2xpZW50ZSwgZGVzY3VicmllbmRvIHN1IGdyYW4gcG90ZW5jaWFsIGVuIG3Dumx0aXBsZXMgYWVyb3B1ZXJ0b3MgY29tbyBhZXJvbGluZWEgbMOtZGVyLiAgDQoNCiMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IGJsdWU7Ij7Cv1BvciBxdcOpIHNlIHJldHJhc2FuIGxvcyB2dWVsb3M/PC9zcGFuPg0KDQpTZWfDum4gRGVzdGlubzogIA0KDQoxLiAqKkFOQyoqIHRpZW5lIGVsIHJldHJhc28gcG9yY2VudHVhbCBtw6FzIGFsdG8gY29uICoqNzUlKiogeSBjb24gcmV0cmFkbyBwcm9tZWRpbyBkZSBtaW51dG9zIGRlICoqMTIuODhtaW4qKg0KMi4gKipYTkEqKiB0aWVuZSBkZSBsb3MgcmV0cmFzb3MgcG9yY2VudHVhbCBtw6FzIGJham9zIGNvbiAqKjI1LjQ4JSoqIHkgY29uIHJldHJhZG8gcHJvbWVkaW8gZGUgbWludXRvcyBkZSAqKjYuNG1pbioqDQpgYGB7cn0NCnN1bW1hcnlfZGVsYXkgPC0gZmxpZ2h0cyAlPiUNCiAgZ3JvdXBfYnkoZGVzdCkgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwgIA0KICAgIHRvdGFsX2ZsaWdodHMgPSBuKCksICAgICAgICAgICAgICAgICAgICAgICANCiAgICB0b3RhbF9kZWxheWVkX2ZsaWdodHMgPSBzdW0oZGVwX2RlbGF5ID4gMCwgbmEucm0gPSBUUlVFKSwNCiAgICBwZXJjX2RlbGF5ZWRfZmxpZ2h0cyA9IHsNCiAgICAgIHRvdGFsX2RlbGF5ZWRfZmxpZ2h0cyAvIHRvdGFsX2ZsaWdodHMgKiAxMDANCiAgICB9DQogICkgJT4lDQphcnJhbmdlKGRlc2MocGVyY19kZWxheWVkX2ZsaWdodHMpKQ0Kc3VtbWFyeV9kZWxheQ0KYGBgDQpgYGB7cn0NCiMgRmlsdHJhciBsb3MgMTAgYWVyb3B1ZXJ0b3MgY29uIG1heW9yIHJldHJhc28NCnRvcF8xMF9haXJwb3J0cyA8LSBzdW1tYXJ5X2RlbGF5ICU+JQ0KICBhcnJhbmdlKGRlc2MoYXZnX2RlbGF5KSkgJT4lDQogIGhlYWQoMTApDQoNCiMgQ3JlYXIgdW4gZ3LDoWZpY28gZGUgYmFycmFzDQpnZ3Bsb3QodG9wXzEwX2FpcnBvcnRzLCBhZXMoeCA9IGRlc3QsIHkgPSBhdmdfZGVsYXkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnModGl0bGUgPSAiVG9wIDEwIGFlcm9wdWVydG9zIGNvbiBtYXlvciByZXRyYXNvIHByb21lZGlvIiwNCiAgICAgICB4ID0gIkFlcm9wdWVydG8gZGUgZGVzdGlubyIsDQogICAgICAgeSA9ICJSZXRyYXNvIHByb21lZGlvIChtaW51dG9zKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANClNlZ8O6biBIb3JhIGRlIFBhcnRpZGE6ICANCg0KMS4gQSBsYSAqKmhvcmEgMTc6MDAqKiwgZWwgcmV0cmFzbyBwcm9tZWRpbyBlcyBkZSAqKjIxLjEwIG1pbnV0b3MqKiB5IGVsIHBvcmNlbnRhamUgZGUgdnVlbG9zIHJldHJhc2Fkb3MgZXMgZGVsICoqNDkuNjclKiouICAgDQoyLiBBIGxhICoqaG9yYSAxOTowMCoqLCBlbCByZXRyYXNvIHByb21lZGlvIGVuIG1pbnV0b3MgYXVtZW50YSBoYXN0YSAqKjI0Ljc4KiogeSBlbCBwb3JjZW50YWplIGEgKio1MC41NSUqKi4gU2luIGVtYmFyZ28gbWVub3MgY2FudGlkYWQgZGUgdnVlbG9zIHNlIHZlbiBhZmVjdGFkb3MuICANCjMuIEEgbGEgKipob3JhIDY6MDBhbSoqLCBlbCByZXRyYXNvIHByb21lZGlvIGVzIGVsIG3DoXMgYmFqbywgc2llbmRvIGVuIG1pbnV0b3MgZGUgKioxLjY0KiogeSBlbiBwb3JjZW50YWplIGVzIGRlICoqMjAuOTIlKiouICAgDQpgYGB7cn0NCnJldHJhc29faG9yYXMgPC0gZmxpZ2h0cyAlPiUNCiAgZ3JvdXBfYnkoaG91cikgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwgIA0KICAgIHRvdGFsX2ZsaWdodHMgPSBuKCksICAgICAgICAgICAgICAgICAgICAgICANCiAgICB0b3RhbF9kZWxheWVkX2ZsaWdodHMgPSBzdW0oZGVwX2RlbGF5ID4gMCwgbmEucm0gPSBUUlVFKSwNCiAgICBwZXJjX2RlbGF5ZWRfZmxpZ2h0cyA9IHsNCiAgICAgIHRvdGFsX2RlbGF5ZWRfZmxpZ2h0cyAvIHRvdGFsX2ZsaWdodHMgKiAxMDANCiAgICB9DQogICkgJT4lDQphcnJhbmdlKGRlc2ModG90YWxfZGVsYXllZF9mbGlnaHRzKSkNCnJldHJhc29faG9yYXMNCmBgYA0KYGBge3J9DQojIENyZWEgdW4gZ3LDoWZpY28gZGUgYmFycmFzIHBhcmEgbW9zdHJhciBlbCBuw7ptZXJvIHRvdGFsIGRlIHZ1ZWxvcyByZXRyYXNhZG9zIHBvciBob3JhDQpnZ3Bsb3QocmV0cmFzb19ob3JhcywgYWVzKHggPSBob3VyLCB5ID0gdG90YWxfZGVsYXllZF9mbGlnaHRzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJza3libHVlIikgKw0KICBsYWJzKHRpdGxlID0gIlRvdGFsIGRlIHZ1ZWxvcyByZXRyYXNhZG9zIHBvciBob3JhIiwNCiAgICAgICB4ID0gIkhvcmEgZGVsIGRpYSIsDQogICAgICAgeSA9ICJUb3RhbCBkZSB2dWVsb3MgcmV0cmFzYWRvcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCiMgQ3JlYSB1biBncsOhZmljbyBkZSBsw61uZWFzIHBhcmEgbW9zdHJhciBlbCBwb3JjZW50YWplIGRlIHZ1ZWxvcyByZXRyYXNhZG9zIHBvciBob3JhDQpnZ3Bsb3QocmV0cmFzb19ob3JhcywgYWVzKHggPSBob3VyLCB5ID0gcGVyY19kZWxheWVkX2ZsaWdodHMpKSArDQogIGdlb21fbGluZShjb2xvciA9ICJyZWQiKSArDQogIGxhYnModGl0bGUgPSAiUG9yY2VudGFqZSBkZSB2dWVsb3MgcmV0cmFzYWRvcyBwb3IgaG9yYSIsDQogICAgICAgeCA9ICJIb3JhIGRlbCBkaWEiLA0KICAgICAgIHkgPSAiUG9yY2VudGFqZSBkZSB2dWVsb3MgcmV0cmFzYWRvcyAoJSkiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpSZXRyYXNvIHNlZ8O6biBBZXJvbMOtbmVhOiAgDQoNCjEuICoqV04qKiB0aWVuZSBlbCByZXRyYXNvIHBvcmNlbnR1YWwgbcOhcyBhbHRvIGRlICoqNTMuNDIqKi4gICANCjIuICoqRkwqKiB0aWVuZSBlbCBzZWd1bmRvIHJldHJhc28gcG9yY2VudHVhbCBtw6FzIGFsdG8gZGUgKio1MC43MyoqLiAgIA0KMy4gKipVUyoqIHkgKipIQSoqIHRpZW5lbiBiYWpvcyBwb3JjZW50YWplcyBkZSByZXRyYXNvcyAoKioxMC41NSoqIHkgKioxMi41OCBtaW51dG9zKiogcmVzcGVjdGl2YW1lbnRlKSBwZXJvIHN1cyBwb3JjZW50YWplcyBkZSB2dWVsb3MgcmV0cmFzYWRvcyBzb24gZGUgbG9zIG3DoXMgYmFqb3MgKCoqMjMuMjUlKiogeSAqKjIwLjE4JSoqIHJlc3BlY3RpdmFtZW50ZSkuICANCjQuICoqQW1lcmljYW4gQWlybGluZXMqKiBzZSBlbmN1ZW50cmEgZW50cmUgbGFzIGFlcm9saW5lYXMgY29uIG1lbm9yIHBvcmNlbnRhamUgZGUgcmV0cmFzbw0KYGBge3J9DQp0b3BfYm90dG9tXzMgPC0gZmxpZ2h0cyAlPiUNCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogIHN1bW1hcmlzZShhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIHRvdGFsX2ZsaWdodHMgPSBuKCksDQogICAgICAgICAgICB0b3RhbF9kZWxheWVkX2ZsaWdodHMgPSBzdW0oZGVwX2RlbGF5ID4gMCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIHBlcmNfZGVsYXllZF9mbGlnaHRzID0gdG90YWxfZGVsYXllZF9mbGlnaHRzIC8gdG90YWxfZmxpZ2h0cyAqIDEwMCkgJT4lDQogIGFycmFuZ2UoZGVzYyhwZXJjX2RlbGF5ZWRfZmxpZ2h0cykpDQoNCnRvcF9ib3R0b21fMw0KYGBgDQpgYGB7cn0NCnRpdHVsbyA8LSAiVG9wIDMgQWVyb2xpbmVhcyAoUmV0cmFzbyBQcm9tZWRpbykiDQpnZ3Bsb3QodG9wX2JvdHRvbV8zLCBhZXMoeCA9IGNhcnJpZXIsIHkgPSBwZXJjX2RlbGF5ZWRfZmxpZ2h0cykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9IHRpdHVsbywNCiAgICAgICB4ID0gIkFlcm9saW5lYSIsDQogICAgICAgeSA9ICJSZXRyYXNvIHByb21lZGlvIChtaW51dG9zKSIsDQogICAgICAgIyBSb3RhdGUgeC1heGlzIGxhYmVscyBmb3IgYmV0dGVyIHJlYWRhYmlsaXR5DQogICAgICAgeC50ZXh0LmFuZ2xlID0gNDUNCiAgKSArDQogIHRoZW1lX21pbmltYWwoKQ0KYGBgDQpSZXRyYXNvIHNlZ8O6biBNb2RlbG8gZGUgQXZpw7NuOiAgDQoxLiBQb2RlbW9zIHZlciBxdWUgbG9zIG1vZGVsb3MgZGUgYXZpw7NuICoqTjI1OEpCLCBOMjI4SkIgeSBOMTU5ODAqKiBzb24gbG9zIHF1ZSB0aWVuZW4gbWF5b3IgcG9yY2VudGFqZSBkZSByZXRyYXNvIHNpZW5kbyAqKjQzJSwgNDIlIHkgNTAlKiogcmVzcGVjdGl2YW1lbnRlLg0KMi4gTG9zIG1vZGVsb3MgKipOMzY0TkIsIE4zNzQxOSB5IE4zNzU1RCoqIHNvbiBsb3MgcXVlIHRpZW5lbiBtZW5vciBjYW50aWRhZCBkZSB2dWVsb3MgYWZlY3RhZG9zICoqc2llbmRvIDQ2IGxvcyB2dWVsb3MgYWZlY3RhZG9zKiogKHJldHJhc2Fkb3MpLCBzaW4gZW1iYXJnbyBsb3MgcG9yY2VudGFqZSBzaWd1ZW4gYWx0b3MuICANCg0KYGBge3J9DQpyZXRyYXNvX21vZGVsIDwtIGZsaWdodHMgJT4lDQogIGdyb3VwX2J5KHRhaWxudW0pICU+JQ0KICBzdW1tYXJpemUoDQogICAgYXZnX2RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksICANCiAgICB0b3RhbF9mbGlnaHRzID0gbigpLCAgICAgICAgICAgICAgICAgICAgICAgDQogICAgdG90YWxfZGVsYXllZF9mbGlnaHRzID0gc3VtKGRlcF9kZWxheSA+IDAsIG5hLnJtID0gVFJVRSksDQogICAgcGVyY19kZWxheWVkX2ZsaWdodHMgPSB7DQogICAgICB0b3RhbF9kZWxheWVkX2ZsaWdodHMgLyB0b3RhbF9mbGlnaHRzICogMTAwDQogICAgfQ0KICApICU+JQ0KYXJyYW5nZShkZXNjKHRvdGFsX2RlbGF5ZWRfZmxpZ2h0cykpDQpyZXRyYXNvX21vZGVsDQpgYGANCmBgYHtyfQ0KdG9wXzVfbW9kZWxvcyA8LSByZXRyYXNvX21vZGVsICU+JQ0KICBoZWFkKDUpDQoNCiMgQ3JlYXIgdW4gZ3LDoWZpY28gZGUgYmFycmFzDQpnZ3Bsb3QodG9wXzVfbW9kZWxvcywgYWVzKHggPSB0YWlsbnVtLCB5ID0gdG90YWxfZGVsYXllZF9mbGlnaHRzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gdGl0dWxvLA0KICAgICAgIHggPSAiTW9kZWxvIGRlIGF2aW9uICh0YWlsIG51bWJlcikiLA0KICAgICAgIHkgPSAiQ2FudGlkYWQgZGUgdnVlbG9zIChSZXRyYXNhZG9zKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANClJldHJhc28gc2Vnw7puIEh1bWVkYWQ6IChObyB0YW4gc2lnbmlmYWNhbnRlKSAgICAgIA0KRXN0b3MgcHVlZGVuIHZlcnNlIGFmZWN0YWRvcyBkZXBlbmRpZW5kbyBkZTogIA0KVGlwbyBkZSBhZXJvbmF2ZTogQWxndW5vcyBhdmlvbmVzIHNvbiBtw6FzIHNlbnNpYmxlcyBhIGxhIGh1bWVkYWQgcXVlIG90cm9zLiBMb3MgYXZpb25lcyBtw6FzIHBlcXVlw7FvcyBvIGNvbiBtb3RvcmVzIG3DoXMgYW50aWd1b3MgcHVlZGVuIHZlcnNlIG3DoXMgYWZlY3RhZG9zIHBvciBsYSBodW1lZGFkIGFsdGEuICANCkNvbmRpY2lvbmVzIGNsaW3DoXRpY2FzOiBMYSB2aXNpYmlsaWRhZCwgbGEgdGVtcGVyYXR1cmEgeSBsYSB2ZWxvY2lkYWQgZGVsIHZpZW50byB0YW1iacOpbiBpbmZsdXllbiBlbiBsYSBkZWNpc2nDs24gZGUgZGVzcGVnYXIgbyBuby4gTGEgaHVtZWRhZCBhbHRhIGNvbWJpbmFkYSBjb24gb3Ryb3MgZmFjdG9yZXMgY2xpbcOhdGljb3MgYWR2ZXJzb3MgYXVtZW50YSBsYSBwcm9iYWJpbGlkYWQgZGUgdW4gcmV0cmFzbyBvIGNhbmNlbGFjacOzbi4gIA0KKipIdW1lZGFkIChodW1pZCk6KiouICANCg0KLUh1bWVkYWQgYmFqYSAobWVub3MgZGVsIDQwJSk6IEVuIGdlbmVyYWwsIG5vIGhheSBwcm9ibGVtYXMgcGFyYSB2b2xhci4gICAgDQotSHVtZWRhZCBtb2RlcmFkYSAoNDAlLTcwJSk6IExhIG1heW9yw61hIGRlIGxvcyBhdmlvbmVzIHB1ZWRlbiB2b2xhciBzaW4gcHJvYmxlbWFzLiBBbGd1bmFzIGFlcm9sw61uZWFzIHB1ZWRlbiB0ZW5lciByZXN0cmljY2lvbmVzIHBhcmEgY2llcnRvcyB0aXBvcyBkZSBhZXJvbmF2ZXMgbyBydXRhcy4gICAgDQotSHVtZWRhZCBhbHRhIChtw6FzIGRlbCA3MCUpOiBBdW1lbnRhIGVsIHJpZXNnbyBkZSByZXRyYXNvcyBvIGNhbmNlbGFjaW9uZXMuIExhcyBhZXJvbMOtbmVhcyBwdWVkZW4gdGVuZXIgcmVzdHJpY2Npb25lcyBtw6FzIHNldmVyYXMgcGFyYSB2b2xhciBlbiBlc3RhcyBjb25kaWNpb25lcy4gICAgDQoNClBvZGVtb3MgdmVyIHF1ZSBsYSBtYXlvciBjYW50aWRhZCBkZSB2dWVsb3MgcmV0cmFzYWRvcyBwcmVzZW50YWJhbiB1bmEgaHVtZWRhZCBkZSAqKjEwMCoqLCBkYW5kbyBlbiBwcm9tZWRpbyBkZSBtaW51dG9zIHVuIHJldHJhc28gZGUgKioyMy4xNW1pbioqLiAgICANClkgcG9yIG90cm8gbGFkbyBjdWFuZG8gbGEgaHVtZWRhZCBlcyBkZSAqKjYwKiosIGVsIHByb21lZGlvIGRlIHJldHJhc28gZGUgbWludXRvcyBlcyBkZSAqKjQuNThtaW51dG9zKiouICAgIA0KDQoNCmBgYHtyfQ0KI1ByaW1lcm8gdW5pcmVtb3MgbGEgYmFzZSBkZSBkYXRvcyBhIHdlYXRoZXIgdXNhbmRvIE1lcmdlDQpiYXNlZXZpZGVuY2lhIDwtIG1lcmdlKGZsaWdodHMsd2VhdGhlcixieT1jKCJvcmlnaW4iLCJ0aW1lX2hvdXIiKSkNCiNBaG9yYSBzaSB2ZW1vcyBsYSBjb3JyZWxhY2nDs24NCnJldHJhc29faHVtZWRhZCA8LSBiYXNlZXZpZGVuY2lhICU+JQ0KICBncm91cF9ieShodW1pZCkgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwgIA0KICAgIHRvdGFsX2ZsaWdodHMgPSBuKCksICAgICAgICAgICAgICAgICAgICAgICANCiAgICB0b3RhbF9kZWxheWVkX2ZsaWdodHMgPSBzdW0oZGVwX2RlbGF5ID4gMCwgbmEucm0gPSBUUlVFKSwNCiAgICBwZXJjX2RlbGF5ZWRfZmxpZ2h0cyA9IHsNCiAgICAgIHRvdGFsX2RlbGF5ZWRfZmxpZ2h0cyAvIHRvdGFsX2ZsaWdodHMgKiAxMDANCiAgICB9DQogICkgJT4lDQphcnJhbmdlKGRlc2ModG90YWxfZGVsYXllZF9mbGlnaHRzKSkNCnJldHJhc29faHVtZWRhZA0KYGBgDQpSZXRyYXNvIHNlZ8O6biBNZXNlcyBkZWwgQcOxbzogIA0KUG9kZW1vcyBvYnNlcnZhciBxdWUgbG9zIG1lc2VzIGVuIGxvcyBxdWUgc2UgcHJvZHVjZW4gbWF5b3JlcyByZXRyYXNvcyBkZSBzYWxpZGEgZXMgZW4gbG9zIG1lc2VzIGRlOiAgDQoNCisgKipKdWxpbyoqOiBDb24gdW4gKio0Ny4yNjklKiogKHBvcmNlbnRhamUgZGUgcmV0cmFzbykgeSByZXRyYXNvIGVuIG1pbnV0b3MgZGUgKioyMS43M21pbioqLiAgDQorICoqRGljaWVtYnJlKio6IENvbiB1biAqKjQ4LjE2JSoqIChwb3JjZW50YWplIGRlIHJldHJhc28pIHkgcmV0cmFzbyBlbiBtaW51dG9zIGRlICoqMTYuNTdtaW4qKi4NCg0KYGBge3J9DQpyZXRyYXNvX21lcyA8LSBmbGlnaHRzICU+JQ0KICBncm91cF9ieShtb250aCkgJT4lDQogIHN1bW1hcml6ZSgNCiAgICBhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwgIA0KICAgIHRvdGFsX2ZsaWdodHMgPSBuKCksICAgICAgICAgICAgICAgICAgICAgICANCiAgICB0b3RhbF9kZWxheWVkX2ZsaWdodHMgPSBzdW0oZGVwX2RlbGF5ID4gMCwgbmEucm0gPSBUUlVFKSwNCiAgICBwZXJjX2RlbGF5ZWRfZmxpZ2h0cyA9IHsNCiAgICAgIHRvdGFsX2RlbGF5ZWRfZmxpZ2h0cyAvIHRvdGFsX2ZsaWdodHMgKiAxMDANCiAgICB9DQogICkgJT4lDQphcnJhbmdlKGRlc2ModG90YWxfZGVsYXllZF9mbGlnaHRzKSkNCnJldHJhc29fbWVzDQpgYGANCmBgYHtyfQ0KdGl0dWxvIDwtICJNZXNlcyB5IHJldHJhc29zIGVuIHByb21lZGlvIChtaW51dG9zKSINCmdncGxvdChyZXRyYXNvX21lcywgYWVzKHggPSBmYWN0b3IobW9udGgsIGxldmVscyA9IDE6MTIsIGxhYmVscyA9IG1vbnRoLm5hbWUpLCB5ID0gcGVyY19kZWxheWVkX2ZsaWdodHMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnModGl0bGUgPSB0aXR1bG8sDQogICAgICAgeCA9ICJNZXMiLA0KICAgICAgIHkgPSAiUmV0cmFzbyBwcm9tZWRpbyAobWludXRvcykiDQogICkgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKQ0KYGBgDQoNCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+RXZpZGVuY2lhIDIuPC9zcGFuPg0KRXZpZGVuY2lhIDIgLSBBbmFsw610aWNhIGRlc2NyaXB0aXZhIChJbnRlZ3JhY2nDs24gZGUgZGF0b3MgYSB0cmF2w6lzIGRlIG1vZGVsbyBlbnRpZGFkLXJlbGFjacOzbikgIA0KQ29tcHJvbWlzbyDDqXRpY28geSBjaXVkYWRhbm8uIFNlIHRlIGhhIHNvbGljaXRhZG8gaGFjZXIgdW4gZXN0dWRpbyBzb2JyZSBsYSBzaXR1YWNpw7NuIGFjdHVhbCBkZSBsYSBhZXJvbMOtbmVhIEFtZXJpY2FuIEFpcmxpbmVzIHlhDQpxdWUgc2UgbmVjZXNpdGEgcmV2aXNhciBzdXMgZGVzdGlub3MsIGhvcmFyaW9zIHkgYXZpb25lcyBjb24gbG9zIHF1ZSBjdWVudGEgcGFyYSBoYWNlciBwcm9wdWVzdGFzDQpkZSBhdW1lbnRvIG8gcmVkdWNjacOzbiBkZSB2dWVsb3MgcG9yIGRlc3Rpbm8geSBob3JhcmlvcywgYXPDrSBjb21vIGxhIGNhbnRpZGFkIGRlIGF2aW9uZXMuICANCiFbXShDOlxcVXNlcnNcXEhQXFxEZXNrdG9wXFxEYXRpc1xcdEJCTzBSLmdpZikgIA0KDQoNCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij4xLiBEYXRvcyBHZW5lcmFsZXMuPC9zcGFuPiAgDQoNCiMjIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+MS4xIENvbnN1bHRhIHkgZXhwbG9yYWNpw7NuIGRlbCBkYXRhIGZyYW1lIHBsYW5lcyB5IHdlYXRoZXIuIjwvc3Bhbj4NCmBgYHtyfQ0Kdmlldyh3ZWF0aGVyKQ0KdmlldyhwbGFuZXMpDQpgYGAgIA0KDQojIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjEuMi4JU2UgbmVjZXNpdGEgc2FiZXIgZGUgY2FkYSB2dWVsbywgbGEgYWVyb2zDrW5lYSwgZWwgYWVyb3B1ZXJ0byBkZSBvcmlnZW4geSBlbCBhZXJvcHVlcnRvIGRlc3Rpbm8uIjwvc3Bhbj4NCmBgYHtyfQ0KYWVyb2xpbmVhcyA8LSBmbGlnaHRzICU+JSANCiAgc2VsZWN0KGNhcnJpZXIsb3JpZ2luLGRlc3QpDQphZXJvbGluZWFzDQpgYGANCiMjIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+MS4zLglFbiBsYSBjb25zdWx0YSBhbnRlcmlvciBzZSBuZWNlc2l0YSBjb25vY2VyIGVsIG5vbWJyZSBkZSBsYSBhZXJvbMOtbmVhLiI8L3NwYW4+DQpgYGB7cn0NCmFlcm9saW5lYXNfbm9tYnJlIDwtIGFlcm9saW5lYXMgJT4lDQogIGxlZnRfam9pbihhaXJsaW5lcywgYnkgPSAiY2FycmllciIpDQphZXJvbGluZWFzX25vbWJyZQ0KYGBgDQojIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjEuNC4JU2UgbmVjZXNpdGEgc2FiZXIgbGEgY2FudGlkYWQgZGUgdnVlbG9zIHBvciBjYWRhIGRlc3Rpbm8gcGFyYSBpZGVudGlmaWNhciBjdcOhbGVzIHNvbiBsb3MgZGVzdGlub3MgbcOhcyBidXNjYWRvcy4iPC9zcGFuPg0KYGBge3J9DQpjYW50X3Z1ZWxvcyA8LSBmbGlnaHRzICU+JSANCiAgc2VsZWN0KGNhcnJpZXIsIGRlc3QpICU+JSANCiAgY291bnQoZGVzdCkNCmNhbnRfdnVlbG9zIDwtIGNhbnRfdnVlbG9zICU+JQ0KICBhcnJhbmdlKGRlc2MobikpDQpjYW50X3Z1ZWxvcw0KYGBgDQpMb3MgZGVzdGlub3MgbcOhcyBidXNjYWRvcyBzb24gT1JEIChBZXJvcHVlcnRvIEludGVybmFjaW9uYWwgTydIYXJlKSBjb24gMTcsMjgzIHZ1ZWxvcywgQVRMIChBdGxhbnRhKSBjb24gMTcsMjE1IHZ1ZWxvcyB5IExBWCAoTG9zIEFuZ2VsZXMpIGNvbiAxNiwxNzQgdnVlbG9zLiAgDQoNCiFbXShDOlxcVXNlcnNcXEhQXFxEZXNrdG9wXFxEYXRpc1xcY2hpY2Fnby1jaHJpc3RvcGhlci1hbHZhcmVuZ2EtdW5zcGxhc2guanBnKSAgDQoNCg0KIyMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij4xLjUuIEFncmVnYXIgZWwgbm9tYnJlIGRlIGxhIGFlcm9sw61uZWEgYSBsYSB0YWJsYSBhbnRlcmlvci4iPC9zcGFuPg0KYGBge3J9DQpjYW50X3Z1ZWxvczEgPC0gZmxpZ2h0cyAlPiUNCiAgc2VsZWN0KGNhcnJpZXIsIGRlc3QpICU+JQ0KICBncm91cF9ieShjYXJyaWVyLCBkZXN0KSAlPiUNCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JQ0KICB1bmdyb3VwKCkgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkNCmNhbnRfdnVlbG9zMQ0KYGBgICANCg0KTGEgYWVyb2zDrW5lYSBjb24gbWF5b3IgY2FudGlkYWQgZGUgdnVlbG9zIGVzIERMIChERUxUQSBBSVJMSU5FUyk6IERlbHRhIEFpciBMaW5lcyBlcyB1bmEgYWVyb2zDrW5lYSBjb21lcmNpYWwgZXN0YWRvdW5pZGVuc2UgY3V5YSBiYXNlIGVzdMOhIHNpdHVhZGEgZW4gQXRsYW50YSwgR2VvcmdpYS4gRXMgbWllbWJybyBmdW5kYWRvciwganVudG8gY29uIEFlcm9tw6l4aWNvLCBBaXIgRnJhbmNlIHkgS29yZWFuIEFpciwgZGUgU2t5VGVhbSwgdW5hIGFsaWFuemEgZGUgYWVyb2zDrW5lYXMgZ2xvYmFsZXMgcXVlIG9mcmVjZSBhIGxvcyBjbGllbnRlcyB1biBncmFuIG7Dum1lcm8gZGUgZGVzdGlub3MgYWxyZWRlZG9yIGRlbCBtdW5kbywgdnVlbG9zIHkgb3Ryb3Mgc2VydmljaW9zICANCg0KIyMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij4xLjYuIFNlIG5lY2VzaXRhIGNvbm9jZXIgbGFzIGFlcm9sw61uZWFzIChjbGF2ZSB5IG5vbWJyZSkgeSBkZXN0aW5vcyBxdWUgdnVlbGFuIHBvciBsYSBNYcOxYW5hOiBkZSA2IGEgMTIsIFRhcmRlOiBkZSAxMiBhIDE5ICwgTm9jaGU6IGRlIDE5IGEgMjQgeSBNYWRydWdhZGEgZGUgMjQgYSA2LiI8L3NwYW4+DQpgYGB7cn0NCnZ1ZWxvX3BvcmhvcmEgPC0gZmxpZ2h0cyAlPiUNCnNlbGVjdChjYXJyaWVyLCBkZXN0LCBzY2hlZF9kZXBfdGltZSkgJT4lDQogIGxlZnRfam9pbihhaXJsaW5lcywgYnkgPSAiY2FycmllciIpDQoNCmNsYXNfaG9yYTwtIG11dGF0ZSh2dWVsb19wb3Job3JhLCBjbGFzX2hvcmFyaW8gPSBpZmVsc2Uoc2NoZWRfZGVwX3RpbWUgJWluJSA2MDA6MTE1OSwiTW9ybmluZyIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzY2hlZF9kZXBfdGltZSAlaW4lIDEyMDA6MTg1OSwiQWZlcnRub29uIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNjaGVkX2RlcF90aW1lICVpbiUgMTkwMDoyNDAwLCJOaWdodCIsICJNYWRydWdhZGEiKSkpKQ0KY2xhc19ob3JhDQpgYGAgIA0KDQojIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjEuNy5TZSBuZWNlc2l0YSBzYWJlciBsYSBjYW50aWRhZCBkZSB2dWVsb3MgcG9yIGFlcm9sw61uZWEgeSBkZXN0aW5vIHF1ZSBoYXkgcG9yIGxhIE1hw7FhbmEsIFRhcmRlLCBOb2NoZSB5IE1hZHJ1Z2FkYS4iPC9zcGFuPg0KYGBge3J9DQojIEFncnVwYXIgcG9yIGFlcm9sw61uZWEsIGRlc3Rpbm8geSBmcmFuamEgaG9yYXJpYSB5IGNvbnRhciBsYSBjYW50aWRhZCBkZSB2dWVsb3MNCnZ1ZWxvc19jb250ZW8gPC0gY2xhc19ob3JhICU+JSAgDQogIGdyb3VwX2J5KGNhcnJpZXIsIGRlc3QsIGNsYXNfaG9yYXJpbykgJT4lIGNvdW50KCkNCg0KIyBNb3N0cmFyIGxvcyByZXN1bHRhZG9zDQp2dWVsb3NfY29udGVvDQpgYGAgIA0KDQojIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjEuOC5TZSBuZWNlc2l0YSBzYWJlciBhIHF1w6kgZGVzdGlub3MgdnVlbGEgbGEgYWVyb2zDrW5lYSBBbWVyaWNhbiBBaXJsaW5lcyBJbmMuLUFBIGR1cmFudGUgbGEgbWFkcnVnYWRhLiI8L3NwYW4+DQpgYGB7cn0NCmRlc3Rpbm9zX2FtZXJpY2FuIDwtIGNsYXNfaG9yYSAlPiUgDQogIHNlbGVjdChjYXJyaWVyLG5hbWUsIGRlc3QsY2xhc19ob3JhcmlvKSAlPiUgDQogIGZpbHRlcihjYXJyaWVyID09ICJBQSIgJiBjbGFzX2hvcmFyaW8gPT0gIk1hZHJ1Z2FkYSIpICU+JSANCiAgZ3JvdXBfYnkoY2FycmllcixuYW1lLCBkZXN0LGNsYXNfaG9yYXJpbykNCmRlc3Rpbm9zX2FtZXJpY2FuDQpgYGANCkFtZXJpY2FuIEFpcmxpbmVzIHJlYWxpemEgdnVlbG9zIGRlIG1hZHJ1Z2FkYSBhIMO6bmljYW1lbnRlIGVsIGRlc3Rpbm8gZGUgTWlhbWkuDQohW10oQzpcXFVzZXJzXFxIUFxcRGVza3RvcFxcRGF0aXNcXDMzOTY1Ni1Eb3dudG93bi1NaWFtaS5qcGcpDQojIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjEuOS5RdcOpIGF2aW9uZXMgdXRpbGl6YSBsYSBhZXJvbMOtbmVhIEFBPyBhZXJvbMOtbmVhLCB0aXBvLCBtb3RvciB5IG7Dum1lcm8gZGUgYXNpZW50b3MgeSDCv0N1w6FudG9zIHZ1ZWxvcyBzZSBoYW4gcmVhbGl6YWRvIGNvbiBjYWRhIHVubz8gKGVsaW1pbmEgbG9zIE5BJ3MpIjwvc3Bhbj4NCmBgYHtyfQ0KYXZpb25fYW1lcmljYW4gPC0gZmxpZ2h0cyAlPiUNCiAgbGVmdF9qb2luKHBsYW5lcywgYnkgPSAidGFpbG51bSIpICU+JQ0KICBzZWxlY3QoY2FycmllciwgdHlwZSwgZW5naW5lLCBzZWF0cykgJT4lDQogIGZpbHRlcihjYXJyaWVyID09ICJBQSIsICFpcy5uYSh0eXBlKSkgJT4lDQogIGdyb3VwX2J5KGNhcnJpZXIsdHlwZSxlbmdpbmUsc2VhdHMpICU+JSANCiAgY291bnQoKQ0KYXZpb25fYW1lcmljYW4NCmBgYA0KDQojIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogc2t5IGJsdWU7Ij5WaXN1YWxpemFjacOzbiBkZSBkYXRvczwvc3Bhbj4NCkVuIGxvcyBhdmFuY2VzIGFudGVyaW9yZXMgc2UgaGFuIHJlYWxpemFkbyBkaWZlcmVudGVzIGFuw6FsaXNpcyB5IGFob3JhIG5vcyBzb2xpY2l0YW4gaGFjZXIgdmlzdWFsaXphY2lvbmVzIGRlIGxhDQphZXJvbMOtbmVhIEFtZXJpY2FuIEFpcmxpbmVzIHBhcmEgbG9zIGVqZWN1dGl2b3MgY29uIGxhcyBzaWd1aWVudGVzIGNhcmFjdGVyw61zdGljYXMuDQpEZW50cm8gZGUgbGFzIGFlcm9sw61uZWFzIGVsIHJldHJhc28gdGFudG8gZW4gbGEgaG9yYSBkZSBwYXJ0aWRhIGNvbW8gZW4gbGEgaG9yYSBkZSBsbGVnYWRhIGEgc3UgZGVzdGlubyB2YW4NCmdlbmVyYW5kbyBpbmRpY2Fkb3JlcyBuZWdhdGl2b3MuDQojIyMjIFNlIHNvbGljaXRhIGFuYWxpemFyIHBhcmEgbGEgYWVyb2zDrW5lYSBBbWVyaWNhbiBBaXJsaW5lcyBzaSBsb3MgdnVlbG9zIHF1ZSB0aWVuZW4gcmV0cmFzbyBlbiBsYSBwYXJ0aWRhIHRhbWJpw6luIHRpZW5lbiByZXRyYXNvIGVuIGxhIGhvcmEgZGUgbGxlZ2FkYS4gIA0KYGBge3J9DQojIEZpbHRyYXIgbG9zIHZ1ZWxvcyBkZSBBbWVyaWNhbiBBaXJsaW5lcyAoQUEpDQphbWVyaWNhbl9mbGlnaHRzIDwtIGZsaWdodHMgJT4lIGZpbHRlcihjYXJyaWVyID09ICJBQSIpDQoNCiMgTW9zdHJhciBsYSByZWxhY2nDs24gZW50cmUgZWwgcmV0cmFzbyBlbiBsYSBwYXJ0aWRhIHkgZWwgcmV0cmFzbyBlbiBsYSBsbGVnYWRhDQpjb3IoYW1lcmljYW5fZmxpZ2h0cyRkZXBfZGVsYXksIGFtZXJpY2FuX2ZsaWdodHMkYXJyX2RlbGF5LCB1c2UgPSAiY29tcGxldGUub2JzIikNCmBgYA0KYGBge3J9DQojIEZpbHRyYXIgbG9zIHZ1ZWxvcyBkZSBBbWVyaWNhbiBBaXJsaW5lcyAoQUEpDQphbWVyaWNhbl9mbGlnaHRzIDwtIGZsaWdodHMgJT4lIGZpbHRlcihjYXJyaWVyID09ICJBQSIpDQoNCiMgQ3JlYXIgdW4gZ3LDoWZpY28gZGUgZGlzcGVyc2nDs24NCmdncGxvdChhbWVyaWNhbl9mbGlnaHRzLCBhZXMoeCA9IGRlcF9kZWxheSwgeSA9IGFycl9kZWxheSkpICsNCiAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNSwgY29sb3IgPSAiYmx1ZSIpICsNCiAgbGFicyhtYWluID0gIlJlbGFjacOzbiBlbnRyZSBSZXRyYXNvIGVuIFNhbGlkYSB5IExsZWdhZGEgcGFyYSBBbWVyaWNhbiBBaXJsaW5lcyIsIHggPSAiUmV0cmFzbyBlbiBsYSBQYXJ0aWRhIChtaW51dG9zKSIsIHkgPSAiUmV0cmFzbyBlbiBsYSBMbGVnYWRhIChtaW51dG9zKSIpICsNCiAgdGhlbWVfbWluaW1hbCgpDQpgYGANCkVsIHJlc3VsdGFkbyBkZSBsYSBjb3JyZWxhY2nDs24gZW50cmUgZWwgcmV0cmFzbyBlbiBsYSBwYXJ0aWRhIHkgZWwgcmV0cmFzbyBlbiBsYSBsbGVnYWRhIHBhcmEgbG9zIHZ1ZWxvcyBkZSBBbWVyaWNhbiBBaXJsaW5lcyAoQUEpIGVzIGFwcm94aW1hZGFtZW50ZSAwLjg5MTcuIEVzdGUgdmFsb3IgY2VyY2FubyBhIDEgaW5kaWNhIHVuYSBmdWVydGUgY29ycmVsYWNpw7NuIHBvc2l0aXZhIGVudHJlIGFtYmFzIHZhcmlhYmxlcy4gRW4gb3RyYXMgcGFsYWJyYXMsIGhheSB1bmEgdGVuZGVuY2lhIGEgcXVlIGxvcyB2dWVsb3MgcXVlIGV4cGVyaW1lbnRhbiByZXRyYXNvIGVuIGxhIHNhbGlkYSB0YW1iacOpbiB0ZW5nYW4gcmV0cmFzbyBlbiBsYSBsbGVnYWRhLiAgDQoNCiMjIyMgVGVtcGVyYXR1cmEgeSBzdXMgdmFyaWFjaW9uZXMNCiMjIyMgVmlzdWFsaXphIGxhIHRlbmRlbmNpYSBkZSBsYSB0ZW1wZXJhdHVyYSBkdXJhbnRlIGxvcyBwcmltZXJvcyAxNSBkw61hcyBkZWwgbWVzIGRlIEVuZXJvIGVuIGxvcyB2dWVsb3MgcXVlIHBhcnRlbiBkZWwgYWVyb3B1ZXJ0byDigJxOZXdhcmssIEVXUuKAnSwgdXRpbGl6YXIgdW5hIGdyw6FmaWNhIGRlIGzDrW5lYS4NCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KDQojIEZpbHRyYXIgbG9zIGRhdG9zIHBhcmEgbG9zIHByaW1lcm9zIDE1IGTDrWFzIGRlIGVuZXJvIGVuIGVsIGFlcm9wdWVydG8gTmV3YXJrDQp3ZWF0aGVyX2phbnVhcnkgPC0gd2VhdGhlciAlPiUNCiAgZmlsdGVyKG1vbnRoID09IDEgJiBkYXkgPD0gMTUgJiBvcmlnaW4gPT0gIkVXUiIpDQoNCiMgR3LDoWZpY28gZGUgbMOtbmVhIHBhcmEgbGEgdGVuZGVuY2lhIGRlIHRlbXBlcmF0dXJhDQpnZ3Bsb3Qod2VhdGhlcl9qYW51YXJ5LCBhZXMoeCA9IGRheSwgeSA9IHRlbXApKSArDQogIGdlb21fbGluZShjb2xvciA9ICJibGFjayIsIHNpemUgPSAxKSArDQogIGxhYnMobWFpbj0iVGVuZGVuY2lhIGRlIGxhIFRlbXBlcmF0dXJhIGVuIGxvcyBQcmltZXJvcyAxNSBEw61hcyBkZSBFbmVybyAoQWVyb3B1ZXJ0byBOZXdhcmspIiwNCiAgICAgICB4PXdlYXRoZXJfamFudWFyeSRkYXksDQogICAgICAgeT13ZWF0aGVyX2phbnVhcnkkdGVtcCkNCmBgYA0KIyMjIyBWaXN1YWxpemEgbGEgdGVtcGVyYXR1cmEgbcOhcyBmcmVjdWVudGUgZW4gbG9zIHByaW1lcm9zIDE1IGTDrWFzIGRlbCBtZXMgZGUgRW5lcm8sIHV0aWxpemFyIHVuIGhpc3Ryb2dyYW1hLg0KYGBge3J9DQojIEZpbHRyYXIgbG9zIGRhdG9zIHBhcmEgbG9zIHByaW1lcm9zIDE1IGTDrWFzIGRlIGVuZXJvIGVuIGVsIGFlcm9wdWVydG8gTmV3YXJrDQp3ZWF0aGVyX2phbnVhcnkgPC0gd2VhdGhlciAlPiUNCiAgZmlsdGVyKG1vbnRoID09IDEgJiBkYXkgPD0gMTUgJiBvcmlnaW4gPT0gIkVXUiIpDQoNCiMgR3LDoWZpY28gZGUgbMOtbmVhIHBhcmEgbGEgdGVuZGVuY2lhIGRlIHRlbXBlcmF0dXJhDQpnZ3Bsb3Qod2VhdGhlcl9qYW51YXJ5LCBhZXMoeCA9IHRlbXApKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnMobWFpbj0iVGVuZGVuY2lhIGRlIGxhIFRlbXBlcmF0dXJhIGVuIGxvcyBQcmltZXJvcyAxNSBEw61hcyBkZSBFbmVybyAoQWVyb3B1ZXJ0byBOZXdhcmspIiwNCiAgICAgICB4PXdlYXRoZXJfamFudWFyeSRkYXksDQogICAgICAgeT13ZWF0aGVyX2phbnVhcnkkdGVtcCkNCmBgYA0KIyMjIyBVdGlsaXphIEZhY2V0cyBwYXJhIG9ic2VydmFyIGPDs21vIHZhcsOtYSBsYSB0ZW1wZXJhdHVyYSBlbiBjYWRhIG1lcyBlbiBlbCBoaXN0b2dyYW1hIGRlbCBwdW50byBhbnRlcmlvciAuDQpgYGB7cn0NCndlYXRoZXIgJT4lDQogIGdncGxvdChhZXMoeCA9IHRlbXApKSArDQogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMiwgZmlsbCA9ICJza3libHVlIiwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiSGlzdG9ncmFtYSBkZSBUZW1wZXJhdHVyYXMgcG9yIE1lcyIsDQogICAgICAgeCA9ICJUZW1wZXJhdHVyYSAoRmFocmVuaGVpdCkiLA0KICAgICAgIHkgPSAiRnJlY3VlbmNpYSIpICsNCiAgZmFjZXRfd3JhcCh+bW9udGgpDQpgYGANCiMjIyMgTsO6bWVybyBkZSB2dWVsb3MgcXVlIHNhbGllcm9uIGRlIE51ZXZhIFlvcmsgZW4gMjAxMyBwb3IgYWVyb2zDrW5lYSAobW9zdHJhciBzb2xhbWVudGUgbGFzIDEwIGFlcm9sw61uZWFzIGNvbiBtw6FzIHZ1ZWxvcyksIHV0aWxpemFyIGdyw6FmaWNhIGRlIGJhcnJhcy4NCmBgYHtyfQ0KZmxpZ2h0cyAlPiUNCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogIHN1bW1hcmlzZShudW1fZmxpZ2h0cyA9IG4oKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhudW1fZmxpZ2h0cykpICU+JQ0KICBzbGljZSgxOjEwKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gcmVvcmRlcihjYXJyaWVyLCAtbnVtX2ZsaWdodHMpLCB5ID0gbnVtX2ZsaWdodHMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArDQogIGxhYnModGl0bGUgPSAiTnVtZXJvIGRlIHZ1ZWxvcyBwb3IgYWVyb2xpbmVhIiwNCiAgICAgICB4ID0gIkFlcm9saW5lYSIsDQogICAgICAgeSA9ICJOdW1lcm8gZGUgVnVlbG9zIikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KU2Vnw7puIGVsIGdyw6FmaWNvICJOw7ptZXJvIGRlIHZ1ZWxvcyBwb3IgYWVyb2zDrW5lYSBlbiAyMDEzIiwgc2Ugb2JzZXJ2YSBxdWUgbGFzIGFlcm9sw61uZWFzIGNvbiBtYXlvciBjYW50aWRhZCBkZSB2dWVsb3MgZGVzZGUgTnVldmEgWW9yayBkdXJhbnRlIGVzZSBhw7FvIGZ1ZXJvbiAiVW5pdGVkIEFpcmxpbmVzIiB5ICJKZXRCbHVlIEFpcndheXMiLiBFc3RhcyBkb3MgYWVyb2zDrW5lYXMgbGlkZXJhbiBzaWduaWZpY2F0aXZhbWVudGUgZW4gdMOpcm1pbm9zIGRlIGxhIGNhbnRpZGFkIGRlIHZ1ZWxvcywgc3VwZXJhbmRvIGEgb3RyYXMgY29tcGHDscOtYXMuIEVsIGdyw6FmaWNvIHByb3BvcmNpb25hIHVuYSByw6FwaWRhIHZpc3VhbGl6YWNpw7NuIGRlIGxhIGRpc3RyaWJ1Y2nDs24gZGUgdnVlbG9zIGVudHJlIGxhcyBhZXJvbMOtbmVhcyBwcmluY2lwYWxlcywgc2llbmRvIMO6dGlsIHBhcmEgY29tcHJlbmRlciBsYSBwYXJ0aWNpcGFjacOzbiByZWxhdGl2YSBkZSBjYWRhIHVuYSBlbiBlbCB0csOhZmljbyBhw6lyZW8gZGVzZGUgTnVldmEgWW9yayBlbiAyMDEzLg0KIyMjIyBWaXN1YWxpemEgZWwgcHVudG8gYW50ZXJpb3IgZW4gdW5hIGdyw6FmaWNhIGRlIHBpZS4NCmBgYHtyfQ0KU3lzLnNldGxvY2FsZSgiTENfQ1RZUEUiLCAiZW5fVVMuVVRGLTgiKQ0KIyBGaWx0cmFtb3MgbG9zIGRhdG9zIHBhcmEgb2J0ZW5lciBsYSBjYW50aWRhZCBkZSB2dWVsb3MgcG9yIGFlcm9sw61uZWENCnRvcF9haXJsaW5lcyA8LSBmbGlnaHRzICU+JQ0KICBncm91cF9ieShjYXJyaWVyKSAlPiUNCiAgc3VtbWFyaXNlKG51bV9mbGlnaHRzID0gbigpKSAlPiUNCiAgYXJyYW5nZShkZXNjKG51bV9mbGlnaHRzKSkgJT4lDQogIHNsaWNlKDE6MTApICAjIFNlbGVjY2lvbmFtb3MgbGFzIDEwIGFlcm9sw61uZWFzIGNvbiBtw6FzIHZ1ZWxvcw0KZ2dwbG90KHRvcF9haXJsaW5lcywgYWVzKHggPSAiIiwgeSA9IG51bV9mbGlnaHRzLCBmaWxsID0gZmFjdG9yKGNhcnJpZXIpKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAxKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIGxhYnModGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZWwgTsO6bWVybyBkZSBWdWVsb3MgcG9yIEFlcm9sw61uZWEgZGVzZGUgTnVldmEgWW9yayBlbiAyMDEzIiwNCiAgICAgICBmaWxsID0gIkFlcm9sw61uZWEiLA0KICAgICAgIHggPSBOVUxMLA0KICAgICAgIHkgPSBOVUxMKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQ0KYGBgDQojIyMjIFJlbGFjaW9uYSBlbCBkYXRhIGZyYW1lIGZsaWd0aHMgY29uIGVsIGRhdGEgZnJhbWUgYWlycG9ydHMgYSB0cmF2w6lzIGRlbCBjYW1wbyBkZXN0aW5vLg0KYGBge3J9DQojIFJlYWxpemEgbGEgdW5pw7NuIGRlIGxvcyBkYXRhIGZyYW1lcyBmbGlnaHRzIHkgYWlycG9ydHMgcG9yIGVsIGNhbXBvIGRlc3Rpbm8NCnVuaW9uX2Z5YSA8LSBsZWZ0X2pvaW4oZmxpZ2h0cywgYWlycG9ydHMsIGJ5ID0gYygiZGVzdCIgPSAiZmFhIikpDQpgYGANCg0KIyMjIyBDcmVhIHVuIG51ZXZvIGRhdGEgZnJhbWUgY29uIGVsIHB1bnRvIGFudGVyaW9yIMO6bmljYW1lbnRlIGNvbiBsb3MgNSBjYXJyaWVycyBjb24gbcOhcyB2dWVsb3MgcG9yIGRlc3Rpbm8NCmBgYHtyfQ0KIyBDcmVhIHVuIG51ZXZvIGRhdGEgZnJhbWUgY29uIGxvcyA1IGNhcnJpZXJzIGNvbiBtw6FzIHZ1ZWxvcw0KdG9wX2NhcnJpZXJzIDwtIHVuaW9uX2Z5YSAlPiUNCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogIHN1bW1hcmlzZShudW1fZmxpZ2h0cyA9IG4oKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhudW1fZmxpZ2h0cykpICU+JQ0KICBzbGljZSgxOjUpICU+JQ0KICB1bmdyb3VwKCkNCg0KIyBNdWVzdHJhIGVsIG51ZXZvIGRhdGEgZnJhbWUNCnByaW50KHRvcF9jYXJyaWVycykNCg0KZmxpZ2h0c190b3BfY2FycmllcnMgPC0gdW5pb25fZnlhICU+JQ0KICBmaWx0ZXIoY2FycmllciAlaW4lIHRvcF9jYXJyaWVycyRjYXJyaWVyKQ0KYGBgDQojIyMjIFJlYWxpemEgdW5hIHZpc3VhbGl6YWNpw7NuIGRlbCBwdW50byBhbnRlcmlvciBkZSBsYXMgc2lndWllbnRlcyB0cmVzIGZvcm1hcy4NCmBgYHtyfQ0KIyBEYXRhRnJhbWUgY29uIGxvcyByZXN1bHRhZG9zDQp0b3BfY2FycmllcnMgPC0gdW5pb25fZnlhICU+JQ0KICBncm91cF9ieShjYXJyaWVyLCBvcmlnaW4pICU+JQ0KICBzdW1tYXJpc2UobnVtX2ZsaWdodHMgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MobnVtX2ZsaWdodHMpKSAlPiUNCiAgc2xpY2UoMTo1KSAlPiUNCiAgdW5ncm91cCgpDQoNCmdncGxvdCh0b3BfY2FycmllcnMsIGFlcyh4ID0gY2FycmllciwgeSA9IG51bV9mbGlnaHRzLCBmaWxsID0gYXMuZmFjdG9yKGNhcnJpZXIpKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArDQogIGxhYnMoeCA9ICJDYXJyaWVyIiwgeSA9ICJOdW1iZXIgb2YgRmxpZ2h0cyIsIHRpdGxlID0gIlRvcCA1IENhcnJpZXJzIGNvbiBtw6FzIHZ1ZWxvcyBwb3IgYWVyb3B1ZXJ0byIpICsNCiAgZmFjZXRfd3JhcCh+b3JpZ2luLCBzY2FsZXMgPSAiZnJlZV94IikgKw0KICB0aGVtZV9taW5pbWFsKCkNCmBgYA0KYGBge3J9DQpnZ3Bsb3QoZmxpZ2h0c190b3BfY2FycmllcnMsIGFlcyh4ID0gY2FycmllciwgZmlsbCA9IGNhcnJpZXIpKSArDQogIGdlb21fYmFyKCkgKw0KICBsYWJzKHRpdGxlID0gIkNhbnRpZGFkIGRlIHZ1ZWxvcyBwb3IgYWVyb2zDrW5lYSIsIHggPSAiQWVyb2zDrW5lYSIsIHkgPSAiQ2FudGlkYWQgZGUgdnVlbG9zIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICBnZW9tX3RleHQoc3RhdCA9ICJjb3VudCIsIGFlcyhsYWJlbCA9IC4uY291bnQuLiwgZ3JvdXAgPSBjYXJyaWVyKSwgdmp1c3QgPSAtMC41KQ0KYGBgDQpgYGB7cn0NCmdncGxvdChmbGlnaHRzX3RvcF9jYXJyaWVycywgYWVzKHggPSBkZXN0LCBmaWxsID0gY2FycmllcikpICsNCiAgZ2VvbV9iYXIoKSArDQogIGxhYnModGl0bGUgPSAiQ2FudGlkYWQgZGUgdnVlbG9zIHBvciBkZXN0aW5vIiwgeCA9ICJEZXN0aW5vIiwgeSA9ICJDYW50aWRhZCBkZSB2dWVsb3MiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpDQpgYGANCg0KIyMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogYmx1ZTsiPiBDb25jbHVzaW9uZXM8L3NwYW4+DQoNCi0gTG9zIHZ1ZWxvcyBxdWUgc2FsZW4gZW4gbWVzZXMgZGUgYWx0YSBkZW1hbmRhIHRpZW5lbiBtw6FzIHJldHJhc29zIGRlYmlkbyBhIGxhIG1heW9yIGNvbXBsZWppZGFkIGVuIGxhcyBvcGVyYWNpb25lcyB5IGVsIGF1bWVudG8gZGVsIHRyw6FmaWNvLiBQb3IgZWplbXBsbywgZW4ganVsaW8geSBkaWNpZW1icmUsIHNlIGVuY3VlbnRyYW4gbG9zIHZ1ZWxvcyBxdWUgdGllbmVuIG1heW9yZXMgcG9yY2VudGFqZXMgZGUgcmV0cmFzbywgdGVuaWVuZG8gcG9yY2VudGFqZXMgZGUgNDcuMjclIHkgZGUgNDguMTYlLCBtaWVudHJhcyBxdWUgZWwgbWVzIGRlIHNlcHRpZW1icmUgdGllbmUgdW4gcG9yY2VudGFqZSBkZSAyOC4zNCUuIEVzdG8gcG9kcsOtYSBoYWNlciBxdWUgZW1wcmVzYXMgdGlwbyBBbWVyaWNhbiBBaXJsaW5lcyBzZSBlbmZvcXVlbiBtw6FzIGVuIGVzdG9zIG1lc2VzIHBhcmEgYWJhc3RlY2VyIGxhIGF0ZW5jacOzbiB5IG9wZXJhY2lvbmVzDQoNCi0gTGFzIGFlcm9sw61uZWFzIGVqZXJjZW4gdW4gaW1wYWN0byBzaWduaWZpY2F0aXZvIGVuIGxvcyByZXRyYXNvcyBkZSBsb3MgdnVlbG9zLCB5YSBxdWUgbGEgZGlzcG9uaWJpbGlkYWQgZGUgcGVyc29uYWwgeSBsYSBkZW1hbmRhIGRlIHZpYWplcyB2YXLDrWFuIGVudHJlIGVsbGFzLiBFc3RvIHNlIHJlZmxlamEgZW4gcXVlIFNvdXRod2VzdCBBaXJsaW5lcyBDby4gdGllbmUgdW4gw61uZGljZSBkZSByZXRyYXNvIGRlbCA1My40JSAoY29uIDEyIG1pbCB2dWVsb3MgdG90YWxlcyksIG1pZW50cmFzIHF1ZSBIYXdhaWlhbiBBaXJsaW5lcyBJbmMuIHNvbG8gcmVnaXN0cmEgdW4gMjAuMiUgZGUgcmV0cmFzb3MgKGNvbiAzNDIgdnVlbG9zKS4gKipBbWVyaWNhbiBBaXJsaW5lcyoqIHNlIGVuY3VlbnRyYSBlbnRyZSBsYXMgYWVyb2xpbmVhcyBjb24gbWVub3IgcG9yY2VudGFqZSBkZSByZXRyYXNvLCB0ZW5pZW5kbyB1biBwb3JjZW50YWplIGRlIDMxJS4gIA0KDQotTG9zIGRhdG9zIG11ZXN0cmFuIHF1ZSBhIGxhcyAxNzowMCBob3JhcyBoYXkgdW4gcmV0cmFzbyBwcm9tZWRpbyBkZSAyMS4xMCBtaW51dG9zLCBhZmVjdGFuZG8gY2FzaSBsYSBtaXRhZCBkZSBsb3MgdnVlbG9zICg0OS42NyUpLiBBIGxhcyAxOTowMCBob3JhcywgZWwgcmV0cmFzbyBwcm9tZWRpbyBhdW1lbnRhIGxpZ2VyYW1lbnRlIGEgMjQuNzggbWludXRvcywgY29uIG1lbm9zIHZ1ZWxvcyBhZmVjdGFkb3MuIEVuIGNvbnRyYXN0ZSwgYSBsYXMgNjowMCBhLm0uLCBlbCByZXRyYXNvIHByb21lZGlvIGVzIGVsIG3DoXMgYmFqbyAoMS42NCBtaW51dG9zKSwgY29uIHNvbG8gZWwgMjAuOTIlIGRlIGxvcyB2dWVsb3MgYWZlY3RhZG9zLiBFc3RvcyByZXN1bHRhZG9zIGRlc3RhY2FuIGPDs21vIGxhIGhvcmEgZGUgc2FsaWRhIGluZmx1eWUgZW4gbGEgaW5jaWRlbmNpYSB5IG1hZ25pdHVkIGRlIGxvcyByZXRyYXNvcyBlbiBsb3MgdnVlbG9zLiAgDQoNCi1Mb3MgZGF0b3MgcmV2ZWxhbiBkaXNwYXJpZGFkZXMgc2lnbmlmaWNhdGl2YXMgZW4gbG9zIHJldHJhc29zIGRlIHZ1ZWxvcyBzZWfDum4gZWwgZGVzdGluby4gQU5DIGRlc3RhY2EgY29uIGVsIG1heW9yIHBvcmNlbnRhamUgZGUgcmV0cmFzb3MsIGFsY2FuemFuZG8gZWwgNzUlLCB5IHVuIHJldHJhc28gcHJvbWVkaW8gZGUgMTIuODggbWludXRvcywgc3VnaXJpZW5kbyBwb3NpYmxlcyBkZXNhZsOtb3Mgb3BlcmF0aXZvcyBlbiBlc2FzIHJ1dGFzLiBQb3Igb3RybyBsYWRvLCBYTkEgbXVlc3RyYSB1bm8gZGUgbG9zIHBvcmNlbnRhamVzIGRlIHJldHJhc28gbcOhcyBiYWpvcywgY29uIHNvbG8gdW4gMjUuNDglIGRlIHZ1ZWxvcyBhZmVjdGFkb3MgeSB1biByZXRyYXNvIHByb21lZGlvIGRlIDYuNCBtaW51dG9zLCBpbmRpY2FuZG8gdW5hIGdlc3Rpw7NuIG9wZXJhdGl2YSBtw6FzIGVmaWNpZW50ZSBvIGNvbmRpY2lvbmVzIGZhdm9yYWJsZXMgZW4gc3VzIHJ1dGFzLiBFc3RvcyByZXN1bHRhZG9zIHN1YnJheWFuIGxhIGltcG9ydGFuY2lhIGRlIGNvbnNpZGVyYXIgZWwgZGVzdGlubyBlc3BlY8OtZmljbyBhbCBldmFsdWFyIGxvcyBwYXRyb25lcyBkZSByZXRyYXNvIGVuIGxvcyB2dWVsb3MuICAgDQoNCi1FbiBsYSBub2NoZSBzZSBvYnNlcnZhIGxhIG1heW9yIHByb3BvcmNpw7NuIGRlIHJldHJhc29zIGVuIGNvbXBhcmFjacOzbiBjb24gbGEgbWHDsWFuYSwgZGViaWRvIGEgbGEgbWVub3IgZGlzcG9uaWJpbGlkYWQgZGUgcGVyc29uYWwgKHNpbiBxdWUgbGEgZGVtYW5kYSBlc3TDqSByZWxhY2lvbmFkYSBjb24gZXN0bykuIFNlIGRlc3RhY2EgcXVlIGVudHJlIGxhcyBob3JhcyA3IGEgOSBwbSwgc2UgcmVnaXN0cmEgdW4gNTAuNSUgeSA1MS4yJSBkZSByZXRyYXNvcywgcmVzcGVjdGl2YW1lbnRlLCBldmlkZW5jaWFuZG8gdW4gcHVudG8gw6FsZ2lkbyBlbiBlc3RlIHBlcsOtb2RvLiAgICANCg0KIyMjIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogYmx1ZTsiPiBDb21wcm9taXNvIMOpdGljbyB5IGNpdWRhZGFubyAoRmFiaWFuYSk8L3NwYW4+ICANCg0KRW4gbnVlc3RybyBkZWJlIGNvbW8gYW5hbGlzdGFzIGRlIGRhdG9zIG5vcyBjb21wcm9tZXRlbW9zIGEgc2VyIGp1c3RvcyBjb24gbG9zIGRhdG9zIGRlIHVuYSBlbXByZXNhLiBFc3RvIGltcGxpY2EgZ2FyYW50aXphciBsYSBjb25maWRlbmNpYWxpZGFkIGRlIGxhIGluZm9ybWFjacOzbiBzZW5zaWJsZSwgdXRpbGl6YXIgbcOpdG9kb3MgeSB0w6ljbmljYXMgw6l0aWNhcyBlbiBlbCBhbsOhbGlzaXMsIHkgcHJlc2VudGFyIGxvcyByZXN1bHRhZG9zIGRlIG1hbmVyYSB0cmFuc3BhcmVudGUgeSBjb21wcmVuc2libGUuIEFkZW3DoXMsIG5vcyBjb21wcm9tZXRlbW9zIGEgY3Vlc3Rpb25hciBjdWFscXVpZXIgcHLDoWN0aWNhIHF1ZSBwdWVkYSBjb21wcm9tZXRlciBsYSBpbnRlZ3JpZGFkIGRlIGxvcyBkYXRvcyBvIGVsIGFuw6FsaXNpcywgYWJvZ2FuZG8gc2llbXByZSBwb3IgbGEgdG9tYSBkZSBkZWNpc2lvbmVzIMOpdGljYXMgeSByZXNwb25zYWJsZXMuICANCg0KDQojIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiBibHVlOyI+IENvbXByb21pc28gw6l0aWNvIHkgY2l1ZGFkYW5vIChTYWx2YWRvcik8L3NwYW4+DQpFbiBudWVzdHJvIGRlYmUgY29tbyBhbmFsaXN0YXMgZGUgZGF0b3Mgbm9zIGNvbXByb21ldGVtb3MgYSBzZXIganVzdG9zIGNvbiBsb3MgZGF0b3MgZGUgdW5hIGVtcHJlc2EuIEVzdG8gaW1wbGljYSBnYXJhbnRpemFyIGxhIGNvbmZpZGVuY2lhbGlkYWQgZGUgbGEgaW5mb3JtYWNpw7NuIHNlbnNpYmxlLCB1dGlsaXphciBtw6l0b2RvcyB5IHTDqWNuaWNhcyDDqXRpY2FzIGVuIGVsIGFuw6FsaXNpcywgeSBwcmVzZW50YXIgbG9zIHJlc3VsdGFkb3MgZGUgbWFuZXJhIHRyYW5zcGFyZW50ZSB5IGNvbXByZW5zaWJsZS4gQWRlbcOhcywgbm9zIGNvbXByb21ldGVtb3MgYSBjdWVzdGlvbmFyIGN1YWxxdWllciBwcsOhY3RpY2EgcXVlIHB1ZWRhIGNvbXByb21ldGVyIGxhIGludGVncmlkYWQgZGUgbG9zIGRhdG9zIG8gZWwgYW7DoWxpc2lzLCBhYm9nYW5kbyBzaWVtcHJlIHBvciBsYSB0b21hIGRlIGRlY2lzaW9uZXMgw6l0aWNhcyB5IHJlc3BvbnNhYmxlcy4gIA0KDQojIyMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiBibHVlOyI+IENvbXByb21pc28gw6l0aWNvIHkgY2l1ZGFkYW5vIChQYXVsZXR0ZSk8L3NwYW4+ICANCkVuIG51ZXN0cm8gZGViZSBjb21vIGFuYWxpc3RhcyBkZSBkYXRvcyBub3MgY29tcHJvbWV0ZW1vcyBhIHNlciBqdXN0b3MgY29uIGxvcyBkYXRvcyBkZSB1bmEgZW1wcmVzYS4gRXN0byBpbXBsaWNhIGdhcmFudGl6YXIgbGEgY29uZmlkZW5jaWFsaWRhZCBkZSBsYSBpbmZvcm1hY2nDs24gc2Vuc2libGUsIHV0aWxpemFyIG3DqXRvZG9zIHkgdMOpY25pY2FzIMOpdGljYXMgZW4gZWwgYW7DoWxpc2lzLCB5IHByZXNlbnRhciBsb3MgcmVzdWx0YWRvcyBkZSBtYW5lcmEgdHJhbnNwYXJlbnRlIHkgY29tcHJlbnNpYmxlLiBBZGVtw6FzLCBub3MgY29tcHJvbWV0ZW1vcyBhIGN1ZXN0aW9uYXIgY3VhbHF1aWVyIHByw6FjdGljYSBxdWUgcHVlZGEgY29tcHJvbWV0ZXIgbGEgaW50ZWdyaWRhZCBkZSBsb3MgZGF0b3MgbyBlbCBhbsOhbGlzaXMsIGFib2dhbmRvIHNpZW1wcmUgcG9yIGxhIHRvbWEgZGUgZGVjaXNpb25lcyDDqXRpY2FzIHkgcmVzcG9uc2FibGVzLiAgDQoNCiMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IGJsdWU7Ij4gQ29tcHJvbWlzbyDDqXRpY28geSBjaXVkYWRhbm8gKCk8L3NwYW4+ICANCkVuIG51ZXN0cm8gZGViZSBjb21vIGFuYWxpc3RhcyBkZSBkYXRvcyBub3MgY29tcHJvbWV0ZW1vcyBhIHNlciBqdXN0b3MgY29uIGxvcyBkYXRvcyBkZSB1bmEgZW1wcmVzYS4gRXN0byBpbXBsaWNhIGdhcmFudGl6YXIgbGEgY29uZmlkZW5jaWFsaWRhZCBkZSBsYSBpbmZvcm1hY2nDs24gc2Vuc2libGUsIHV0aWxpemFyIG3DqXRvZG9zIHkgdMOpY25pY2FzIMOpdGljYXMgZW4gZWwgYW7DoWxpc2lzLCB5IHByZXNlbnRhciBsb3MgcmVzdWx0YWRvcyBkZSBtYW5lcmEgdHJhbnNwYXJlbnRlIHkgY29tcHJlbnNpYmxlLiBBZGVtw6FzLCBub3MgY29tcHJvbWV0ZW1vcyBhIGN1ZXN0aW9uYXIgY3VhbHF1aWVyIHByw6FjdGljYSBxdWUgcHVlZGEgY29tcHJvbWV0ZXIgbGEgaW50ZWdyaWRhZCBkZSBsb3MgZGF0b3MgbyBlbCBhbsOhbGlzaXMsIGFib2dhbmRvIHNpZW1wcmUgcG9yIGxhIHRvbWEgZGUgZGVjaXNpb25lcyDDqXRpY2FzIHkgcmVzcG9uc2FibGVzLiAgDQoNCiMjIyMgPHNwYW4gc3R5bGUgPSAiY29sb3I6IGJsdWU7Ij4gQmlibGlvZ3JhZmlhIDwvc3Bhbj4gIA0KDQpKb2huc29uLCBSLiAoMjAxOCkuICJFdGhpY3MgaW4gRGF0YSBTY2llbmNlOiBBbiBJbnRyb2R1Y3Rpb24uIiBPJ1JlaWxseSBNZWRpYS4gIA0KDQpEYXZlbnBvcnQsIFQuLCAmIEhhcnJpcywgSi4gKDIwMTcpLiAiQ29tcGV0aW5nIG9uIEFuYWx5dGljczogVXBkYXRlZCwgd2l0aCBhIE5ldyBJbnRyb2R1Y3Rpb24uIiBIYXJ2YXJkIEJ1c2luZXNzIFJldmlldyBQcmVzcy4gIA0KDQpEaWFrb3BvdWxvcywgTi4gKDIwMTYpLiAiRGF0YSBFdGhpY3MgYW5kIHRoZSBSb2xlIG9mIERhdGEgU2NpZW5jZSBpbiB0aGUgRm91cnRoIEluZHVzdHJpYWwgUmV2b2x1dGlvbi4iIEpvdXJuYWwgb2YgRGF0YSBTY2llbmNlLCAxNCg0KSwgNTUzLTU2Mi4gIA0K