Contexto

El paquete nycflights13 contiene información sobre todos los vuelos que partieron desde Nueva York (EWR, JFK y LGA) a destinos en los Estados Unidos en 2013. Fueron 336,776 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 = información de construcción de cada avión
  • airports = nombres y ubicaciones de aeropuertos
  • airlines = relación entre nombre y códigos de las aerolíneas

Fuente:
Origen de los datos

Instalar paquetes y llamar librerías

Guardar bases de datos

library(nycflights13)
flights <- flights
weather <- weather
planes <- planes
airports <- airports
airlines <- airlines

Análisis

En este segmento pudimos utilizar las funciones más comúnes del análisis exploratorio, el cuál es el primer paso para cualquier trabajo de manipulación de datos.

Parte 1

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" ...

En los datos del df Flights podemos observar datos de tipo:

int = números enteros

num = números con decimales y negativos

chr = datos alfabéticos

POSIXct = formato de fecha hora (YYYY-MM-DD HH:mm:ss)

Otros tipos de datos no incluidos en la tabla pueden ser:

dbl = dobles, o números reales

dttm = fechas y horas (una fecha + una hora)

Relación entre bases de datos

1. 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>

2. 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" ...
#POSIXct: Formato fecha y hora
#Date:fecha(En R es Año, Mes y Día)

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

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

Es un dataframe, contiene variables ordenadas en diferentes columnas y renglones.

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>

Se muestran los 6 primeros o 6 últimos renglones de flights

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  
## 

Parte 2

En este segmento

Se nos ha consultado encontrar las aerolíneas con mayor número de distancia recorrida y promedio de distancia por viaje.

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. 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 aerolineas 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))
res03
## # 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

Esta tabla muestra los mayores vuelos por distancia, por vuelo, este es el vuelo más largo del aeropuerto JFK a HNL (Nueva York a Honolulú).

Pero si en realidad queremos saber las aerolíneas con más millas recorridas, mostramos la siguiente tabla pero sin la posibilidad de mostrar las columnas origin y dest.

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)

# Agrupa por carrier
res031 <- group_by(res02, carrier)

# Opcionalmente, si deseas sumarizar la distancia total por aerolínea podrías añadir:
res031_summary <- summarise(res031, total_distance = sum(distance))

# Visualiza el resultado
res031_summary <- res031_summary %>% arrange(desc(total_distance))
res031_summary
## # A tibble: 13 × 2
##    carrier total_distance
##    <chr>            <dbl>
##  1 UA            76256278
##  2 B6            40261280
##  3 DL            38759882
##  4 AA            37261176
##  5 VX            12902327
##  6 WN             5963462
##  7 US             4866023
##  8 EV             4574275
##  9 AS             1715028
## 10 HA             1704186
## 11 9E             1686158
## 12 F9             1109700
## 13 MQ              853368

Obtenemos el dato que UA (United Airlines) es la aerolínea con la mayor distancia recorrida en total.

4. Suma y la media de las distancias recorridas por carrier, eliminando los NA’s e interpretando qué significa la suma y la media de las distancias recorridas.

res04 <- res031 %>% group_by(carrier) %>%  
  summarize(sumdistance=sum(distance, na.rm=TRUE), meandistance=mean(distance, na.rm=TRUE)) 
res04 %>% arrange(desc(sumdistance))
## # A tibble: 13 × 3
##    carrier sumdistance meandistance
##    <chr>         <dbl>        <dbl>
##  1 UA         76256278        1941.
##  2 B6         40261280        1648.
##  3 DL         38759882        1791.
##  4 AA         37261176        1607.
##  5 VX         12902327        2499.
##  6 WN          5963462        1556.
##  7 US          4866023        2143.
##  8 EV          4574275        1146.
##  9 AS          1715028        2402 
## 10 HA          1704186        4983 
## 11 9E          1686158        1225.
## 12 F9          1109700        1620 
## 13 MQ           853368        1147

En esta tabla obtenemos sumdistance que representa la suma de las distancias recorridas por aerolínea en vuelos que salen de Nueva York, para meandistance obtenemos el promedio de distancia por aerolínea.

Ordenamos la suma de distancias y obtenemos el mismo dato que la tabla anterior, UA es la aerolínea con más distancia recorrida.

res051 <- res03 %>% group_by(carrier) %>%  
  summarize(sumdistance=sum(distance, na.rm=TRUE), meandistance=mean(distance, na.rm=TRUE)) 
res051 %>% arrange(desc(meandistance))
## # A tibble: 13 × 3
##    carrier sumdistance meandistance
##    <chr>         <dbl>        <dbl>
##  1 HA          1704186        4983 
##  2 VX         12902327        2499.
##  3 AS          1715028        2402 
##  4 US          4866023        2143.
##  5 UA         76256278        1941.
##  6 DL         38759882        1791.
##  7 B6         40261280        1648.
##  8 F9          1109700        1620 
##  9 AA         37261176        1607.
## 10 WN          5963462        1556.
## 11 9E          1686158        1225.
## 12 MQ           853368        1147 
## 13 EV          4574275        1146.

Ordenando de manera descendiente por el promedio de distancia recorrida, obtenemos que HA (Hawaian Airlines) es la aerolínea con el promedio más grande de distancia recorrida por viaje, esto debido a que sus vuelos llevan a Honolulú, el vuelo más largo realizado desde los aeropuertos en Nueva York. La distancia promedio de un vuelo de HA fue de 4983 millas.

A pesar de tener los vuelos más largos, no contienen la mayor distancia recorrida en total.

5. Ordenar en forma descendente por distancia recorrida

res041 <- res031 %>% group_by(carrier) %>%  
  summarize(sumdistance=sum(distance, na.rm=TRUE), meandistance=mean(distance, na.rm=TRUE)) 
res041 %>% arrange(desc(sumdistance))
## # A tibble: 13 × 3
##    carrier sumdistance meandistance
##    <chr>         <dbl>        <dbl>
##  1 UA         76256278        1941.
##  2 B6         40261280        1648.
##  3 DL         38759882        1791.
##  4 AA         37261176        1607.
##  5 VX         12902327        2499.
##  6 WN          5963462        1556.
##  7 US          4866023        2143.
##  8 EV          4574275        1146.
##  9 AS          1715028        2402 
## 10 HA          1704186        4983 
## 11 9E          1686158        1225.
## 12 F9          1109700        1620 
## 13 MQ           853368        1147

6. Identificar si las aerolíneas líderes son las mismas en los tres aeropuertos cuyo origen es Nueva York ( John F. Kennedy (JFK), La Guardia (LGA) and Newark Liberty (EWR) ).

Genera un data frame para cada aeropuerto. Funciones: filter(), arrange()

Primero creamos los DataFrames para cada aeropuerto

res04 <- res03 %>% group_by(carrier,origin,dest) %>%  
  summarize(sumdistance=sum(distance, na.rm=TRUE), meandistance=mean(distance, na.rm=TRUE)) 
## `summarise()` has grouped output by 'carrier', 'origin'. You can override using
## the `.groups` argument.
res05 <- arrange(res04,carrier,sumdistance)
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))
EWR
## # A tibble: 50 × 5
## # Groups:   carrier, origin [9]
##    carrier origin dest  sumdistance meandistance
##    <chr>   <chr>  <chr>       <dbl>        <dbl>
##  1 AA      EWR    DFW       2818088         1372
##  2 AA      EWR    MIA       1158780         1085
##  3 AA      EWR    LAX        895710         2454
##  4 AS      EWR    SEA       1715028         2402
##  5 B6      EWR    FLL       1476090         1065
##  6 B6      EWR    SJU        609432         1608
##  7 B6      EWR    RSW        389820         1068
##  8 DL      EWR    SLC        697026         1969
##  9 EV      EWR    MCI       1480752         1092
## 10 EV      EWR    OMA        852768         1134
## # ℹ 40 more rows

Ahora obtenemos la suma de las distancias obtenidas y las ordenamos de manera descendiente para cada aeropuerto.

JFK_grouped <- JFK %>%
  group_by(carrier) %>%
  summarise(total_sumdistance = sum(sumdistance)) %>%
  arrange(desc(total_sumdistance))
JFK_grouped
## # A tibble: 8 × 2
##   carrier total_sumdistance
##   <chr>               <dbl>
## 1 B6               34655295
## 2 DL               31056240
## 3 AA               21347674
## 4 UA               11496375
## 5 VX                8972450
## 6 US                2366147
## 7 HA                1704186
## 8 9E                1417408
LGA_grouped <- LGA %>%
  group_by(carrier) %>%
  summarise(total_sumdistance = sum(sumdistance)) %>%
  arrange(desc(total_sumdistance))
LGA_grouped
## # A tibble: 9 × 2
##   carrier total_sumdistance
##   <chr>               <dbl>
## 1 AA               11040924
## 2 DL                7006616
## 3 UA                6812736
## 4 B6                3130643
## 5 WN                1765200
## 6 F9                1109700
## 7 MQ                 853368
## 8 EV                 384263
## 9 9E                 268750
EWR_grouped <- EWR %>%
  group_by(carrier) %>%
  summarise(total_sumdistance = sum(sumdistance)) %>%
  arrange(desc(total_sumdistance))
EWR_grouped
## # A tibble: 9 × 2
##   carrier total_sumdistance
##   <chr>               <dbl>
## 1 UA               57947167
## 2 AA                4872578
## 3 WN                4198262
## 4 EV                4190012
## 5 VX                3929877
## 6 US                2499876
## 7 B6                2475342
## 8 AS                1715028
## 9 DL                 697026

Obteniendo las aerolíneas con mayor distancia recorrida separadas por los aeropuertos de Nueva York, nos damos cuenta que sólo en el aeropuerto EWR la aerolínea United Airlines sigue siendo líder en distancia total, mientras qué en LGA es American Airlines y en JFK es JetBlue.

Parte 3

Se nos 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.

Datos Generales

1. Consultar las tablas planes y weather para que conozcamos su contenido.

view(planes)
view(weather)
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
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>

2. Se necesita saber de cada vuelo: La aerolinea, 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

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

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 con origen en Nueva York en 2013 son Chicago con 17,283 vuelos, Atlanta con 17,215 vuelos y Los Angeles con 16,174 vuelos.

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

Esta tabla ahora nos muestra las aerolíneas y destinos con mayor cantidad de vuelos. La aerolínea “Delta Airlines” tuvo la mayor cantidad de vuelos hacia Atlanta.

###6 . Se necesita conocer las aerolíneas (clave y nombre) y destinos que vuelan de: 6 a 12, 12 a 19 , 19 a 24, y 24 a 6.

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"))))
clasxhora
## # 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.     Mañana      
##  6 UA      ORD              558 United Air Lines Inc.    Madrugada   
##  7 B6      FLL              600 JetBlue Airways          Mañana      
##  8 EV      IAD              600 ExpressJet Airlines Inc. Mañana      
##  9 B6      MCO              600 JetBlue Airways          Mañana      
## 10 AA      ORD              600 American Airlines Inc.   Mañana      
## # ℹ 336,766 more rows

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()
cant_clasxhora
## # A tibble: 741 × 4
## # Groups:   carrier, dest, clas_horario [741]
##    carrier dest  clas_horario     n
##    <chr>   <chr> <chr>        <int>
##  1 9E      ATL   Mañana          59
##  2 9E      AUS   Tarde            2
##  3 9E      AVL   Mañana          10
##  4 9E      BGR   Noche            1
##  5 9E      BNA   Mañana           6
##  6 9E      BNA   Noche            1
##  7 9E      BNA   Tarde          467
##  8 9E      BOS   Mañana         271
##  9 9E      BOS   Noche           94
## 10 9E      BOS   Tarde          549
## # ℹ 731 more rows

8. Se necesita saber a qué destinos vuela la aerolínea American Airlines Inc.-AA durante la madrugada (24am-6am).

destinos_aa <- clasxhora %>% 
  select(carrier,name, dest,clas_horario) %>% 
  filter(carrier == "AA" & clas_horario == "Madrugada") %>% 
  group_by(carrier,name, dest,clas_horario)
destinos_aa
## # 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

Encontramos que el único destino de American Airlines por la madrugada es hacia Miami.

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()

Los datos indican que:
AA utiliza principalmente aviones de tipo “Fixed wing multi engine”. AA utiliza principalmente motores “turbo fan” en sus aviones. AA utiliza aviones que tienen desde 2 asientos hasta 330 asientos.

Retrasos en vuelos con origen de Nueva York

Después de haber examinado en detalle las tablas de nycflights13, es el momento de identificar diversos descubrimientos que nos ayuden a resolver el problema planteado: ¿Cuáles son los causantes de los retrasos en vuelos con origen de Nueva York?

Retrasos por aerolínea

bdgrande <- merge(flights,airlines, by="carrier")
bdgrande2 <- left_join(bdgrande, planes, by="tailnum")
bdgrande3 <- left_join(bdgrande2,weather, by=c("origin", "time_hour"))
bdgrande3 <- mutate(bdgrande3, dist_Km = distance*1.609)
bdevidencia <- left_join(bdgrande3,weather, by=c("origin", "time_hour"))
retrasos_aerolinea <- bdgrande3 %>%
  group_by(carrier) %>%
  summarise(retraso_promedio = mean(dep_delay, na.rm = TRUE),
            total_vuelos = n(),
            total_vuelos_atrasados = sum(dep_delay > 0, na.rm = TRUE),
            porcentaje_de_retraso = total_vuelos_atrasados/ total_vuelos * 100) %>%
  mutate(calificacion_aerolinea = rank(-porcentaje_de_retraso)) %>%
  arrange(desc(retraso_promedio))

retrasos_aerolinea
## # A tibble: 16 × 6
##    carrier retraso_promedio total_vuelos total_vuelos_atrasados
##    <chr>              <dbl>        <int>                  <int>
##  1 F9                 20.2           685                    341
##  2 EV                 20.0         54173                  23139
##  3 YV                 19.0           601                    233
##  4 FL                 18.7          3260                   1654
##  5 WN                 17.7         12275                   6558
##  6 9E                 16.7         18460                   7063
##  7 B6                 13.0         54635                  21445
##  8 VX                 12.9          5162                   2225
##  9 OO                 12.6            32                      9
## 10 UA                 12.1         58665                  27261
## 11 MQ                 10.6         26397                   8031
## 12 DL                  9.26        48110                  15241
## 13 AA                  8.59        32729                  10162
## 14 AS                  5.80          714                    226
## 15 HA                  4.90          342                     69
## 16 US                  3.78        20536                   4775
## # ℹ 2 more variables: porcentaje_de_retraso <dbl>, calificacion_aerolinea <dbl>

Usando una función de rank(), podemos ver que la aerolinea con mayor proporción de retrasos en sus vuelos es 1. WN con 53.42%. Le sigue 2. FL con 50.74%, y 3. F9 con 49.78%.

Siguente, vemos que la aerolinea con mayor retrasos promedio en minutos por vuelo es F9 con 20.2 minutos, luego EV con 19.9 minutos, y finalmente YV con 18.9 minutos.

Es crítico notar que en ambos análisis, aparece Frontier Airlines (F9). Si sumamos sus minutos de retraso promedio con la cantidad de vuelos atrasados del año, nos da 6888 minutos que perdieron los clientes. Si hacemos lo mismo con Expressjet Airlines (EV), fueron aproximadamente 462,780 minutos que la aerolinea le quitó a sus clientes.

Retrasos por aeropuerto de origen

