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 nombres y códigos de las aerolíneas

Fuente:
Origen de los datos

Instalar paquetes y llamar librerías

# install.packages("nycflights13")
library(nycflights13)
## Warning: package 'nycflights13' was built under R version 4.3.3
# install.packages("tidyverse")
library(tidyverse)
## Warning: package 'tidyverse' was built under R version 4.3.3
## Warning: package 'lubridate' was built under R version 4.3.3
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.4.4     ✔ tibble    3.2.1
## ✔ lubridate 1.9.3     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Guardar bases de datos

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

Relación entre bases de datos

Avance 1

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" ...
# int: entero (sin decimales)
# num: numérico (con decimales)
# chr: caractér (letras o palabras)
# Date: Fecha (en R va año-mes-dia)
# POSIXct: formato fecha (fecha y hora)

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

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

# Las 5 clases de objetos son:
# 1. numeric: número real o decimales
# 2. Integer: números enteros
# 3. Complex: números complejos
# 4. Character: caractéres
# 5. Logical: TRUE o FALSE

# Las 4 clases de objetos compuestos son:
# 1. list: lista
# 2. matrix: matriz
# 3. array: colección de objetos
# 4. data.frame: base de datos

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

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

5. Muestra los primeros 6 renglones de “flights”. También los últimos 6

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

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

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

Manejo de Datos

Select

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

df1 <- flights %>% select(carrier, flight) # Selección de columnas específicas
df2 <- flights %>% select(carrier:distance) # Selección de rango de columnas
df3 <- flights %>% select(-carrier, -flight) # Eliminar columnas específicas
df4 <- flights %>% select(-carrier:-distance) # Eliminar rango de columnas
df5 <- flights %>% select(aerolinea = carrier) # Selecciona una columna y le cambia el nombre 
df6 <- flights %>% rename(aerolinea = carrier) # Cambiar nombre

Filter

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

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

Distinct

La función distinct sirve para eliminar renglones duplicados.

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

Merge

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

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

Mutate

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

Ejercicios

# 1. Encuentra todos los vuelos que tuvieron un atraso en llegada de dos horas o más
ejercicio1 <- bdgrande2 %>% filter(arr_delay>=120)

# 2. Encuentra todos los vuelos que llegaron a Houston (IAH O HOU)
ejercicio2 <- bdgrande2 %>% filter(dest == "IAH" | dest == "HOU")

# 3. Encuentra todos los vuelos operados por United, American o Delta
ejercicio3 <- bdgrande2 %>% filter(carrier == "UA" | carrier == "AA" | carrier == "DL")

# 4. Encuentra todos los vuelos que despegaron en Julio, Agosto o Septiembre.
ejercicio4 <- bdgrande2 %>% filter(month %in% c (7:9))

# 5. Encuentra todos los vuelos que arrivaron más de 2 horas tarde, pero no despegaron tarde.
ejercicio5 <- bdgrande2 %>% filter(arr_delay>120 & dep_delay <= 0)
  
# 6. Encuentra todos los vuelos que se retrasaron al menos 1 hora, pero que llegaron antes 30 minutos o más.
ejercicio6 <- bdgrande2 %>% filter(dep_delay>=60 & arr_delay<= -30)

# 7. Encuentra todos los vuelos que salieron entre la medianoche y las 6 a.m. 
ejercicio7 <- bdgrande2 %>% filter(dep_time==2400 | dep_time<=600)

Arrange

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

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

Summarize

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

# Obtén el retraso promedio de despegue de todos los vuelos 
summarize(bdgrande2, mean(dep_delay, na.rm=TRUE))
##   mean(dep_delay, na.rm = TRUE)
## 1                      13.17979

Group by

Agrupa tabla basado en algunas columnas.

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

Avance 2

Se nos ha solicitado consultar cuáles son las aerolíneas de mayor tráfico aéreo en origen y destino.

1. Aerolíneas de mayor tráfico”

# Hacemos summary de flights para ver todas las columnas con las que cuenta la base de datos
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  
## 
# Instrucciones: define un criterio para encontrar las aerolíneas que han recorrido más distancia (en millas) y crea un nuevo data frame que filtre solamente a las aeorlíneas que han recorridao una distancia superior a la media, se desea ver los campos carrier, distance, origin, dest en forma descendente por distance. Ejemplo: aerolíneas con millas recorridas superiores a la media, ordenadas en forma descendente.

df2 <- flights %>% select(carrier, distance, origin, dest) 
df3 <- df2 %>% filter(distance > 1040)
df3
## # A tibble: 127,665 × 4
##    carrier distance origin dest 
##    <chr>      <dbl> <chr>  <chr>
##  1 UA          1400 EWR    IAH  
##  2 UA          1416 LGA    IAH  
##  3 AA          1089 JFK    MIA  
##  4 B6          1576 JFK    BQN  
##  5 B6          1065 EWR    FLL  
##  6 UA          2475 JFK    LAX  
##  7 UA          2565 EWR    SFO  
##  8 AA          1389 LGA    DFW  
##  9 UA          2227 EWR    LAS  
## 10 B6          1076 LGA    FLL  
## # ℹ 127,655 more rows
df4 <- df3 %>% arrange(desc(distance))
df4
## # 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
df5 <- df4 %>% 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.
df5
## # A tibble: 150 × 5
## # Groups:   carrier, origin [26]
##    carrier origin dest  sumdistance meandistance
##    <chr>   <chr>  <chr>       <dbl>        <dbl>
##  1 9E      JFK    AUS          3042         1521
##  2 9E      JFK    DFW        507715         1391
##  3 9E      JFK    MCI        307188         1113
##  4 9E      JFK    MSY        515352         1182
##  5 9E      JFK    SAT         84111         1587
##  6 9E      LGA    DFW         19446         1389
##  7 9E      LGA    MCI         94095         1107
##  8 9E      LGA    MSY          1183         1183
##  9 9E      LGA    RSW         72360         1080
## 10 9E      LGA    SRQ         81666         1047
## # ℹ 140 more rows

2. Aerolíneas de mayor tráfico”

df5 <- df4 %>% 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.
df5
## # A tibble: 150 × 5
## # Groups:   carrier, origin [26]
##    carrier origin dest  sumdistance meandistance
##    <chr>   <chr>  <chr>       <dbl>        <dbl>
##  1 9E      JFK    AUS          3042         1521
##  2 9E      JFK    DFW        507715         1391
##  3 9E      JFK    MCI        307188         1113
##  4 9E      JFK    MSY        515352         1182
##  5 9E      JFK    SAT         84111         1587
##  6 9E      LGA    DFW         19446         1389
##  7 9E      LGA    MCI         94095         1107
##  8 9E      LGA    MSY          1183         1183
##  9 9E      LGA    RSW         72360         1080
## 10 9E      LGA    SRQ         81666         1047
## # ℹ 140 more rows
df6 <- arrange(df5,carrier,sumdistance)

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

Avance 3

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

view(planes)
view(weather)

2. Se necesita saber de cada vuelo, la aerolinea, el aeropuerto de origen y el aeropuerto destino.

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

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

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

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

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

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

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

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

Agrega un nuevo campo a la tabla con el nombre de clas_horario y agrega, mañana, tarde, noche y madrugada según sea el caso.

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

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

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

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

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

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

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

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

En la evidencia se presentó la necesidad de mejorar la posición competitiva de una de las aerolíneas líderes en los aeropuertos de Nueva York, American Airlines, por lo que a continuación se presentarán datos y la explicación de porqué la aerolínea los debe de tomar en cuenta para posicionarse como líder. Anteriormente se nombró que Newark Liberty International Airport es la sede de United Air Lines, por lo que suena lógico que sea la aerolínea con mayor cantidad de vuelos en New York con 58,665, mientras que American Airlines sólo cuenta con 32,729, es decir un 44% menos, teniendo una menor oportunidad de ofrecer más variedad de vuelos y consecuentemente perdiendo cuota de mercado. Además, durante la noche American Airlines ofrece menos de la ⅕ de los vuelos que ofrece en la madrugada o tarde, por lo que se puede perder un segmento de mercado, como las empresas, las cuáles muchas veces mandan ejecutivos a viajes de un día, regresando en la noche a su casa.

Adicionalmente, la mayoría de los vuelos de la madrugada de American Airlines son a Miami, por lo que tienen una oferta muy limitada y sus aviones tienen máximo 330 asientos, a comparación de otras aerolíneas, como Delta Air Lines, la cuál cuenta con aviones de hasta 450 asientos, pudiendo transportar a un 36% más de pasajeros. Finalmente,los aviones de tipo “Fixed wind multi engine” y motor “Turbo-fan” son por mucho los aviones de American Airlines que más vuelos y asientos tienen, pudiendo decir que son más eficientes. La suma de todos estos factores, son los causantes de que la aerolínea no sea la líder, pero si opta por hacer cambios como implementar más vuelos en la noche, comprar aviones con más cantidad de asientos, aumentar los destinos y mantener su atraso promedio, el cuál es uno de lo menores con 8,59 minutos, la empresa puede mejorar en gran medida su posicionamiento en la industria.

Hallazgos y conclusiones

¿Qué influye en el retraso de los vuelos?

Para responder a la pregunta anterior, se hicieron una serie de modelos de regresión y bases de datos, para poder llegar a una o más respuestas concisas.

Retraso por aerolínea

Nos permite identificar qué aerolínea tiene más retrasos de salida, lo que se puede asociar con poca comunicación dentro de las operaciones.

vuelos_por_aerolinea <- flights %>% group_by(carrier) %>% summarize(avg_delay = mean(dep_delay, na.rm = TRUE))
vuelos_por_aerolinea
## # A tibble: 16 × 2
##    carrier avg_delay
##    <chr>       <dbl>
##  1 9E          16.7 
##  2 AA           8.59
##  3 AS           5.80
##  4 B6          13.0 
##  5 DL           9.26
##  6 EV          20.0 
##  7 F9          20.2 
##  8 FL          18.7 
##  9 HA           4.90
## 10 MQ          10.6 
## 11 OO          12.6 
## 12 UA          12.1 
## 13 US           3.78
## 14 VX          12.9 
## 15 WN          17.7 
## 16 YV          19.0
aerolineasdelay <- vuelos_por_aerolinea[vuelos_por_aerolinea$avg_delay > 15, ]
aerolineasdelay
## # A tibble: 6 × 2
##   carrier avg_delay
##   <chr>       <dbl>
## 1 9E           16.7
## 2 EV           20.0
## 3 F9           20.2
## 4 FL           18.7
## 5 WN           17.7
## 6 YV           19.0

Como se puede apreciar, las aerolíneas que traen los vuelos con retrasos más pesados son Endeavor Air Inc, ExpressJet Airlines Inc, Frontier Airlines Inc, AirTran Airways Corporation, Southwest Airlines Co y Mesa Airlines Inc.

Retraso por aeropuerto

Nos permite identificar en qué aeropuerto los vuelos suelen salir más tarde, lo que nos puede decir qué aeropuerto es el que tiene más tráfico.

vuelos_por_aeropuerto <- flights %>% group_by(origin) %>% summarize(avg_delay = mean(dep_delay, na.rm = TRUE))
vuelos_por_aeropuerto
## # A tibble: 3 × 2
##   origin avg_delay
##   <chr>      <dbl>
## 1 EWR         15.1
## 2 JFK         12.1
## 3 LGA         10.3
ggplot(vuelos_por_aeropuerto, aes(x = origin, y = avg_delay)) + geom_bar(stat = "identity", fill = "skyblue") + labs(title = "Retraso Promedio por Aeropuerto de Origen", x = "Aeropuerto de Origen", y = "Retraso Promedio (minutos)") + theme_minimal()

Retraso por hora

Nos permite identificar a qué hora se suelen dar los retrasos más pesados.

vuelos_por_hora <- flights %>% mutate(hour = hour(time_hour)) %>% group_by(hour) %>% summarize(avg_delay = mean(dep_delay, na.rm = TRUE))
vuelos_por_hora
## # A tibble: 20 × 2
##     hour avg_delay
##    <int>     <dbl>
##  1     1   NaN    
##  2     5     0.688
##  3     6     1.64 
##  4     7     1.91 
##  5     8     4.13 
##  6     9     4.58 
##  7    10     6.50 
##  8    11     7.19 
##  9    12     8.61 
## 10    13    11.4  
## 11    14    13.8  
## 12    15    16.9  
## 13    16    18.8  
## 14    17    21.1  
## 15    18    21.1  
## 16    19    24.8  
## 17    20    24.3  
## 18    21    24.2  
## 19    22    18.8  
## 20    23    14.0
horasmastrafic <- vuelos_por_hora[13:19, ]
horasmastrafic
## # A tibble: 7 × 2
##    hour avg_delay
##   <int>     <dbl>
## 1    16      18.8
## 2    17      21.1
## 3    18      21.1
## 4    19      24.8
## 5    20      24.3
## 6    21      24.2
## 7    22      18.8
ggplot(vuelos_por_hora, aes(x = hour, y = avg_delay)) + geom_bar(stat = "identity", fill = "skyblue") + labs(title = "Retraso Promedio por Hora del Día", x = "Hora del Día", y = "Retraso Promedio (minutos)") + theme_minimal()
## Warning: Removed 1 rows containing missing values (`position_stack()`).

