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 NY en 2013
  • weather = datos meteroló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 aerolineas

Instalar paquetes y llamar librerĆ­as

#Para instalar librerĆ­as: install.packages("nycflights")
library(nycflights13)
library(stats)
library(tidyverse)
## ── 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.5.0     āœ” 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

Fuente: Origen de los datos

Relación entre las bases de datos

1. Cargar en memoria la tabla ā€œflightsā€ y mostrar su contenido

# La caarga 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
# num: numerico (decimales)
# chr: caracter (letras)
# date: fecha (en R va aƱo-mes-dia)
# POSIXct: formato fecha y hora

3. ĀæCuĆ”l es la clase de ā€œflightsā€ y quĆ© significa?

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

# Las 4 clases de objetos compuestos son:
# 1. list: lista (una columna)
# 2. matix: matriz (varias columnas, todos el mismo tipo de datos [numeros, letras, etc])
# 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>

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

Conclusión avance 1

En este trabajo pudimos utilizar las funciones mÔs comunes del anÔlisis exploratorio, el cual es el primer paso para cualquier trabajo de manipulación de datos.

Avance 2

Se nos ha solicitado consultar cuƔles son las aerolƭneas de mayor trƔfico aƩreo en origen y destino.
Contamos con un data frame llamado flights que contiene toda la información de los vuelos de todos los aeropuertos de New York.

aerolineas <- table(flights$carrier)
enorden <- sort(aerolineas)
enorden
## 
##    OO    HA    YV    F9    AS    FL    VX    WN    9E    US    MQ    AA    DL 
##    32   342   601   685   714  3260  5162 12275 18460 20536 26397 32729 48110 
##    EV    B6    UA 
## 54173 54635 58665

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 recorrido una distancia superior a la media, se desean ver los campos carrier, distance, origin, dest en forma descendente por distance.

promedio <- mean(flights$distance)
promedio
## [1] 1039.913
df <- flights
df <- flights %>% filter(distance >= promedio)

dfaerolineas <- table(df$carrier)
#dforden tiene a df en orden descendiente

dforden <- sort(dfaerolineas)
dforden
## 
##    HA    F9    AS    MQ    9E    US    WN    EV    VX    DL    AA    B6    UA 
##   342   685   714   744  1377  2271  3832  3991  5162 21637 23190 24426 39294
view(dforden)

Ahora, usando solamente las top 5 aerolineas con mƔs vuelos arriba de la media, encontraremos de quƩ aeropuertos salieron los vuelos largos y con quƩ aerolineas

resumen_aerolineas <- df %>% filter(origin == "JFK") %>%  group_by(carrier) %>%  summarise(distancia_promedio = mean(distance, na.rm = TRUE)) %>%  arrange(desc(distancia_promedio)) 

Con estos datos, podemos ver que Hawaiian Airlines tiene los vuelos con mƔs distancia promedio fuera de todas las aerolƭneas. Esto siendo debido probablemente a que HA viaja mucho ida y vuelta a las islas de Hawaii, las cuales estƔn muy lejos. La distancia promedio de un vuelo de HA fue de 4983 millas.

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

jfk <- flights %>% filter(origin=="JFK") %>% group_by(carrier) %>% summarize(num_vuelos = n())
lga <- flights %>% filter(origin=="LGA") %>% group_by(carrier) %>% summarize(num_vuelos = n())
ewr <- flights %>% filter(origin=="EWR") %>% group_by(carrier) %>% summarize(num_vuelos = n())

Avance 3

Descripción

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. Para el desarrollo de la situación problema considera las funciones sugeridas en cada paso. Consulta y explora el data frame planes y weather para que conozcas su contenido.

vuelostodos <- merge(flights, planes, by="tailnum")
vuelosAA <- vuelostodos %>% filter(carrier =="AA")
AA <- vuelosAA %>% select(carrier)
vuelosAAfiltrados<- vuelosAA%>% select(origin:dest)
vuelostodos <- left_join(flights, airlines, by="carrier")

Con esas tres funciones, logramos: 1. Hacer una base de datos de nada mƔs la fila de AA.
2. Merge todos los vuelos de la base de datos flights con la base de datos planes
3. Filtrar esa base de datos nueva para encontrar solamente los vuelos de AA.
4. De esos vuelos, seleccionar solamente las columnas de origen y destino.

countoriginfeoAA <- count(vuelosAAfiltrados,origin, name="Cantidad de vuelos")
count_originAA <- arrange(countoriginfeoAA, desc("Cantidad de vuelos"))
countoriginfeos <- count(vuelostodos,origin, name="Cantidad de vuelos")
count_origin_TODOS <- arrange(countoriginfeos, desc("Cantidad de vuelos"))

Con una función de count(), encontramos que los vuelos de AA consisten de 1145 vuelos saliendo de EWR, 5500 saliendo de JFK, y 3526 saliendo de LGA.

countdestfeoAA<- count(vuelosAAfiltrados,origin,dest, name ="Cantidad de vuelos")
count_destAA <- arrange(countdestfeoAA,desc("Cantidad de vuelos"))
countdestfeos <- count(vuelostodos,origin,dest, name ="Cantidad de vuelos")
count_dest_TODOS <- arrange(countdestfeos,desc("Cantidad de vuelos"))

Al correr la funcion count() de arriba, encontramos los destinos de los vuelos AA. El favorito destino de AA es Los Angeles (LAX, 3178), luego Chicago O’Hare (ORD, 2500), luego Dallas Fort Worth (DFW, 1613), etc…

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.

maƱana <- vuelostodos %>% filter(hour >= 6 & hour <= 12)
tarde <- vuelostodos %>% filter(hour > 12 & hour <= 19)
noche <- vuelostodos %>% filter(hour >= 19 & hour <= 24)
madrugada <- vuelostodos %>% filter(hour > 0 & hour < 6)

vuelosmaƱana <- maƱana %>% select(year:day,hour,minute,carrier,name,dest)
vuelostarde <- tarde %>% select(year:day,hour,minute,carrier,name,dest)
vuelosnoche <- noche %>% select(year:day,hour,minute,carrier,name,dest)
vuelosmadrugada <- madrugada %>% select(year:day,hour,minute,carrier,name,dest)