retrasos_aerolinea <- bdgrande3 %>%
  group_by(origin) %>%
  summarise(retraso_promedio = mean(dep_delay, na.rm = TRUE),
            total_vuelos = n(),
            total_vuelos_atrasados = sum(dep_delay > 0, na.rm = TRUE),
            porcentaje_de_retraso = total_vuelos_atrasados/ total_vuelos * 100) %>%
  mutate(calificacion_aerolinea = rank(-porcentaje_de_retraso)) %>%
  arrange(desc(retraso_promedio))

retrasos_aerolinea
## # A tibble: 3 × 6
##   origin retraso_promedio total_vuelos total_vuelos_atrasados
##   <chr>             <dbl>        <int>                  <int>
## 1 EWR                15.1       120835                  52711
## 2 JFK                12.1       111279                  42031
## 3 LGA                10.3       104662                  33690
## # ℹ 2 more variables: porcentaje_de_retraso <dbl>, calificacion_aerolinea <dbl>

Igual que las aerolíneas, usando summarize(), mean(), mutate(), arrange(), y rank() podemos ver los resultados de los aeropuertos de origen (JFK, EWR, LGA).
EWR fue el aeropuerto con más porcentaje de vuelos con retraso (43.62%) y también fue el aeropuerto con más retraso promedio por vuelo, con 15.1 minutos. El segundo aeropuerto con más porcentaje de vuelos con retraso y retraso promedio en minutos es JFK con 37.7% de sus vuelos sufriendo retraso, y 12.1 minutos promedio por retraso. Finalmente, tenemos LGA con 32.2% y 10.3 minutos por retraso.

retrasos_aerolinea <- bdgrande3 %>%
  group_by(hour.x) %>%
  summarise(retraso_promedio = mean(dep_delay, na.rm = TRUE),
            total_vuelos = n(),
            total_vuelos_atrasados = sum(dep_delay > 0, na.rm = TRUE),
            porcentaje_de_retraso = total_vuelos_atrasados/ total_vuelos * 100) %>%
  mutate(calificacion_aerolinea = rank(-porcentaje_de_retraso)) %>%
  arrange(desc(porcentaje_de_retraso))

retrasos_aerolinea
## # A tibble: 20 × 6
##    hour.x retraso_promedio total_vuelos total_vuelos_atrasados
##     <dbl>            <dbl>        <int>                  <int>
##  1     20           24.3          16739                   8633
##  2     21           24.2          10933                   5596
##  3     19           24.8          21441                  10839
##  4     17           21.1          24426                  12132
##  5     18           21.1          21783                  10636
##  6     15           16.9          23888                  11364
##  7     16           18.8          23002                  10699
##  8     22           18.8           2639                   1184
##  9     23           14.0           1061                    461
## 10     14           13.8          21706                   9257
## 11     13           11.4          19956                   8183
## 12     12            8.61         18181                   6408
## 13     11            7.19         16033                   5034
## 14     10            6.50         16708                   4942
## 15      9            4.58         20312                   5392
## 16      5            0.688         1953                    489
## 17      8            4.13         27242                   6790
## 18      7            1.91         22821                   4963
## 19      6            1.64         25951                   5430
## 20      1          NaN                1                      0
## # ℹ 2 more variables: porcentaje_de_retraso <dbl>, calificacion_aerolinea <dbl>

De igual manera que analizamos los aeropuertos y sus aerolíneas, ahora analizaremos las horas del día. Estamos prorizando el dato porcentaje_de_retraso pues creemos que es el indicador más relevante a la investigación. Por esa misma razón, usamos rank() para ver más claramente las horas del día con mayor porcentaje de retraso. En el caso de las horas, podemos ver que las horas de la tarde-noche son las que más sufren de retrasos, pues las horas 20:00, 21:00, 19:00, 17:00, y 18:00 son las horas rankeadas 1-5 del punto de vista de porcentaje de retraso. Estas horas, al ser las horas más ocupadas de los aeropuertos, (USA TODAY, 2017) son las que más probable son de sufrir un retraso. Tienes entre 51.6% y 48.8% chance de sufrir un retraso si tu vuelo sale a estas horas de Nueva York.

flights_weather <- left_join(flights, weather, by = c("year", "month", "day", "hour", "origin"))
flights_weather_clean <- subset(flights_weather, dep_delay < quantile(dep_delay, 0.99, na.rm = TRUE))

flights_weather_clean <- subset(flights_weather, dep_delay < quantile(dep_delay, 0.99, na.rm = TRUE)) 
regresion_weather_clean <- lm(dep_delay ~ temp + dewp + humid + wind_dir + wind_gust + pressure + visib, data = flights_weather_clean)
summary(regresion_weather_clean)
## 
## Call:
## lm(formula = dep_delay ~ temp + dewp + humid + wind_dir + wind_gust + 
##     pressure + visib, data = flights_weather_clean)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -47.04 -14.88 -10.29   1.07 187.83 
## 
## Coefficients:
##               Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 199.742508  18.842115  10.601  < 2e-16 ***
## temp          0.350796   0.065811   5.330 9.83e-08 ***
## dewp         -0.318637   0.072222  -4.412 1.03e-05 ***
## humid         0.304856   0.040632   7.503 6.31e-14 ***
## wind_dir     -0.007110   0.001562  -4.553 5.30e-06 ***
## wind_gust     0.191084   0.021632   8.833  < 2e-16 ***
## pressure     -0.201095   0.017432 -11.536  < 2e-16 ***
## visib        -1.127130   0.128199  -8.792  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 29.34 on 72319 degrees of freedom
##   (252869 observations deleted due to missingness)
## Multiple R-squared:  0.02119,    Adjusted R-squared:  0.0211 
## F-statistic: 223.7 on 7 and 72319 DF,  p-value: < 2.2e-16

En el análisis que realizamos del modelo de regresión lineal con la variable de weather, se identificaron condiciones meterológicas que explican la variabilidad en los retrasos de los vuelos en un 2.1% y lo indica en el R2 ajustada de 0.0211. Esta variable es mucho más significativa que otras variables como humedad, dirección del viento, presión, etc. Y el impacto de estas variables es mucho menor, por ejemplo, el incremento de la temperatura aumenta en 0.35 minutos por cada grado Fahrenheit, y el aumento de visibilidad reduce en 1.127 minutos por milla. Aunque afectan estos aspectos en los retrasos, hay más factores que tienen una influencia mayor en los retrasos de los vuelos.

Visualización de los Datos

Visualización de la temperatura durante los primeros 15 días de enero con una gráfica de línea:

library(ggplot2)
weather_january <- weather %>%
  filter(month == 1, day <= 15, origin == "EWR")

ggplot(weather_january, aes(x = day, y = temp)) +
  geom_line() +
  labs(title = "Temperatura durante los primeros 15 días de enero", x = "Día", y = "Temperatura (°F)")

###Interpretación de gráfica: Con esta gráfica podemos observar la temperatura durante los primeros días del mes de enero en el aeropuerto de Newark (EWR), además de notar que tiene ciertas tendencias de aumento y alteración que nos pueden estar señalando la autoridad de los sistemas climáticos temporales. Entre sus temperaturas podemos ver que se encuentran entre menos de 35°F y casi alcanzando 50°F, esto nos puede indicar que es posible que estas temperaturas lleguen a perjudicar los servicios aeroportuarios y la planeación de los vuelos a causa de el impacto en la seguridad y operatividad de las aeronaves.

##Histograma de la temperatura más frecuente en los primeros 15 días de enero

ggplot(weather_january, aes(x = temp)) +
  geom_histogram(bins = 30, fill = "blue", color = "black") +
  labs(title = "Histograma de la temperatura en Enero", x = "Temperatura (°F)", y = "Frecuencia")

###Interpretación de gráfica: En este histograma observamos una clara división en dos grupos diferentes, que nos señalan dos rangos que fueron frecuentes, lo que nos puede mostrar variaciones en las normas climáticas durante el mes. Esta gráfica nos ayuda a poder prevenir alteraciones climáticas que afecten a las necesidades operativas del aeropuerto.

##Facets para observar como varía la temperatura cada mes

weather %>% 
  ggplot(aes(x = temp)) +
  geom_histogram(bins = 30) +
  facet_wrap(~month) +
  labs(title = "Distribución de la temperatura por mes", x = "Temperatura (°F)", y = "Frecuencia")

##Interpretación de gráfica: Aquí podemos ver cómo existe un patrón estacional referente a la temperatura en el aeropuerto de Newark, que tiene temperaturas frías y cálidas, lo que es fundamental para la administración y planeación relacionada con los aeropuertos en lo que resta del año.

##Número de vuelos que salieron de Nueva York por aerolínea en 2013 con un gráfico de barras

flights %>% 
  filter(origin %in% c("JFK", "LGA", "EWR")) %>%
  group_by(carrier) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = reorder(carrier, -count), y = count)) +
  geom_bar(stat = "identity", fill = "coral") +
  labs(title = "Número de vuelos por aerolínea en 2013", x = "Aerolínea", y = "Cantidad de vuelos") +
  theme(axis.text.x = element_text(angle = 90, hjust = 1))

##Interpretación de gráfica: En este gráfico podemos ver como pocas aerolíneas son las que encabezan la cantidad de vuelos que hubo en NYC en 2013, lo que muestra una asignación desigual del tráfico aéreo y puede llegar a encaminar servicios aeroportuarios y a la planeación de infraestructura.

##Gráfica de pie para el número de vuelos por aerolínea

flights %>% 
  group_by(carrier) %>%
  summarise(count = n()) %>%
  ggplot(aes(x = "", y = count, fill = carrier)) +
  geom_bar(width = 1, stat = "identity") +
  coord_polar("y") +
  labs(title = "Distribución de vuelos por aerolínea")

##Interpretación de gráfica: En esta gráfica de pie vemos que ciertas aerolíneas son las que lideran el mercado de vuelos en la ciudad de Nueva York, lo que se evidencia en las secciones más grandes, mientras que otras presentaron una menor colaboración.

##Relacionar el dataframe flights con el dataframe airports usando el campo destino

flights_airports <- flights %>%
  left_join(airports, by = c("dest" = "faa"))

##Crear un nuevo dataframe con el punto anterior únicamente con los 5 carriers con más vuelos por destino

top_carriers <- flights %>%
  group_by(carrier) %>%
  summarise(count = n()) %>%
  arrange(desc(count)) %>%
  slice(1:5) %>%
  ungroup() %>%
  select(carrier)

flights_top_carriers <- flights_airports %>%
  filter(carrier %in% top_carriers$carrier)

##Visualización del punto anterior de las siguientes tres formas

##**Gráfico de barras para la cantidad de vuelos por aerolínea:**

# Asumiendo que flights_top_carriers contiene los datos de los vuelos de los 5 principales transportistas
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()

##Interpretación de Gráfica: Esta gráfica de barras nos sirve para comparar el volumen de operaciones que tiene cada aerolínea y con esto poder realizar análisis de capacidad operativa y análisis competitivos, como vemos en la gráfica la aerolínea UA va de primera, teniendo la mayor cantidad de vuelos.

#**Gráfico de barras para la cantidad de vuelos por destino**

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))

##Interpretación de Gráfica: Observamos la cantidad de vuelos que hay a los diferentes destinos que son operados por las siguientes aerolíneas (AA, B6, DL, EV, UA), en este caso podemos ver como cada color va representando una aerolínea distinta y se observa que la altura de estas barras es la cantidad de vuelos a los diferentes destinos. Es posible notar como ciertos destinos presentan una gran concentración de vuelos por más de una aerolínea, en cambio otros cuentan con una menor cantidad, lo que nos muestra la popularidad de dichos destinos.

##**Gráfico de barras para la cantidad de vuelos por día del mes**

ggplot(flights_top_carriers, aes(x = factor(day), fill = carrier)) +
  geom_bar() +
  labs(title = "Cantidad de vuelos por día del mes", x = "Día del mes", y = "Cantidad de vuelos") +
  theme_minimal()

##Interpretación de Gráfica: En esta gráfica podemos observar que las barras muestran los números de vuelos diarios en un mes, para diferentes aerolíneas. Las capas de color nos indican cuál aerolínea es de la que se esta hablando y que contribución de vuelos tienen en total en un día. Ahora hablando sobre la altura combinada de estas barras, nos da a entender que el número de vuelos se mantiene constante en el mes, sin ningún tipo de cambios drásticos. Esto es bueno ya que nos señala que existe una operación regular en el aeropuerto sin grandes modificaciones en el tráfico aéreo por parte de las aerolíneas.

Conclusión Final

En nuestro análisis detallado de la base de datos nycflights13, analizamos tendencias y patrones clave para poder determinar los retrasos de los vuelos que parten de Nueva york en 2013. La aerolínea United Airlines lideró en términos de millas recorridas desde EWR, mientras que la de American Airlines y JetBlue fueron los que lideraron en LGA y JFK, así como los destinos más frecuentados incluyeron Atlanta, Los Ángeles y Chicago.

Estos análisis nos indican las horas de tarde a noche en el cuál hay mayores retrasos, con los retrasos aumentando hasta el 51.6% de retraso para los vuelos que salen después de las 20:00 y la congestión de estos vuelos durante las horas pico. Las aerolíneas indicaron diferentes variaciones significativas en los retrasos, como Southwest Airlines con un 53.42% en sus vuelos retrasados. En los aeropuertos, EWR obtuvo el mayor porcentaje de vuelos retrasados con un porcentaje de 43.62% y el mayor retraso promedio de 15.1 minutos por cada vuelo.

Sin embargo, aunque las condiciones meteorológicas son estadísticamente significativas solo se explicaron en un 2.1% de la variabilidad que tienen los retrasos de los vuelos. Aunque el clima afecta los retrasos, otros factores como la gestión aeroportuaria y las operaciones de las aerolíneas nos indican un impacto más sustancial lo que vemos como un gran hallazgo para determinar las variables que más impactan. Identificamos que existen oportunidades de mejora en la gestión operativa y en respuesta hacia las condiciones climáticas, debido a que los retrasos son un complejo influenciado por una variedad de factores, desde las decisiones estratégicas de cada aerolínea, hasta la congestión aeroportuaria.

Gracias a estos datos pudimos analizar la problemática de los retrasos, entre todas las variables que analizamos obtuvimos las más importantes. El “Columbia Metropolitan Airport” es el destino con mayor porcentaje de retrasos siendo el 53% de las veces, este aeropuerto genera atrasos en la mitad de sus vuelos, este porcentaje indica que los retrasos son responsabilidad del aeropuerto destino. El aeropuerto destino con más promedio de retraso es Traverse City, Michigan con 89 minutos promedio de retraso. Ahora considerando las variables naturales encontramos que la humedad juega el papel más importante en los retrasos de los aviones, en el 98% de ellos la humedad fue medianamente alta e influyó en el tiempo de vuelo, salida y llegada.

Ética y responsabilidad en los Negocios

Dereck Iker Villafaña Romero

El uso de las bases de datos en nuestra carrera y futuras prácticas debe ser utilizado de manera muy respetuosa y responsable, tomando en cuenta que en el futuro estaré muy probablemente trabajando con bases de datos de empresas o personas, a la hora de realizar algún análisis o trabajo, debo comprender la importancia de respetar y cuidar estos datos. La información de las empresas es uno de sus más valiosos activos y estoy consciente que siempre debo actuar con integridad a la hora de trabajar con estos datos. Me comprometo a siempre respetar la privacidad de las personas involucradas en las bases de datos cuándo se involucren datos personales o datos críticos de la empresa que puedan ser utilizados en su contra por terceros.

Carolina Suárez Rodríguez

Al hablar de la integridad nos referimos al hablar de transparencia, es decir ser éticos y responsables con las acciones que tomamos al tomar una decisión, cabe recalcar que siempre debemos utilizar esta transparencia a la hora de trabajar en una empresa y con sus informaciones clasificadas. Es de suma importancia conservar siempre tu integridad para así lograr formar lazos de confianza con tus mismos clientes, para así poder garantizar un éxito duradero.