Como se puede apreciar, las horas en las que los vuelos presentan retrasos para despegar más pesados son de 4 a 10, con un retraso promedio de 22 minutos.

Retrasos y condiciones del clima

Este código nos permite crear una dataframe nueva usando flights y weather, usando como columnas clave el año, el mes, el día, la hora y el origen. Es una manera de crear una dataframe la cual nos permite utilizar los datos dentro de weather, los cuales creemos que podría tener un impacto en el retraso de los vuelos.

vuelos_clima <- flights %>% left_join(weather, by = c("year", "month", "day", "hour", "origin"))
regresionclima <- lm(dep_delay ~ temp + wind_speed + wind_gust + precip + visib + pressure + dewp + humid, data = vuelos_clima)
summary(regresionclima)
## 
## Call:
## lm(formula = dep_delay ~ temp + wind_speed + wind_gust + precip + 
##     visib + pressure + dewp + humid, data = vuelos_clima)
## 
## Residuals:
##    Min     1Q Median     3Q    Max 
## -57.42 -17.08 -11.71  -0.02 754.95 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept) 198.47760   23.13779   8.578  < 2e-16 ***
## temp          0.47232    0.08368   5.644 1.66e-08 ***
## wind_speed   -0.11051    0.05870  -1.883   0.0598 .  
## wind_gust     0.31959    0.05118   6.244 4.28e-10 ***
## precip       -8.57069   11.70037  -0.733   0.4639    
## visib        -1.52831    0.17091  -8.942  < 2e-16 ***
## pressure     -0.20658    0.02165  -9.543  < 2e-16 ***
## dewp         -0.38823    0.09213  -4.214 2.51e-05 ***
## humid         0.42391    0.05118   8.283  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 37.82 on 73224 degrees of freedom
##   (263543 observations deleted due to missingness)
## Multiple R-squared:  0.02406,    Adjusted R-squared:  0.02395 
## F-statistic: 225.6 on 8 and 73224 DF,  p-value: < 2.2e-16
ggplot(vuelos_clima, aes(x = temp, y = dep_delay)) + geom_point(color = "blue", alpha = 0.5) + labs(title = "Relación entre Retraso de Vuelo y Temperatura", x = "Temperatura (°C)", y = "Retraso de Vuelo (minutos)") + theme_minimal()
## Warning: Removed 9800 rows containing missing values (`geom_point()`).

Para nuestro hallazgo, cuestiones climatológicas no tienen un impacto significativo en el retraso con el que despegan los vuelos, ya que basándonos en el modelo de regresión lineal anteriormente mostrado, la R cuadrada es de 0.02

Retraso por día de la semana

Calcular el retraso por día de la semana nos dará una perspectiva en cuáles son los días más ocupados en cuestión de vuelos de la semana.

# Filtrar los vuelos con datos completos (sin valores faltantes)
flights_clean <- flights %>% filter(!is.na(dep_delay))

# Calcular el retraso promedio por día de la semana
retraso_promedio_por_dia <- flights_clean %>% group_by(day_of_week = weekdays(time_hour)) %>% summarize(avg_delay = mean(dep_delay, na.rm = TRUE))
retraso_promedio_por_dia
## # A tibble: 7 × 2
##   day_of_week avg_delay
##   <chr>           <dbl>
## 1 Friday          14.7 
## 2 Monday          14.8 
## 3 Saturday         7.65
## 4 Sunday          11.6 
## 5 Thursday        16.1 
## 6 Tuesday         10.6 
## 7 Wednesday       11.8
ggplot(retraso_promedio_por_dia, aes(x = day_of_week, y = avg_delay)) + geom_line(color = "blue", size = 1) + geom_point(color = "red", size = 3) + labs(title = "Retraso Promedio por Día de la Semana", x = "Día de la Semana", y = "Retraso Promedio (minutos)") + theme_minimal()
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?

Como se puede apreciar, los días más ocupados serían lunes, jueves y viernes, el día menos ocupado sería el sabado.

Conclusión

En conclusión, al observar los data frames de vuelos y clima pudimos identificar distintos factores que influyen en que los vuelos lleguen tarde. Estos factores son la hora a la que estos salen, la distancia que tienen que recorrer, y las aerolíneas.

Antes de empezar el código, nosotros creíamos que el principal factor era el clima, pero al hacer un modelo de regresión que probara que el clima tiene un impacto en el retraso de los vuelos nos dimos cuenta que no era acertado, ya que la R cuadrada fue de 0,02, por lo que fue prácticamente nula.

El realizar un análisis estadístico descriptivo nos sirvió para observar y analizar diferentes factores de los dataframes, como flights. Por ejemplo, pudimos identificar cosas como que en promedio el dep_delay es de 13 a 18 minutos, lo que nos permite inferir que son más los vuelos que salen atrasados que los que salen a tiempo o adelantados.

Enfocándonos un poco más, pudimos ver que los vuelos que salen entre las 16:00 y 22:00 son los que suelen tener en promedio un mayor retraso, saliendo entre 18 y 24 minutos después de lo establecido. Mientras que, los demás sólo salían entre 0 y 16 minutos atrasados, lo que se puede deber a que mientras más tarde es, más vuelos retrasados se van acumulando.

Por otro lado, también pudimos observar que el atraso depende mucho de la aerolínea, ya que en el caso de US Airways Inc en promedio sólo salía 3,78 minutos después, mientras que Frontier Airlines Inc. salía 20,22 minutos después, es decir más de 5 veces más tarde que US Airways Inc. Así mismo, en el caso de American Airlines, de 32,093 vuelos que tuvo desde New York en el 2013, 10,161 salieron con retraso, lo que representa aproximadamente un 32% de sus vuelos y su retraso promedio fue de 8,6 minutos.

Adicionalmente, pudimos identificar que en promedio el vuelo con la mayor distancia recorrida es el de Hawaiian Airlines Inc que va desde New York(JFK) a Honolulu(HNL), lo que nos podría indicar que hay atrasos, debido a la distancia recorrida o eventos, como tsunamis o tormentas que son muy comunes en Hawaii. De igual manera, de los 100 vuelos que tuvieron un atraso de más de 1000 minutos, 6 corresponden a Los Angeles International Airport, lo que se puede deber de igual manera a la distancia que tiene con Nueva York.

Finalmente, se contempló que los vuelos que tuvieron como origen el aeropuerto de Newark presentaron en promedio un retraso de 15 minutos, contra los 10 de La Guardia. Esto se debe a que Newark es el aeropuerto con mayor cantidad de vuelos. Los Jueves fueron el día con mayor retraso con 19 minutos, seguido por los Lunes y Viernes, es decir los días que se viajan normalmente para el fin de semana.

La suma de todos estos factores nombrados anteriormente son los responsables de que los vuelos lleguen tarde.

Compromiso ético y ciudadano (Jorge Pons - A01424108)

La integridad es un valor fundamental en cualquier disciplina profesional. Representa la honestidad, la coherencia y la congruencia entre lo que decimos, pensamos y hacemos. En el contexto de la ética profesional, la integridad implica actuar de manera íntegra, respetando los principios y valores que rigen nuestra profesión. Con esta actividad me comprometo a aplicar mis conocimientos, a esforzarme en su desarrollo y a no servirme de medios no autorizados o ilícitos para realizarla. Tener acceso a la información de una empresa conlleva responsabilidades éticas. Debemos utilizarla de manera íntegra, respetando la confidencialidad y evitando beneficios personales o daños a la organización. La integridad y el cumplimiento del código ético son esenciales para tomar decisiones informadas y proteger la privacidad de la información empresarial.

Compromiso ético y ciudadano (Rafaella Pérez - A00837142)

La integridad es un valor de suma importancia para la convivencia sana en una comunidad, ya que esta nos permite actuar con honestidad y coherencia en cada una de nuestras actividades(Naciones Unidad, 2024). Esta es un pilar fundamental para el desarrollo profesional y social, ya que primero te deja progresar en tu carrera al demostrar tus capacidades, sin necesidad de hacer trampa o hacer cosas indebidas. Y segundo, para el desarrollo social, ya que se crean relaciones interpersonales sólidas, donde predomina la confianza. (DPC, 2024). Uno de los mayores problemas a nivel mundial es la corrupción tanto en los gobiernos, como en las empresas, y esta es causado justamente por la falta de integridad, la cuál empieza desde acciones pequeñas del día a día, hasta grandes que llegan a afectar a millones de personas.

Enfocándonos en mi caso, mi código ético de disciplina se basa en pensar 2 veces antes de actuar. Muchas veces, las personas nos dejamos llevar por el mal camino, ya que buscamos la perfección o no creemos en las consecuencias que puede traer, pero esto va más allá de si nos descubren y tenemos una repercusión, pues se trata en que realmente el trabajo no refleja lo que sabemos o hacemos, pues fue hecho con el esfuerzo de otro(Preparatoria Panamericana, 2021). Una mis filosofías de trabajo, la cuál fue inculcada por mi mamá es: “Mejor una mala nota, pero propia, que una buena, pero ajena”, y la verdad es que años después sólo puedo decir lo mucho que estoy de acuerdo, prefiero aprender y demostrar lo que soy capaz o exigirme más para alcanzar mi mejor versión, que fingir ser alguien que no soy.

Hoy en día, es muy común tener acceso a ciertos datos de las empresas, debido al Internet. Por eso, uno debe de tener mucho cuidado, ya que en ciertos casos, como los retos que hacemos en el Tecnológico de Monterrey, la información es confidencial, siendo totalmente nuestra responsabilidad lo que pasa con esos datos. En caso de usarla incorrectamente, se puede tener hasta problemas legales, como demandas. Por otro lado, el que cierta información esté disponible en internet, permite tener cierta transparencia, al poder observar documentos como los estados financieros o proyectos que se están llevando a cabo, los cuáles son especialmente útiles, cuando somos inversiones o accionistas de una empresa.

Compromiso ético y ciudadano (Óscar Retes - A01383653)

La integridad, entendida como un valor esencial en cualquier ámbito profesional, adquiere un significado trascendente cuando se tienen en cuenta sus diversas facetas. Este principio es una piedra angular que engloba la honestidad, la coherencia y la congruencia en todas nuestras acciones, pensamientos y expresiones. En el contexto de la ética profesional, la integridad se manifiesta como un compromiso inquebrantable de actuar con integridad y defender los principios y valores que guían nuestro trabajo. Teniendo esto en cuenta, al abordar una tarea o proyecto, me comprometo a aplicar cuidadosamente mis conocimientos, dedicándome a su desarrollo y rechazando el uso de medios ilícitos o ilegales para realizar mis tareas.

El acceso a la información dentro de una empresa no es sólo un privilegio, sino también una gran responsabilidad ética. Este acceso conlleva una serie de tareas y responsabilidades que deben llevarse a cabo con la máxima integridad. Es importante hacer pleno uso de esta información, proteger cuidadosamente su confidencialidad y evitar cualquier intento de obtener ventaja personal o dañar a la organización. La integridad, por tanto, se manifiesta como un escudo protector que nos insta a adherir fielmente a un código ético que sirve como guía infalible para tomar decisiones informadas y mantener la confidencialidad de la información empresarial. En última instancia, es esta integridad y estricto cumplimiento de los principios éticos lo que nos permite navegar por el complejo panorama de la ética empresarial con confianza y respeto por nuestro trabajo y nuestro entorno social.