AquĆ­ se construyeron bases de datos nuevas seleccionando solamente aquellos datos necesarios de la base de datos ā€œvuelostodosā€ que se usa mĆŗltiples veces en mi trabajo.

Agrega un nuevo campo a la tabla con el nombre de clas_horario y agrega ā€œmaƱanaā€, ā€œtardeā€, ā€œnocheā€, ā€œmadrugadaā€ segĆŗn lo que corresponde.

vuelostodos <- vuelostodos %>% mutate(clas_horario = ifelse(hour >= 6 & hour <12, "maƱana", ifelse(hour >= 12 & hour <19, "tarde", ifelse(hour >= 19 & hour <23, "noche",ifelse(hour >= 0 & hour <6, "madrugada",NA)))))

La base de datos ā€œvuelostodosā€ contiene la columna de la clase de horario en el que volaron los aviones. Use esta base de datos mĆ”s adelante para encontrar cuantos vuelos volaba cada aerolĆ­nea por destino. Aun que no sĆ© si es la manera mĆ”s eficiente, use ifelse uno ā€œadentroā€ del otro para ir deduciendo en donde deben de actuar. Con este mĆ©todo, logramos aƱadir la columna de clas_horario.

Se necesita saber la cantidad de vuelos por aerolƭnea y destino que hay por la MaƱana, Tarde, Noche y Madrugada

clasificacionvuelos <- vuelostodos %>% count(name, dest, clas_horario, name ="Cantidad de vuelos")
clasificacionvuelos <- clasificacionvuelos %>% arrange(desc("Cantidad de vuelos"))

la base de datos ā€œclasificacionvuelosā€ contiene todos los vuelos que salieron de algĆŗn aeropuerto de Nueva York. EstĆ”n organizados alfabĆ©ticamente por las aerolĆ­neas.

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

AAmaƱana <- clasificacionvuelos %>% filter(name =="American Airlines Inc.", clas_horario == "madrugada")

El único destino que voló American Airlines desde alguno de los aeropuertos de NYC fue a Miami (Seguro mucha fiesta)

Āæ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

aviones_AA <- left_join(vuelosAA, planes, by="tailnum")
vuelosxavion <- aviones_AA %>% filter(!is.na(type.x)) %>% count(type.x, name="Cantidad de vuelos")

Conclusiones Finales

Con una base de datos tan extensa como lo es ā€œnycflights13ā€, podemos extraer mucha información no solo de las aerolĆ­neas y sus aviones, sino los vuelos que hacen, la distancia, el tiempo, el tipo de avión que utilizan, etc. Con este ejercicio, logramos definir algunos hallazgos que parecen importantes para expandir nuestro conocimiento de los vuelos y aeropuertos de Nueva York, ya sea La Guardia (LGA), John F. Kennedy (JFK), o Newark Liberty (EWR).

Hallazgos

  1. Los vuelos que volaron mƔs seguido fueron: JFK a LAX (11262 veces al aƱo, 31 veces al dƭa), LGA a ATL (10263 veces al aƱo, 29 veces al dƭa), y LGA a ORD (8857 veces al aƱo, 24.6 veces al dƭa)

  2. Las aerolĆ­neas con mayor distancia promedio fueron Hawaiian Airlines (4983 millas), United Airlines (2535 millas), y Virgin America (2495 millas)

  3. Curiosamente, no aparecen vuelos que despeguen entre 1a.m y 5a.m, ya que los primeros datos del dĆ­a, por asĆ­ decirlo, empiezan alas 5a.m

  4. AA utilizó 3 diferentes tipos de aviones para llevar a cabos sus traslados. Estos siendo ā€œFixed wing multi engineā€ (9318 vuelos) ā€œFixed wing single engineā€ (729) y ā€œRotorcraftā€ (124) El primero, el ā€œFixed wing multi engineā€ es el avión tĆ­pico que te imaginas. Ya sea un Airbus, Boeing, etc. El single engine son mucho mĆ”s pequeƱos, pues aguanta mucho menos carga. Finalmente, los Rotorcraft, son aquellos que parecen helicópteros (mirar imagen)

Aunque por sí mismos estos datos no parezcan muy importantes, se pueden utilizar para identificar problemas que pueden causar una pérdida de dinero en algún futuro. Este trabajo me ayudó a implementar todos los aprendizajes que me llevé de mi clase de Manipulación de Datos, y ahora puedo implimentar estos aprendizajes en proyectos personales y/o profesionales.