Federico Zorrilla Jasso

Somos muy afortunados que como institución muchas empresas nos comparten sus bases de datos. En el bloque de Indicadores y Riesgos con Visión Estratégica, trabajamos con los datos de Arca Continental, una empresa muy grande que valúa sus datos. En un futuro, idealmente trabajaré con las bases de datos de diversas empresas, y es necesario tener en cuenta que esos datos son oro. Una empresa te confía con ellos, y la competencia haría lo que sea para conseguirlos. Han habido miles de millones de casos que algún extorsionador “breachea” los datos de una empresa, y amenaza con publicarlos. Ahora imagina lo fácil que es si este hacker hubiera decidido hackearme a mí. Seguramente es más fácil que hackear a una empresa, y ahora yo estoy ligado al problema. Por esta razón y muchas más, es crítico cuidar de los datos que nos comparten las empresas con las que trabajamos.

LS0tDQp0aXRsZTogIkV2aWRlbmNpYSAxIEFuYWzDrXRpY2EgZGVzY3JpcHRpdmEgIHkgRXZpZGVuY2lhIDIgLSBBbmFsw610aWNhIGRlc2NyaXB0aXZhICINCmF1dGhvcjogIkVxdWlwbyA5Og0KICANCkNhcm9saW5hIFN1w6FyZXogUm9kcsOtZ3VleiAtIEEwMDgzNzkyMi4gDQpEZXJlY2sgSWtlciBWaWxsYWZhw7FhIFJvbWVybyAtIEEwMDU3Mzc1Ni4gDQpGZWRlcmljbyBab3JyaWxsYSBKYXNzbyAtIEEwMDgzNjYyOSIgDQpkYXRlOiAiMDUvMDMvMjAyNCINCm91dHB1dDogDQogIGh0bWxfZG9jdW1lbnQ6DQogICAgdG9jOiBUUlVFDQogICAgdG9jX2Zsb2F0OiBUUlVFDQogICAgY29kZV9kb3dubG9hZDogVFJVRQ0KICAgIHRoZW1lOiB5ZXRpICAgICAgIA0KLS0tDQohW10oQzpcXFVzZXJzXFxVc3VhcmlvXFxEb3dubG9hZHNcXDBhODVmNzFlMTAxMWQ3NDIzOGI3ODVkOWI1NDAxODk5LmdpZikNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5Db250ZXh0bzwvc3Bhbj4NCkVsIHBhcXVldGUgKipueWNmbGlnaHRzMTMqKiBjb250aWVuZSBpbmZvcm1hY2nDs24gc29icmUgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgcGFydGllcm9uIGRlc2RlIE51ZXZhIFlvcmsgKEVXUiwgSkZLIHkgTEdBKSBhIGRlc3Rpbm9zIGVuIGxvcyBFc3RhZG9zIFVuaWRvcyBlbiAyMDEzLiAgRnVlcm9uIDMzNiw3NzYgdnVlbG9zIGVuIHRvdGFsLiBQYXJhIGF5dWRhciBhIGNvbXByZW5kZXIgbGFzIGNhdXNhcyBkZSBsb3MgcmV0cmFzb3MsIHRhbWJpw6luIGluY2x1eWUgb3Ryb3MgY29uanVudG9zIGRlIGRhdG9zIMO6dGlsZXMuICANCg0KRXN0ZSBwYXF1ZXRlIGluY2x1eWUgbGFzIHNpZ3VpZW50ZXMgdGFibGFzOg0KDQorICoqKmZsaWdodHMqKiogPSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzYWxpZXJvbiBkZSBOdWV2YSBZb3JrIGVuIDIwMTMgIA0KKyAqKip3ZWF0aGVyKioqID0gZGF0b3MgbWV0ZW9yb2zDs2dpY29zIHBvciBob3JhIGRlIGNhZGEgYWVyb3B1ZXJ0byAgDQorICoqKnBsYW5lcyoqKiA9IGluZm9ybWFjacOzbiBkZSBjb25zdHJ1Y2Npw7NuIGRlIGNhZGEgYXZpw7NuICANCisgKioqYWlycG9ydHMqKiogPSBub21icmVzIHkgdWJpY2FjaW9uZXMgZGUgYWVyb3B1ZXJ0b3MgIA0KKyAqKiphaXJsaW5lcyoqKiA9IHJlbGFjacOzbiBlbnRyZSBub21icmUgeSBjw7NkaWdvcyBkZSBsYXMgYWVyb2zDrW5lYXMgIA0KDQoNCkZ1ZW50ZTogIA0KW09yaWdlbiBkZSBsb3MgZGF0b3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9ueWNmbGlnaHRzMTMvaW5kZXguaHRtbCkNCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+SW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hczwvc3Bhbj4NCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQ0KI2luc3RhbGwucGFja2FnZXMoIm55Y2ZsaWdodHMxMyIpDQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCiNpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpgYGANCg0KDQojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5HdWFyZGFyIGJhc2VzIGRlIGRhdG9zPC9zcGFuPg0KYGBge3J9DQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykNCmZsaWdodHMgPC0gZmxpZ2h0cw0Kd2VhdGhlciA8LSB3ZWF0aGVyDQpwbGFuZXMgPC0gcGxhbmVzDQphaXJwb3J0cyA8LSBhaXJwb3J0cw0KYWlybGluZXMgPC0gYWlybGluZXMNCmBgYA0KDQoNCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkFuw6FsaXNpczwvc3Bhbj4NCg0KRW4gZXN0ZSBzZWdtZW50byBwdWRpbW9zIHV0aWxpemFyIGxhcyBmdW5jaW9uZXMgbcOhcyBjb23Dum5lcyBkZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbywgZWwgY3XDoWwgZXMgZWwgcHJpbWVyIHBhc28gcGFyYSBjdWFscXVpZXIgdHJhYmFqbyBkZSBtYW5pcHVsYWNpw7NuIGRlIGRhdG9zLg0KDQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5QYXJ0ZSAxPC9zcGFuPg0KDQoNCg0KIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+Q29uc3VsdGEgbGEgZXN0cnVjdHVyYSBkZSBmbGlnaHRzPC9zcGFuPg0KIyMjIMK/Q3XDoWxlcyBzb24gbG9zIGNhbXBvcyB5IHN1cyB0aXBvcyBkZSBkYXRvcz8uICBJZGVudGlmaWNhIGxvcyBkaWZlcmVudGVzIHRpcG9zIGRlIGRhdG9zIHkgZXhwbGljYSBlbiBxdcOpIGNvbnNpc3RlIGNhZGEgdW5vIGRlIGVsbG9zIHkgY3XDoWwgZXMgbGEgZGlmZXJlbmNpYSBlbnRyZSB1bm8geSBvdHJvLCBpbmNsdXllbmRvIGxvcyBzaWd1aWVudGVzIHRpcG9zIGRlIGRhdG9zOiBpbnQsIGRibCwgY2hyLCBkdHRtLg0KDQpgYGB7cn0NCnN0cihmbGlnaHRzKQ0KDQpgYGANCkVuIGxvcyBkYXRvcyBkZWwgKmRmKiAqKkZsaWdodHMqKiBwb2RlbW9zIG9ic2VydmFyIGRhdG9zIGRlIHRpcG86DQoNCg0KDQppbnQgPSBuw7ptZXJvcyBlbnRlcm9zDQoNCg0KbnVtID0gbsO6bWVyb3MgY29uIGRlY2ltYWxlcyB5IG5lZ2F0aXZvcw0KDQoNCmNociA9IGRhdG9zIGFsZmFiw6l0aWNvcw0KDQoNClBPU0lYY3QgPSBmb3JtYXRvIGRlIGZlY2hhIGhvcmEgKFlZWVktTU0tREQgSEg6bW06c3MpDQoNCg0KDQpPdHJvcyB0aXBvcyBkZSBkYXRvcyBubyBpbmNsdWlkb3MgZW4gbGEgdGFibGEgcHVlZGVuIHNlcjoNCg0KZGJsID0gZG9ibGVzLCBvIG7Dum1lcm9zIHJlYWxlcw0KDQoNCmR0dG0gPSBmZWNoYXMgeSBob3JhcyAodW5hIGZlY2hhICsgdW5hIGhvcmEpDQoNCg0KIyMgUmVsYWNpw7NuIGVudHJlIGJhc2VzIGRlIGRhdG9zDQohW10oQzpcXFVzZXJzXFxVc3VhcmlvXFxEb3dubG9hZHNcXENhcHR1cmEgZGUgcGFudGFsbGEgMjAyNC0wMi0xOSAxMjE3MjUucG5nKQ0KDQoNCiMjIDEuIENhcmdhciBlbiBtZW1vcmlhIGxhIHRhYmxhICJmbGlnaHRzIiB5IG1vc3RyYXIgc3UgY29udGVuaWRvLg0KYGBge3J9DQojIExhIGNhcmdhIGEgbWVtb3JpYSBzZSBoaXpvIGVuIGVsIHBhc28gYW50ZXJpb3INCmZsaWdodHMNCmBgYA0KDQoNCiMjIDIuIENvbnN1bHRhIGxhIGVzdHJ1Y3R1cmEgZGUgImZsaWdodHMiLg0KYGBge3J9DQpzdHIoZmxpZ2h0cykNCiNQT1NJWGN0OiBGb3JtYXRvIGZlY2hhIHkgaG9yYQ0KI0RhdGU6ZmVjaGEoRW4gUiBlcyBBw7FvLCBNZXMgeSBEw61hKQ0KYGBgDQoNCg0KDQoNCg0KIyMgMy4gwr9DdcOhbCBlcyBsYSBjbGFzZSBkZSBmbGlnaHRzPyB5IMK/UXXDqSBzaWduaWZpY2E/DQpgYGB7cn0NCmNsYXNzKGZsaWdodHMpDQpgYGANCkVzIHVuIGRhdGFmcmFtZSwgY29udGllbmUgdmFyaWFibGVzIG9yZGVuYWRhcyBlbiBkaWZlcmVudGVzIGNvbHVtbmFzIHkgcmVuZ2xvbmVzLiANCg0KDQojIyA0LiDCv0N1w6FudGFzIGNvbHVtbmFzIHRpZW5lIGZsaWdodHM/DQpgYGB7cn0NCm5jb2woZmxpZ2h0cykNCmBgYA0KIyMgNS4gwr9DdcOhbnRvcyByZW5nbG9uZXMgdGllbmUgZmxpZ2h0cz8NCg0KYGBge3J9DQpucm93KGZsaWdodHMpDQpgYGANCiMjIDYuIMK/Q3XDoWwgZXMgbGEgZGltZW5zacOzbiBkZSBmbGlnaHRzPw0KDQpgYGB7cn0NCmRpbShmbGlnaHRzKQ0KYGBgDQojIyA3LiBDb25zdWx0YSBsYSB0YWJsYSBmbGlnaHRzDQpgYGB7ciBlY2hvPVRSVUV9DQp2aWV3KGZsaWdodHMpDQoNCmBgYA0KDQojIyA4LiBHZW5lcmEgdW4gb3V0cHV0IGRlIGxhIHRhYmxhIGZsaWdodHMuIFV0aWxpemEgbGFzIGZ1bmNpb25lcyBoZWFkIHkgdGFpbCwgwr9DdcOhbnRvcyByZW5nbG9uZXMgbXVlc3RyYW4gcG9yIGRlZmVjdG8gY2FkYSBmdW5jacOzbj8NCg0KYGBge3IgZWNobz1UUlVFfQ0KDQpoZWFkKGZsaWdodHMpDQp0YWlsKGZsaWdodHMpDQpgYGANClNlIG11ZXN0cmFuIGxvcyA2IHByaW1lcm9zIG8gNiDDumx0aW1vcyByZW5nbG9uZXMgZGUgKmZsaWdodHMqDQoNCg0KIyMgOS4gQWhvcmEgbXVlc3RyYSBsb3MgcHJpbWVyb3MgNTAgcmVnaXN0cm9zIHkgbG9zIMO6bHRpbW9zIDIwLCDCv0PDs21vIGxvIGhhcsOtYXM/IA0KDQpgYGB7ciBlY2hvPVRSVUV9DQoNCmhlYWQoZmxpZ2h0cyw1MCkNCnRhaWwoZmxpZ2h0cywyMCkNCg0KYGBgDQoNCiMjIDEwLiBFbmN1ZW50cmEgbG9zIHJlc3VsdGFkb3MgZGVzY3JpcHRpdm9zIGRlIGxhcyB2YXJpYWJsZXMgZW4gbGEgYmFzZSBkZSBkYXRvcy4gRWplbXBsbzogcHJvbWVkaW8sIG1vZGEsIG3DrW5pbW8sIG3DoXhpbW8sIGV0Yy4gDQoNCkZ1bmNpw7NuOiBzdW1tYXJ5LiANCg0KYGBge3J9DQogIA0Kc3VtbWFyeShmbGlnaHRzKQ0KDQpgYGANCg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlBhcnRlIDI8L3NwYW4+DQoNCg0KIyMgRW4gZXN0ZSBzZWdtZW50byANCg0KDQoNCiMjIFNlIG5vcyBoYSBjb25zdWx0YWRvIGVuY29udHJhciBsYXMgYWVyb2zDrW5lYXMgY29uIG1heW9yIG7Dum1lcm8gZGUgZGlzdGFuY2lhIHJlY29ycmlkYSB5IHByb21lZGlvIGRlIGRpc3RhbmNpYSBwb3IgdmlhamUuDQpJbnN0cnVjY2lvbmVzOg0KDQpMaWJyZXLDrWFzIHJlcXVlcmlkYXM6IA0K4oCiCVBhcXVldGVzICByZXF1ZXJpZG9zIHBhcmEgbGEgcHLDoWN0aWNhOiAgdGlkeXZlcnNlLCBueWZsaWdodHMxMyANCiAgRWwgcGFxdWV0ZSB0aWR5dmVyc2UgaW5jbHV5ZSB2YXJpYXMgbGlicmVyw61hcyBlbnRyZSBlbGxhcyBnZ3Bsb3QyLCBkcGx5ciwgdGlkeXZlcnNlDQogIEVsIHBhcXVldGUgbnlmbGlnaHRzMTMgaW5jbHV5ZSB2YXJpYXMgYmFzZXMgZGUgZGF0b3MgZW50cmUgZWxsYXMgZmxpZ2h0cyANCuKAoiBMaWJyZXLDrWFzIHF1ZSBkZWJlbiBlc3RhciBpbnN0YWxhZGFzOiAgZ2dwbG90MiwgIGRwbHlyLCB0aWR5dmVyc2UNCg0KYGBge3J9DQoNCmxpYnJhcnkobnljZmxpZ2h0czEzKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGRwbHlyKQ0KZGF0YSgiZmxpZ2h0cyIpDQpgYGANCg0KIyMgMS4gTW9zdHJhciBsYSBiYXNlIGRlIGRhdG9zIGZsaWdodHMgcGFyYSBxdWUgY29ub3pjYXMgc3UgY29udGVuaWRvDQoNCmBgYHtyfQ0KdmlldyhmbGlnaHRzKQ0KYGBgDQoNCg0KIyMgMi4JRW5jdWVudHJhIGxvcyBkYXRvcyBkZXNjcmlwdGl2b3MgZGVsIGRhdGEgZnJhbWUgZmxpZ2h0cy4gSWRlbnRpZmljYSBsYSBtZWRpYSBkZSBsYXMgZGlzdGFuY2lhcyByZWNvcnJpZGFzIGVuIG1pbGxhcy4NCmBgYHtyfQ0Kc3VtbWFyeShmbGlnaHRzKQ0KYGBgDQoNCg0KIyMgMy4JQWVyb2zDrW5lYXMgY29uIG1pbGxhcyByZWNvcnJpZGFzIHN1cGVyaW9yZXMgYSBsYSBtZWRpYSwgb3JkZW5hZGFzIGVuIGZvcm1hIGRlc2NlbmRlbnRlLg0KDQoNCmBgYHtyfQ0KI3NlbGVjY2lvbmEgbGFzIHZhcmlhYmxlcyBjYXJyaWVyLCBkaXN0YW5jZSwgb3JpZ2luLCBkZXN0IGRlIGxhIHRhYmxhDQpyZXMwMSA8LSBzZWxlY3QoZmxpZ2h0cywgY2FycmllciwgZGlzdGFuY2UsIG9yaWdpbiwgZGVzdCkNCg0KI3NlIGZpbHRyYSBsYXMgYWVyb2xpbmVhcyBjb24gbWlsbGFzIHJlY29ycmlkYXMgc3VwZXJpb3JlcyBhIGxhIG1lZGlhIC0gMTA0MCANCnJlczAyIDwtIGZpbHRlcihyZXMwMSwgZGlzdGFuY2UgPjEwNDApIA0KDQojb3JkZW5hIGVuIGZvcm1hIGRlc2NlbmRlbnRlIHBvciBkaXN0YW5jaWEgcmVjb3JyaWRhIA0KcmVzMDMgPC0gYXJyYW5nZShyZXMwMiwgZGVzYyhkaXN0YW5jZSkpDQpyZXMwMw0KYGBgDQpFc3RhIHRhYmxhIG11ZXN0cmEgbG9zIG1heW9yZXMgdnVlbG9zIHBvciBkaXN0YW5jaWEsIHBvciB2dWVsbywgZXN0ZSBlcyBlbCB2dWVsbyBtw6FzIGxhcmdvIGRlbCBhZXJvcHVlcnRvIEpGSyBhIEhOTCAoTnVldmEgWW9yayBhIEhvbm9sdWzDuikuDQoNCg0KUGVybyBzaSBlbiByZWFsaWRhZCBxdWVyZW1vcyBzYWJlciBsYXMgYWVyb2zDrW5lYXMgY29uIG3DoXMgbWlsbGFzIHJlY29ycmlkYXMsIG1vc3RyYW1vcyBsYSBzaWd1aWVudGUgdGFibGEgcGVybyBzaW4gbGEgcG9zaWJpbGlkYWQgZGUgbW9zdHJhciBsYXMgY29sdW1uYXMgb3JpZ2luIHkgZGVzdC4NCg0KYGBge3J9DQpyZXMwMSA8LSBzZWxlY3QoZmxpZ2h0cywgY2FycmllciwgZGlzdGFuY2UsIG9yaWdpbiwgZGVzdCkNCg0KIyBTZSBmaWx0cmEgbGFzIGFlcm9sw61uZWFzIGNvbiBtaWxsYXMgcmVjb3JyaWRhcyBzdXBlcmlvcmVzIGEgbGEgbWVkaWEgLSAxMDQwDQpyZXMwMiA8LSBmaWx0ZXIocmVzMDEsIGRpc3RhbmNlID4gMTA0MCkNCg0KIyBBZ3J1cGEgcG9yIGNhcnJpZXINCnJlczAzMSA8LSBncm91cF9ieShyZXMwMiwgY2FycmllcikNCg0KIyBPcGNpb25hbG1lbnRlLCBzaSBkZXNlYXMgc3VtYXJpemFyIGxhIGRpc3RhbmNpYSB0b3RhbCBwb3IgYWVyb2zDrW5lYSBwb2Ryw61hcyBhw7FhZGlyOg0KcmVzMDMxX3N1bW1hcnkgPC0gc3VtbWFyaXNlKHJlczAzMSwgdG90YWxfZGlzdGFuY2UgPSBzdW0oZGlzdGFuY2UpKQ0KDQojIFZpc3VhbGl6YSBlbCByZXN1bHRhZG8NCnJlczAzMV9zdW1tYXJ5IDwtIHJlczAzMV9zdW1tYXJ5ICU+JSBhcnJhbmdlKGRlc2ModG90YWxfZGlzdGFuY2UpKQ0KcmVzMDMxX3N1bW1hcnkNCmBgYA0KDQpPYnRlbmVtb3MgZWwgZGF0byBxdWUgVUEgKFVuaXRlZCBBaXJsaW5lcykgZXMgbGEgYWVyb2zDrW5lYSBjb24gbGEgbWF5b3IgZGlzdGFuY2lhIHJlY29ycmlkYSBlbiB0b3RhbC4NCg0KDQoNCg0KDQojIyA0LiBTdW1hIHkgbGEgbWVkaWEgZGUgbGFzIGRpc3RhbmNpYXMgcmVjb3JyaWRhcyBwb3IgKmNhcnJpZXIqLCBlbGltaW5hbmRvIGxvcyBOQSdzIGUgaW50ZXJwcmV0YW5kbyBxdcOpIHNpZ25pZmljYSBsYSBzdW1hIHkgbGEgbWVkaWEgZGUgbGFzIGRpc3RhbmNpYXMgcmVjb3JyaWRhcy4NCg0KYGBge3J9DQoNCnJlczA0IDwtIHJlczAzMSAlPiUgZ3JvdXBfYnkoY2FycmllcikgJT4lICANCiAgc3VtbWFyaXplKHN1bWRpc3RhbmNlPXN1bShkaXN0YW5jZSwgbmEucm09VFJVRSksIG1lYW5kaXN0YW5jZT1tZWFuKGRpc3RhbmNlLCBuYS5ybT1UUlVFKSkgDQpyZXMwNCAlPiUgYXJyYW5nZShkZXNjKHN1bWRpc3RhbmNlKSkNCg0KYGBgDQoNCkVuIGVzdGEgdGFibGEgb2J0ZW5lbW9zICpzdW1kaXN0YW5jZSogcXVlIHJlcHJlc2VudGEgbGEgc3VtYSBkZSBsYXMgZGlzdGFuY2lhcyByZWNvcnJpZGFzIHBvciBhZXJvbMOtbmVhIGVuIHZ1ZWxvcyBxdWUgc2FsZW4gZGUgTnVldmEgWW9yaywgcGFyYSAqbWVhbmRpc3RhbmNlKiBvYnRlbmVtb3MgZWwgcHJvbWVkaW8gZGUgZGlzdGFuY2lhIHBvciBhZXJvbMOtbmVhLg0KDQpPcmRlbmFtb3MgbGEgc3VtYSBkZSBkaXN0YW5jaWFzIHkgb2J0ZW5lbW9zIGVsIG1pc21vIGRhdG8gcXVlIGxhIHRhYmxhIGFudGVyaW9yLCBVQSBlcyBsYSBhZXJvbMOtbmVhIGNvbiBtw6FzIGRpc3RhbmNpYSByZWNvcnJpZGEuDQoNCg0KDQpgYGB7cn0NCg0KcmVzMDUxIDwtIHJlczAzICU+JSBncm91cF9ieShjYXJyaWVyKSAlPiUgIA0KICBzdW1tYXJpemUoc3VtZGlzdGFuY2U9c3VtKGRpc3RhbmNlLCBuYS5ybT1UUlVFKSwgbWVhbmRpc3RhbmNlPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVRSVUUpKSANCnJlczA1MSAlPiUgYXJyYW5nZShkZXNjKG1lYW5kaXN0YW5jZSkpDQoNCmBgYA0KDQoNCk9yZGVuYW5kbyBkZSBtYW5lcmEgZGVzY2VuZGllbnRlIHBvciBlbCBwcm9tZWRpbyBkZSBkaXN0YW5jaWEgcmVjb3JyaWRhLCBvYnRlbmVtb3MgcXVlIEhBIChIYXdhaWFuIEFpcmxpbmVzKSBlcyBsYSBhZXJvbMOtbmVhIGNvbiBlbCBwcm9tZWRpbyBtw6FzIGdyYW5kZSBkZSBkaXN0YW5jaWEgcmVjb3JyaWRhIHBvciB2aWFqZSwgZXN0byBkZWJpZG8gYSBxdWUgc3VzIHZ1ZWxvcyBsbGV2YW4gYSBIb25vbHVsw7osIGVsIHZ1ZWxvIG3DoXMgbGFyZ28gcmVhbGl6YWRvIGRlc2RlIGxvcyBhZXJvcHVlcnRvcyBlbiBOdWV2YSBZb3JrLiBMYSBkaXN0YW5jaWEgcHJvbWVkaW8gZGUgdW4gdnVlbG8gZGUgSEEgZnVlIGRlIDQ5ODMgbWlsbGFzLg0KDQpBIHBlc2FyIGRlIHRlbmVyIGxvcyB2dWVsb3MgbcOhcyBsYXJnb3MsIG5vIGNvbnRpZW5lbiBsYSBtYXlvciBkaXN0YW5jaWEgcmVjb3JyaWRhIGVuIHRvdGFsLg0KDQoNCiMjIDUuIE9yZGVuYXIgZW4gZm9ybWEgZGVzY2VuZGVudGUgcG9yIGRpc3RhbmNpYSByZWNvcnJpZGENCg0KYGBge3J9DQpyZXMwNDEgPC0gcmVzMDMxICU+JSBncm91cF9ieShjYXJyaWVyKSAlPiUgIA0KICBzdW1tYXJpemUoc3VtZGlzdGFuY2U9c3VtKGRpc3RhbmNlLCBuYS5ybT1UUlVFKSwgbWVhbmRpc3RhbmNlPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVRSVUUpKSANCnJlczA0MSAlPiUgYXJyYW5nZShkZXNjKHN1bWRpc3RhbmNlKSkNCmBgYA0KDQoNCg0KDQoNCg0KIyMgNi4gIElkZW50aWZpY2FyIHNpIGxhcyBhZXJvbMOtbmVhcyBsw61kZXJlcyBzb24gbGFzIG1pc21hcyBlbiBsb3MgdHJlcyBhZXJvcHVlcnRvcyBjdXlvIG9yaWdlbiBlcyBOdWV2YSBZb3JrICggSm9obiBGLiBLZW5uZWR5IChKRkspLCBMYSBHdWFyZGlhIChMR0EpIGFuZCBOZXdhcmsgTGliZXJ0eSAgKEVXUikgKS4gIA0KDQoNCkdlbmVyYSB1biBkYXRhIGZyYW1lIHBhcmEgY2FkYSBhZXJvcHVlcnRvLiANCkZ1bmNpb25lczogZmlsdGVyKCksIGFycmFuZ2UoKSANCg0KDQojIyBQcmltZXJvIGNyZWFtb3MgbG9zICpEYXRhRnJhbWVzKiBwYXJhIGNhZGEgYWVyb3B1ZXJ0bw0KDQpgYGB7cn0NCnJlczA0IDwtIHJlczAzICU+JSBncm91cF9ieShjYXJyaWVyLG9yaWdpbixkZXN0KSAlPiUgIA0KICBzdW1tYXJpemUoc3VtZGlzdGFuY2U9c3VtKGRpc3RhbmNlLCBuYS5ybT1UUlVFKSwgbWVhbmRpc3RhbmNlPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVRSVUUpKSANCnJlczA1IDwtIGFycmFuZ2UocmVzMDQsY2FycmllcixzdW1kaXN0YW5jZSkNCkpGSyA9IHJlczA1ICU+JSAgDQogIGZpbHRlcihvcmlnaW4gPT0gIkpGSyIpICAlPiUNCiAgYXJyYW5nZShjYXJyaWVyLCBkZXNjKHN1bWRpc3RhbmNlKSkNCkxHQSA9IHJlczA1ICU+JSAgDQogIGZpbHRlcihvcmlnaW4gPT0gIkxHQSIpICAlPiUNCiAgYXJyYW5nZShjYXJyaWVyLCBkZXNjKHN1bWRpc3RhbmNlKSkNCkVXUiA9IHJlczA1ICU+JSAgDQogIGZpbHRlcihvcmlnaW4gPT0gIkVXUiIpICAlPiUNCiAgYXJyYW5nZShjYXJyaWVyLCBkZXNjKHN1bWRpc3RhbmNlKSkNCkVXUg0KYGBgDQoNCkFob3JhIG9idGVuZW1vcyBsYSBzdW1hIGRlIGxhcyBkaXN0YW5jaWFzIG9idGVuaWRhcyB5IGxhcyBvcmRlbmFtb3MgZGUgbWFuZXJhIGRlc2NlbmRpZW50ZSBwYXJhIGNhZGEgYWVyb3B1ZXJ0by4NCmBgYHtyfQ0KSkZLX2dyb3VwZWQgPC0gSkZLICU+JQ0KICBncm91cF9ieShjYXJyaWVyKSAlPiUNCiAgc3VtbWFyaXNlKHRvdGFsX3N1bWRpc3RhbmNlID0gc3VtKHN1bWRpc3RhbmNlKSkgJT4lDQogIGFycmFuZ2UoZGVzYyh0b3RhbF9zdW1kaXN0YW5jZSkpDQpKRktfZ3JvdXBlZA0KYGBgDQoNCg0KYGBge3J9DQpMR0FfZ3JvdXBlZCA8LSBMR0EgJT4lDQogIGdyb3VwX2J5KGNhcnJpZXIpICU+JQ0KICBzdW1tYXJpc2UodG90YWxfc3VtZGlzdGFuY2UgPSBzdW0oc3VtZGlzdGFuY2UpKSAlPiUNCiAgYXJyYW5nZShkZXNjKHRvdGFsX3N1bWRpc3RhbmNlKSkNCkxHQV9ncm91cGVkDQpgYGANCg0KDQpgYGB7cn0NCkVXUl9ncm91cGVkIDwtIEVXUiAlPiUNCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF9zdW1kaXN0YW5jZSA9IHN1bShzdW1kaXN0YW5jZSkpICU+JQ0KICBhcnJhbmdlKGRlc2ModG90YWxfc3VtZGlzdGFuY2UpKQ0KRVdSX2dyb3VwZWQNCmBgYA0KDQoNCk9idGVuaWVuZG8gbGFzIGFlcm9sw61uZWFzIGNvbiBtYXlvciBkaXN0YW5jaWEgcmVjb3JyaWRhIHNlcGFyYWRhcyBwb3IgbG9zIGFlcm9wdWVydG9zIGRlIE51ZXZhIFlvcmssIG5vcyBkYW1vcyBjdWVudGEgcXVlIHPDs2xvIGVuIGVsIGFlcm9wdWVydG8gKkVXUiogbGEgYWVyb2zDrW5lYSBVbml0ZWQgQWlybGluZXMgc2lndWUgc2llbmRvIGzDrWRlciBlbiBkaXN0YW5jaWEgdG90YWwsIG1pZW50cmFzIHF1w6kgZW4gKkxHQSogZXMgQW1lcmljYW4gQWlybGluZXMgeSBlbiAqSkZLKiBlcyBKZXRCbHVlLg0KDQoNCg0KIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5QYXJ0ZSAzPC9zcGFuPg0KDQoNClNlIG5vcyBoYSBzb2xpY2l0YWRvIGhhY2VyIHVuIGVzdHVkaW8gc29icmUgbGEgc2l0dWFjacOzbiBhY3R1YWwgZGUgbGEgYWVyb2zDrW5lYSAiQW1lcmljYW4NCkFpcmxpbmVzIiB5YSBxdWUgc2UgbmVjZXNpdGEgcmV2aXNhciBzdXMgZGVzdGlub3MsIGhvcmFyaW9zLCB5IGF2aW9uZXMgY29uIGxvcyBxdWUgY3VlbnRhIHBhcmENCmhhY2VyIHByb3B1ZXN0YXMgZGUgYXVtZW50byBvIHJlZHVjY2nDs24gZGUgdnVlbG9zIHBvciBkZXN0aW5vIHkgaG9yYXJpb3MsIGFzw60gY29tbyBsYQ0KY2FudGlkYWQgZGUgYXZpb25lcy4NCg0KDQojIyBEYXRvcyBHZW5lcmFsZXMNCg0KDQoNCg0KIyMjIDEuCUNvbnN1bHRhciBsYXMgdGFibGFzICpwbGFuZXMqIHkgKndlYXRoZXIqIHBhcmEgcXVlIGNvbm96Y2Ftb3Mgc3UgY29udGVuaWRvLg0KYGBge3J9DQp2aWV3KHBsYW5lcykNCnZpZXcod2VhdGhlcikNCnBsYW5lcw0Kd2VhdGhlcg0KYGBgDQoNCiMjIyAyLglTZSBuZWNlc2l0YSBzYWJlciBkZSBjYWRhIHZ1ZWxvOiBMYSBhZXJvbGluZWEsIGVsIGFlcm9wdWVydG8gZGUgb3JpZ2VuIHkgZWwgYWVyb3B1ZXJ0byBkZXN0aW5vLg0KYGBge3J9DQphZXJvbGluZWFzIDwtIGZsaWdodHMgJT4lIA0KICBzZWxlY3QoY2FycmllcixvcmlnaW4sZGVzdCkNCmFlcm9saW5lYXMNCmBgYA0KDQojIyMgMy4JRW4gbGEgY29uc3VsdGEgYW50ZXJpb3Igc2UgbmVjZXNpdGEgY29ub2NlciBlbCBub21icmUgZGUgbGEgYWVyb2zDrW5lYS4NCmBgYHtyfQ0KYWVyb2xpbmVhc19ub21icmUgPC0gYWVyb2xpbmVhcyAlPiUNCiAgbGVmdF9qb2luKGFpcmxpbmVzLCBieSA9ICJjYXJyaWVyIikNCmFlcm9saW5lYXNfbm9tYnJlDQpgYGANCg0KIyMjIDQuIFNlIG5lY2VzaXRhIHNhYmVyIGxhIGNhbnRpZGFkIGRlIHZ1ZWxvcyBwb3IgY2FkYSBkZXN0aW5vIHBhcmEgaWRlbnRpZmljYXIgY3XDoWxlcyBzb24gbG9zIGRlc3Rpbm9zIG3DoXMgYnVzY2Fkb3MuDQpgYGB7cn0NCmNhbnRfdnVlbG9zIDwtIGZsaWdodHMgJT4lIA0KICBzZWxlY3QoY2FycmllciwgZGVzdCkgJT4lIA0KICBjb3VudChkZXN0KQ0KY2FudF92dWVsb3MgPC0gY2FudF92dWVsb3MgJT4lDQogIGFycmFuZ2UoZGVzYyhuKSkNCg0KY2FudF92dWVsb3MNCiAgDQpgYGANCg0KDQpMb3MgZGVzdGlub3MgbcOhcyBidXNjYWRvcyBjb24gb3JpZ2VuIGVuIE51ZXZhIFlvcmsgZW4gMjAxMyBzb24gQ2hpY2FnbyBjb24gMTcsMjgzIHZ1ZWxvcywgQXRsYW50YSBjb24gMTcsMjE1IHZ1ZWxvcyB5IExvcyBBbmdlbGVzIGNvbiAxNiwxNzQgdnVlbG9zLg0KDQojIyMgNS4gQWdyZWdhciBlbCBub21icmUgZGUgbGEgYWVyb2zDrW5lYSBhIGxhIHRhYmxhIGFudGVyaW9yLg0KDQpgYGB7cn0NCmNhbnRfdnVlbG9zMSA8LSBmbGlnaHRzICU+JQ0KICBzZWxlY3QoY2FycmllciwgZGVzdCkgJT4lDQogIGdyb3VwX2J5KGNhcnJpZXIsIGRlc3QpICU+JQ0KICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lDQogIHVuZ3JvdXAoKSAlPiUNCiAgYXJyYW5nZShkZXNjKG4pKQ0KY2FudF92dWVsb3MxDQpgYGANCg0KRXN0YSB0YWJsYSBhaG9yYSBub3MgbXVlc3RyYSBsYXMgYWVyb2zDrW5lYXMgeSBkZXN0aW5vcyBjb24gbWF5b3IgY2FudGlkYWQgZGUgdnVlbG9zLiBMYSBhZXJvbMOtbmVhICJEZWx0YSBBaXJsaW5lcyIgdHV2byBsYSBtYXlvciBjYW50aWRhZCBkZSB2dWVsb3MgaGFjaWEgQXRsYW50YS4NCg0KIyMjNiAuIFNlIG5lY2VzaXRhIGNvbm9jZXIgbGFzIGFlcm9sw61uZWFzIChjbGF2ZSB5IG5vbWJyZSkgeSBkZXN0aW5vcyBxdWUgdnVlbGFuIGRlOiA2IGEgMTIsIDEyIGEgMTkgLCAxOSBhIDI0LCB5IDI0IGEgNi4NCmBgYHtyfQ0KY2Fycmllcl9ob3JhcmlvIDwtIGZsaWdodHMgJT4lDQpzZWxlY3QoY2FycmllciwgZGVzdCwgc2NoZWRfZGVwX3RpbWUpICU+JQ0KICBsZWZ0X2pvaW4oYWlybGluZXMsIGJ5ID0gImNhcnJpZXIiKQ0KDQpjbGFzeGhvcmE8LSBtdXRhdGUoY2Fycmllcl9ob3JhcmlvLCBjbGFzX2hvcmFyaW8gPSBpZmVsc2Uoc2NoZWRfZGVwX3RpbWUgJWluJSA2MDA6MTE1OSwiTWHDsWFuYSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzY2hlZF9kZXBfdGltZSAlaW4lIDEyMDA6MTg1OSwiVGFyZGUiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc2NoZWRfZGVwX3RpbWUgJWluJSAxOTAwOjI0MDAsIk5vY2hlIiwgIk1hZHJ1Z2FkYSIpKSkpDQpjbGFzeGhvcmENCmBgYA0KDQojIyMgNy5TZSBuZWNlc2l0YSBzYWJlciBsYSBjYW50aWRhZCBkZSB2dWVsb3MgcG9yIGFlcm9sw61uZWEgeSBkZXN0aW5vIHF1ZSBoYXkgcG9yIGxhIE1hw7FhbmEsIFRhcmRlLCBOb2NoZSB5IE1hZHJ1Z2FkYS4NCmBgYHtyfQ0KY2FudF9jbGFzeGhvcmEgPC0gY2xhc3hob3JhICU+JSANCiAgICAgICAgICAgICBncm91cF9ieShjYXJyaWVyLCBkZXN0LGNsYXNfaG9yYXJpbykgJT4lIGNvdW50KCkNCmNhbnRfY2xhc3hob3JhDQoNCmBgYCAgICAgICAgICAgICAgICAgICAgICAgDQogDQojIyMgOC4gU2UgbmVjZXNpdGEgc2FiZXIgYSBxdcOpIGRlc3Rpbm9zIHZ1ZWxhIGxhIGFlcm9sw61uZWEgQW1lcmljYW4gQWlybGluZXMgSW5jLi1BQSAgZHVyYW50ZSBsYSBtYWRydWdhZGEgKDI0YW0tNmFtKS4gDQpgYGB7cn0NCmRlc3Rpbm9zX2FhIDwtIGNsYXN4aG9yYSAlPiUgDQogIHNlbGVjdChjYXJyaWVyLG5hbWUsIGRlc3QsY2xhc19ob3JhcmlvKSAlPiUgDQogIGZpbHRlcihjYXJyaWVyID09ICJBQSIgJiBjbGFzX2hvcmFyaW8gPT0gIk1hZHJ1Z2FkYSIpICU+JSANCiAgZ3JvdXBfYnkoY2FycmllcixuYW1lLCBkZXN0LGNsYXNfaG9yYXJpbykNCmRlc3Rpbm9zX2FhDQpgYGANCg0KRW5jb250cmFtb3MgcXVlIGVsIMO6bmljbyBkZXN0aW5vIGRlIEFtZXJpY2FuIEFpcmxpbmVzIHBvciBsYSBtYWRydWdhZGEgZXMgaGFjaWEgTWlhbWkuDQoNCiMjIyA5LiDCv1F1w6kgYXZpb25lcyB1dGlsaXphIGxhIGFlcm9sw61uZWEgQUE/IGFlcm9sw61uZWEsIHRpcG8sIG1vdG9yIHkgbsO6bWVybyBkZSBhc2llbnRvcyB5IMK/Q3XDoW50b3MgdnVlbG9zIHNlIGhhbiByZWFsaXphZG8gY29uIGNhZGEgdW5vPyBlbGltaW5hIGxvcyBOQSdzDQpgYGB7cn0NCmF2aW9uX2FhIDwtIGZsaWdodHMgJT4lDQogIGxlZnRfam9pbihwbGFuZXMsIGJ5ID0gInRhaWxudW0iKSAlPiUNCiAgc2VsZWN0KGNhcnJpZXIsIHR5cGUsIGVuZ2luZSwgc2VhdHMpICU+JQ0KICBmaWx0ZXIoY2FycmllciA9PSAiQUEiLCAhaXMubmEodHlwZSkpICU+JQ0KICBncm91cF9ieShjYXJyaWVyLHR5cGUsZW5naW5lLHNlYXRzKSAlPiUgDQogIGNvdW50KCkNCiANCg0KYGBgDQpMb3MgZGF0b3MgaW5kaWNhbiBxdWU6ICANCkFBIHV0aWxpemEgcHJpbmNpcGFsbWVudGUgYXZpb25lcyBkZSB0aXBvICJGaXhlZCB3aW5nIG11bHRpIGVuZ2luZSIuDQpBQSB1dGlsaXphIHByaW5jaXBhbG1lbnRlIG1vdG9yZXMgInR1cmJvIGZhbiIgZW4gc3VzIGF2aW9uZXMuDQpBQSB1dGlsaXphIGF2aW9uZXMgcXVlIHRpZW5lbiBkZXNkZSAyIGFzaWVudG9zIGhhc3RhIDMzMCBhc2llbnRvcy4NCg0KIyBSZXRyYXNvcyBlbiB2dWVsb3MgY29uIG9yaWdlbiBkZSBOdWV2YSBZb3JrDQpEZXNwdcOpcyBkZSBoYWJlciBleGFtaW5hZG8gZW4gZGV0YWxsZSBsYXMgdGFibGFzIGRlIG55Y2ZsaWdodHMxMywgZXMgZWwgbW9tZW50byBkZSBpZGVudGlmaWNhciBkaXZlcnNvcyBkZXNjdWJyaW1pZW50b3MgcXVlIG5vcyBheXVkZW4gYSByZXNvbHZlciBlbCBwcm9ibGVtYSBwbGFudGVhZG86IMK/Q3XDoWxlcyBzb24gbG9zICoqY2F1c2FudGVzKiogZGUgbG9zIHJldHJhc29zIGVuIHZ1ZWxvcyBjb24gb3JpZ2VuIGRlIE51ZXZhIFlvcms/DQoNCiMjIFJldHJhc29zIHBvciBhZXJvbMOtbmVhDQpgYGB7cn0NCmJkZ3JhbmRlIDwtIG1lcmdlKGZsaWdodHMsYWlybGluZXMsIGJ5PSJjYXJyaWVyIikNCmJkZ3JhbmRlMiA8LSBsZWZ0X2pvaW4oYmRncmFuZGUsIHBsYW5lcywgYnk9InRhaWxudW0iKQ0KYmRncmFuZGUzIDwtIGxlZnRfam9pbihiZGdyYW5kZTIsd2VhdGhlciwgYnk9Yygib3JpZ2luIiwgInRpbWVfaG91ciIpKQ0KYmRncmFuZGUzIDwtIG11dGF0ZShiZGdyYW5kZTMsIGRpc3RfS20gPSBkaXN0YW5jZSoxLjYwOSkNCmJkZXZpZGVuY2lhIDwtIGxlZnRfam9pbihiZGdyYW5kZTMsd2VhdGhlciwgYnk9Yygib3JpZ2luIiwgInRpbWVfaG91ciIpKQ0KcmV0cmFzb3NfYWVyb2xpbmVhIDwtIGJkZ3JhbmRlMyAlPiUNCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogIHN1bW1hcmlzZShyZXRyYXNvX3Byb21lZGlvID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICB0b3RhbF92dWVsb3MgPSBuKCksDQogICAgICAgICAgICB0b3RhbF92dWVsb3NfYXRyYXNhZG9zID0gc3VtKGRlcF9kZWxheSA+IDAsIG5hLnJtID0gVFJVRSksDQogICAgICAgICAgICBwb3JjZW50YWplX2RlX3JldHJhc28gPSB0b3RhbF92dWVsb3NfYXRyYXNhZG9zLyB0b3RhbF92dWVsb3MgKiAxMDApICU+JQ0KICBtdXRhdGUoY2FsaWZpY2FjaW9uX2Flcm9saW5lYSA9IHJhbmsoLXBvcmNlbnRhamVfZGVfcmV0cmFzbykpICU+JQ0KICBhcnJhbmdlKGRlc2MocmV0cmFzb19wcm9tZWRpbykpDQoNCnJldHJhc29zX2Flcm9saW5lYQ0KYGBgDQpVc2FuZG8gdW5hIGZ1bmNpw7NuIGRlIHJhbmsoKSwgcG9kZW1vcyB2ZXIgcXVlIGxhIGFlcm9saW5lYSBjb24gbWF5b3IgcHJvcG9yY2nDs24gZGUgcmV0cmFzb3MgZW4gc3VzIHZ1ZWxvcyBlcyAxLiAqV04qIGNvbiAqKjUzLjQyJSoqLiBMZSBzaWd1ZSAyLiAqRkwqIGNvbiAqKjUwLjc0JSoqLCB5IDMuICpGOSogY29uICoqNDkuNzglKiouDQoNClNpZ3VlbnRlLCB2ZW1vcyBxdWUgbGEgYWVyb2xpbmVhIGNvbiBtYXlvciByZXRyYXNvcyBwcm9tZWRpbyBlbiBtaW51dG9zIHBvciB2dWVsbyBlcyAqRjkqIGNvbiAqKjIwLjIqKiBtaW51dG9zLCBsdWVnbyAqRVYqIGNvbiAqKjE5LjkqKiBtaW51dG9zLCB5IGZpbmFsbWVudGUgKllWKiBjb24gKioxOC45KiogbWludXRvcy4gDQoNCkVzIGNyw610aWNvIG5vdGFyIHF1ZSBlbiBhbWJvcyBhbsOhbGlzaXMsIGFwYXJlY2UgKkZyb250aWVyIEFpcmxpbmVzKiAoRjkpLiBTaSBzdW1hbW9zIHN1cyBtaW51dG9zIGRlIHJldHJhc28gcHJvbWVkaW8gY29uIGxhIGNhbnRpZGFkIGRlIHZ1ZWxvcyBhdHJhc2Fkb3MgZGVsIGHDsW8sIG5vcyBkYSA2ODg4IG1pbnV0b3MgcXVlIHBlcmRpZXJvbiBsb3MgY2xpZW50ZXMuIFNpIGhhY2Vtb3MgbG8gbWlzbW8gY29uICpFeHByZXNzamV0IEFpcmxpbmVzKiAoRVYpLCBmdWVyb24gYXByb3hpbWFkYW1lbnRlIDQ2Miw3ODAgbWludXRvcyBxdWUgbGEgYWVyb2xpbmVhIGxlIHF1aXTDsyBhIHN1cyBjbGllbnRlcy4gDQoNCiMjIFJldHJhc29zIHBvciBhZXJvcHVlcnRvIGRlIG9yaWdlbg0KYGBge3J9DQpyZXRyYXNvc19hZXJvbGluZWEgPC0gYmRncmFuZGUzICU+JQ0KICBncm91cF9ieShvcmlnaW4pICU+JQ0KICBzdW1tYXJpc2UocmV0cmFzb19wcm9tZWRpbyA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgdG90YWxfdnVlbG9zID0gbigpLA0KICAgICAgICAgICAgdG90YWxfdnVlbG9zX2F0cmFzYWRvcyA9IHN1bShkZXBfZGVsYXkgPiAwLCBuYS5ybSA9IFRSVUUpLA0KICAgICAgICAgICAgcG9yY2VudGFqZV9kZV9yZXRyYXNvID0gdG90YWxfdnVlbG9zX2F0cmFzYWRvcy8gdG90YWxfdnVlbG9zICogMTAwKSAlPiUNCiAgbXV0YXRlKGNhbGlmaWNhY2lvbl9hZXJvbGluZWEgPSByYW5rKC1wb3JjZW50YWplX2RlX3JldHJhc28pKSAlPiUNCiAgYXJyYW5nZShkZXNjKHJldHJhc29fcHJvbWVkaW8pKQ0KDQpyZXRyYXNvc19hZXJvbGluZWENCmBgYA0KSWd1YWwgcXVlIGxhcyBhZXJvbMOtbmVhcywgdXNhbmRvICoqc3VtbWFyaXplKCkqKiwgKiptZWFuKCkqKiwgKiptdXRhdGUoKSoqLCAqKmFycmFuZ2UoKSoqLCB5ICoqcmFuaygpKiogcG9kZW1vcyB2ZXIgbG9zIHJlc3VsdGFkb3MgZGUgbG9zIGFlcm9wdWVydG9zIGRlIG9yaWdlbiAoSkZLLCBFV1IsIExHQSkuICANCioqRVdSKiogZnVlIGVsIGFlcm9wdWVydG8gY29uIG3DoXMgcG9yY2VudGFqZSBkZSB2dWVsb3MgY29uIHJldHJhc28gKiooNDMuNjIlKSoqIHkgdGFtYmnDqW4gZnVlIGVsIGFlcm9wdWVydG8gY29uIG3DoXMgcmV0cmFzbyBwcm9tZWRpbyBwb3IgdnVlbG8sIGNvbiAqKjE1LjEqKiBtaW51dG9zLiBFbCBzZWd1bmRvIGFlcm9wdWVydG8gY29uIG3DoXMgcG9yY2VudGFqZSBkZSB2dWVsb3MgY29uIHJldHJhc28geSByZXRyYXNvIHByb21lZGlvIGVuIG1pbnV0b3MgZXMgKkpGSyogY29uICoqMzcuNyUqKiBkZSBzdXMgdnVlbG9zIHN1ZnJpZW5kbyByZXRyYXNvLCB5ICoqMTIuMSoqIG1pbnV0b3MgcHJvbWVkaW8gcG9yIHJldHJhc28uIEZpbmFsbWVudGUsIHRlbmVtb3MgKkxHQSogY29uICoqMzIuMiUqKiB5ICoqMTAuMyoqIG1pbnV0b3MgcG9yIHJldHJhc28uDQoNCmBgYHtyfQ0KcmV0cmFzb3NfYWVyb2xpbmVhIDwtIGJkZ3JhbmRlMyAlPiUNCiAgZ3JvdXBfYnkoaG91ci54KSAlPiUNCiAgc3VtbWFyaXNlKHJldHJhc29fcHJvbWVkaW8gPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIHRvdGFsX3Z1ZWxvcyA9IG4oKSwNCiAgICAgICAgICAgIHRvdGFsX3Z1ZWxvc19hdHJhc2Fkb3MgPSBzdW0oZGVwX2RlbGF5ID4gMCwgbmEucm0gPSBUUlVFKSwNCiAgICAgICAgICAgIHBvcmNlbnRhamVfZGVfcmV0cmFzbyA9IHRvdGFsX3Z1ZWxvc19hdHJhc2Fkb3MvIHRvdGFsX3Z1ZWxvcyAqIDEwMCkgJT4lDQogIG11dGF0ZShjYWxpZmljYWNpb25fYWVyb2xpbmVhID0gcmFuaygtcG9yY2VudGFqZV9kZV9yZXRyYXNvKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhwb3JjZW50YWplX2RlX3JldHJhc28pKQ0KDQpyZXRyYXNvc19hZXJvbGluZWENCmBgYA0KRGUgaWd1YWwgbWFuZXJhIHF1ZSBhbmFsaXphbW9zIGxvcyBhZXJvcHVlcnRvcyB5IHN1cyBhZXJvbMOtbmVhcywgYWhvcmEgYW5hbGl6YXJlbW9zIGxhcyBob3JhcyBkZWwgZMOtYS4gRXN0YW1vcyBwcm9yaXphbmRvIGVsIGRhdG8gKipwb3JjZW50YWplX2RlX3JldHJhc28qKiBwdWVzIGNyZWVtb3MgcXVlIGVzIGVsIGluZGljYWRvciBtw6FzIHJlbGV2YW50ZSBhIGxhIGludmVzdGlnYWNpw7NuLiBQb3IgZXNhIG1pc21hIHJhesOzbiwgdXNhbW9zIHJhbmsoKSBwYXJhIHZlciBtw6FzIGNsYXJhbWVudGUgbGFzIGhvcmFzIGRlbCBkw61hIGNvbiBtYXlvciAqKnBvcmNlbnRhamUgZGUgcmV0cmFzbyoqLiBFbiBlbCBjYXNvIGRlIGxhcyBob3JhcywgcG9kZW1vcyB2ZXIgcXVlIGxhcyBob3JhcyBkZSBsYSB0YXJkZS1ub2NoZSBzb24gbGFzIHF1ZSBtw6FzIHN1ZnJlbiBkZSByZXRyYXNvcywgcHVlcyBsYXMgaG9yYXMgKioyMDowMCwgMjE6MDAsIDE5OjAwLCAxNzowMCwgeSAxODowMCoqIHNvbiBsYXMgaG9yYXMgKnJhbmtlYWRhcyogMS01IGRlbCBwdW50byBkZSB2aXN0YSBkZSAqKnBvcmNlbnRhamUgZGUgcmV0cmFzbyoqLiBFc3RhcyBob3JhcywgYWwgc2VyIGxhcyBob3JhcyBtw6FzIG9jdXBhZGFzIGRlIGxvcyBhZXJvcHVlcnRvcywgKFVTQSBUT0RBWSwgMjAxNykgc29uIGxhcyBxdWUgbcOhcyBwcm9iYWJsZSBzb24gZGUgc3VmcmlyIHVuIHJldHJhc28uIFRpZW5lcyBlbnRyZSAqKjUxLjYlKiogeSAqKjQ4LjglKiogY2hhbmNlIGRlIHN1ZnJpciB1biByZXRyYXNvIHNpIHR1IHZ1ZWxvIHNhbGUgYSBlc3RhcyBob3JhcyBkZSBOdWV2YSBZb3JrLiANCmBgYHtyfQ0KDQpmbGlnaHRzX3dlYXRoZXIgPC0gbGVmdF9qb2luKGZsaWdodHMsIHdlYXRoZXIsIGJ5ID0gYygieWVhciIsICJtb250aCIsICJkYXkiLCAiaG91ciIsICJvcmlnaW4iKSkNCmZsaWdodHNfd2VhdGhlcl9jbGVhbiA8LSBzdWJzZXQoZmxpZ2h0c193ZWF0aGVyLCBkZXBfZGVsYXkgPCBxdWFudGlsZShkZXBfZGVsYXksIDAuOTksIG5hLnJtID0gVFJVRSkpDQoNCmZsaWdodHNfd2VhdGhlcl9jbGVhbiA8LSBzdWJzZXQoZmxpZ2h0c193ZWF0aGVyLCBkZXBfZGVsYXkgPCBxdWFudGlsZShkZXBfZGVsYXksIDAuOTksIG5hLnJtID0gVFJVRSkpIA0KcmVncmVzaW9uX3dlYXRoZXJfY2xlYW4gPC0gbG0oZGVwX2RlbGF5IH4gdGVtcCArIGRld3AgKyBodW1pZCArIHdpbmRfZGlyICsgd2luZF9ndXN0ICsgcHJlc3N1cmUgKyB2aXNpYiwgZGF0YSA9IGZsaWdodHNfd2VhdGhlcl9jbGVhbikNCnN1bW1hcnkocmVncmVzaW9uX3dlYXRoZXJfY2xlYW4pDQoNCg0KYGBgDQpFbiBlbCBhbsOhbGlzaXMgcXVlIHJlYWxpemFtb3MgZGVsICoqbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsKiogY29uIGxhIHZhcmlhYmxlIGRlICoqd2VhdGhlcioqLCBzZSBpZGVudGlmaWNhcm9uIGNvbmRpY2lvbmVzIG1ldGVyb2zDs2dpY2FzIHF1ZSBleHBsaWNhbiBsYSB2YXJpYWJpbGlkYWQgZW4gbG9zIHJldHJhc29zIGRlIGxvcyB2dWVsb3MgZW4gdW4gKioyLjElKiogeSBsbyBpbmRpY2EgZW4gZWwgKipSMiBhanVzdGFkYSBkZSAwLjAyMTEqKi4gRXN0YSB2YXJpYWJsZSBlcyBtdWNobyBtw6FzIHNpZ25pZmljYXRpdmEgcXVlIG90cmFzIHZhcmlhYmxlcyBjb21vIGh1bWVkYWQsIGRpcmVjY2nDs24gZGVsIHZpZW50bywgcHJlc2nDs24sIGV0Yy4gWSBlbCBpbXBhY3RvIGRlIGVzdGFzIHZhcmlhYmxlcyBlcyBtdWNobyBtZW5vciwgcG9yIGVqZW1wbG8sIGVsIGluY3JlbWVudG8gZGUgbGEgdGVtcGVyYXR1cmEgYXVtZW50YSBlbiAqKjAuMzUgbWludXRvcyoqIHBvciBjYWRhIGdyYWRvIEZhaHJlbmhlaXQsIHkgZWwgYXVtZW50byBkZSB2aXNpYmlsaWRhZCByZWR1Y2UgZW4gKioxLjEyNyoqIG1pbnV0b3MgcG9yIG1pbGxhLiBBdW5xdWUgYWZlY3RhbiBlc3RvcyBhc3BlY3RvcyBlbiBsb3MgcmV0cmFzb3MsIGhheSBtw6FzIGZhY3RvcmVzIHF1ZSB0aWVuZW4gdW5hIGluZmx1ZW5jaWEgbWF5b3IgZW4gbG9zIHJldHJhc29zIGRlIGxvcyB2dWVsb3MuDQoNCg0KDQojIyBWaXN1YWxpemFjacOzbiBkZSBsb3MgRGF0b3MNCiMjIFZpc3VhbGl6YWNpw7NuIGRlIGxhIHRlbXBlcmF0dXJhIGR1cmFudGUgbG9zIHByaW1lcm9zIDE1IGTDrWFzIGRlIGVuZXJvIGNvbiB1bmEgZ3LDoWZpY2EgZGUgbMOtbmVhOg0KDQpgYGB7cn0NCmxpYnJhcnkoZ2dwbG90MikNCndlYXRoZXJfamFudWFyeSA8LSB3ZWF0aGVyICU+JQ0KICBmaWx0ZXIobW9udGggPT0gMSwgZGF5IDw9IDE1LCBvcmlnaW4gPT0gIkVXUiIpDQoNCmdncGxvdCh3ZWF0aGVyX2phbnVhcnksIGFlcyh4ID0gZGF5LCB5ID0gdGVtcCkpICsNCiAgZ2VvbV9saW5lKCkgKw0KICBsYWJzKHRpdGxlID0gIlRlbXBlcmF0dXJhIGR1cmFudGUgbG9zIHByaW1lcm9zIDE1IGTDrWFzIGRlIGVuZXJvIiwgeCA9ICJEw61hIiwgeSA9ICJUZW1wZXJhdHVyYSAowrBGKSIpDQoNCg0KYGBgDQojIyNJbnRlcnByZXRhY2nDs24gZGUgZ3LDoWZpY2E6IA0KQ29uIGVzdGEgZ3LDoWZpY2EgcG9kZW1vcyBvYnNlcnZhciBsYSB0ZW1wZXJhdHVyYSBkdXJhbnRlIGxvcyBwcmltZXJvcyBkw61hcyBkZWwgbWVzIGRlIGVuZXJvIGVuIGVsIGFlcm9wdWVydG8gZGUgTmV3YXJrIChFV1IpLCBhZGVtw6FzIGRlIG5vdGFyIHF1ZSB0aWVuZSBjaWVydGFzIHRlbmRlbmNpYXMgZGUgYXVtZW50byB5IGFsdGVyYWNpw7NuIHF1ZSBub3MgcHVlZGVuIGVzdGFyIHNlw7FhbGFuZG8gbGEgYXV0b3JpZGFkIGRlIGxvcyBzaXN0ZW1hcyBjbGltw6F0aWNvcyB0ZW1wb3JhbGVzLiBFbnRyZSBzdXMgdGVtcGVyYXR1cmFzIHBvZGVtb3MgdmVyIHF1ZSBzZSBlbmN1ZW50cmFuIGVudHJlIG1lbm9zIGRlIDM1wrBGIHkgY2FzaSBhbGNhbnphbmRvIDUwwrBGLCBlc3RvIG5vcyBwdWVkZSBpbmRpY2FyIHF1ZSBlcyBwb3NpYmxlIHF1ZSBlc3RhcyB0ZW1wZXJhdHVyYXMgbGxlZ3VlbiBhIHBlcmp1ZGljYXIgbG9zIHNlcnZpY2lvcyBhZXJvcG9ydHVhcmlvcyB5IGxhIHBsYW5lYWNpw7NuIGRlIGxvcyB2dWVsb3MgYSBjYXVzYSBkZSBlbCBpbXBhY3RvIGVuIGxhIHNlZ3VyaWRhZCB5IG9wZXJhdGl2aWRhZCBkZSBsYXMgYWVyb25hdmVzLg0KDQoNCiMjSGlzdG9ncmFtYSBkZSBsYSB0ZW1wZXJhdHVyYSBtw6FzIGZyZWN1ZW50ZSBlbiBsb3MgcHJpbWVyb3MgMTUgZMOtYXMgZGUgZW5lcm8NCmBgYHtyfQ0KZ2dwbG90KHdlYXRoZXJfamFudWFyeSwgYWVzKHggPSB0ZW1wKSkgKw0KICBnZW9tX2hpc3RvZ3JhbShiaW5zID0gMzAsIGZpbGwgPSAiYmx1ZSIsIGNvbG9yID0gImJsYWNrIikgKw0KICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbWEgZGUgbGEgdGVtcGVyYXR1cmEgZW4gRW5lcm8iLCB4ID0gIlRlbXBlcmF0dXJhICjCsEYpIiwgeSA9ICJGcmVjdWVuY2lhIikNCg0KYGBgDQojIyNJbnRlcnByZXRhY2nDs24gZGUgZ3LDoWZpY2E6IA0KRW4gZXN0ZSBoaXN0b2dyYW1hIG9ic2VydmFtb3MgdW5hIGNsYXJhIGRpdmlzacOzbiBlbiBkb3MgZ3J1cG9zIGRpZmVyZW50ZXMsIHF1ZSBub3Mgc2XDsWFsYW4gZG9zIHJhbmdvcyBxdWUgZnVlcm9uIGZyZWN1ZW50ZXMsIGxvIHF1ZSBub3MgcHVlZGUgbW9zdHJhciB2YXJpYWNpb25lcyBlbiBsYXMgbm9ybWFzIGNsaW3DoXRpY2FzIGR1cmFudGUgZWwgbWVzLiBFc3RhIGdyw6FmaWNhIG5vcyBheXVkYSBhIHBvZGVyICBwcmV2ZW5pciBhbHRlcmFjaW9uZXMgY2xpbcOhdGljYXMgcXVlIGFmZWN0ZW4gYSBsYXMgbmVjZXNpZGFkZXMgb3BlcmF0aXZhcyBkZWwgYWVyb3B1ZXJ0by4NCg0KDQojI0ZhY2V0cyBwYXJhIG9ic2VydmFyIGNvbW8gdmFyw61hIGxhIHRlbXBlcmF0dXJhIGNhZGEgbWVzDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kd2VhdGhlciAlPiUgDQogIGdncGxvdChhZXMoeCA9IHRlbXApKSArDQogIGdlb21faGlzdG9ncmFtKGJpbnMgPSAzMCkgKw0KICBmYWNldF93cmFwKH5tb250aCkgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgbGEgdGVtcGVyYXR1cmEgcG9yIG1lcyIsIHggPSAiVGVtcGVyYXR1cmEgKMKwRikiLCB5ID0gIkZyZWN1ZW5jaWEiKQ0KDQpgYGANCiMjSW50ZXJwcmV0YWNpw7NuIGRlIGdyw6FmaWNhOiBBcXXDrSBwb2RlbW9zIHZlciBjw7NtbyBleGlzdGUgdW4gcGF0csOzbiBlc3RhY2lvbmFsIHJlZmVyZW50ZSBhIGxhIHRlbXBlcmF0dXJhIGVuIGVsIGFlcm9wdWVydG8gZGUgTmV3YXJrLCBxdWUgdGllbmUgdGVtcGVyYXR1cmFzIGZyw61hcyAgeSBjw6FsaWRhcywgbG8gcXVlIGVzIGZ1bmRhbWVudGFsIHBhcmEgbGEgYWRtaW5pc3RyYWNpw7NuIHkgcGxhbmVhY2nDs24gcmVsYWNpb25hZGEgY29uIGxvcyBhZXJvcHVlcnRvcyBlbiBsbyBxdWUgcmVzdGEgZGVsIGHDsW8uDQoNCg0KIyNOw7ptZXJvIGRlIHZ1ZWxvcyBxdWUgc2FsaWVyb24gZGUgTnVldmEgWW9yayBwb3IgYWVyb2zDrW5lYSBlbiAyMDEzIGNvbiB1biBncsOhZmljbyBkZSBiYXJyYXMNCmBgYHtyfQ0KZmxpZ2h0cyAlPiUgDQogIGZpbHRlcihvcmlnaW4gJWluJSBjKCJKRksiLCAiTEdBIiwgIkVXUiIpKSAlPiUNCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IHJlb3JkZXIoY2FycmllciwgLWNvdW50KSwgeSA9IGNvdW50KSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJjb3JhbCIpICsNCiAgbGFicyh0aXRsZSA9ICJOw7ptZXJvIGRlIHZ1ZWxvcyBwb3IgYWVyb2zDrW5lYSBlbiAyMDEzIiwgeCA9ICJBZXJvbMOtbmVhIiwgeSA9ICJDYW50aWRhZCBkZSB2dWVsb3MiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpDQoNCmBgYA0KIyNJbnRlcnByZXRhY2nDs24gZGUgZ3LDoWZpY2E6IEVuIGVzdGUgZ3LDoWZpY28gcG9kZW1vcyB2ZXIgY29tbyBwb2NhcyBhZXJvbMOtbmVhcyBzb24gbGFzIHF1ZSBlbmNhYmV6YW4gbGEgY2FudGlkYWQgZGUgdnVlbG9zIHF1ZSBodWJvIGVuIE5ZQyBlbiAyMDEzLCBsbyBxdWUgbXVlc3RyYSB1bmEgYXNpZ25hY2nDs24gZGVzaWd1YWwgZGVsIHRyw6FmaWNvIGHDqXJlbyB5IHB1ZWRlIGxsZWdhciBhIGVuY2FtaW5hciBzZXJ2aWNpb3MgYWVyb3BvcnR1YXJpb3MgeSBhIGxhIHBsYW5lYWNpw7NuIGRlIGluZnJhZXN0cnVjdHVyYS4NCg0KIyNHcsOhZmljYSBkZSBwaWUgcGFyYSBlbCBuw7ptZXJvIGRlIHZ1ZWxvcyBwb3IgYWVyb2zDrW5lYQ0KYGBge3J9DQpmbGlnaHRzICU+JSANCiAgZ3JvdXBfYnkoY2FycmllcikgJT4lDQogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lDQogIGdncGxvdChhZXMoeCA9ICIiLCB5ID0gY291bnQsIGZpbGwgPSBjYXJyaWVyKSkgKw0KICBnZW9tX2Jhcih3aWR0aCA9IDEsIHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGNvb3JkX3BvbGFyKCJ5IikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgdnVlbG9zIHBvciBhZXJvbMOtbmVhIikNCg0KYGBgDQojI0ludGVycHJldGFjacOzbiBkZSBncsOhZmljYTogIEVuIGVzdGEgZ3LDoWZpY2EgZGUgcGllIHZlbW9zIHF1ZSBjaWVydGFzIGFlcm9sw61uZWFzIHNvbiBsYXMgcXVlIGxpZGVyYW4gZWwgbWVyY2FkbyBkZSB2dWVsb3MgZW4gbGEgY2l1ZGFkIGRlIE51ZXZhIFlvcmssIGxvIHF1ZSBzZSBldmlkZW5jaWEgZW4gbGFzIHNlY2Npb25lcyBtw6FzIGdyYW5kZXMsIG1pZW50cmFzIHF1ZSBvdHJhcyBwcmVzZW50YXJvbiB1bmEgbWVub3IgY29sYWJvcmFjacOzbi4NCg0KIyNSZWxhY2lvbmFyIGVsIGRhdGFmcmFtZSBmbGlnaHRzIGNvbiBlbCBkYXRhZnJhbWUgYWlycG9ydHMgdXNhbmRvIGVsIGNhbXBvIGRlc3Rpbm8NCmBgYHtyfQ0KZmxpZ2h0c19haXJwb3J0cyA8LSBmbGlnaHRzICU+JQ0KICBsZWZ0X2pvaW4oYWlycG9ydHMsIGJ5ID0gYygiZGVzdCIgPSAiZmFhIikpDQpgYGANCg0KIyNDcmVhciB1biBudWV2byBkYXRhZnJhbWUgY29uIGVsIHB1bnRvIGFudGVyaW9yIMO6bmljYW1lbnRlIGNvbiBsb3MgNSBjYXJyaWVycyBjb24gbcOhcyB2dWVsb3MgcG9yIGRlc3Rpbm8NCmBgYHtyfQ0KdG9wX2NhcnJpZXJzIDwtIGZsaWdodHMgJT4lDQogIGdyb3VwX2J5KGNhcnJpZXIpICU+JQ0KICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoY291bnQpKSAlPiUNCiAgc2xpY2UoMTo1KSAlPiUNCiAgdW5ncm91cCgpICU+JQ0KICBzZWxlY3QoY2FycmllcikNCg0KZmxpZ2h0c190b3BfY2FycmllcnMgPC0gZmxpZ2h0c19haXJwb3J0cyAlPiUNCiAgZmlsdGVyKGNhcnJpZXIgJWluJSB0b3BfY2FycmllcnMkY2FycmllcikNCg0KYGBgDQoNCg0KIyNWaXN1YWxpemFjacOzbiBkZWwgcHVudG8gYW50ZXJpb3IgZGUgbGFzIHNpZ3VpZW50ZXMgdHJlcyBmb3JtYXMNCmBgYHtyfQ0KIyMqKkdyw6FmaWNvIGRlIGJhcnJhcyBwYXJhIGxhIGNhbnRpZGFkIGRlIHZ1ZWxvcyBwb3IgYWVyb2zDrW5lYToqKg0KDQojIEFzdW1pZW5kbyBxdWUgZmxpZ2h0c190b3BfY2FycmllcnMgY29udGllbmUgbG9zIGRhdG9zIGRlIGxvcyB2dWVsb3MgZGUgbG9zIDUgcHJpbmNpcGFsZXMgdHJhbnNwb3J0aXN0YXMNCmdncGxvdChmbGlnaHRzX3RvcF9jYXJyaWVycywgYWVzKHggPSBjYXJyaWVyLCBmaWxsID0gY2FycmllcikpICsNCiAgZ2VvbV9iYXIoKSArDQogIGxhYnModGl0bGUgPSAiQ2FudGlkYWQgZGUgdnVlbG9zIHBvciBhZXJvbMOtbmVhIiwgeCA9ICJBZXJvbMOtbmVhIiwgeSA9ICJDYW50aWRhZCBkZSB2dWVsb3MiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCiMjSW50ZXJwcmV0YWNpw7NuIGRlIEdyw6FmaWNhOiANCkVzdGEgZ3LDoWZpY2EgZGUgYmFycmFzIG5vcyBzaXJ2ZSBwYXJhIGNvbXBhcmFyIGVsIHZvbHVtZW4gZGUgb3BlcmFjaW9uZXMgcXVlIHRpZW5lIGNhZGEgYWVyb2zDrW5lYSB5IGNvbiBlc3RvIHBvZGVyIHJlYWxpemFyIGFuw6FsaXNpcyBkZSBjYXBhY2lkYWQgb3BlcmF0aXZhIHkgYW7DoWxpc2lzIGNvbXBldGl0aXZvcywgY29tbyB2ZW1vcyBlbiBsYSBncsOhZmljYSBsYSBhZXJvbMOtbmVhIFVBIHZhIGRlIHByaW1lcmEsIHRlbmllbmRvIGxhIG1heW9yIGNhbnRpZGFkIGRlIHZ1ZWxvcy4gDQogIA0KICANCmBgYHtyfQ0KIyoqR3LDoWZpY28gZGUgYmFycmFzIHBhcmEgbGEgY2FudGlkYWQgZGUgdnVlbG9zIHBvciBkZXN0aW5vKioNCg0KZ2dwbG90KGZsaWdodHNfdG9wX2NhcnJpZXJzLCBhZXMoeCA9IGRlc3QsIGZpbGwgPSBjYXJyaWVyKSkgKw0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJDYW50aWRhZCBkZSB2dWVsb3MgcG9yIGRlc3Rpbm8iLCB4ID0gIkRlc3Rpbm8iLCB5ID0gIkNhbnRpZGFkIGRlIHZ1ZWxvcyIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkNCg0KDQpgYGANCiMjSW50ZXJwcmV0YWNpw7NuIGRlIEdyw6FmaWNhOiANCk9ic2VydmFtb3MgbGEgY2FudGlkYWQgZGUgdnVlbG9zIHF1ZSBoYXkgYSBsb3MgZGlmZXJlbnRlcyBkZXN0aW5vcyBxdWUgc29uIG9wZXJhZG9zIHBvciBsYXMgc2lndWllbnRlcyBhZXJvbMOtbmVhcyAoQUEsIEI2LCBETCwgRVYsIFVBKSwgZW4gZXN0ZSBjYXNvIHBvZGVtb3MgdmVyIGNvbW8gY2FkYSBjb2xvciB2YSByZXByZXNlbnRhbmRvIHVuYSBhZXJvbMOtbmVhIGRpc3RpbnRhIHkgc2Ugb2JzZXJ2YSBxdWUgbGEgYWx0dXJhIGRlIGVzdGFzIGJhcnJhcyBlcyBsYSBjYW50aWRhZCBkZSB2dWVsb3MgYSBsb3MgZGlmZXJlbnRlcyBkZXN0aW5vcy4gRXMgcG9zaWJsZSBub3RhciBjb21vIGNpZXJ0b3MgZGVzdGlub3MgcHJlc2VudGFuIHVuYSBncmFuIGNvbmNlbnRyYWNpw7NuICBkZSB2dWVsb3MgcG9yIG3DoXMgZGUgdW5hIGFlcm9sw61uZWEsIGVuIGNhbWJpbyBvdHJvcyBjdWVudGFuIGNvbiB1bmEgbWVub3IgY2FudGlkYWQsIGxvIHF1ZSBub3MgbXVlc3RyYSBsYSBwb3B1bGFyaWRhZCBkZSBkaWNob3MgZGVzdGlub3MuDQoNCg0KYGBge3J9DQojIyoqR3LDoWZpY28gZGUgYmFycmFzIHBhcmEgbGEgY2FudGlkYWQgZGUgdnVlbG9zIHBvciBkw61hIGRlbCBtZXMqKg0KDQpnZ3Bsb3QoZmxpZ2h0c190b3BfY2FycmllcnMsIGFlcyh4ID0gZmFjdG9yKGRheSksIGZpbGwgPSBjYXJyaWVyKSkgKw0KICBnZW9tX2JhcigpICsNCiAgbGFicyh0aXRsZSA9ICJDYW50aWRhZCBkZSB2dWVsb3MgcG9yIGTDrWEgZGVsIG1lcyIsIHggPSAiRMOtYSBkZWwgbWVzIiwgeSA9ICJDYW50aWRhZCBkZSB2dWVsb3MiKSArDQogIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCiMjSW50ZXJwcmV0YWNpw7NuIGRlIEdyw6FmaWNhOg0KRW4gZXN0YSBncsOhZmljYSBwb2RlbW9zIG9ic2VydmFyIHF1ZSBsYXMgYmFycmFzIG11ZXN0cmFuIGxvcyBuw7ptZXJvcyBkZSB2dWVsb3MgZGlhcmlvcyBlbiB1biBtZXMsIHBhcmEgZGlmZXJlbnRlcyBhZXJvbMOtbmVhcy4gTGFzIGNhcGFzIGRlIGNvbG9yIG5vcyBpbmRpY2FuIGN1w6FsIGFlcm9sw61uZWEgZXMgZGUgbGEgcXVlIHNlIGVzdGEgaGFibGFuZG8geSBxdWUgY29udHJpYnVjacOzbiBkZSB2dWVsb3MgdGllbmVuIGVuIHRvdGFsIGVuIHVuIGTDrWEuIEFob3JhIGhhYmxhbmRvIHNvYnJlIGxhIGFsdHVyYSBjb21iaW5hZGEgZGUgZXN0YXMgYmFycmFzLCBub3MgZGEgYSBlbnRlbmRlciBxdWUgZWwgbsO6bWVybyBkZSB2dWVsb3Mgc2UgbWFudGllbmUgY29uc3RhbnRlIGVuIGVsIG1lcywgc2luIG5pbmfDum4gdGlwbyBkZSBjYW1iaW9zIGRyw6FzdGljb3MuIEVzdG8gZXMgYnVlbm8geWEgcXVlIG5vcyBzZcOxYWxhIHF1ZSBleGlzdGUgdW5hIG9wZXJhY2nDs24gcmVndWxhciBlbiBlbCBhZXJvcHVlcnRvIHNpbiBncmFuZGVzIG1vZGlmaWNhY2lvbmVzIGVuIGVsIHRyw6FmaWNvIGHDqXJlbyBwb3IgcGFydGUgZGUgbGFzIGFlcm9sw61uZWFzLiANCg0KDQojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPiBDb25jbHVzacOzbiBGaW5hbCA8L3NwYW4+DQoNCkVuIG51ZXN0cm8gYW7DoWxpc2lzIGRldGFsbGFkbyBkZSBsYSBiYXNlIGRlIGRhdG9zIG55Y2ZsaWdodHMxMywgYW5hbGl6YW1vcyB0ZW5kZW5jaWFzIHkgcGF0cm9uZXMgY2xhdmUgcGFyYSBwb2RlciBkZXRlcm1pbmFyIGxvcyByZXRyYXNvcyBkZSBsb3MgdnVlbG9zIHF1ZSBwYXJ0ZW4gZGUgTnVldmEgeW9yayBlbiAyMDEzLiBMYSBhZXJvbMOtbmVhIFVuaXRlZCBBaXJsaW5lcyBsaWRlcsOzIGVuIHTDqXJtaW5vcyBkZSBtaWxsYXMgcmVjb3JyaWRhcyBkZXNkZSBFV1IsIG1pZW50cmFzIHF1ZSBsYSBkZSBBbWVyaWNhbiBBaXJsaW5lcyB5IEpldEJsdWUgZnVlcm9uIGxvcyBxdWUgbGlkZXJhcm9uIGVuIExHQSB5IEpGSywgYXPDrSBjb21vIGxvcyBkZXN0aW5vcyBtw6FzIGZyZWN1ZW50YWRvcyBpbmNsdXllcm9uIEF0bGFudGEsIExvcyDDgW5nZWxlcyB5IENoaWNhZ28uDQoNCkVzdG9zIGFuw6FsaXNpcyBub3MgaW5kaWNhbiBsYXMgaG9yYXMgZGUgdGFyZGUgYSBub2NoZSBlbiBlbCBjdcOhbCBoYXkgbWF5b3JlcyByZXRyYXNvcywgY29uIGxvcyByZXRyYXNvcyBhdW1lbnRhbmRvIGhhc3RhIGVsICoqNTEuNiUqKiBkZSByZXRyYXNvIHBhcmEgbG9zIHZ1ZWxvcyBxdWUgc2FsZW4gZGVzcHXDqXMgZGUgbGFzICoqMjA6MDAqKiB5IGxhIGNvbmdlc3Rpw7NuIGRlIGVzdG9zIHZ1ZWxvcyBkdXJhbnRlIGxhcyBob3JhcyBwaWNvLiBMYXMgYWVyb2zDrW5lYXMgaW5kaWNhcm9uICBkaWZlcmVudGVzIHZhcmlhY2lvbmVzIHNpZ25pZmljYXRpdmFzIGVuIGxvcyByZXRyYXNvcywgY29tbyBTb3V0aHdlc3QgQWlybGluZXMgY29uIHVuICoqNTMuNDIlKiogZW4gc3VzIHZ1ZWxvcyByZXRyYXNhZG9zLiBFbiBsb3MgYWVyb3B1ZXJ0b3MsIEVXUiBvYnR1dm8gZWwgbWF5b3IgcG9yY2VudGFqZSBkZSB2dWVsb3MgcmV0cmFzYWRvcyBjb24gdW4gcG9yY2VudGFqZSBkZSAqKjQzLjYyJSoqIHkgZWwgbWF5b3IgcmV0cmFzbyBwcm9tZWRpbyBkZSAqKjE1LjEqKiBtaW51dG9zIHBvciBjYWRhIHZ1ZWxvLiANCg0KU2luIGVtYmFyZ28sIGF1bnF1ZSBsYXMgY29uZGljaW9uZXMgbWV0ZW9yb2zDs2dpY2FzIHNvbiBlc3RhZMOtc3RpY2FtZW50ZSBzaWduaWZpY2F0aXZhcyBzb2xvIHNlIGV4cGxpY2Fyb24gZW4gdW4gKioyLjElKiogZGUgbGEgdmFyaWFiaWxpZGFkIHF1ZSB0aWVuZW4gbG9zIHJldHJhc29zIGRlIGxvcyB2dWVsb3MuIEF1bnF1ZSBlbCBjbGltYSBhZmVjdGEgbG9zIHJldHJhc29zLCBvdHJvcyBmYWN0b3JlcyBjb21vIGxhIGdlc3Rpw7NuIGFlcm9wb3J0dWFyaWEgeSBsYXMgb3BlcmFjaW9uZXMgZGUgbGFzIGFlcm9sw61uZWFzIG5vcyBpbmRpY2FuIHVuIGltcGFjdG8gbcOhcyBzdXN0YW5jaWFsIGxvIHF1ZSB2ZW1vcyBjb21vIHVuIGdyYW4gaGFsbGF6Z28gcGFyYSBkZXRlcm1pbmFyIGxhcyB2YXJpYWJsZXMgcXVlIG3DoXMgaW1wYWN0YW4uICBJZGVudGlmaWNhbW9zIHF1ZSBleGlzdGVuIG9wb3J0dW5pZGFkZXMgZGUgbWVqb3JhIGVuIGxhIGdlc3Rpw7NuIG9wZXJhdGl2YSB5IGVuIHJlc3B1ZXN0YSBoYWNpYSBsYXMgY29uZGljaW9uZXMgY2xpbcOhdGljYXMsIGRlYmlkbyBhIHF1ZSBsb3MgcmV0cmFzb3Mgc29uIHVuIGNvbXBsZWpvIGluZmx1ZW5jaWFkbyBwb3IgdW5hIHZhcmllZGFkIGRlIGZhY3RvcmVzLCBkZXNkZSBsYXMgZGVjaXNpb25lcyBlc3RyYXTDqWdpY2FzIGRlIGNhZGEgYWVyb2zDrW5lYSwgaGFzdGEgbGEgY29uZ2VzdGnDs24gYWVyb3BvcnR1YXJpYS4gDQoNCkdyYWNpYXMgYSBlc3RvcyBkYXRvcyBwdWRpbW9zIGFuYWxpemFyIGxhIHByb2JsZW3DoXRpY2EgZGUgbG9zIHJldHJhc29zLCBlbnRyZSB0b2RhcyBsYXMgdmFyaWFibGVzIHF1ZSBhbmFsaXphbW9zIG9idHV2aW1vcyBsYXMgbcOhcyBpbXBvcnRhbnRlcy4gRWwgIkNvbHVtYmlhIE1ldHJvcG9saXRhbiBBaXJwb3J0IiBlcyBlbCBkZXN0aW5vIGNvbiBtYXlvciBwb3JjZW50YWplIGRlIHJldHJhc29zIHNpZW5kbyBlbCAqKjUzJSoqIGRlIGxhcyB2ZWNlcywgZXN0ZSBhZXJvcHVlcnRvIGdlbmVyYSBhdHJhc29zIGVuIGxhIG1pdGFkIGRlIHN1cyB2dWVsb3MsIGVzdGUgcG9yY2VudGFqZSBpbmRpY2EgcXVlIGxvcyByZXRyYXNvcyBzb24gcmVzcG9uc2FiaWxpZGFkIGRlbCBhZXJvcHVlcnRvIGRlc3Rpbm8uIEVsIGFlcm9wdWVydG8gZGVzdGlubyBjb24gbcOhcyBwcm9tZWRpbyBkZSByZXRyYXNvIGVzIFRyYXZlcnNlIENpdHksIE1pY2hpZ2FuIGNvbiA4OSBtaW51dG9zIHByb21lZGlvIGRlIHJldHJhc28uIEFob3JhIGNvbnNpZGVyYW5kbyBsYXMgdmFyaWFibGVzIG5hdHVyYWxlcyBlbmNvbnRyYW1vcyBxdWUgbGEgaHVtZWRhZCBqdWVnYSBlbCBwYXBlbCBtw6FzIGltcG9ydGFudGUgZW4gbG9zIHJldHJhc29zIGRlIGxvcyBhdmlvbmVzLCBlbiBlbCAqKjk4JSoqIGRlIGVsbG9zIGxhIGh1bWVkYWQgZnVlIG1lZGlhbmFtZW50ZSBhbHRhIGUgaW5mbHV5w7MgZW4gZWwgdGllbXBvIGRlIHZ1ZWxvLCBzYWxpZGEgeSBsbGVnYWRhLiANCg0KDQojIyDDiXRpY2EgeSByZXNwb25zYWJpbGlkYWQgZW4gbG9zIE5lZ29jaW9zDQoNCiMjIyBEZXJlY2sgSWtlciBWaWxsYWZhw7FhIFJvbWVybw0KRWwgdXNvIGRlIGxhcyBiYXNlcyBkZSBkYXRvcyBlbiBudWVzdHJhIGNhcnJlcmEgeSBmdXR1cmFzIHByw6FjdGljYXMgZGViZSBzZXIgdXRpbGl6YWRvIGRlIG1hbmVyYSBtdXkgcmVzcGV0dW9zYSB5IHJlc3BvbnNhYmxlLCB0b21hbmRvIGVuIGN1ZW50YSBxdWUgZW4gZWwgZnV0dXJvIGVzdGFyw6kgbXV5IHByb2JhYmxlbWVudGUgdHJhYmFqYW5kbyBjb24gYmFzZXMgZGUgZGF0b3MgZGUgZW1wcmVzYXMgbyBwZXJzb25hcywgYSBsYSBob3JhIGRlIHJlYWxpemFyIGFsZ8O6biBhbsOhbGlzaXMgbyB0cmFiYWpvLCBkZWJvIGNvbXByZW5kZXIgbGEgaW1wb3J0YW5jaWEgZGUgcmVzcGV0YXIgeSBjdWlkYXIgZXN0b3MgZGF0b3MuIExhIGluZm9ybWFjacOzbiBkZSBsYXMgZW1wcmVzYXMgZXMgdW5vIGRlIHN1cyBtw6FzIHZhbGlvc29zIGFjdGl2b3MgeSBlc3RveSBjb25zY2llbnRlIHF1ZSBzaWVtcHJlIGRlYm8gYWN0dWFyIGNvbiBpbnRlZ3JpZGFkIGEgbGEgaG9yYSBkZSB0cmFiYWphciBjb24gZXN0b3MgZGF0b3MuIE1lIGNvbXByb21ldG8gYSBzaWVtcHJlIHJlc3BldGFyIGxhIHByaXZhY2lkYWQgZGUgbGFzIHBlcnNvbmFzIGludm9sdWNyYWRhcyBlbiBsYXMgYmFzZXMgZGUgZGF0b3MgY3XDoW5kbyBzZSBpbnZvbHVjcmVuIGRhdG9zIHBlcnNvbmFsZXMgbyBkYXRvcyBjcsOtdGljb3MgZGUgbGEgZW1wcmVzYSBxdWUgcHVlZGFuIHNlciB1dGlsaXphZG9zIGVuIHN1IGNvbnRyYSBwb3IgdGVyY2Vyb3MuDQoNCiMjIyBDYXJvbGluYSBTdcOhcmV6IFJvZHLDrWd1ZXoNCkFsIGhhYmxhciBkZSBsYSBpbnRlZ3JpZGFkICBub3MgcmVmZXJpbW9zIGFsIGhhYmxhciBkZSB0cmFuc3BhcmVuY2lhLCBlcyBkZWNpciBzZXIgw6l0aWNvcyB5IHJlc3BvbnNhYmxlcyBjb24gbGFzIGFjY2lvbmVzIHF1ZSB0b21hbW9zIGFsIHRvbWFyIHVuYSBkZWNpc2nDs24sIGNhYmUgcmVjYWxjYXIgcXVlIHNpZW1wcmUgZGViZW1vcyB1dGlsaXphciBlc3RhIHRyYW5zcGFyZW5jaWEgYSBsYSBob3JhIGRlIHRyYWJhamFyIGVuIHVuYSBlbXByZXNhIHkgY29uIHN1cyBpbmZvcm1hY2lvbmVzIGNsYXNpZmljYWRhcy4gRXMgZGUgc3VtYSBpbXBvcnRhbmNpYSBjb25zZXJ2YXIgc2llbXByZSB0dSBpbnRlZ3JpZGFkIHBhcmEgYXPDrSBsb2dyYXIgZm9ybWFyIGxhem9zIGRlIGNvbmZpYW56YSBjb24gdHVzIG1pc21vcyBjbGllbnRlcywgcGFyYSBhc8OtIHBvZGVyIGdhcmFudGl6YXIgdW4gw6l4aXRvIGR1cmFkZXJvLg0KDQojIyMgRmVkZXJpY28gWm9ycmlsbGEgSmFzc28NClNvbW9zIG11eSBhZm9ydHVuYWRvcyBxdWUgY29tbyBpbnN0aXR1Y2nDs24gbXVjaGFzIGVtcHJlc2FzIG5vcyBjb21wYXJ0ZW4gc3VzIGJhc2VzIGRlIGRhdG9zLiBFbiBlbCBibG9xdWUgZGUgSW5kaWNhZG9yZXMgeSBSaWVzZ29zIGNvbiBWaXNpw7NuIEVzdHJhdMOpZ2ljYSwgdHJhYmFqYW1vcyBjb24gbG9zIGRhdG9zIGRlIEFyY2EgQ29udGluZW50YWwsIHVuYSBlbXByZXNhIG11eSBncmFuZGUgcXVlIHZhbMO6YSBzdXMgZGF0b3MuIEVuIHVuIGZ1dHVybywgaWRlYWxtZW50ZSB0cmFiYWphcsOpIGNvbiBsYXMgYmFzZXMgZGUgZGF0b3MgZGUgZGl2ZXJzYXMgZW1wcmVzYXMsIHkgZXMgbmVjZXNhcmlvIHRlbmVyIGVuIGN1ZW50YSBxdWUgZXNvcyBkYXRvcyBzb24gb3JvLiBVbmEgZW1wcmVzYSB0ZSBjb25mw61hIGNvbiBlbGxvcywgeSBsYSBjb21wZXRlbmNpYSBoYXLDrWEgbG8gcXVlIHNlYSBwYXJhIGNvbnNlZ3Vpcmxvcy4gSGFuIGhhYmlkbyBtaWxlcyBkZSBtaWxsb25lcyBkZSBjYXNvcyBxdWUgYWxnw7puIGV4dG9yc2lvbmFkb3IgImJyZWFjaGVhIiBsb3MgZGF0b3MgZGUgdW5hIGVtcHJlc2EsIHkgYW1lbmF6YSBjb24gcHVibGljYXJsb3MuIEFob3JhIGltYWdpbmEgbG8gZsOhY2lsIHF1ZSBlcyBzaSBlc3RlIGhhY2tlciBodWJpZXJhIGRlY2lkaWRvIGhhY2tlYXJtZSBhIG3DrS4gU2VndXJhbWVudGUgZXMgbcOhcyBmw6FjaWwgcXVlIGhhY2tlYXIgYSB1bmEgZW1wcmVzYSwgeSBhaG9yYSB5byBlc3RveSBsaWdhZG8gYWwgcHJvYmxlbWEuIFBvciBlc3RhIHJhesOzbiB5IG11Y2hhcyBtw6FzLCBlcyBjcsOtdGljbyBjdWlkYXIgZGUgbG9zIGRhdG9zIHF1ZSBub3MgY29tcGFydGVuIGxhcyBlbXByZXNhcyBjb24gbGFzIHF1ZSB0cmFiYWphbW9zLiANCg==