LS0tDQp0aXRsZTogIkV2aWRlbmNpYV9maW5hbF9lcTYiDQphdXRob3I6ICJSYWZhZWxsYSBQw6lyZXotIEEwMDgzNzE0MiAvIE9zY2FyIFJldGVzLSBBMDEzODM2NTMvIEpvcmdlIFBvbnMtIEEwMTQyNDEwOCINCmRhdGU6ICIyMDI0LTAzLTE1Ig0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KICAgIHRvY19mbG9hdDogdHJ1ZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUNCiAgICB0aGVtZTogY29zbW8NCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogdHJ1ZQ0KLS0tDQoNCiFbXShDOlxcVXNlcnNcXGptcG8yXFxEb3dubG9hZHNcXE1lbWUgdnVlbG9zLmpwZykNCg0KIyBbQ29udGV4dG9de3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpFbCBwYXF1ZXRlICoqbnljZmxpZ2h0czEzKiogY29udGllbmUgaW5mb3JtYWNpw7NuIHNvYnJlIHRvZG9zIGxvcyB2dWVsb3MgcXVlIHBhcnRpZXJvbiBkZXNkZSBOdWV2YSBZb3JrIChFV1IsIEpGSyB5IExHQSkgYSBkZXN0aW5vcyBlbiBsb3MgRXN0YWRvcyBVbmlkb3MgZW4gMjAxMy4NCg0KRnVlcm9uIDMzNiw3NzYgdnVlbG9zIGVuIHRvdGFsLiBQYXJhIGF5dWRhciBhIGNvbXByZW5kZXIgbGFzIGNhdXNhcyBkZSBsb3MgcmV0cmFzb3MsIHRhbWJpw6luIGluY2x1eWUgb3Ryb3MgY29uanVudG9zIGRlIGRhdG9zIMO6dGlsZXMuDQoNCkVzdGUgcGFxdWV0ZSBpbmNsdXllIGxhcyBzaWd1aWVudGVzIHRhYmxhczoNCg0KLSAgIGZsaWdodHMgPSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzYWxpZXJvbiBkZSBOdWV2YSBZb3JrIGVuIDIwMTNcDQotICAgd2VhdGhlciA9IGRhdG9zIG1ldGVvcm9sw7NnaWNvcyBwb3IgaG9yYSBkZSBjYWRhIGFlcm9wdWVydG9cDQotICAgcGxhbmVzID0gaW5mb3JtYWNpw7NuIGRlIGNvbnN0cnVjY2nDs24gZGUgY2FkYSBhdmnDs25cDQotICAgYWlycG9ydHMgPSBub21icmVzIHkgdWJpY2FjaW9uZXMgZGUgYWVyb3B1ZXJ0b3NcDQotICAgYWlybGluZXMgPSByZWxhY2nDs24gZW50cmUgbm9tYnJlcyB5IGPDs2RpZ29zIGRlIGxhcyBhZXJvbMOtbmVhcw0KDQpGdWVudGU6XA0KW09yaWdlbiBkZSBsb3MgZGF0b3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9ueWNmbGlnaHRzMTMvbnljZmxpZ2h0czEzLnBkZikNCg0KIyBbSW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hc117c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KIyBpbnN0YWxsLnBhY2thZ2VzKCJueWNmbGlnaHRzMTMiKQ0KbGlicmFyeShueWNmbGlnaHRzMTMpDQojIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmBgYA0KDQojIFtHdWFyZGFyIGJhc2VzIGRlIGRhdG9zXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQpmbGlnaHRzIDwtIGZsaWdodHMNCndlYXRoZXIgPC0gd2VhdGhlcg0KcGxhbmVzIDwtIHBsYW5lcyANCmFpcnBvcnRzIDwtIGFpcnBvcnRzDQphaXJsaW5lcyA8LSBhaXJsaW5lcyANCmBgYA0KDQojIFtSZWxhY2nDs24gZW50cmUgYmFzZXMgZGUgZGF0b3Nde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQohW10oL1VzZXJzL29zY2FyL0Rvd25sb2Fkcy9yZWxhdGlvbmFsLW55Y2ZsaWdodHMucG5nKQ0KDQojIFtBdmFuY2UgMV17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCiMjIFsxLiBDYXJnYXIgZW4gbWVtb3JpYSBsYSB0YWJsYSAiZmxpZ2h0cyIgeSBtb3N0cmFyIHN1IGNvbnRlbmlkb117c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KIyBMYSBjYXJnYSBhIG1lbW9yaWEgc2UgaGl6byBlbiBlbCBwYXNvIGFudGVyaW9yDQpmbGlnaHRzDQpgYGANCg0KIyMgWzIuIENvbnN1bHRhIGxhIGVzdHJ1Y3R1cmEgZGUgImZsaWdodHMiXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQpzdHIoZmxpZ2h0cykNCiMgaW50OiBlbnRlcm8gKHNpbiBkZWNpbWFsZXMpDQojIG51bTogbnVtw6lyaWNvIChjb24gZGVjaW1hbGVzKQ0KIyBjaHI6IGNhcmFjdMOpciAobGV0cmFzIG8gcGFsYWJyYXMpDQojIERhdGU6IEZlY2hhIChlbiBSIHZhIGHDsW8tbWVzLWRpYSkNCiMgUE9TSVhjdDogZm9ybWF0byBmZWNoYSAoZmVjaGEgeSBob3JhKQ0KYGBgDQoNCiMjIFszLiDCv0N1w6FsIGVzIGxhIGNsYXNlIGRlICJmbGlnaHRzIiB5IHF1w6kgc2lnbmlmaWNhP117c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KY2xhc3MoZmxpZ2h0cykNCiMgY2xhc3MoYSkNCg0KIyBMYXMgNSBjbGFzZXMgZGUgb2JqZXRvcyBzb246DQojIDEuIG51bWVyaWM6IG7Dum1lcm8gcmVhbCBvIGRlY2ltYWxlcw0KIyAyLiBJbnRlZ2VyOiBuw7ptZXJvcyBlbnRlcm9zDQojIDMuIENvbXBsZXg6IG7Dum1lcm9zIGNvbXBsZWpvcw0KIyA0LiBDaGFyYWN0ZXI6IGNhcmFjdMOpcmVzDQojIDUuIExvZ2ljYWw6IFRSVUUgbyBGQUxTRQ0KDQojIExhcyA0IGNsYXNlcyBkZSBvYmpldG9zIGNvbXB1ZXN0b3Mgc29uOg0KIyAxLiBsaXN0OiBsaXN0YQ0KIyAyLiBtYXRyaXg6IG1hdHJpeg0KIyAzLiBhcnJheTogY29sZWNjacOzbiBkZSBvYmpldG9zDQojIDQuIGRhdGEuZnJhbWU6IGJhc2UgZGUgZGF0b3MNCg0KYGBgDQoNCiMjIFs0LiDCv0N1w6FudGFzIGNvbHVtbmFzIHkgcmVuZ2xvbmVzIHRpZW5lICJmbGlnaHRzIj8gwr9DdcOhbCBlcyBzdSBkaW1lbnNpw7NuP117c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KIyBOw7ptZXJvIGRlIGNvbHVtbmFzDQpuY29sKGZsaWdodHMpDQojIE7Dum1lcm8gZGUgcmVuZ2xvbmVzDQpucm93KGZsaWdodHMpDQojIERpbWVuc2nDs24NCmRpbShmbGlnaHRzKQ0KYGBgDQoNCiMjIFs1LiBNdWVzdHJhIGxvcyBwcmltZXJvcyA2IHJlbmdsb25lcyBkZSAiZmxpZ2h0cyIuIFRhbWJpw6luIGxvcyDDumx0aW1vcyA2XXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQpoZWFkKGZsaWdodHMpDQp0YWlsKGZsaWdodHMpDQojIFNpIHF1aXNpZXJhbW9zIDcgcmVuZ2xvbmVzOiBoZWFkKGZsaWdodHMsNykNCmBgYA0KDQojIyBbNi4gTXVlc3RyYSBsb3MgZXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MgZGUgImZsaWdodHMiXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQpzdW1tYXJ5KGZsaWdodHMpDQpgYGANCg0KIyBbTWFuZWpvIGRlIERhdG9zXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KIyMgW1NlbGVjdF17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCkxhIGZ1bmNpw7NuICpzZWxlY3QqIHNpcnZlIHBhcmEgc2VsZWNjaW9uYXIgY29sdW1uYXMgZGUgdW5hIHRhYmxhICgqZGF0YSBmcmFtZSopLg0KDQpgYGB7cn0NCmRmMSA8LSBmbGlnaHRzICU+JSBzZWxlY3QoY2FycmllciwgZmxpZ2h0KSAjIFNlbGVjY2nDs24gZGUgY29sdW1uYXMgZXNwZWPDrWZpY2FzDQpkZjIgPC0gZmxpZ2h0cyAlPiUgc2VsZWN0KGNhcnJpZXI6ZGlzdGFuY2UpICMgU2VsZWNjacOzbiBkZSByYW5nbyBkZSBjb2x1bW5hcw0KZGYzIDwtIGZsaWdodHMgJT4lIHNlbGVjdCgtY2FycmllciwgLWZsaWdodCkgIyBFbGltaW5hciBjb2x1bW5hcyBlc3BlY8OtZmljYXMNCmRmNCA8LSBmbGlnaHRzICU+JSBzZWxlY3QoLWNhcnJpZXI6LWRpc3RhbmNlKSAjIEVsaW1pbmFyIHJhbmdvIGRlIGNvbHVtbmFzDQpkZjUgPC0gZmxpZ2h0cyAlPiUgc2VsZWN0KGFlcm9saW5lYSA9IGNhcnJpZXIpICMgU2VsZWNjaW9uYSB1bmEgY29sdW1uYSB5IGxlIGNhbWJpYSBlbCBub21icmUgDQpkZjYgPC0gZmxpZ2h0cyAlPiUgcmVuYW1lKGFlcm9saW5lYSA9IGNhcnJpZXIpICMgQ2FtYmlhciBub21icmUNCmBgYA0KDQojIyBbRmlsdGVyXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KTGEgZnVuY2nDs24gKmZpbHRlciogc2lydmUgcGFyYSBzZWxlY2Npb25hciByZW5nbG9uZXMgZGUgdW5hIHRhYmxhICgqZGF0YSBmcmFtZSopLg0KDQpgYGB7cn0NCmRmNyA8LSBmbGlnaHRzICU+JSBmaWx0ZXIoZGVwX2RlbGF5Pj01MDApICMgRXh0cmFlIHJlbmdsb25lcyBxdWUgY3VtcGxhbiBjb25kaWNpw7NuICANCiMgQ29uZGljaW9uYWxlczogSWd1YWwgPT0sIERlc2lndWFsID0hPSwgTWF5b3IgcXVlID4sIE1heW9yIG8gaWd1YWwgcXVlID49LCBNZW5vciBxdWUgPCwgTWVub3IgbyBpZ3VhbCBxdWUgPD0gIA0KIyBPcGVyYWRvcmVzIGzDs2dpY29zOiBBTkQgJiwgT1IgfCwgTk9UICEgIA0KZGY4IDwtIGZsaWdodHMgJT4lIGZpbHRlcihkZXBfZGVsYXk+PTUwMCwgZGVwX2RlbGF5PDYwMCkgIyBFeHRyYWUgcmVuZ2xvbmVzIHF1ZSBjdW1wbGFuIGNvbiBkb3MgY29uZGljaW9uZXMNCmRmOSA8LSBmbGlnaHRzICU+JSBzbGljZSgxMDAwOjEwOTkpICMgRXh0cmFlIGxvcyBuw7ptZXJvcyBkZSBsb3MgcmVuZ2xvbmVzIGluZGljYWRvcywgc2luIGltcG9ydGFyIHN1cyB2YWxvcmVzDQpgYGANCg0KIyMgW0Rpc3RpbmN0XXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KTGEgZnVuY2nDs24gKmRpc3RpbmN0KiBzaXJ2ZSBwYXJhIGVsaW1pbmFyIHJlbmdsb25lcyBkdXBsaWNhZG9zLg0KDQpgYGB7cn0NCmRmMTAgPC0gZGlzdGluY3QoZmxpZ2h0cykgIyBEZWphciBzb2xvIGxvcyByZW5nbG9uZXMgZGlmZXJlbnRlcywgYm9ycmEgdG9kb3MgbG9zIHJlcGV0aWRvcy4NCmBgYA0KDQojIyBbTWVyZ2Vde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpMYSBmdW5jacOzbiAqbWVyZ2UqIHNpcnZlIHBhcmEganVudGFyIGJhc2VzIGRlIGRhdG9zLg0KDQpgYGB7cn0NCmJkZ3JhbmRlIDwtIG1lcmdlKGZsaWdodHMsYWlybGluZXMsIGJ5PSJjYXJyaWVyIikNCmJkZ3JhbmRlMiA8LSBtZXJnZShiZGdyYW5kZSxwbGFuZXMsIGJ5PSJ0YWlsbnVtIikNCmBgYA0KDQojIyBbTXV0YXRlXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQpiZGdyYW5kZTMgPC0gbXV0YXRlKGJkZ3JhbmRlMiwgZGlzdF9tdHMgPSBkaXN0YW5jZSoxLjYwOSkNCiMgQWdyZWdhIHZhcmlhYmxlcyBudWV2YXMgY2FsY3VsYWRhcyBhIHBhcnRpciBkZSB2YXJpYWJsZXMgZXhpc3RlbnRlcyBlbiBsYSBiYXNlIGRlIGRhdG9zDQpgYGANCg0KIyMgW0VqZXJjaWNpb3Nde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpgYGB7cn0NCiMgMS4gRW5jdWVudHJhIHRvZG9zIGxvcyB2dWVsb3MgcXVlIHR1dmllcm9uIHVuIGF0cmFzbyBlbiBsbGVnYWRhIGRlIGRvcyBob3JhcyBvIG3DoXMNCmVqZXJjaWNpbzEgPC0gYmRncmFuZGUyICU+JSBmaWx0ZXIoYXJyX2RlbGF5Pj0xMjApDQoNCiMgMi4gRW5jdWVudHJhIHRvZG9zIGxvcyB2dWVsb3MgcXVlIGxsZWdhcm9uIGEgSG91c3RvbiAoSUFIIE8gSE9VKQ0KZWplcmNpY2lvMiA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihkZXN0ID09ICJJQUgiIHwgZGVzdCA9PSAiSE9VIikNCg0KIyAzLiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBvcGVyYWRvcyBwb3IgVW5pdGVkLCBBbWVyaWNhbiBvIERlbHRhDQplamVyY2ljaW8zIDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGNhcnJpZXIgPT0gIlVBIiB8IGNhcnJpZXIgPT0gIkFBIiB8IGNhcnJpZXIgPT0gIkRMIikNCg0KIyA0LiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgZGVzcGVnYXJvbiBlbiBKdWxpbywgQWdvc3RvIG8gU2VwdGllbWJyZS4NCmVqZXJjaWNpbzQgPC0gYmRncmFuZGUyICU+JSBmaWx0ZXIobW9udGggJWluJSBjICg3OjkpKQ0KDQojIDUuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBhcnJpdmFyb24gbcOhcyBkZSAyIGhvcmFzIHRhcmRlLCBwZXJvIG5vIGRlc3BlZ2Fyb24gdGFyZGUuDQplamVyY2ljaW81IDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGFycl9kZWxheT4xMjAgJiBkZXBfZGVsYXkgPD0gMCkNCiAgDQojIDYuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzZSByZXRyYXNhcm9uIGFsIG1lbm9zIDEgaG9yYSwgcGVybyBxdWUgbGxlZ2Fyb24gYW50ZXMgMzAgbWludXRvcyBvIG3DoXMuDQplamVyY2ljaW82IDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGRlcF9kZWxheT49NjAgJiBhcnJfZGVsYXk8PSAtMzApDQoNCiMgNy4gRW5jdWVudHJhIHRvZG9zIGxvcyB2dWVsb3MgcXVlIHNhbGllcm9uIGVudHJlIGxhIG1lZGlhbm9jaGUgeSBsYXMgNiBhLm0uIA0KZWplcmNpY2lvNyA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihkZXBfdGltZT09MjQwMCB8IGRlcF90aW1lPD02MDApDQpgYGANCg0KIyMgW0FycmFuZ2Vde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpTaW1pbGFyIGEgZmlsdGVyKCkgcGVybyBlbiBsdWdhciBkZSBzZWxlY2Npb25hciByZW5nbG9uZXMsIGxvcyBvcmRlbmEgZGUgbWVub3IgYSBtYXlvci4NCg0KYGBge3J9DQpkZjExIDwtIGFycmFuZ2UoYmRncmFuZGUyLHllYXIueCxtb250aCxkYXkpDQpgYGANCg0KIyMgW1N1bW1hcml6ZV17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCkNvbGFwc2EgdW5hIHRhYmxhIGEgdW4gc8OzbG8gcmVuZ2zDs24uDQoNCmBgYHtyfQ0KIyBPYnTDqW4gZWwgcmV0cmFzbyBwcm9tZWRpbyBkZSBkZXNwZWd1ZSBkZSB0b2RvcyBsb3MgdnVlbG9zIA0Kc3VtbWFyaXplKGJkZ3JhbmRlMiwgbWVhbihkZXBfZGVsYXksIG5hLnJtPVRSVUUpKQ0KYGBgDQoNCiMjIFtHcm91cCBieV17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCkFncnVwYSB0YWJsYSBiYXNhZG8gZW4gYWxndW5hcyBjb2x1bW5hcy4NCg0KYGBge3J9DQojIE9idGVuZXIgZWwgcmV0cmFzbyBwcm9tZWRpbyBkZSBkZXNwZWd1ZSBwb3IgZMOtYQ0KcG9yX2RpYSA8LSBncm91cF9ieShiZGdyYW5kZTIsIHllYXIueCwgbW9udGgsIGRheSkNCnN1bW1hcml6ZShwb3JfZGlhLCBtZWFuKGRlcF9kZWxheSwgbmEucm09VFJVRSkpDQpgYGANCg0KIyBbQXZhbmNlIDJde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpTZSBub3MgaGEgc29saWNpdGFkbyBjb25zdWx0YXIgY3XDoWxlcyBzb24gbGFzIGFlcm9sw61uZWFzIGRlIG1heW9yIHRyw6FmaWNvIGHDqXJlbyBlbiBvcmlnZW4geSBkZXN0aW5vLg0KDQojIyBbMS4gQWVyb2zDrW5lYXMgZGUgbWF5b3IgdHLDoWZpY28iXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQojIEhhY2Vtb3Mgc3VtbWFyeSBkZSBmbGlnaHRzIHBhcmEgdmVyIHRvZGFzIGxhcyBjb2x1bW5hcyBjb24gbGFzIHF1ZSBjdWVudGEgbGEgYmFzZSBkZSBkYXRvcw0Kc3VtbWFyeShmbGlnaHRzKQ0KDQojIEluc3RydWNjaW9uZXM6IGRlZmluZSB1biBjcml0ZXJpbyBwYXJhIGVuY29udHJhciBsYXMgYWVyb2zDrW5lYXMgcXVlIGhhbiByZWNvcnJpZG8gbcOhcyBkaXN0YW5jaWEgKGVuIG1pbGxhcykgeSBjcmVhIHVuIG51ZXZvIGRhdGEgZnJhbWUgcXVlIGZpbHRyZSBzb2xhbWVudGUgYSBsYXMgYWVvcmzDrW5lYXMgcXVlIGhhbiByZWNvcnJpZGFvIHVuYSBkaXN0YW5jaWEgc3VwZXJpb3IgYSBsYSBtZWRpYSwgc2UgZGVzZWEgdmVyIGxvcyBjYW1wb3MgY2FycmllciwgZGlzdGFuY2UsIG9yaWdpbiwgZGVzdCBlbiBmb3JtYSBkZXNjZW5kZW50ZSBwb3IgZGlzdGFuY2UuIEVqZW1wbG86IGFlcm9sw61uZWFzIGNvbiBtaWxsYXMgcmVjb3JyaWRhcyBzdXBlcmlvcmVzIGEgbGEgbWVkaWEsIG9yZGVuYWRhcyBlbiBmb3JtYSBkZXNjZW5kZW50ZS4NCg0KZGYyIDwtIGZsaWdodHMgJT4lIHNlbGVjdChjYXJyaWVyLCBkaXN0YW5jZSwgb3JpZ2luLCBkZXN0KSANCmRmMyA8LSBkZjIgJT4lIGZpbHRlcihkaXN0YW5jZSA+IDEwNDApDQpkZjMNCg0KZGY0IDwtIGRmMyAlPiUgYXJyYW5nZShkZXNjKGRpc3RhbmNlKSkNCmRmNA0KDQpkZjUgPC0gZGY0ICU+JSBncm91cF9ieShjYXJyaWVyLG9yaWdpbixkZXN0KSAlPiUgIHN1bW1hcml6ZShzdW1kaXN0YW5jZT1zdW0oZGlzdGFuY2UsIG5hLnJtPVRSVUUpLCBtZWFuZGlzdGFuY2U9bWVhbihkaXN0YW5jZSwgbmEucm09VFJVRSkpIA0KZGY1DQpgYGANCg0KIyMgWzIuIEFlcm9sw61uZWFzIGRlIG1heW9yIHRyw6FmaWNvIl17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KZGY1IDwtIGRmNCAlPiUgZ3JvdXBfYnkoY2FycmllcixvcmlnaW4sZGVzdCkgJT4lICBzdW1tYXJpemUoc3VtZGlzdGFuY2U9c3VtKGRpc3RhbmNlLCBuYS5ybT1UUlVFKSwgbWVhbmRpc3RhbmNlPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVRSVUUpKSANCmRmNQ0KDQpkZjYgPC0gYXJyYW5nZShkZjUsY2FycmllcixzdW1kaXN0YW5jZSkNCg0KSkZLID0gZGY2ICU+JSBmaWx0ZXIob3JpZ2luID09ICJKRksiKSAlPiUgYXJyYW5nZShjYXJyaWVyLCBkZXNjKHN1bWRpc3RhbmNlKSkNCkxHQSA9IGRmNiAlPiUgZmlsdGVyKG9yaWdpbiA9PSAiTEdBIikgJT4lIGFycmFuZ2UoY2FycmllciwgZGVzYyhzdW1kaXN0YW5jZSkpDQpFV1IgPSBkZjYgJT4lIGZpbHRlcihvcmlnaW4gPT0gIkVXUiIpICU+JSBhcnJhbmdlKGNhcnJpZXIsIGRlc2Moc3VtZGlzdGFuY2UpKQ0KYGBgDQoNCg0KIyBbQXZhbmNlIDNde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQojIyBbMS4gQ29uc3VsdGEgbGFzIHRhYmxhcyBwbGFuZXMgeSB3ZWF0aGVyIHBhcmEgcXVlIGNvbm96Y2FzIHN1IGNvbnRlbmlkby5de3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpgYGB7cn0NCnZpZXcocGxhbmVzKQ0Kdmlldyh3ZWF0aGVyKQ0KYGBgDQoNCiMjIFsyLiBTZSBuZWNlc2l0YSBzYWJlciBkZSBjYWRhIHZ1ZWxvLCBsYSBhZXJvbGluZWEsIGVsIGFlcm9wdWVydG8gZGUgb3JpZ2VuIHkgZWwgYWVyb3B1ZXJ0byBkZXN0aW5vLl17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KYWVyb2xpbmVhcyA8LSBmbGlnaHRzICU+JSANCiAgc2VsZWN0KGNhcnJpZXIsb3JpZ2luLGRlc3QpDQpgYGANCg0KIyMgWzMuIEVuIGxhIGNvbnN1bHRhIGFudGVyaW9yIHNlIG5lY2VzaXRhIGNvbm9jZXIgZWwgbm9tYnJlIGRlIGxhIGFlcm9sw61uZWEuXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQphZXJvbGluZWFzX25vbWJyZSA8LSBhZXJvbGluZWFzICU+JQ0KICBsZWZ0X2pvaW4oYWlybGluZXMsIGJ5ID0gImNhcnJpZXIiKQ0KYGBgDQoNCiMjIFs0LiBTZSBuZWNlc2l0YSBzYWJlciBsYSBjYW50aWRhZCBkZSB2dWVsb3MgcG9yIGNhZGEgZGVzdGlubyBwYXJhIGlkZW50aWZpY2FyIGN1w6FsZXMgc29uIGxvcyBkZXN0aW5vcyBtw6FzIGJ1c2NhZG9zLl17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KY2FudF92dWVsb3MgPC0gZmxpZ2h0cyAlPiUgDQogIHNlbGVjdChjYXJyaWVyLCBkZXN0KSAlPiUgDQogIGNvdW50KGNhcnJpZXIpDQogIA0KYGBgDQoNCiMjIFs1LiBBZ3JlZ2FyIGVsIG5vbWJyZSBkZSBsYSBhZXJvbMOtbmVhIGEgbGEgdGFibGEgYW50ZXJpb3IuXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQpjYW50X3Z1ZWxvc19ub21icmUgPC0gY2FudF92dWVsb3MgJT4lDQogIGxlZnRfam9pbihhaXJsaW5lcywgYnkgPSAiY2FycmllciIpDQpgYGANCg0KIyMgWzYuIFNlIG5lY2VzaXRhIGNvbm9jZXIgbGFzIGFlcm9sw61uZWFzIChjbGF2ZSB5IG5vbWJyZSkgeSBkZXN0aW5vcyBxdWUgdnVlbGFuIHBvciBsYSBNYcOxYW5hOiBkZSA2IGEgMTIsIFRhcmRlOiBkZSAxMiBhIDE5ICwgTm9jaGU6IGRlIDE5IGEgMjQgeSBNYWRydWdhZGEgZGUgMjQgYSA2Ll17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCiMjIyBbQWdyZWdhIHVuIG51ZXZvIGNhbXBvIGEgbGEgdGFibGEgY29uIGVsIG5vbWJyZSBkZSBjbGFzX2hvcmFyaW8geSBhZ3JlZ2EsIG1hw7FhbmEsIHRhcmRlLCBub2NoZSB5IG1hZHJ1Z2FkYSBzZWfDum4gc2VhIGVsIGNhc28uXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KYGBge3J9DQpjYXJyaWVyX2hvcmFyaW8gPC0gZmxpZ2h0cyAlPiUNCnNlbGVjdChjYXJyaWVyLCBkZXN0LCBzY2hlZF9kZXBfdGltZSkgJT4lDQogIGxlZnRfam9pbihhaXJsaW5lcywgYnkgPSAiY2FycmllciIpDQoNCmNsYXN4aG9yYTwtIG11dGF0ZShjYXJyaWVyX2hvcmFyaW8sIGNsYXNfaG9yYXJpbyA9IGlmZWxzZShzY2hlZF9kZXBfdGltZSAlaW4lIDYwMDoxMTU5LCJNYcOxYW5hIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNjaGVkX2RlcF90aW1lICVpbiUgMTIwMDoxODU5LCJUYXJkZSIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmZWxzZShzY2hlZF9kZXBfdGltZSAlaW4lIDE5MDA6MjQwMCwiTm9jaGUiLCAiTWFkcnVnYWRhIikpKSkNCmBgYA0KDQojIyBbNy5TZSBuZWNlc2l0YSBzYWJlciBsYSBjYW50aWRhZCBkZSB2dWVsb3MgcG9yIGFlcm9sw61uZWEgeSBkZXN0aW5vIHF1ZSBoYXkgcG9yIGxhIE1hw7FhbmEsIFRhcmRlLCBOb2NoZSB5IE1hZHJ1Z2FkYS5de3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpgYGB7cn0NCmNhbnRfY2xhc3hob3JhIDwtIGNsYXN4aG9yYSAlPiUgDQogICAgICAgICAgICAgZ3JvdXBfYnkoY2FycmllciwgZGVzdCxjbGFzX2hvcmFyaW8pICU+JSBjb3VudCgpDQoNCmBgYA0KDQojIyBbOCBTZSBuZWNlc2l0YSBzYWJlciBhIHF1w6kgZGVzdGlub3MgdnVlbGEgbGEgYWVyb2zDrW5lYSBBbWVyaWNhbiBBaXJsaW5lcyBJbmMuLUFBIGR1cmFudGUgbGEgbWFkcnVnYWRhLl17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KZGVzdGlub3NfYWEgPC0gY2xhc3hob3JhICU+JSANCiAgc2VsZWN0KGNhcnJpZXIsbmFtZSwgZGVzdCxjbGFzX2hvcmFyaW8pICU+JSANCiAgZmlsdGVyKGNhcnJpZXIgPT0gIkFBIiAmIGNsYXNfaG9yYXJpbyA9PSAiTWFkcnVnYWRhIikgJT4lIA0KICBncm91cF9ieShjYXJyaWVyLG5hbWUsIGRlc3QsY2xhc19ob3JhcmlvKQ0KYGBgDQoNCiMjIFs5LiDCv1F1w6kgYXZpb25lcyB1dGlsaXphIGxhIGFlcm9sw61uZWEgQUE/IGFlcm9sw61uZWEsIHRpcG8sIG1vdG9yIHkgbsO6bWVybyBkZSBhc2llbnRvcyB5IMK/Q3XDoW50b3MgdnVlbG9zIHNlIGhhbiByZWFsaXphZG8gY29uIGNhZGEgdW5vPyBlbGltaW5hIGxvcyBOQSdzLl17c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNCmBgYHtyfQ0KYXZpb25fYWEgPC0gZmxpZ2h0cyAlPiUNCiAgbGVmdF9qb2luKHBsYW5lcywgYnkgPSAidGFpbG51bSIpICU+JQ0KICBzZWxlY3QoY2FycmllciwgdHlwZSwgZW5naW5lLCBzZWF0cykgJT4lDQogIGZpbHRlcihjYXJyaWVyID09ICJBQSIsICFpcy5uYSh0eXBlKSkgJT4lDQogIGdyb3VwX2J5KGNhcnJpZXIsdHlwZSxlbmdpbmUsc2VhdHMpICU+JSANCiAgY291bnQoKQ0KIA0KDQpgYGANCiAgDQpFbiBsYSBldmlkZW5jaWEgc2UgcHJlc2VudMOzIGxhIG5lY2VzaWRhZCBkZSBtZWpvcmFyIGxhIHBvc2ljacOzbiBjb21wZXRpdGl2YSBkZSB1bmEgZGUgbGFzDQphZXJvbMOtbmVhcyBsw61kZXJlcyBlbiBsb3MgYWVyb3B1ZXJ0b3MgZGUgTnVldmEgWW9yaywgQW1lcmljYW4gQWlybGluZXMsIHBvciBsbyBxdWUgYSBjb250aW51YWNpw7NuIHNlIHByZXNlbnRhcsOhbiBkYXRvcyB5IGxhIGV4cGxpY2FjacOzbiBkZSBwb3JxdcOpIGxhIGFlcm9sw61uZWEgbG9zIGRlYmUgZGUgdG9tYXIgZW4gY3VlbnRhIHBhcmEgcG9zaWNpb25hcnNlIGNvbW8gbMOtZGVyLg0KQW50ZXJpb3JtZW50ZSBzZSBub21icsOzIHF1ZSBOZXdhcmsgTGliZXJ0eSBJbnRlcm5hdGlvbmFsIEFpcnBvcnQgZXMgbGEgc2VkZSBkZSBVbml0ZWQgQWlyIExpbmVzLCBwb3IgbG8gcXVlIHN1ZW5hIGzDs2dpY28gcXVlIHNlYSBsYSBhZXJvbMOtbmVhIGNvbiBtYXlvciBjYW50aWRhZCBkZSB2dWVsb3MgZW4gTmV3IFlvcmsgY29uIDU4LDY2NSwgbWllbnRyYXMgcXVlIEFtZXJpY2FuIEFpcmxpbmVzIHPDs2xvIGN1ZW50YSBjb24gMzIsNzI5LCBlcyBkZWNpciB1biA0NCUgbWVub3MsIHRlbmllbmRvIHVuYSBtZW5vciBvcG9ydHVuaWRhZCBkZSBvZnJlY2VyIG3DoXMgdmFyaWVkYWQgZGUgdnVlbG9zIHkgY29uc2VjdWVudGVtZW50ZSBwZXJkaWVuZG8gY3VvdGEgZGUgbWVyY2Fkby4gQWRlbcOhcywgZHVyYW50ZSBsYSBub2NoZSBBbWVyaWNhbiBBaXJsaW5lcyBvZnJlY2UgbWVub3MgZGUgbGEg4oWVIGRlIGxvcyB2dWVsb3MgcXVlIG9mcmVjZSBlbiBsYSBtYWRydWdhZGEgbyB0YXJkZSwgcG9yIGxvIHF1ZSBzZSBwdWVkZSBwZXJkZXIgdW4gc2VnbWVudG8gZGUgbWVyY2FkbywgY29tbyBsYXMgZW1wcmVzYXMsIGxhcyBjdcOhbGVzIG11Y2hhcyB2ZWNlcyBtYW5kYW4gZWplY3V0aXZvcyBhIHZpYWplcyBkZSB1biBkw61hLCByZWdyZXNhbmRvIGVuIGxhIG5vY2hlIGEgc3UgY2FzYS4gDQoNCg0KQWRpY2lvbmFsbWVudGUsIGxhIG1heW9yw61hIGRlIGxvcyB2dWVsb3MgZGUgbGEgbWFkcnVnYWRhIGRlIEFtZXJpY2FuIEFpcmxpbmVzIHNvbiBhIE1pYW1pLCBwb3IgbG8gcXVlIHRpZW5lbiB1bmEgb2ZlcnRhIG11eSBsaW1pdGFkYSB5IHN1cyBhdmlvbmVzIHRpZW5lbiBtw6F4aW1vIDMzMCBhc2llbnRvcywgYSBjb21wYXJhY2nDs24gZGUgb3RyYXMgYWVyb2zDrW5lYXMsIGNvbW8gRGVsdGEgQWlyIExpbmVzLCBsYSBjdcOhbCBjdWVudGEgY29uIGF2aW9uZXMgZGUgaGFzdGEgNDUwIGFzaWVudG9zLCBwdWRpZW5kbyB0cmFuc3BvcnRhciBhIHVuIDM2JSBtw6FzIGRlIHBhc2FqZXJvcy4gRmluYWxtZW50ZSxsb3MgYXZpb25lcyBkZSB0aXBvIOKAnEZpeGVkIHdpbmQgbXVsdGkgZW5naW5l4oCdIHkgbW90b3Ig4oCcVHVyYm8tZmFu4oCdIHNvbiBwb3IgbXVjaG8gbG9zIGF2aW9uZXMgZGUgQW1lcmljYW4gQWlybGluZXMgcXVlIG3DoXMgdnVlbG9zIHkgYXNpZW50b3MgdGllbmVuLCBwdWRpZW5kbyBkZWNpciBxdWUgc29uIG3DoXMgZWZpY2llbnRlcy4gDQpMYSBzdW1hIGRlIHRvZG9zIGVzdG9zIGZhY3RvcmVzLCBzb24gbG9zIGNhdXNhbnRlcyBkZSBxdWUgbGEgYWVyb2zDrW5lYSBubyBzZWEgbGEgbMOtZGVyLCBwZXJvIHNpIG9wdGEgcG9yIGhhY2VyIGNhbWJpb3MgY29tbyBpbXBsZW1lbnRhciBtw6FzIHZ1ZWxvcyBlbiBsYSBub2NoZSwgY29tcHJhciBhdmlvbmVzIGNvbiBtw6FzIGNhbnRpZGFkIGRlIGFzaWVudG9zLCBhdW1lbnRhciBsb3MgZGVzdGlub3MgeSBtYW50ZW5lciBzdSBhdHJhc28gcHJvbWVkaW8sIGVsIGN1w6FsIGVzIHVubyBkZSBsbyBtZW5vcmVzIGNvbiA4LDU5IG1pbnV0b3MsIGxhIGVtcHJlc2EgcHVlZGUgbWVqb3JhciBlbiBncmFuIG1lZGlkYSBzdSBwb3NpY2lvbmFtaWVudG8gZW4gbGEgaW5kdXN0cmlhLg0KDQojIFtIYWxsYXpnb3MgeSBjb25jbHVzaW9uZXNde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQojIyBbwr9RdcOpIGluZmx1eWUgZW4gZWwgcmV0cmFzbyBkZSBsb3MgdnVlbG9zP117c3R5bGU9ImNvbG9yOiBibHVlOyJ9DQoNClBhcmEgcmVzcG9uZGVyIGEgbGEgcHJlZ3VudGEgYW50ZXJpb3IsIHNlIGhpY2llcm9uIHVuYSBzZXJpZSBkZSBtb2RlbG9zIGRlIHJlZ3Jlc2nDs24geSBiYXNlcyBkZSBkYXRvcywgcGFyYSBwb2RlciBsbGVnYXIgYSB1bmEgbyBtw6FzIHJlc3B1ZXN0YXMgY29uY2lzYXMuDQoNCiMjIFtSZXRyYXNvIHBvciBhZXJvbMOtbmVhXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KTm9zIHBlcm1pdGUgaWRlbnRpZmljYXIgcXXDqSBhZXJvbMOtbmVhIHRpZW5lIG3DoXMgcmV0cmFzb3MgZGUgc2FsaWRhLCBsbyBxdWUgc2UgcHVlZGUgYXNvY2lhciBjb24gcG9jYSBjb211bmljYWNpw7NuIGRlbnRybyBkZSBsYXMgb3BlcmFjaW9uZXMuDQoNCmBgYHtyfQ0KdnVlbG9zX3Bvcl9hZXJvbGluZWEgPC0gZmxpZ2h0cyAlPiUgZ3JvdXBfYnkoY2FycmllcikgJT4lIHN1bW1hcml6ZShhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCnZ1ZWxvc19wb3JfYWVyb2xpbmVhDQoNCmFlcm9saW5lYXNkZWxheSA8LSB2dWVsb3NfcG9yX2Flcm9saW5lYVt2dWVsb3NfcG9yX2Flcm9saW5lYSRhdmdfZGVsYXkgPiAxNSwgXQ0KYWVyb2xpbmVhc2RlbGF5DQpgYGANCg0KQ29tbyBzZSBwdWVkZSBhcHJlY2lhciwgbGFzIGFlcm9sw61uZWFzIHF1ZSB0cmFlbiBsb3MgdnVlbG9zIGNvbiByZXRyYXNvcyBtw6FzIHBlc2Fkb3Mgc29uIEVuZGVhdm9yIEFpciBJbmMsIEV4cHJlc3NKZXQgQWlybGluZXMgSW5jLCBGcm9udGllciBBaXJsaW5lcyBJbmMsIEFpclRyYW4gQWlyd2F5cyBDb3Jwb3JhdGlvbiwgU291dGh3ZXN0IEFpcmxpbmVzIENvIHkgTWVzYSBBaXJsaW5lcyBJbmMuDQoNCiMjIFtSZXRyYXNvIHBvciBhZXJvcHVlcnRvXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KTm9zIHBlcm1pdGUgaWRlbnRpZmljYXIgZW4gcXXDqSBhZXJvcHVlcnRvIGxvcyB2dWVsb3Mgc3VlbGVuIHNhbGlyIG3DoXMgdGFyZGUsIGxvIHF1ZSBub3MgcHVlZGUgZGVjaXIgcXXDqSBhZXJvcHVlcnRvIGVzIGVsIHF1ZSB0aWVuZSBtw6FzIHRyw6FmaWNvLg0KDQpgYGB7cn0NCnZ1ZWxvc19wb3JfYWVyb3B1ZXJ0byA8LSBmbGlnaHRzICU+JSBncm91cF9ieShvcmlnaW4pICU+JSBzdW1tYXJpemUoYXZnX2RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpDQp2dWVsb3NfcG9yX2Flcm9wdWVydG8NCg0KZ2dwbG90KHZ1ZWxvc19wb3JfYWVyb3B1ZXJ0bywgYWVzKHggPSBvcmlnaW4sIHkgPSBhdmdfZGVsYXkpKSArIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArIGxhYnModGl0bGUgPSAiUmV0cmFzbyBQcm9tZWRpbyBwb3IgQWVyb3B1ZXJ0byBkZSBPcmlnZW4iLCB4ID0gIkFlcm9wdWVydG8gZGUgT3JpZ2VuIiwgeSA9ICJSZXRyYXNvIFByb21lZGlvIChtaW51dG9zKSIpICsgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KIyMgW1JldHJhc28gcG9yIGhvcmFde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpOb3MgcGVybWl0ZSBpZGVudGlmaWNhciBhIHF1w6kgaG9yYSBzZSBzdWVsZW4gZGFyIGxvcyByZXRyYXNvcyBtw6FzIHBlc2Fkb3MuDQoNCmBgYHtyfQ0KdnVlbG9zX3Bvcl9ob3JhIDwtIGZsaWdodHMgJT4lIG11dGF0ZShob3VyID0gaG91cih0aW1lX2hvdXIpKSAlPiUgZ3JvdXBfYnkoaG91cikgJT4lIHN1bW1hcml6ZShhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkNCnZ1ZWxvc19wb3JfaG9yYQ0KDQpob3Jhc21hc3RyYWZpYyA8LSB2dWVsb3NfcG9yX2hvcmFbMTM6MTksIF0NCmhvcmFzbWFzdHJhZmljDQoNCmdncGxvdCh2dWVsb3NfcG9yX2hvcmEsIGFlcyh4ID0gaG91ciwgeSA9IGF2Z19kZWxheSkpICsgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAic2t5Ymx1ZSIpICsgbGFicyh0aXRsZSA9ICJSZXRyYXNvIFByb21lZGlvIHBvciBIb3JhIGRlbCBEw61hIiwgeCA9ICJIb3JhIGRlbCBEw61hIiwgeSA9ICJSZXRyYXNvIFByb21lZGlvIChtaW51dG9zKSIpICsgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KQ29tbyBzZSBwdWVkZSBhcHJlY2lhciwgbGFzIGhvcmFzIGVuIGxhcyBxdWUgbG9zIHZ1ZWxvcyBwcmVzZW50YW4gcmV0cmFzb3MgcGFyYSBkZXNwZWdhciBtw6FzIHBlc2Fkb3Mgc29uIGRlIDQgYSAxMCwgY29uIHVuIHJldHJhc28gcHJvbWVkaW8gZGUgMjIgbWludXRvcy4NCg0KIyMgW1JldHJhc29zIHkgY29uZGljaW9uZXMgZGVsIGNsaW1hXXtzdHlsZT0iY29sb3I6IGJsdWU7In0NCg0KRXN0ZSBjw7NkaWdvIG5vcyBwZXJtaXRlIGNyZWFyIHVuYSBkYXRhZnJhbWUgbnVldmEgdXNhbmRvIGZsaWdodHMgeSB3ZWF0aGVyLCB1c2FuZG8gY29tbyBjb2x1bW5hcyBjbGF2ZSBlbCBhw7FvLCBlbCBtZXMsIGVsIGTDrWEsIGxhIGhvcmEgeSBlbCBvcmlnZW4uIEVzIHVuYSBtYW5lcmEgZGUgY3JlYXIgdW5hIGRhdGFmcmFtZSBsYSBjdWFsIG5vcyBwZXJtaXRlIHV0aWxpemFyIGxvcyBkYXRvcyBkZW50cm8gZGUgd2VhdGhlciwgbG9zIGN1YWxlcyBjcmVlbW9zIHF1ZSBwb2Ryw61hIHRlbmVyIHVuIGltcGFjdG8gZW4gZWwgcmV0cmFzbyBkZSBsb3MgdnVlbG9zLg0KDQpgYGB7cn0NCnZ1ZWxvc19jbGltYSA8LSBmbGlnaHRzICU+JSBsZWZ0X2pvaW4od2VhdGhlciwgYnkgPSBjKCJ5ZWFyIiwgIm1vbnRoIiwgImRheSIsICJob3VyIiwgIm9yaWdpbiIpKQ0KcmVncmVzaW9uY2xpbWEgPC0gbG0oZGVwX2RlbGF5IH4gdGVtcCArIHdpbmRfc3BlZWQgKyB3aW5kX2d1c3QgKyBwcmVjaXAgKyB2aXNpYiArIHByZXNzdXJlICsgZGV3cCArIGh1bWlkLCBkYXRhID0gdnVlbG9zX2NsaW1hKQ0Kc3VtbWFyeShyZWdyZXNpb25jbGltYSkNCg0KZ2dwbG90KHZ1ZWxvc19jbGltYSwgYWVzKHggPSB0ZW1wLCB5ID0gZGVwX2RlbGF5KSkgKyBnZW9tX3BvaW50KGNvbG9yID0gImJsdWUiLCBhbHBoYSA9IDAuNSkgKyBsYWJzKHRpdGxlID0gIlJlbGFjacOzbiBlbnRyZSBSZXRyYXNvIGRlIFZ1ZWxvIHkgVGVtcGVyYXR1cmEiLCB4ID0gIlRlbXBlcmF0dXJhICjCsEMpIiwgeSA9ICJSZXRyYXNvIGRlIFZ1ZWxvIChtaW51dG9zKSIpICsgdGhlbWVfbWluaW1hbCgpDQpgYGANCg0KUGFyYSBudWVzdHJvIGhhbGxhemdvLCBjdWVzdGlvbmVzIGNsaW1hdG9sw7NnaWNhcyBubyB0aWVuZW4gdW4gaW1wYWN0byBzaWduaWZpY2F0aXZvIGVuIGVsIHJldHJhc28gY29uIGVsIHF1ZSBkZXNwZWdhbiBsb3MgdnVlbG9zLCB5YSBxdWUgYmFzw6FuZG9ub3MgZW4gZWwgbW9kZWxvIGRlIHJlZ3Jlc2nDs24gbGluZWFsIGFudGVyaW9ybWVudGUgbW9zdHJhZG8sIGxhIFIgY3VhZHJhZGEgZXMgZGUgMC4wMg0KDQojIyBbUmV0cmFzbyBwb3IgZMOtYSBkZSBsYSBzZW1hbmFde3N0eWxlPSJjb2xvcjogYmx1ZTsifQ0KDQpDYWxjdWxhciBlbCByZXRyYXNvIHBvciBkw61hIGRlIGxhIHNlbWFuYSBub3MgZGFyw6EgdW5hIHBlcnNwZWN0aXZhIGVuIGN1w6FsZXMgc29uIGxvcyBkw61hcyBtw6FzIG9jdXBhZG9zIGVuIGN1ZXN0acOzbiBkZSB2dWVsb3MgZGUgbGEgc2VtYW5hLg0KDQpgYGB7cn0NCiMgRmlsdHJhciBsb3MgdnVlbG9zIGNvbiBkYXRvcyBjb21wbGV0b3MgKHNpbiB2YWxvcmVzIGZhbHRhbnRlcykNCmZsaWdodHNfY2xlYW4gPC0gZmxpZ2h0cyAlPiUgZmlsdGVyKCFpcy5uYShkZXBfZGVsYXkpKQ0KDQojIENhbGN1bGFyIGVsIHJldHJhc28gcHJvbWVkaW8gcG9yIGTDrWEgZGUgbGEgc2VtYW5hDQpyZXRyYXNvX3Byb21lZGlvX3Bvcl9kaWEgPC0gZmxpZ2h0c19jbGVhbiAlPiUgZ3JvdXBfYnkoZGF5X29mX3dlZWsgPSB3ZWVrZGF5cyh0aW1lX2hvdXIpKSAlPiUgc3VtbWFyaXplKGF2Z19kZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKQ0KcmV0cmFzb19wcm9tZWRpb19wb3JfZGlhDQoNCmdncGxvdChyZXRyYXNvX3Byb21lZGlvX3Bvcl9kaWEsIGFlcyh4ID0gZGF5X29mX3dlZWssIHkgPSBhdmdfZGVsYXkpKSArIGdlb21fbGluZShjb2xvciA9ICJibHVlIiwgc2l6ZSA9IDEpICsgZ2VvbV9wb2ludChjb2xvciA9ICJyZWQiLCBzaXplID0gMykgKyBsYWJzKHRpdGxlID0gIlJldHJhc28gUHJvbWVkaW8gcG9yIETDrWEgZGUgbGEgU2VtYW5hIiwgeCA9ICJEw61hIGRlIGxhIFNlbWFuYSIsIHkgPSAiUmV0cmFzbyBQcm9tZWRpbyAobWludXRvcykiKSArIHRoZW1lX21pbmltYWwoKQ0KDQpgYGANCg0KQ29tbyBzZSBwdWVkZSBhcHJlY2lhciwgbG9zIGTDrWFzIG3DoXMgb2N1cGFkb3Mgc2Vyw61hbiBsdW5lcywganVldmVzIHkgdmllcm5lcywgZWwgZMOtYSBtZW5vcyBvY3VwYWRvIHNlcsOtYSBlbCBzYWJhZG8uDQoNCiMjIDxzcGFuIHN0eWxlID0gImNvbG9yOiBibHVlOyI+IENvbmNsdXNpw7NuPC9zcGFuPg0KDQpFbiBjb25jbHVzacOzbiwgYWwgb2JzZXJ2YXIgbG9zIGRhdGEgZnJhbWVzIGRlIHZ1ZWxvcyB5IGNsaW1hIHB1ZGltb3MgaWRlbnRpZmljYXIgZGlzdGludG9zIGZhY3RvcmVzIHF1ZSBpbmZsdXllbiBlbiBxdWUgbG9zIHZ1ZWxvcyBsbGVndWVuIHRhcmRlLiBFc3RvcyBmYWN0b3JlcyBzb24gbGEgaG9yYSBhIGxhIHF1ZSBlc3RvcyBzYWxlbiwgbGEgZGlzdGFuY2lhIHF1ZSB0aWVuZW4gcXVlIHJlY29ycmVyLCB5IGxhcyBhZXJvbMOtbmVhcy4NCg0KQW50ZXMgZGUgZW1wZXphciBlbCBjw7NkaWdvLCBub3NvdHJvcyBjcmXDrWFtb3MgcXVlIGVsIHByaW5jaXBhbCBmYWN0b3IgZXJhIGVsIGNsaW1hLCBwZXJvIGFsIGhhY2VyIHVuIG1vZGVsbyBkZSByZWdyZXNpw7NuIHF1ZSBwcm9iYXJhIHF1ZSBlbCBjbGltYSB0aWVuZSB1biBpbXBhY3RvIGVuIGVsIHJldHJhc28gZGUgbG9zIHZ1ZWxvcyBub3MgZGltb3MgY3VlbnRhIHF1ZSBubyBlcmEgYWNlcnRhZG8sIHlhIHF1ZSBsYSBSIGN1YWRyYWRhIGZ1ZSBkZSAwLDAyLCBwb3IgbG8gcXVlIGZ1ZSBwcsOhY3RpY2FtZW50ZSBudWxhLg0KDQpFbCByZWFsaXphciB1biBhbsOhbGlzaXMgZXN0YWTDrXN0aWNvIGRlc2NyaXB0aXZvIG5vcyBzaXJ2acOzIHBhcmEgb2JzZXJ2YXIgeSBhbmFsaXphciBkaWZlcmVudGVzIGZhY3RvcmVzIGRlIGxvcyBkYXRhZnJhbWVzLCBjb21vIGZsaWdodHMuIFBvciBlamVtcGxvLCBwdWRpbW9zIGlkZW50aWZpY2FyIGNvc2FzIGNvbW8gcXVlIGVuIHByb21lZGlvIGVsIGRlcF9kZWxheSBlcyBkZSAxMyBhIDE4IG1pbnV0b3MsIGxvIHF1ZSBub3MgcGVybWl0ZSBpbmZlcmlyIHF1ZSBzb24gbcOhcyBsb3MgdnVlbG9zIHF1ZSBzYWxlbiBhdHJhc2Fkb3MgcXVlIGxvcyBxdWUgc2FsZW4gYSB0aWVtcG8gbyBhZGVsYW50YWRvcy4gDQoNCkVuZm9jw6FuZG9ub3MgdW4gcG9jbyBtw6FzLCBwdWRpbW9zIHZlciBxdWUgbG9zIHZ1ZWxvcyBxdWUgc2FsZW4gZW50cmUgbGFzIDE2OjAwIHkgMjI6MDAgc29uIGxvcyBxdWUgc3VlbGVuIHRlbmVyIGVuIHByb21lZGlvIHVuIG1heW9yIHJldHJhc28sIHNhbGllbmRvIGVudHJlIDE4IHkgMjQgbWludXRvcyBkZXNwdcOpcyBkZSBsbyBlc3RhYmxlY2lkby4gTWllbnRyYXMgcXVlLCBsb3MgZGVtw6FzIHPDs2xvIHNhbMOtYW4gZW50cmUgMCB5IDE2IG1pbnV0b3MgYXRyYXNhZG9zLCBsbyBxdWUgc2UgcHVlZGUgZGViZXIgYSBxdWUgbWllbnRyYXMgbcOhcyB0YXJkZSBlcywgbcOhcyB2dWVsb3MgcmV0cmFzYWRvcyBzZSB2YW4gYWN1bXVsYW5kby4gDQoNClBvciBvdHJvIGxhZG8sIHRhbWJpw6luIHB1ZGltb3Mgb2JzZXJ2YXIgcXVlIGVsIGF0cmFzbyBkZXBlbmRlIG11Y2hvIGRlIGxhIGFlcm9sw61uZWEsIHlhIHF1ZSBlbiBlbCBjYXNvIGRlIFVTIEFpcndheXMgSW5jIGVuIHByb21lZGlvIHPDs2xvIHNhbMOtYSAzLDc4IG1pbnV0b3MgZGVzcHXDqXMsIG1pZW50cmFzIHF1ZSBGcm9udGllciBBaXJsaW5lcyBJbmMuIHNhbMOtYSAyMCwyMiBtaW51dG9zIGRlc3B1w6lzLCBlcyBkZWNpciBtw6FzIGRlIDUgdmVjZXMgbcOhcyB0YXJkZSBxdWUgVVMgQWlyd2F5cyBJbmMuIEFzw60gbWlzbW8sIGVuIGVsIGNhc28gZGUgQW1lcmljYW4gQWlybGluZXMsIGRlIDMyLDA5MyB2dWVsb3MgcXVlIHR1dm8gZGVzZGUgTmV3IFlvcmsgZW4gZWwgMjAxMywgMTAsMTYxIHNhbGllcm9uIGNvbiByZXRyYXNvLCBsbyBxdWUgcmVwcmVzZW50YSBhcHJveGltYWRhbWVudGUgdW4gMzIlIGRlIHN1cyB2dWVsb3MgeSBzdSByZXRyYXNvIHByb21lZGlvIGZ1ZSBkZSA4LDYgbWludXRvcy4gDQoNCkFkaWNpb25hbG1lbnRlLCBwdWRpbW9zIGlkZW50aWZpY2FyIHF1ZSBlbiBwcm9tZWRpbyBlbCB2dWVsbyBjb24gbGEgbWF5b3IgZGlzdGFuY2lhIHJlY29ycmlkYSBlcyBlbCBkZSBIYXdhaWlhbiBBaXJsaW5lcyBJbmMgcXVlIHZhIGRlc2RlIE5ldyBZb3JrKEpGSykgYSBIb25vbHVsdShITkwpLCBsbyBxdWUgbm9zIHBvZHLDrWEgaW5kaWNhciBxdWUgaGF5IGF0cmFzb3MsIGRlYmlkbyBhIGxhIGRpc3RhbmNpYSByZWNvcnJpZGEgbyBldmVudG9zLCBjb21vIHRzdW5hbWlzIG8gdG9ybWVudGFzIHF1ZSBzb24gbXV5IGNvbXVuZXMgZW4gSGF3YWlpLiBEZSBpZ3VhbCBtYW5lcmEsIGRlIGxvcyAxMDAgdnVlbG9zIHF1ZSB0dXZpZXJvbiB1biBhdHJhc28gZGUgbcOhcyBkZSAxMDAwIG1pbnV0b3MsIDYgY29ycmVzcG9uZGVuIGEgTG9zIEFuZ2VsZXMgSW50ZXJuYXRpb25hbCBBaXJwb3J0LCBsbyBxdWUgc2UgcHVlZGUgZGViZXIgZGUgaWd1YWwgbWFuZXJhIGEgbGEgZGlzdGFuY2lhIHF1ZSB0aWVuZSBjb24gTnVldmEgWW9yay4gDQoNCkZpbmFsbWVudGUsIHNlIGNvbnRlbXBsw7MgcXVlIGxvcyB2dWVsb3MgcXVlIHR1dmllcm9uIGNvbW8gb3JpZ2VuIGVsIGFlcm9wdWVydG8gZGUgTmV3YXJrIHByZXNlbnRhcm9uIGVuIHByb21lZGlvIHVuIHJldHJhc28gZGUgMTUgbWludXRvcywgY29udHJhIGxvcyAxMCBkZSBMYSBHdWFyZGlhLiBFc3RvIHNlIGRlYmUgYSBxdWUgTmV3YXJrICBlcyBlbCBhZXJvcHVlcnRvIGNvbiBtYXlvciBjYW50aWRhZCBkZSB2dWVsb3MuIExvcyBKdWV2ZXMgZnVlcm9uIGVsIGTDrWEgY29uIG1heW9yIHJldHJhc28gY29uIDE5IG1pbnV0b3MsIHNlZ3VpZG8gcG9yIGxvcyBMdW5lcyB5IFZpZXJuZXMsIGVzIGRlY2lyIGxvcyBkw61hcyBxdWUgc2UgdmlhamFuIG5vcm1hbG1lbnRlIHBhcmEgZWwgZmluIGRlIHNlbWFuYS4NCg0KTGEgc3VtYSBkZSB0b2RvcyBlc3RvcyBmYWN0b3JlcyBub21icmFkb3MgYW50ZXJpb3JtZW50ZSBzb24gbG9zIHJlc3BvbnNhYmxlcyBkZSBxdWUgbG9zIHZ1ZWxvcyBsbGVndWVuIHRhcmRlLiANCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogYmx1ZTsiPiBDb21wcm9taXNvIMOpdGljbyB5IGNpdWRhZGFubyAoSm9yZ2UgUG9ucyAtIEEwMTQyNDEwOCk8L3NwYW4+DQoNCkxhIGludGVncmlkYWQgZXMgdW4gdmFsb3IgZnVuZGFtZW50YWwgZW4gY3VhbHF1aWVyIGRpc2NpcGxpbmEgcHJvZmVzaW9uYWwuIFJlcHJlc2VudGEgbGEgaG9uZXN0aWRhZCwgbGEgY29oZXJlbmNpYSB5IGxhIGNvbmdydWVuY2lhIGVudHJlIGxvIHF1ZSBkZWNpbW9zLCBwZW5zYW1vcyB5IGhhY2Vtb3MuIEVuIGVsIGNvbnRleHRvIGRlIGxhIMOpdGljYSBwcm9mZXNpb25hbCwgbGEgaW50ZWdyaWRhZCBpbXBsaWNhIGFjdHVhciBkZSBtYW5lcmEgw61udGVncmEsIHJlc3BldGFuZG8gbG9zIHByaW5jaXBpb3MgeSB2YWxvcmVzIHF1ZSByaWdlbiBudWVzdHJhIHByb2Zlc2nDs24uIENvbiBlc3RhIGFjdGl2aWRhZCBtZSBjb21wcm9tZXRvIGEgYXBsaWNhciBtaXMgY29ub2NpbWllbnRvcywgYSBlc2Zvcnphcm1lIGVuIHN1IGRlc2Fycm9sbG8geSBhIG5vIHNlcnZpcm1lIGRlIG1lZGlvcyBubyBhdXRvcml6YWRvcyBvIGlsw61jaXRvcyBwYXJhIHJlYWxpemFybGEuIFRlbmVyICBhY2Nlc28gYSBsYSBpbmZvcm1hY2nDs24gZGUgdW5hIGVtcHJlc2EgY29ubGxldmEgcmVzcG9uc2FiaWxpZGFkZXMgw6l0aWNhcy4gRGViZW1vcyB1dGlsaXphcmxhIGRlIG1hbmVyYSDDrW50ZWdyYSwgcmVzcGV0YW5kbyBsYSBjb25maWRlbmNpYWxpZGFkIHkgZXZpdGFuZG8gYmVuZWZpY2lvcyBwZXJzb25hbGVzIG8gZGHDsW9zIGEgbGEgb3JnYW5pemFjacOzbi4gTGEgaW50ZWdyaWRhZCB5IGVsIGN1bXBsaW1pZW50byBkZWwgY8OzZGlnbyDDqXRpY28gc29uIGVzZW5jaWFsZXMgcGFyYSB0b21hciBkZWNpc2lvbmVzIGluZm9ybWFkYXMgeSBwcm90ZWdlciBsYSBwcml2YWNpZGFkIGRlIGxhIGluZm9ybWFjacOzbiBlbXByZXNhcmlhbC4NCg0KLSDCv1BvciBxdcOpIHRvZGEgZW1wcmVzYSBkZWJlIGNvbnRhciBjb24gdW4gY8OzZGlnbyDDqXRpY28/IChuLmQuKS4gRWR1LnBlLiBSZXRyaWV2ZWQgTWFyY2ggMTMsIDIwMjQsIGZyb20gaHR0cHM6Ly93d3cuZXNhbi5lZHUucGUvY29uZXhpb24tZXNhbi9wb3ItcXVlLXRvZGEtZW1wcmVzYS1kZWJlLWNvbnRhci1jb24tdW4tY29kaWdvLWV0aWNvIA0KLSBDw7NkaWdvIGRlIMOJdGljYSB5IENvbmR1Y3RhIFByb2Zlc2lvbmFsIGRlIEFDTS4gKG4uZC4pLiBBY20ub3JnLiBSZXRyaWV2ZWQgTWFyY2ggMTMsIDIwMjQsIGZyb20gaHR0cHM6Ly93d3cuYWNtLm9yZy9hYm91dC1hY20vY29kZS1vZi1ldGhpY3MtaW4tc3BhbmlzaA0KLSDigaBDw7NkaWdvIMOJdGljbyBkZSBsb3MgQWRvbGVzY2VudGVzIHkgc3VzIERlYmVyZXMuICgyMDIxLCBNYXJjaCA4KS4gU295ZXRpY2EuY29tLiBodHRwczovL3NveWV0aWNhLmNvbS9jb2RpZ28tZXRpY28tZGUtbG9zLWFkb2xlc2NlbnRlcy8NCg0KIyA8c3BhbiBzdHlsZSA9ICJjb2xvcjogYmx1ZTsiPiBDb21wcm9taXNvIMOpdGljbyB5IGNpdWRhZGFubyAoUmFmYWVsbGEgUMOpcmV6IC0gQTAwODM3MTQyKTwvc3Bhbj4NCg0KTGEgaW50ZWdyaWRhZCBlcyB1biB2YWxvciBkZSBzdW1hIGltcG9ydGFuY2lhIHBhcmEgbGEgY29udml2ZW5jaWEgc2FuYSBlbiB1bmEgY29tdW5pZGFkLCB5YSBxdWUgZXN0YSBub3MgIHBlcm1pdGUgYWN0dWFyIGNvbiBob25lc3RpZGFkIHkgY29oZXJlbmNpYSBlbiBjYWRhIHVuYSBkZSBudWVzdHJhcyBhY3RpdmlkYWRlcyhOYWNpb25lcyBVbmlkYWQsIDIwMjQpLiBFc3RhIGVzIHVuIHBpbGFyIGZ1bmRhbWVudGFsIHBhcmEgZWwgZGVzYXJyb2xsbyBwcm9mZXNpb25hbCB5IHNvY2lhbCwgeWEgcXVlIHByaW1lcm8gdGUgZGVqYSBwcm9ncmVzYXIgZW4gdHUgY2FycmVyYSBhbCBkZW1vc3RyYXIgdHVzIGNhcGFjaWRhZGVzLCBzaW4gbmVjZXNpZGFkIGRlIGhhY2VyIHRyYW1wYSBvIGhhY2VyIGNvc2FzIGluZGViaWRhcy4gWSBzZWd1bmRvLCBwYXJhIGVsIGRlc2Fycm9sbG8gc29jaWFsLCB5YSBxdWUgc2UgY3JlYW4gcmVsYWNpb25lcyBpbnRlcnBlcnNvbmFsZXMgc8OzbGlkYXMsIGRvbmRlIHByZWRvbWluYSBsYSBjb25maWFuemEuIChEUEMsIDIwMjQpLiBVbm8gZGUgbG9zIG1heW9yZXMgcHJvYmxlbWFzIGEgbml2ZWwgbXVuZGlhbCBlcyBsYSBjb3JydXBjacOzbiB0YW50byBlbiBsb3MgZ29iaWVybm9zLCBjb21vIGVuIGxhcyBlbXByZXNhcywgeSBlc3RhIGVzIGNhdXNhZG8ganVzdGFtZW50ZSBwb3IgbGEgZmFsdGEgZGUgaW50ZWdyaWRhZCwgbGEgY3XDoWwgZW1waWV6YSBkZXNkZSBhY2Npb25lcyBwZXF1ZcOxYXMgZGVsIGTDrWEgYSBkw61hLCBoYXN0YSBncmFuZGVzIHF1ZSBsbGVnYW4gYSBhZmVjdGFyIGEgbWlsbG9uZXMgZGUgcGVyc29uYXMuIA0KDQpFbmZvY8OhbmRvbm9zIGVuIG1pIGNhc28sIG1pIGPDs2RpZ28gw6l0aWNvIGRlIGRpc2NpcGxpbmEgc2UgYmFzYSBlbiBwZW5zYXIgMiB2ZWNlcyBhbnRlcyBkZSBhY3R1YXIuIE11Y2hhcyB2ZWNlcywgbGFzIHBlcnNvbmFzIG5vcyBkZWphbW9zIGxsZXZhciBwb3IgZWwgbWFsIGNhbWlubywgeWEgcXVlIGJ1c2NhbW9zIGxhIHBlcmZlY2Npw7NuIG8gbm8gY3JlZW1vcyBlbiBsYXMgY29uc2VjdWVuY2lhcyBxdWUgcHVlZGUgdHJhZXIsIHBlcm8gZXN0byB2YSBtw6FzIGFsbMOhIGRlIHNpIG5vcyBkZXNjdWJyZW4geSB0ZW5lbW9zIHVuYSByZXBlcmN1c2nDs24sIHB1ZXMgc2UgdHJhdGEgZW4gcXVlIHJlYWxtZW50ZSBlbCB0cmFiYWpvIG5vIHJlZmxlamEgbG8gcXVlIHNhYmVtb3MgbyBoYWNlbW9zLCBwdWVzIGZ1ZSBoZWNobyBjb24gZWwgZXNmdWVyem8gZGUgb3RybyhQcmVwYXJhdG9yaWEgUGFuYW1lcmljYW5hLCAyMDIxKS4gVW5hIG1pcyBmaWxvc29mw61hcyBkZSB0cmFiYWpvLCBsYSBjdcOhbCBmdWUgaW5jdWxjYWRhIHBvciBtaSBtYW3DoSBlczog4oCcTWVqb3IgdW5hIG1hbGEgbm90YSwgcGVybyBwcm9waWEsIHF1ZSB1bmEgYnVlbmEsIHBlcm8gYWplbmHigJ0sIHkgbGEgdmVyZGFkIGVzIHF1ZSBhw7FvcyBkZXNwdcOpcyBzw7NsbyBwdWVkbyBkZWNpciBsbyBtdWNobyBxdWUgZXN0b3kgZGUgYWN1ZXJkbywgcHJlZmllcm8gYXByZW5kZXIgeSBkZW1vc3RyYXIgbG8gcXVlIHNveSBjYXBheiBvIGV4aWdpcm1lIG3DoXMgcGFyYSBhbGNhbnphciBtaSBtZWpvciB2ZXJzacOzbiwgcXVlIGZpbmdpciBzZXIgYWxndWllbiBxdWUgbm8gc295LiANCg0KSG95IGVuIGTDrWEsIGVzIG11eSBjb23Dum4gdGVuZXIgYWNjZXNvIGEgY2llcnRvcyBkYXRvcyBkZSBsYXMgZW1wcmVzYXMsIGRlYmlkbyBhbCBJbnRlcm5ldC4gUG9yIGVzbywgdW5vIGRlYmUgZGUgdGVuZXIgbXVjaG8gY3VpZGFkbywgeWEgcXVlIGVuIGNpZXJ0b3MgY2Fzb3MsIGNvbW8gbG9zIHJldG9zIHF1ZSBoYWNlbW9zIGVuIGVsIFRlY25vbMOzZ2ljbyBkZSBNb250ZXJyZXksIGxhIGluZm9ybWFjacOzbiBlcyBjb25maWRlbmNpYWwsIHNpZW5kbyB0b3RhbG1lbnRlIG51ZXN0cmEgcmVzcG9uc2FiaWxpZGFkIGxvIHF1ZSBwYXNhIGNvbiBlc29zIGRhdG9zLiBFbiBjYXNvIGRlIHVzYXJsYSBpbmNvcnJlY3RhbWVudGUsIHNlIHB1ZWRlIHRlbmVyIGhhc3RhIHByb2JsZW1hcyBsZWdhbGVzLCBjb21vIGRlbWFuZGFzLiBQb3Igb3RybyBsYWRvLCBlbCBxdWUgY2llcnRhIGluZm9ybWFjacOzbiBlc3TDqSBkaXNwb25pYmxlIGVuIGludGVybmV0LCBwZXJtaXRlIHRlbmVyIGNpZXJ0YSB0cmFuc3BhcmVuY2lhLCBhbCBwb2RlciBvYnNlcnZhciBkb2N1bWVudG9zIGNvbW8gbG9zIGVzdGFkb3MgZmluYW5jaWVyb3MgbyBwcm95ZWN0b3MgcXVlIHNlIGVzdMOhbiBsbGV2YW5kbyBhIGNhYm8sIGxvcyBjdcOhbGVzIHNvbiBlc3BlY2lhbG1lbnRlIMO6dGlsZXMsIGN1YW5kbyBzb21vcyBpbnZlcnNpb25lcyBvIGFjY2lvbmlzdGFzIGRlIHVuYSBlbXByZXNhLiANCg0KLSBEZXNjb25vY2lkby4gKDIwMjQpLiBOYWNpb25lcyBVbmlkYWQuIExhIGNpZW5jaWEgZGUgbGEgSW50ZWdyaWRhZC4gUmVjdXBlcmFkbyBlbCAxMiBkZSBGZWJyZXJvIGRlbCAyMDI0LiBodHRwczovL3d3dy51bm9kYy5vcmcvdW5vZGMvZXMvbGlzdGVuLWZpcnN0L3N1cGVyLXNraWxscy9pbnRlZ3JpdHkuaHRtbA0KDQotIERlc2Nvbm9jaWRvLiAoMjAyNCkuIERpcmVjY2nDs24gZGUgcGFydGljaXBhY2nDs24gY2l1ZGFkYW5hLiBJbnRlZ3JpZGFkLiBSZWN1cGVyYWRvIGVsIDEyIGRlIEZlYnJlcm8gZGVsIDIwMjQuIGh0dHBzOi8vd3d3LmllZW0ub3JnLm14L0RQQy9jb25zZWpvc19wcm9tb3RvcmVzL2ludGVncmlkYWQuaHRtbA0KDQotIE1lamlhIEwuICgyMDIxKS4gUHJlcGFyYXRvcmlhIFBhbmFtZXJpY2FuYS4gTGEgaW1wb3J0YW5jaWFkZSBsYSBpbnRlZ3JpZGFkIG1vcmFsIGVuIGxhIGFkb2xlc2NlbmNpYS4gUmVjdXBlcmFkb2VsIDEyIGRlIE1hcnpvIGRlbCAyMDI0LiBodHRwczovL2Jsb2cudXAuZWR1Lm14L3ByZXBhdXAvZmVtZW5pbC9sYS1pbXBvcnRhbmNpYS1kZS1sYS1pbnRlZ3JpZGFkLW1vcmFsLWVuLWxhLXByZXBhcmF0b3JpYQ0KDQojIDxzcGFuIHN0eWxlID0gImNvbG9yOiBibHVlOyI+IENvbXByb21pc28gw6l0aWNvIHkgY2l1ZGFkYW5vICjDk3NjYXIgUmV0ZXMgLSBBMDEzODM2NTMpPC9zcGFuPg0KDQpMYSBpbnRlZ3JpZGFkLCBlbnRlbmRpZGEgY29tbyB1biB2YWxvciBlc2VuY2lhbCBlbiBjdWFscXVpZXIgw6FtYml0byBwcm9mZXNpb25hbCwgYWRxdWllcmUgdW4gc2lnbmlmaWNhZG8gdHJhc2NlbmRlbnRlIGN1YW5kbyBzZSB0aWVuZW4gZW4gY3VlbnRhIHN1cyBkaXZlcnNhcyBmYWNldGFzLiBFc3RlIHByaW5jaXBpbyBlcyB1bmEgcGllZHJhIGFuZ3VsYXIgcXVlIGVuZ2xvYmEgbGEgaG9uZXN0aWRhZCwgbGEgY29oZXJlbmNpYSB5IGxhIGNvbmdydWVuY2lhIGVuIHRvZGFzIG51ZXN0cmFzIGFjY2lvbmVzLCBwZW5zYW1pZW50b3MgeSBleHByZXNpb25lcy4gRW4gZWwgY29udGV4dG8gZGUgbGEgw6l0aWNhIHByb2Zlc2lvbmFsLCBsYSBpbnRlZ3JpZGFkIHNlIG1hbmlmaWVzdGEgY29tbyB1biBjb21wcm9taXNvIGlucXVlYnJhbnRhYmxlIGRlIGFjdHVhciBjb24gaW50ZWdyaWRhZCB5IGRlZmVuZGVyIGxvcyBwcmluY2lwaW9zIHkgdmFsb3JlcyBxdWUgZ3XDrWFuIG51ZXN0cm8gdHJhYmFqby4gVGVuaWVuZG8gZXN0byBlbiBjdWVudGEsIGFsIGFib3JkYXIgdW5hIHRhcmVhIG8gcHJveWVjdG8sIG1lIGNvbXByb21ldG8gYSBhcGxpY2FyIGN1aWRhZG9zYW1lbnRlIG1pcyBjb25vY2ltaWVudG9zLCBkZWRpY8OhbmRvbWUgYSBzdSBkZXNhcnJvbGxvIHkgcmVjaGF6YW5kbyBlbCB1c28gZGUgbWVkaW9zIGlsw61jaXRvcyBvIGlsZWdhbGVzIHBhcmEgcmVhbGl6YXIgbWlzIHRhcmVhcy4NCg0KRWwgYWNjZXNvIGEgbGEgaW5mb3JtYWNpw7NuIGRlbnRybyBkZSB1bmEgZW1wcmVzYSBubyBlcyBzw7NsbyB1biBwcml2aWxlZ2lvLCBzaW5vIHRhbWJpw6luIHVuYSBncmFuIHJlc3BvbnNhYmlsaWRhZCDDqXRpY2EuIEVzdGUgYWNjZXNvIGNvbmxsZXZhIHVuYSBzZXJpZSBkZSB0YXJlYXMgeSByZXNwb25zYWJpbGlkYWRlcyBxdWUgZGViZW4gbGxldmFyc2UgYSBjYWJvIGNvbiBsYSBtw6F4aW1hIGludGVncmlkYWQuIEVzIGltcG9ydGFudGUgaGFjZXIgcGxlbm8gdXNvIGRlIGVzdGEgaW5mb3JtYWNpw7NuLCBwcm90ZWdlciBjdWlkYWRvc2FtZW50ZSBzdSBjb25maWRlbmNpYWxpZGFkIHkgZXZpdGFyIGN1YWxxdWllciBpbnRlbnRvIGRlIG9idGVuZXIgdmVudGFqYSBwZXJzb25hbCBvIGRhw7FhciBhIGxhIG9yZ2FuaXphY2nDs24uIExhIGludGVncmlkYWQsIHBvciB0YW50bywgc2UgbWFuaWZpZXN0YSBjb21vIHVuIGVzY3VkbyBwcm90ZWN0b3IgcXVlIG5vcyBpbnN0YSBhIGFkaGVyaXIgZmllbG1lbnRlIGEgdW4gY8OzZGlnbyDDqXRpY28gcXVlIHNpcnZlIGNvbW8gZ3XDrWEgaW5mYWxpYmxlIHBhcmEgdG9tYXIgZGVjaXNpb25lcyBpbmZvcm1hZGFzIHkgbWFudGVuZXIgbGEgY29uZmlkZW5jaWFsaWRhZCBkZSBsYSBpbmZvcm1hY2nDs24gZW1wcmVzYXJpYWwuIEVuIMO6bHRpbWEgaW5zdGFuY2lhLCBlcyBlc3RhIGludGVncmlkYWQgeSBlc3RyaWN0byBjdW1wbGltaWVudG8gZGUgbG9zIHByaW5jaXBpb3Mgw6l0aWNvcyBsbyBxdWUgbm9zIHBlcm1pdGUgbmF2ZWdhciBwb3IgZWwgY29tcGxlam8gcGFub3JhbWEgZGUgbGEgw6l0aWNhIGVtcHJlc2FyaWFsIGNvbiBjb25maWFuemEgeSByZXNwZXRvIHBvciBudWVzdHJvIHRyYWJham8geSBudWVzdHJvIGVudG9ybm8gc29jaWFsLg0KDQotIE1lcmNhZG9sb2d5LCBOLiAoMjAyMSwgNyBkaWNpZW1icmUpLiDCv1BvciBxdcOpIGVzIHRhbiBpbXBvcnRhbnRlIGxhIGludGVncmlkYWQgZGUgdW5hIGVtcHJlc2E/IFJPSEUuIGh0dHBzOi8vZ3J1cG9yb2hlLm14L2ludGVncmlkYWQtZGUtdW5hLWVtcHJlc2EvDQoNCi0gUnViaW8sIEEuIE4uICgyMDIzLCA2IG1hcnpvKS4gSW50ZWdyaWRhZCBjb3Jwb3JhdGl2YSwgYmVuZWZpY2lvcyBkZSBsYXMgYnVlbmFzIHByw6FjdGljYXMuIFJwam1jb25zdWx0b3JpYS4gaHR0cHM6Ly93d3cucnBqbWNvbnN1bHRvcmlhLmNvbS9wb3N0L2ludGVncmlkYWQtY29ycG9yYXRpdmENCg0KLSBDaMOhdmV6LCBFLiBBLiBHLiAoMjAyMSwgMTUganVsaW8pLiBBY2Npb25lcyBwYXJhIHJlZm9yemFyIGxhIGludGVncmlkYWQgY29ycG9yYXRpdmEgZW50cmUgbG9zIGNvbGFib3JhZG9yZXMgZGUgdHUgZW1wcmVzYS4gU3RyYXRlZ28gRmlybWEuIGh0dHBzOi8vc3RyYXRlZ29maXJtYS5jb20vYWNjaW9uZXMtcGFyYS1yZWZvcnphci1sYS1pbnRlZ3JpZGFkLWNvcnBvcmF0aXZhLWVudHJlLWxvcy1jb2xhYm9yYWRvcmVzLWRlLXR1LWVtcHJlc2EvDQo=