LS0tCnRpdGxlOiAiRXZpZGVuY2lhIDEgLSBNYW5pcHVsYWNpw7NuIGRlIGRhdG9zIgphdXRob3I6ICJGZWRlcmljbyBab3JyaWxsYSBBMDA4MzY2MjkiCmRhdGU6ICIyMDI0LTAyLTI2IgpvdXRwdXQ6IAogIGh0bWxfZG9jdW1lbnQ6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQogICAgY29kZV9kb3dubG9hZDogVFJVRQogICAgdGhlbWU6IHlldGkKLS0tCgohW10oL1VzZXJzL2ZlZGV6b3JyaWxsYS9EZXNrdG9wL1IgTWFya2Rvd24vQWlycG9ydF9zeW1ib2wuc3ZnLnBuZykKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+Q29udGV4dG88L3NwYW4+CkVsIHBhcXVldGUgKipueWNmbGlnaHRzMTMqKiBjb250aWVuZSBpbmZvcm1hY2nDs24gc29icmUgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgcGFydGllcm9uIGRlc2RlIE51ZXZhIFlvcmsgKEVXUiwgSkZLLCB5IExHQSkgYSBkZXN0aW5vcyBlbiBsb3MgRXN0YWRvcyBVbmlkb3MgZW4gMjAxMy4gRnVlcm9uIDMzNiw3NzYgdnVlbG9zIGVuIHRvdGFsLiBQYXJhIGF5dWRhciBhIGNvbXByZW5kZXIgbGFzIGNhdXNhcyBkZSBsb3MgcmV0cmFzb3MsIHRhbWJpw6luIGluY2x1eWUgb3Ryb3MgY29uanVudG9zIGRlIGRhdG9zIMO6dGlsZXMuICAKCkVzdGUgcGFxdWV0ZSBpbmNsdXllIGxhcyBzaWd1aWVudGVzIHRhYmxhczogCgorIGZsaWdodHMgPSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzYWxpZXJvbiBkZSBOWSBlbiAyMDEzICAgIAorIHdlYXRoZXIgPSBkYXRvcyBtZXRlcm9sw7NnaWNvcyBwb3IgaG9yYSBkZSBjYWRhIGFlcm9wdWVydG8gIAorIHBsYW5lcyA9IGluZm9ybWFjacOzbiBkZSBjb25zdHJ1Y2Npw7NuIGRlIGNhZGEgYXZpw7NuICAKKyBhaXJwb3J0cyA9IG5vbWJyZXMgeSB1YmljYWNpb25lcyBkZSBhZXJvcHVlcnRvcyAgCisgYWlybGluZXMgPSByZWxhY2nDs24gZW50cmUgbm9tYnJlcyB5IGPDs2RpZ29zIGRlIGxhcyBhZXJvbGluZWFzICAKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+SW5zdGFsYXIgcGFxdWV0ZXMgeSBsbGFtYXIgbGlicmVyw61hczwvc3Bhbj4KYGBge3J9CiNQYXJhIGluc3RhbGFyIGxpYnJlcsOtYXM6IGluc3RhbGwucGFja2FnZXMoIm55Y2ZsaWdodHMiKQpsaWJyYXJ5KG55Y2ZsaWdodHMxMykKbGlicmFyeShzdGF0cykKbGlicmFyeSh0aWR5dmVyc2UpCmBgYAoKCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkd1YXJkYXIgYmFzZXMgZGUgZGF0b3M8L3NwYW4+CmBgYHtyfQpmbGlnaHRzIDwtIGZsaWdodHMKd2VhdGhlciA8LSB3ZWF0aGVyCnBsYW5lcyA8LSBwbGFuZXMKYWlycG9ydHMgPC0gYWlycG9ydHMKYWlybGluZXMgPC0gYWlybGluZXMKYGBgCkZ1ZW50ZToKW09yaWdlbiBkZSBsb3MgZGF0b3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9ueWNmbGlnaHRzMTMvbnljZmxpZ2h0czEzLnBkZikKCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlJlbGFjacOzbiBlbnRyZSBsYXMgYmFzZXMgZGUgZGF0b3M8L3NwYW4+CgohW10oL1VzZXJzL2ZlZGV6b3JyaWxsYS9EZXNrdG9wL1IgTWFya2Rvd24vcmVsYXRpb25hbC1ueWNmbGlnaHRzLnBuZykKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+MS4gQ2FyZ2FyIGVuIG1lbW9yaWEgbGEgdGFibGEgImZsaWdodHMiIHkgbW9zdHJhciBzdSBjb250ZW5pZG88L3NwYW4+CmBgYHtyfQojIExhIGNhYXJnYSBhIG1lbW9yaWEgc2UgaGl6byBlbiBlbCBwYXNvIGFudGVyaW9yCmZsaWdodHMKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPjIuIENvbnN1bHRhIGxhIGVzdHJ1Y3R1cmEgZGUgZmxpZ2h0czwvc3Bhbj4KYGBge3J9CnN0cihmbGlnaHRzKQojIGludDogZW50ZXJvCiMgbnVtOiBudW1lcmljbyAoZGVjaW1hbGVzKQojIGNocjogY2FyYWN0ZXIgKGxldHJhcykKIyBkYXRlOiBmZWNoYSAoZW4gUiB2YSBhw7FvLW1lcy1kaWEpCiMgUE9TSVhjdDogZm9ybWF0byBmZWNoYSB5IGhvcmEKYGBgCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+My4gwr9DdcOhbCBlcyBsYSBjbGFzZSBkZSAiZmxpZ2h0cyIgeSBxdcOpIHNpZ25pZmljYT8gPC9zcGFuPgoKYGBge3J9CmNsYXNzKGZsaWdodHMpCgojIExhcyA1IGNsYXNlcyBkZSBvYmpldG9zIHNvbgojIDEuIG51bWVyaWM6IE7Dum1lcm8gcmVhbCBvIGRlY2ltYWxlcwojIDIuIGludGVnZXI6IG7Dum1lcm9zIGVudGVyb3MKIyAzLiBjb21wbGV4OiBuw7ptZXJvcyBjb21wbGVqb3MKIyA0LiBjaGFyYWN0ZXI6IGNhcmFjdGVyZXMKIyA1LiBsb2dpY2FsOiBUUlVFIG8gRkFMU0UKCiMgTGFzIDQgY2xhc2VzIGRlIG9iamV0b3MgY29tcHVlc3RvcyBzb246CiMgMS4gbGlzdDogbGlzdGEgKHVuYSBjb2x1bW5hKQojIDIuIG1hdGl4OiBtYXRyaXogKHZhcmlhcyBjb2x1bW5hcywgdG9kb3MgZWwgbWlzbW8gdGlwbyBkZSBkYXRvcyBbbnVtZXJvcywgbGV0cmFzLCBldGNdKQojIDMuIGFycmF5OiBjb2xlY2Npw7NuIGRlIG9iamV0b3MKIyA0LiBkYXRhLmZyYW1lOiBiYXNlIGRlIGRhdG9zIAoKCmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij40LiDCv0N1w6FudGFzIGNvbHVtbmFzIHkgcmVuZ2xvbmVzIHRpZW5lICJmbGlnaHRzIj8gwr9DdcOhbCBlcyBzdSBkaW1lbnNpw7NuPzwvc3Bhbj4KYGBge3J9CiMgTsO6bWVybyBkZSBjb2x1bW5hcwpuY29sKGZsaWdodHMpCiMgTsO6bWVybyBkZSByZW5nbG9uZXMKbnJvdyhmbGlnaHRzKQojIERpbWVuc2nDs24KZGltKGZsaWdodHMpCmBgYAoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij41LiBNdWVzdHJhIGxvcyBwcmltZXJvcyA2IHJlbmdsb25lcyBkZSAiZmxpZ2h0cyIuIFRhbWJpw6luIGxvcyDDumx0aW1vcyA2Ljwvc3Bhbj4KYGBge3J9CmhlYWQoZmxpZ2h0cykKdGFpbChmbGlnaHRzKQpgYGAKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij42LiBNdWVzdHJhIGxvcyBlc3RhZMOtc3RpY29zIGRlc2NyaXB0aXZvcyBkZSBmbGlnaHRzPC9zcGFuPgpgYGB7cn0Kc3VtbWFyeShmbGlnaHRzKQpgYGAKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5Db25jbHVzacOzbiBhdmFuY2UgMTwvc3Bhbj4KRW4gZXN0ZSB0cmFiYWpvIHB1ZGltb3MgdXRpbGl6YXIgbGFzIGZ1bmNpb25lcyBtw6FzIGNvbXVuZXMgZGVsIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8sIGVsIGN1YWwgZXMgZWwgcHJpbWVyIHBhc28gcGFyYSBjdWFscXVpZXIgdHJhYmFqbyBkZSBtYW5pcHVsYWNpw7NuIGRlIGRhdG9zLiAKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+QXZhbmNlIDI8L3NwYW4+CgpTZSBub3MgaGEgc29saWNpdGFkbyBjb25zdWx0YXIgY3XDoWxlcyBzb24gbGFzIGFlcm9sw61uZWFzIGRlIG1heW9yIHRyw6FmaWNvIGHDqXJlbyBlbiBvcmlnZW4geSBkZXN0aW5vLiAgCkNvbnRhbW9zIGNvbiB1biBkYXRhIGZyYW1lIGxsYW1hZG8gZmxpZ2h0cyBxdWUgY29udGllbmUgdG9kYSBsYSBpbmZvcm1hY2nDs24gZGUgbG9zIHZ1ZWxvcyBkZSB0b2RvcyBsb3MgYWVyb3B1ZXJ0b3MgZGUgTmV3IFlvcmsuCgpgYGB7cn0KYWVyb2xpbmVhcyA8LSB0YWJsZShmbGlnaHRzJGNhcnJpZXIpCmVub3JkZW4gPC0gc29ydChhZXJvbGluZWFzKQplbm9yZGVuCmBgYApEZWZpbmUgdW4gY3JpdGVyaW8gcGFyYSBlbmNvbnRyYXIgbGFzIGFlcm9sw61uZWFzIHF1ZSBoYW4gcmVjb3JyaWRvIG3DoXMgZGlzdGFuY2lhIChlbiBtaWxsYXMpIHkKY3JlYSB1biBudWV2byBkYXRhIGZyYW1lIHF1ZSBmaWx0cmUgc29sYW1lbnRlIGEgbGFzIGFlb3Jsw61uZWFzIHF1ZSBoYW4gcmVjb3JyaWRvIHVuYSBkaXN0YW5jaWEKc3VwZXJpb3IgYSBsYSBtZWRpYSwgc2UgZGVzZWFuIHZlciBsb3MgY2FtcG9zIGNhcnJpZXIsIGRpc3RhbmNlLCBvcmlnaW4sIGRlc3QgZW4gZm9ybWEKZGVzY2VuZGVudGUgcG9yIGRpc3RhbmNlLgoKYGBge3J9CnByb21lZGlvIDwtIG1lYW4oZmxpZ2h0cyRkaXN0YW5jZSkKcHJvbWVkaW8KCmRmIDwtIGZsaWdodHMKZGYgPC0gZmxpZ2h0cyAlPiUgZmlsdGVyKGRpc3RhbmNlID49IHByb21lZGlvKQoKZGZhZXJvbGluZWFzIDwtIHRhYmxlKGRmJGNhcnJpZXIpCiNkZm9yZGVuIHRpZW5lIGEgZGYgZW4gb3JkZW4gZGVzY2VuZGllbnRlCgpkZm9yZGVuIDwtIHNvcnQoZGZhZXJvbGluZWFzKQpkZm9yZGVuCgp2aWV3KGRmb3JkZW4pCmBgYAoKQWhvcmEsIHVzYW5kbyBzb2xhbWVudGUgbGFzIHRvcCA1IGFlcm9saW5lYXMgY29uIG3DoXMgdnVlbG9zIGFycmliYSBkZSBsYSBtZWRpYSwgZW5jb250cmFyZW1vcyBkZSBxdcOpIGFlcm9wdWVydG9zIHNhbGllcm9uIGxvcyB2dWVsb3MgbGFyZ29zIHkgY29uIHF1w6kgYWVyb2xpbmVhcwoKYGBge3J9CnJlc3VtZW5fYWVyb2xpbmVhcyA8LSBkZiAlPiUgZmlsdGVyKG9yaWdpbiA9PSAiSkZLIikgJT4lICBncm91cF9ieShjYXJyaWVyKSAlPiUgIHN1bW1hcmlzZShkaXN0YW5jaWFfcHJvbWVkaW8gPSBtZWFuKGRpc3RhbmNlLCBuYS5ybSA9IFRSVUUpKSAlPiUgIGFycmFuZ2UoZGVzYyhkaXN0YW5jaWFfcHJvbWVkaW8pKSAKYGBgCgoKQ29uIGVzdG9zIGRhdG9zLCBwb2RlbW9zIHZlciBxdWUgSGF3YWlpYW4gQWlybGluZXMgdGllbmUgbG9zIHZ1ZWxvcyBjb24gbcOhcyBkaXN0YW5jaWEgKipwcm9tZWRpbyoqIGZ1ZXJhIGRlIHRvZGFzIGxhcyBhZXJvbMOtbmVhcy4gRXN0byBzaWVuZG8gZGViaWRvIHByb2JhYmxlbWVudGUgYSBxdWUgSEEgdmlhamEgbXVjaG8gaWRhIHkgdnVlbHRhIGEgbGFzIGlzbGFzIGRlIEhhd2FpaSwgbGFzIGN1YWxlcyBlc3TDoW4gbXV5IGxlam9zLiBMYSBkaXN0YW5jaWEgcHJvbWVkaW8gZGUgdW4gdnVlbG8gZGUgSEEgZnVlIGRlIDQ5ODMgbWlsbGFzLiAgCgpJZGVudGlmaWNhIHNpIGxhcyBhZXJvbMOtbmVhcyBsw61kZXJlcyBzb24gbGFzIG1pc21hcyBlbiBsb3MgdHJlcyBhZXJvcHVlcnRvcyBjdXlvIG9yaWdlbiBlcyBOdWV2YSBZb3JrICggSm9obiBGLiBLZW5uZWR5IChKRkspLCBMYUd1YXJkaWEgKExHQSkgYW5kIE5ld2FyayBMaWJlcnR5IChFV1IpICkuIEdlbmVyYSB1biBkYXRhIGZyYW1lIHBhcmEgY2FkYSBhZXJvcHVlcnRvLgpGdW5jaW9uZXM6IGZpbHRlciwgc2VsZWN0IHkgcmVuYW1lICAKCmBgYHtyfQpqZmsgPC0gZmxpZ2h0cyAlPiUgZmlsdGVyKG9yaWdpbj09IkpGSyIpICU+JSBncm91cF9ieShjYXJyaWVyKSAlPiUgc3VtbWFyaXplKG51bV92dWVsb3MgPSBuKCkpCmxnYSA8LSBmbGlnaHRzICU+JSBmaWx0ZXIob3JpZ2luPT0iTEdBIikgJT4lIGdyb3VwX2J5KGNhcnJpZXIpICU+JSBzdW1tYXJpemUobnVtX3Z1ZWxvcyA9IG4oKSkKZXdyIDwtIGZsaWdodHMgJT4lIGZpbHRlcihvcmlnaW49PSJFV1IiKSAlPiUgZ3JvdXBfYnkoY2FycmllcikgJT4lIHN1bW1hcml6ZShudW1fdnVlbG9zID0gbigpKQoKYGBgCgoKCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkF2YW5jZSAzPC9zcGFuPgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5EZXNjcmlwY2nDs248L3NwYW4+CgpTZSBub3MgaGEgc29saWNpdGFkbyBoYWNlciB1biBlc3R1ZGlvIHNvYnJlIGxhIHNpdHVhY2nDs24gYWN0dWFsIGRlIGxhIGFlcm9sw61uZWEgKipBbWVyaWNhbgpBaXJsaW5lcyoqIHlhIHF1ZSBzZSBuZWNlc2l0YSByZXZpc2FyIHN1cyBkZXN0aW5vcywgaG9yYXJpb3MgeSBhdmlvbmVzIGNvbiBsb3MgcXVlIGN1ZW50YSBwYXJhCmhhY2VyIHByb3B1ZXN0YXMgZGUgYXVtZW50byBvIHJlZHVjY2nDs24gZGUgdnVlbG9zIHBvciBkZXN0aW5vIHkgaG9yYXJpb3MsIGFzw60gY29tbyBsYQpjYW50aWRhZCBkZSBhdmlvbmVzLgpQYXJhIGVsIGRlc2Fycm9sbG8gZGUgbGEgc2l0dWFjacOzbiBwcm9ibGVtYSBjb25zaWRlcmEgbGFzIGZ1bmNpb25lcyBzdWdlcmlkYXMgZW4gY2FkYSBwYXNvLgpDb25zdWx0YSB5IGV4cGxvcmEgZWwgZGF0YSBmcmFtZSBwbGFuZXMgeSB3ZWF0aGVyIHBhcmEgcXVlIGNvbm96Y2FzIHN1IGNvbnRlbmlkby4KCmBgYHtyfQoKdnVlbG9zdG9kb3MgPC0gbWVyZ2UoZmxpZ2h0cywgcGxhbmVzLCBieT0idGFpbG51bSIpCnZ1ZWxvc0FBIDwtIHZ1ZWxvc3RvZG9zICU+JSBmaWx0ZXIoY2FycmllciA9PSJBQSIpCkFBIDwtIHZ1ZWxvc0FBICU+JSBzZWxlY3QoY2FycmllcikKdnVlbG9zQUFmaWx0cmFkb3M8LSB2dWVsb3NBQSU+JSBzZWxlY3Qob3JpZ2luOmRlc3QpCnZ1ZWxvc3RvZG9zIDwtIGxlZnRfam9pbihmbGlnaHRzLCBhaXJsaW5lcywgYnk9ImNhcnJpZXIiKQoKYGBgCkNvbiBlc2FzIHRyZXMgZnVuY2lvbmVzLCBsb2dyYW1vczoKMS4gSGFjZXIgdW5hIGJhc2UgZGUgZGF0b3MgZGUgbmFkYSBtw6FzIGxhIGZpbGEgZGUgQUEuICAKMi4gKk1lcmdlKiB0b2RvcyBsb3MgdnVlbG9zIGRlIGxhIGJhc2UgZGUgZGF0b3MgKmZsaWdodHMqIGNvbiBsYSBiYXNlIGRlIGRhdG9zICpwbGFuZXMqICAKMy4gRmlsdHJhciBlc2EgYmFzZSBkZSBkYXRvcyBudWV2YSBwYXJhIGVuY29udHJhciBzb2xhbWVudGUgbG9zIHZ1ZWxvcyBkZSBBQS4gIAo0LiBEZSBlc29zIHZ1ZWxvcywgc2VsZWNjaW9uYXIgc29sYW1lbnRlIGxhcyBjb2x1bW5hcyBkZSBvcmlnZW4geSBkZXN0aW5vLgoKYGBge3J9CmNvdW50b3JpZ2luZmVvQUEgPC0gY291bnQodnVlbG9zQUFmaWx0cmFkb3Msb3JpZ2luLCBuYW1lPSJDYW50aWRhZCBkZSB2dWVsb3MiKQpjb3VudF9vcmlnaW5BQSA8LSBhcnJhbmdlKGNvdW50b3JpZ2luZmVvQUEsIGRlc2MoIkNhbnRpZGFkIGRlIHZ1ZWxvcyIpKQpgYGAKYGBge3J9CmNvdW50b3JpZ2luZmVvcyA8LSBjb3VudCh2dWVsb3N0b2RvcyxvcmlnaW4sIG5hbWU9IkNhbnRpZGFkIGRlIHZ1ZWxvcyIpCmNvdW50X29yaWdpbl9UT0RPUyA8LSBhcnJhbmdlKGNvdW50b3JpZ2luZmVvcywgZGVzYygiQ2FudGlkYWQgZGUgdnVlbG9zIikpCmBgYAoKQ29uIHVuYSBmdW5jacOzbiBkZSBjb3VudCgpLCBlbmNvbnRyYW1vcyBxdWUgbG9zIHZ1ZWxvcyBkZSBBQSBjb25zaXN0ZW4gZGUgMTE0NSB2dWVsb3Mgc2FsaWVuZG8gZGUgRVdSLCA1NTAwIHNhbGllbmRvIGRlIEpGSywgeSAzNTI2IHNhbGllbmRvIGRlIExHQS4gCgpgYGB7cn0KY291bnRkZXN0ZmVvQUE8LSBjb3VudCh2dWVsb3NBQWZpbHRyYWRvcyxvcmlnaW4sZGVzdCwgbmFtZSA9IkNhbnRpZGFkIGRlIHZ1ZWxvcyIpCmNvdW50X2Rlc3RBQSA8LSBhcnJhbmdlKGNvdW50ZGVzdGZlb0FBLGRlc2MoIkNhbnRpZGFkIGRlIHZ1ZWxvcyIpKQpgYGAKYGBge3J9CmNvdW50ZGVzdGZlb3MgPC0gY291bnQodnVlbG9zdG9kb3Msb3JpZ2luLGRlc3QsIG5hbWUgPSJDYW50aWRhZCBkZSB2dWVsb3MiKQpjb3VudF9kZXN0X1RPRE9TIDwtIGFycmFuZ2UoY291bnRkZXN0ZmVvcyxkZXNjKCJDYW50aWRhZCBkZSB2dWVsb3MiKSkKYGBgCgpBbCBjb3JyZXIgbGEgZnVuY2lvbiBjb3VudCgpIGRlIGFycmliYSwgZW5jb250cmFtb3MgbG9zIGRlc3Rpbm9zIGRlIGxvcyB2dWVsb3MgQUEuIEVsIGZhdm9yaXRvIGRlc3Rpbm8gZGUgQUEgZXMgTG9zIEFuZ2VsZXMgKExBWCwgMzE3OCksIGx1ZWdvIENoaWNhZ28gTydIYXJlIChPUkQsIDI1MDApLCBsdWVnbyBEYWxsYXMgRm9ydCBXb3J0aCAoREZXLCAxNjEzKSwgZXRjLi4uCgpTZSBuZWNlc2l0YSBjb25vY2VyIGxhcyBhZXJvbMOtbmVhcyAoY2xhdmUgeSBub21icmUpIHkgZGVzdGlub3MgcXVlIHZ1ZWxhbiBwb3IgbGEgTWHDsWFuYTogZGUgNgphIDEyLCBUYXJkZTogZGUgMTIgYSAxOSAsIE5vY2hlOiBkZSAxOSBhIDI0IHkgTWFkcnVnYWRhIGRlIDI0IGEgNi4KCmBgYHtyfQptYcOxYW5hIDwtIHZ1ZWxvc3RvZG9zICU+JSBmaWx0ZXIoaG91ciA+PSA2ICYgaG91ciA8PSAxMikKdGFyZGUgPC0gdnVlbG9zdG9kb3MgJT4lIGZpbHRlcihob3VyID4gMTIgJiBob3VyIDw9IDE5KQpub2NoZSA8LSB2dWVsb3N0b2RvcyAlPiUgZmlsdGVyKGhvdXIgPj0gMTkgJiBob3VyIDw9IDI0KQptYWRydWdhZGEgPC0gdnVlbG9zdG9kb3MgJT4lIGZpbHRlcihob3VyID4gMCAmIGhvdXIgPCA2KQoKdnVlbG9zbWHDsWFuYSA8LSBtYcOxYW5hICU+JSBzZWxlY3QoeWVhcjpkYXksaG91cixtaW51dGUsY2FycmllcixuYW1lLGRlc3QpCnZ1ZWxvc3RhcmRlIDwtIHRhcmRlICU+JSBzZWxlY3QoeWVhcjpkYXksaG91cixtaW51dGUsY2FycmllcixuYW1lLGRlc3QpCnZ1ZWxvc25vY2hlIDwtIG5vY2hlICU+JSBzZWxlY3QoeWVhcjpkYXksaG91cixtaW51dGUsY2FycmllcixuYW1lLGRlc3QpCnZ1ZWxvc21hZHJ1Z2FkYSA8LSBtYWRydWdhZGEgJT4lIHNlbGVjdCh5ZWFyOmRheSxob3VyLG1pbnV0ZSxjYXJyaWVyLG5hbWUsZGVzdCkKYGBgCkFxdcOtIHNlIGNvbnN0cnV5ZXJvbiBiYXNlcyBkZSBkYXRvcyBudWV2YXMgKnNlbGVjY2lvbmFuZG8qIHNvbGFtZW50ZSBhcXVlbGxvcyBkYXRvcyBuZWNlc2FyaW9zIGRlIGxhIGJhc2UgZGUgZGF0b3MgInZ1ZWxvc3RvZG9zIiBxdWUgc2UgdXNhIG3Dumx0aXBsZXMgdmVjZXMgZW4gbWkgdHJhYmFqby4gCgpBZ3JlZ2EgdW4gbnVldm8gY2FtcG8gYSBsYSB0YWJsYSBjb24gZWwgbm9tYnJlIGRlIGNsYXNfaG9yYXJpbyB5IGFncmVnYSAibWHDsWFuYSIsICJ0YXJkZSIsICJub2NoZSIsICJtYWRydWdhZGEiIHNlZ8O6biBsbyBxdWUgY29ycmVzcG9uZGUuIApgYGB7cn0KdnVlbG9zdG9kb3MgPC0gdnVlbG9zdG9kb3MgJT4lIG11dGF0ZShjbGFzX2hvcmFyaW8gPSBpZmVsc2UoaG91ciA+PSA2ICYgaG91ciA8MTIsICJtYcOxYW5hIiwgaWZlbHNlKGhvdXIgPj0gMTIgJiBob3VyIDwxOSwgInRhcmRlIiwgaWZlbHNlKGhvdXIgPj0gMTkgJiBob3VyIDwyMywgIm5vY2hlIixpZmVsc2UoaG91ciA+PSAwICYgaG91ciA8NiwgIm1hZHJ1Z2FkYSIsTkEpKSkpKQpgYGAKTGEgYmFzZSBkZSBkYXRvcyAidnVlbG9zdG9kb3MiIGNvbnRpZW5lIGxhIGNvbHVtbmEgZGUgbGEgY2xhc2UgZGUgaG9yYXJpbyBlbiBlbCBxdWUgdm9sYXJvbiBsb3MgYXZpb25lcy4gVXNlIGVzdGEgYmFzZSBkZSBkYXRvcyBtw6FzIGFkZWxhbnRlIHBhcmEgZW5jb250cmFyIGN1YW50b3MgdnVlbG9zIHZvbGFiYSBjYWRhIGFlcm9sw61uZWEgcG9yIGRlc3Rpbm8uIEF1biBxdWUgbm8gc8OpIHNpIGVzIGxhIG1hbmVyYSBtw6FzIGVmaWNpZW50ZSwgdXNlICppZmVsc2UqIHVubyAiYWRlbnRybyIgZGVsIG90cm8gcGFyYSBpciBkZWR1Y2llbmRvIGVuIGRvbmRlIGRlYmVuIGRlICphY3R1YXIqLiBDb24gZXN0ZSBtw6l0b2RvLCBsb2dyYW1vcyBhw7FhZGlyIGxhIGNvbHVtbmEgZGUgY2xhc19ob3JhcmlvLgoKU2UgbmVjZXNpdGEgc2FiZXIgbGEgY2FudGlkYWQgZGUgdnVlbG9zIHBvciBhZXJvbMOtbmVhIHkgZGVzdGlubyBxdWUgaGF5IHBvciBsYSBNYcOxYW5hLCBUYXJkZSwKTm9jaGUgeSBNYWRydWdhZGEKYGBge3J9CmNsYXNpZmljYWNpb252dWVsb3MgPC0gdnVlbG9zdG9kb3MgJT4lIGNvdW50KG5hbWUsIGRlc3QsIGNsYXNfaG9yYXJpbywgbmFtZSA9IkNhbnRpZGFkIGRlIHZ1ZWxvcyIpCmNsYXNpZmljYWNpb252dWVsb3MgPC0gY2xhc2lmaWNhY2lvbnZ1ZWxvcyAlPiUgYXJyYW5nZShkZXNjKCJDYW50aWRhZCBkZSB2dWVsb3MiKSkKYGBgCmxhIGJhc2UgZGUgZGF0b3MgImNsYXNpZmljYWNpb252dWVsb3MiIGNvbnRpZW5lIHRvZG9zIGxvcyB2dWVsb3MgcXVlIHNhbGllcm9uIGRlIGFsZ8O6biBhZXJvcHVlcnRvIGRlIE51ZXZhIFlvcmsuIEVzdMOhbiBvcmdhbml6YWRvcyBhbGZhYsOpdGljYW1lbnRlIHBvciBsYXMgYWVyb2zDrW5lYXMuICAKClNlIG5lY2VzaXRhIHNhYmVyIGEgcXXDqSBkZXN0aW5vcyB2dWVsYSBsYSBhZXJvbMOtbmVhIEFtZXJpY2FuIEFpcmxpbmVzIEluYy4gKEFBKSBkdXJhbnRlIGxhIG1hZHJ1Z2FkYQpgYGB7cn0KQUFtYcOxYW5hIDwtIGNsYXNpZmljYWNpb252dWVsb3MgJT4lIGZpbHRlcihuYW1lID09IkFtZXJpY2FuIEFpcmxpbmVzIEluYy4iLCBjbGFzX2hvcmFyaW8gPT0gIm1hZHJ1Z2FkYSIpCmBgYApFbCDDum5pY28gZGVzdGlubyBxdWUgdm9sw7MgQW1lcmljYW4gQWlybGluZXMgZGVzZGUgYWxndW5vIGRlIGxvcyBhZXJvcHVlcnRvcyBkZSBOWUMgZnVlIGEgTWlhbWkgKFNlZ3VybyBtdWNoYSBmaWVzdGEpICAKCsK/UXXDqSBhdmlvbmVzIHV0aWxpemEgbGEgYWVyb2zDrW5lYSBBQT8gYWVyb2zDrW5lYSwgdGlwbywgbW90b3IgeSBuw7ptZXJvIGRlIGFzaWVudG9zIHkgwr9DdcOhbnRvcwp2dWVsb3Mgc2UgaGFuIHJlYWxpemFkbyBjb24gY2FkYSB1bm8/IGVsaW1pbmEgbG9zIE5BJ3MKYGBge3J9CmF2aW9uZXNfQUEgPC0gbGVmdF9qb2luKHZ1ZWxvc0FBLCBwbGFuZXMsIGJ5PSJ0YWlsbnVtIikKdnVlbG9zeGF2aW9uIDwtIGF2aW9uZXNfQUEgJT4lIGZpbHRlcighaXMubmEodHlwZS54KSkgJT4lIGNvdW50KHR5cGUueCwgbmFtZT0iQ2FudGlkYWQgZGUgdnVlbG9zIikKYGBgCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+Q29uY2x1c2lvbmVzIEZpbmFsZXM8L3NwYW4+CkNvbiB1bmEgYmFzZSBkZSBkYXRvcyB0YW4gZXh0ZW5zYSBjb21vIGxvIGVzICIqbnljZmxpZ2h0czEzKiIsIHBvZGVtb3MgZXh0cmFlciBtdWNoYSBpbmZvcm1hY2nDs24gbm8gc29sbyBkZSBsYXMgYWVyb2zDrW5lYXMgeSBzdXMgYXZpb25lcywgc2lubyBsb3MgdnVlbG9zIHF1ZSBoYWNlbiwgbGEgZGlzdGFuY2lhLCBlbCB0aWVtcG8sIGVsIHRpcG8gZGUgYXZpw7NuIHF1ZSB1dGlsaXphbiwgZXRjLiBDb24gZXN0ZSBlamVyY2ljaW8sIGxvZ3JhbW9zIGRlZmluaXIgYWxndW5vcyBoYWxsYXpnb3MgcXVlIHBhcmVjZW4gaW1wb3J0YW50ZXMgcGFyYSBleHBhbmRpciBudWVzdHJvIGNvbm9jaW1pZW50byBkZSBsb3MgdnVlbG9zIHkgYWVyb3B1ZXJ0b3MgZGUgTnVldmEgWW9yaywgeWEgc2VhIExhIEd1YXJkaWEgKExHQSksIEpvaG4gRi4gS2VubmVkeSAoSkZLKSwgbyBOZXdhcmsgTGliZXJ0eSAoRVdSKS4gCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5IYWxsYXpnb3M8L3NwYW4+CjEuIExvcyB2dWVsb3MgcXVlIHZvbGFyb24gbcOhcyBzZWd1aWRvIGZ1ZXJvbjogSkZLIGEgTEFYICgxMTI2MiB2ZWNlcyBhbCBhw7FvLCAzMSB2ZWNlcyBhbCBkw61hKSwgTEdBIGEgQVRMICgxMDI2MyB2ZWNlcyBhbCBhw7FvLCAyOSB2ZWNlcyBhbCBkw61hKSwgeSBMR0EgYSBPUkQgKDg4NTcgdmVjZXMgYWwgYcOxbywgMjQuNiB2ZWNlcyBhbCBkw61hKSAgCgoyLiBMYXMgYWVyb2zDrW5lYXMgY29uIG1heW9yIGRpc3RhbmNpYSBwcm9tZWRpbyBmdWVyb24gSGF3YWlpYW4gQWlybGluZXMgKDQ5ODMgbWlsbGFzKSwgVW5pdGVkIEFpcmxpbmVzICgyNTM1IG1pbGxhcyksIHkgVmlyZ2luIEFtZXJpY2EgKDI0OTUgbWlsbGFzKSAgCgozLiBDdXJpb3NhbWVudGUsIG5vIGFwYXJlY2VuIHZ1ZWxvcyBxdWUgZGVzcGVndWVuIGVudHJlIDFhLm0geSA1YS5tLCB5YSBxdWUgbG9zIHByaW1lcm9zIGRhdG9zIGRlbCBkw61hLCBwb3IgYXPDrSBkZWNpcmxvLCBlbXBpZXphbiBhbGFzIDVhLm0gIAoKNC4gQUEgdXRpbGl6w7MgMyBkaWZlcmVudGVzIHRpcG9zIGRlIGF2aW9uZXMgcGFyYSBsbGV2YXIgYSBjYWJvcyBzdXMgdHJhc2xhZG9zLiBFc3RvcyBzaWVuZG8gKiJGaXhlZCB3aW5nIG11bHRpIGVuZ2luZSIqICg5MzE4IHZ1ZWxvcykgKiJGaXhlZCB3aW5nIHNpbmdsZSBlbmdpbmUiKiAoNzI5KSB5ICoiUm90b3JjcmFmdCIqICgxMjQpIEVsIHByaW1lcm8sIGVsICIqRml4ZWQgd2luZyBtdWx0aSBlbmdpbmUqIiBlcyBlbCBhdmnDs24gdMOtcGljbyBxdWUgdGUgaW1hZ2luYXMuIFlhIHNlYSB1biBBaXJidXMsIEJvZWluZywgZXRjLiBFbCAqc2luZ2xlIGVuZ2luZSogc29uIG11Y2hvIG3DoXMgcGVxdWXDsW9zLCBwdWVzIGFndWFudGEgbXVjaG8gbWVub3MgY2FyZ2EuIEZpbmFsbWVudGUsIGxvcyAqUm90b3JjcmFmdCosIHNvbiBhcXVlbGxvcyBxdWUgcGFyZWNlbiBoZWxpY8OzcHRlcm9zIChtaXJhciBpbWFnZW4pICAKCkF1bnF1ZSBwb3Igc8OtIG1pc21vcyBlc3RvcyBkYXRvcyBubyBwYXJlemNhbiBtdXkgaW1wb3J0YW50ZXMsIHNlIHB1ZWRlbiB1dGlsaXphciBwYXJhIGlkZW50aWZpY2FyIHByb2JsZW1hcyBxdWUgcHVlZGVuIGNhdXNhciB1bmEgcMOpcmRpZGEgZGUgZGluZXJvIGVuIGFsZ8O6biBmdXR1cm8uIEVzdGUgdHJhYmFqbyBtZSBheXVkw7MgYSBpbXBsZW1lbnRhciB0b2RvcyBsb3MgYXByZW5kaXphamVzIHF1ZSBtZSBsbGV2w6kgZGUgbWkgY2xhc2UgZGUgTWFuaXB1bGFjacOzbiBkZSBEYXRvcywgeSBhaG9yYSBwdWVkbyBpbXBsaW1lbnRhciBlc3RvcyBhcHJlbmRpemFqZXMgZW4gcHJveWVjdG9zIHBlcnNvbmFsZXMgeS9vIHByb2Zlc2lvbmFsZXMuIAoKIVtdKC9Vc2Vycy9mZWRlem9ycmlsbGEvRGVza3RvcC9SIE1hcmtkb3duLzV2MXl4d2Q2Y3RfNzFvaGZqa2ptel92YzAyMDkyMC5wbmcpCiFbXSgvVXNlcnMvZmVkZXpvcnJpbGxhL0Rlc2t0b3AvUiBNYXJrZG93bi9BMzQwLTIwMC5wbmcpCiFbXSgvVXNlcnMvZmVkZXpvcnJpbGxhL0Rlc2t0b3AvUiBNYXJrZG93bi9wMjAxMF9vYmxpcXVlLTEtMTUzNng2NzItMS0xMDI0eDQ0OC5wbmcpCgoKCgoKCgoKCg==