Contexto

El paquete nycflights13 contiene información sore todos los vueles que partieron desde Nueva York(EWR, JFL, LGA) en destinos a 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 el 2013
  • weather = datos metereológicos por hora de cada aeropuerto
  • planes = información de construcción de cada avión
  • airports = nombres y ublicaciones de aeropuertos
  • airlines = relación entre nombres y códigos de las aerolíneas

Fuente: Origen de los datos

Reporte Ejecutivo

En esta evidencia se trabajó con el paquete nycflights, el cuál nos permitió analizar información acerca de los vuelos, destinos, aerolíneas, retrasos entre otros, registrados en los aeropuertos de Nueva York en el 2013. Se utilizaron las funciones más comunes del análisis exploratorio, el cual es el primer paso para cualquier trabajo de manipulación de datos.

La situación problema que se buscaba resolver es saber el por qué los vuelos se retrasan, ya sea en la partida o en la llegada, en los aeropuertos en Nueva York. Con la información brindada en las bases de datos, se pudo realizar un análisis tomando en cuenta diferentes variables, ya sea el clima, el tipo de avión que se utilizaba, la aerolínea, el día de la semana, las temporadas vacacionales e incluso hasta el horario del día. Al analizar esta información se obtuvieron datos, que nos permitirían evaluar cuál es el verdadero motivo por el cual los vuelos se retrasan.

Para este proyecto se utilizaron diferentes paquetes y librerías,

Instalar paquetes y llamar librerías

#install.packages("nycflight13")
library(nycflights13)
#install.packages("tidyverse")
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
#install.packages("dplyr")
library(dplyr)
#install.packages("ggplot2")
library(ggplot2)
data("flights")

Guardar base de datos

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

Relación entre las bases de datos

Relación existente

df <- merge(flights,airlines, by="carrier")
df <- left_join(df,planes, by="tailnum")
df <- left_join(df,weather, by=c("origin","time_hour"))

Data Wrangling

1. Funciones básicas de manejo de datos

Select

La función select sirve para seleccionar columnos de un table (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: -flight) # Eliminar rango de columnas
df5 <- flights %>% select(aerolinea = carrier) # Selecciona una columna y le cambia el nombre
df6 <- flights %>% rename(aerolinea = carrier) # Cambia el nombre de una columna

Filter

La función Filter sirve para seleccionar renglones de un 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 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 caluladas a partir de variables existentes en la base de datos.

Ejercicios

  1. Encuentra todos los vuelos que tuvieron un atraso en llegada de 2 horas o más.
ejercicio1 <- bdgrande2 %>% filter(arr_delay>=120)
  1. Encuentra todos los vuelos que llegaron a Houston (IAN O HOU)
ejercicio2 <- bdgrande2 %>% filter(dest== "IAH" | dest == "HOU")
  1. Encuentra todos los vuelos operados por United, American o Delta.
ejercicio3 <- bdgrande2 %>% filter(carrier %in% c("UA", "AA", "DL"))
  1. Encuentra todos los vuelos que despegaron en Julio, Agosto o Septiembre
ejercicio4 <- bdgrande2 %>% filter(month %in% c(7, 8, 9))
ejercicio4a <- bdgrande2 %>% filter(month == 7 | month == 8 | month == 9) 
  1. Encuentra todos los vuelos que arrivaron más de 2 horas tarde, pero no despegaron tarde.
ejercicio5 <- bdgrande2 %>% filter(arr_delay>120 & dep_time == sched_dep_time)
ejercicio5a <- bdgrande2 %>% filter(arr_delay>120 & dep_delay<=0)
  1. 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)
  1. Encuentra todos los vuelos que salieron entre la medianoche y las 6 a.m.
ejercicio7 <- bdgrande2 %>% filter(dep_time %in% c("2400", "100", "200", "300", "400", "500", "600"))
ejercicio7a <- bdgrande2 %>% filter(dep_time==2400 | dep_time<=600) #CORRECTA
ejercicio7b <- bdgrande2 %>% filter(hour %in% c("0", "1", "2", "3", "4", "5", "6"))

Arrange

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

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

Para acomodar de mayor a menor.

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

Summarize

Colapsa una tabla a un sólo renglón

# Obtén el retraso promedio de salida 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

Evidencia: Parte 1

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

# La carga a memoria se hizo en el paso anterior, consulta de dataframe para recordar su contenido.
view(flights)

2. Datos descriptivos de “flights”

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

3. Criterios para encontrar aerolíneas

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

#Criterio 1: se selecciona las variables.
Criterio1 <- flights %>% select(carrier, distance, origin, dest)

#Criterio 2: se filtran a las aerolineas que tengan una media superior a 1040 en millas recorridas. 
Criterio2 <- Criterio1 %>% filter(distance >1040)

#Criterio 3: se ordena en descendente por la distancia recorrida 
Criterio3 <- Criterio2 %>% arrange(desc(distance))

4. Suma y Media de las distancias recorridas

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

Criterio4 <- Criterio3 %>% group_by(carrier,origin,dest) %>%  
  summarize(distancesuma=sum(distance, na.rm=TRUE), distancepromedio=mean(distance, na.rm=TRUE))
## `summarise()` has grouped output by 'carrier', 'origin'. You can override using
## the `.groups` argument.
# Posteriormente, se ordena de forma descendente en base a la distancia recorrida.
Descendente <- Criterio4 %>% arrange(carrier,distancesuma)

5. Interpretaciones: Parte 1

Aquí se escribe la interpretación…..

6. Identificar aerolíneas líderes en los aeropuertos

#En esta parte se identifica si las aerolíneas líderes son las mismas en los tres aeropuertos cuyo origen es Nueva York ya sea el John F. Kennedy (JFK), el de LaGuardia (LGA) o el de Newark Liberty (EWR). Se genera un dataframe para cada aeropuerto.

Aeropuerto_JFK = Descendente %>% filter(origin == "JFK")  %>% arrange(carrier, desc(distancesuma))
Aeropuerto_LGA = Descendente %>% filter(origin == "LGA")  %>% arrange(carrier, desc(distancesuma))
Aeropuerto_EWR = Descendente %>% filter(origin == "EWR")  %>% arrange(carrier, desc(distancesuma))

7. Conclusión: Parte 1

Aquí se escribe la conclusión de la parte 1 de la evidencia

Evidencia: Parte 2

1. Consulta del dataframe

#Al consultar/llamar el DataFrame nos permite visualizar la base de datos *flights*.
view(flights)

2. Información de cada vuelo

#Se necesita saber de cada vuelo, la aerolínea, el aeropuerto de origen y el aeropuerto destino
vuelos <- flights %>% select(carrier, origin, dest)

#De la consulta anterior se requiere saber el nombre de la aerolínea
aerolínea <- vuelos %>% left_join (airlines, by = "carrier")

3. Cantidad de vuelos por destino

#De la consulta anterior se requiere saber el nombre de la aerolínea (FALTA)

#destnom <- mutate(vuelos_cantidad, airlines)
summary_delay <- df %>%
  group_by(dest) %>%
  summarise(avg_delay = mean(dep_delay, na.rm = TRUE),
            total_flights = n(),
            total_delayed_flights = sum(dep_delay > 0, na.rm = TRUE),
            perc_delayed_flights = total_delayed_flights / total_flights * 100)

4. Aerolíneas y Destinos: Mañana, Tarde, Noche y Madrugada

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

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

turno_MTNM<- mutate(turno_carrier, 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"))))

5. Cantidad de vuelos: Mañana, Tarde y Noche

#Se presenta la cantidad de vuelos por aerolínea y destino que hay en cada turno, ya sea en la mañana, tarde, noche o madrugada.

cantidad_turno_MTNM <- turno_MTNM %>% group_by(carrier, dest, clas_horario) %>% count()

6. Destinos a los que vuela American Airlines en Madrugada

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

7. Aviones que utiliza American Airlines

#Se presenta la aerolínea, tipo, motor, número de asientos y la cantidad de vuelos que se han realizado con cada uno de los aviones.
AA_aviones <- flights %>% left_join(planes, by = "tailnum") %>% select(carrier, type, engine, seats) %>% filter(carrier == "AA", !is.na(type)) %>% group_by(carrier,type,engine,seats) %>% count()

8. Interpretaciones: Parte 2

Aquí se escribe la interpretación…..

9. Visualización de Datos

Visualizaciones de la aerolínea American Airlines para los ejecutivos con las siguientes características. Dentro de las aerolíneas el retraso tanto en la hora de partida como en la hora de llegada a su destino van generando indicadores negativos.

Vuelos con retraso en ida y regreso

#Vuelos de American Airlines que si tienen retraso en la partida también tienen retraso en la hora de llegada.

vuelos_aa <- flights %>% filter(carrier == "AA")
retrasopartida <- mutate(vuelos_aa, dep_delay = dep_time - sched_dep_time)
retrasollegada <- mutate(vuelos_aa, arr_delay = arr_time - sched_arr_time)
partidaAAretrasos <- filter(retrasollegada, dep_delay > 0)
llegadaAAretrasos <- filter(retrasollegada, arr_delay > 0)
AAretrasos_lp <- intersect(partidaAAretrasos, llegadaAAretrasos)
ggplot(AAretrasos_lp, aes(x = dep_delay, y = arr_delay)) +
  geom_point() +
  labs(x = "Retraso en la partida)", y = "Retraso en la llegada") +
  theme_void()

Tendencia de la temperatura

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

EWRenero15 <- weather %>% filter(origin == "EWR", month == 1, day <= 15)
EWRenero15Temp <- select(EWRenero15, day, temp)

EWRenero15TempProm <- EWRenero15Temp %>% group_by(day) %>% summarise(promediotemp = mean(temp, na.rm=TRUE))

ggplot(EWRenero15TempProm, aes(x = day, y = promediotemp)) +
  geom_line() +
  labs(x = "Dia", y = "Temperatura (°C)") +
  theme_void()

Temperatura más frecuente en celsius

#Visualiza la temperatura más frecuente en los primeros 15 días del mes de Enero, utilizar un histrograma.
datos_enero <- df %>%
  filter(month.x == 1, day.x <= 15)

#FALTA CONVERTIR A CELSIUS
datos_enero_celsius <- mutate(datos_enero, celsius=(temp-32)*(5/9))


# Crear el histograma de temperatura
ggplot(datos_enero, aes(x = temp)) +
  geom_histogram(binwidth = 5, color = "white", fill = "skyblue") +
  labs(title = "Histograma de Temperatura en los Primeros 15 Dias de Enero",
       x = "Temperatura", y = "Frecuencia") +
  theme_minimal()
## Warning: Removed 52 rows containing non-finite outside the scale range
## (`stat_bin()`).

datos_enero <- df %>%
  filter(month.x == 1, day.x <= 15)

#CONVERTIR A CELSIUS
datos_enero_celsius <- mutate(datos_enero, celsius=(temp-32)*(5/9))

# Crear el histograma de temperatura
ggplot(datos_enero_celsius, aes(x = celsius)) +
  geom_histogram(binwidth = 5, color = "white", fill = "skyblue") +
  labs(title = "Histograma de Temperatura en los Primeros 15 Dias de Enero",
       x = "Temperatura (°C)", y = "Frecuencia") +
  theme_minimal()
## Warning: Removed 52 rows containing non-finite outside the scale range
## (`stat_bin()`).

Facets

#Utiliza Facets para observar cómo varía la temperatura en cada mes en él histograma del punto anterior
datos <- df %>%
  select(month.x, temp)

#FALTA CONVERTIR A CELSIUS

ggplot(datos, aes(x = temp)) +
  geom_histogram(binwidth = 3, color = "white", fill = "skyblue") +
  facet_wrap(~month.x, nrow = 3) +  # Facetar por mes, con 3 paneles por fila
  labs(title = "Histograma de Temperatura por Mes",
       x = "Temperatura", y = "Frecuencia") +
  theme_minimal()
## Warning: Removed 1573 rows containing non-finite outside the scale range
## (`stat_bin()`).

Vuelos que salieron de Nueva York en el 2013

#Se presentan el número de vuelos que salieron de Nueva York en 2013 por aerolínea y con las 10 aerolínes con más vuelos se realiza una gráfica de barras.
vuelos_cantidad2 <- flights %>% select (carrier, dest) %>% count(carrier)
vuelos_orden <- arrange(vuelos_cantidad2, desc(n))
head(vuelos_orden, 10)
## # A tibble: 10 × 2
##    carrier     n
##    <chr>   <int>
##  1 UA      58665
##  2 B6      54635
##  3 EV      54173
##  4 DL      48110
##  5 AA      32729
##  6 MQ      26397
##  7 US      20536
##  8 9E      18460
##  9 WN      12275
## 10 VX       5162
grafico_barras <- ggplot(head(vuelos_orden, 10), aes(x = carrier, y = n)) +
  geom_bar(stat = "identity") +
  labs(x = "Aerolinea", y = "Cantidad de Vuelos")
grafico_barras

Grafica de pie

grafico_pastel <- grafico_barras +
  coord_polar("y", start = 0)
grafico_pastel

Relación Flights and Airports

#Relaciona el data frame flights con el data frame airports a través del campo destino ¿cómo lograr estas relaciones?
df <- merge(flights,airlines, by="carrier")
df <- left_join(df,planes, by="tailnum")
df <- left_join(df,weather, by=c("origin","time_hour"))

#Estas relaciones se logran a través del uso de funciones como merge y left_join,que permiten encontra las relaciones entre los diferentes data frames. Este paso se realizó al inico del programa para el desarrollo de los otros puntos de análisis.

Visualizaciones Flights and Airports

#Visualizaciones de Flights

# Gráfico de Barras
ggplot(data = vuelos_cantidad2, aes(x = carrier, y = n)) +
  geom_bar(stat = "identity") +
  labs(title = "Cantidad de Vuelos por Aerolínea",
       x = "Aerolínea",
       y = "Cantidad de Vuelos") +
  theme_minimal()

#Gráfico de Pastel
ggplot(data = vuelos_cantidad2, aes(x = "", y = n, fill = carrier)) +
  geom_bar(stat = "identity", width = 1) +
  coord_polar("y") +
  labs(title = "Proporción de Vuelos por Aerolínea",
       x = NULL,
       y = NULL) +
  theme_void()

#Gráfico de Tendencia
ggplot(data = EWRenero15TempProm, aes(x = day, y = promediotemp)) +
  geom_line() +
  labs(title = "Tendencia de Temperatura en Enero",
       x = "Día",
       y = "Temperatura (°C)") +
  theme_minimal()

10. Conclusión: Parte 2

Aquí se pone la conclusión de la parte 2 de la evidencia…..

¿Por qué se retrasan los vuelos en Nueva York?

Interpretación: a continuación se presenta…..falta poner gráficas aquí

#Atrasos de origen, carrier y mes.
atraso_por_origen <- flights %>% group_by(origin) %>% summarise(tiempo_atraso_promedio = mean(dep_delay, na.rm = TRUE))

atraso_por_carrier <- flights %>% group_by(carrier) %>% summarise(tiempo_atraso_promedio = mean(dep_delay, na.rm = TRUE))

atraso_por_mes <- flights %>% group_by(month) %>% summarise(tiempo_atraso_promedio = mean(dep_delay, na.rm = TRUE))

# Resumen por origen
summary_by_origin <- flights %>% group_by(origin) %>% summarize(Media_Dep_Delay = mean(dep_delay, na.rm = TRUE),
Mediana_Dep_Delay = median(dep_delay, na.rm = TRUE), Min_Dep_Delay = min(dep_delay, na.rm = TRUE), Max_Dep_Delay = max(dep_delay, na.rm = TRUE))

# Resumen por aerolínea
summary_by_carrier <- flights %>% group_by(carrier) %>% summarize(Media_Dep_Delay = mean(dep_delay, na.rm = TRUE),
    Mediana_Dep_Delay = median(dep_delay, na.rm = TRUE),
    Min_Dep_Delay = min(dep_delay, na.rm = TRUE),
    Max_Dep_Delay = max(dep_delay, na.rm = TRUE))

# Calcular resumen estadístico por destino
summary_by_dest <- flights %>%
  group_by(dest) %>%
  summarize(Media_Dep_Delay = mean(dep_delay, na.rm = TRUE),
    Mediana_Dep_Delay = median(dep_delay, na.rm = TRUE),
    Min_Dep_Delay = min(dep_delay, na.rm = TRUE),
    Max_Dep_Delay = max(dep_delay, na.rm = TRUE))
## Warning: There were 2 warnings in `summarize()`.
## The first warning was:
## ℹ In argument: `Min_Dep_Delay = min(dep_delay, na.rm = TRUE)`.
## ℹ In group 52: `dest = "LGA"`.
## Caused by warning in `min()`:
## ! no non-missing arguments to min; returning Inf
## ℹ Run `dplyr::last_dplyr_warnings()` to see the 1 remaining warning.
# Crear un conjunto de datos combinando las variables de interés
modelo_data <- flights %>%
  select(dep_delay, carrier, origin, month)

# Ajustar el modelo de regresión lineal
modelo <- lm(dep_delay ~ carrier + origin + month, data = modelo_data)

# Resumen del modelo
summary(modelo)
## 
## Call:
## lm(formula = dep_delay ~ carrier + origin + month, data = modelo_data)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
##  -54.81  -17.38  -12.48   -1.76 1294.85 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  18.80974    0.38810  48.466  < 2e-16 ***
## carrierAA    -7.79414    0.38286 -20.358  < 2e-16 ***
## carrierAS   -11.48010    1.54124  -7.449 9.46e-14 ***
## carrierB6    -3.77186    0.34822 -10.832  < 2e-16 ***
## carrierDL    -7.07511    0.36085 -19.607  < 2e-16 ***
## carrierEV     2.97023    0.39186   7.580 3.47e-14 ***
## carrierF9     4.51664    1.56852   2.880 0.003983 ** 
## carrierFL     2.89628    0.78763   3.677 0.000236 ***
## carrierHA   -12.03652    2.18212  -5.516 3.47e-08 ***
## carrierMQ    -5.61979    0.40732 -13.797  < 2e-16 ***
## carrierOO    -2.92665    7.42779  -0.394 0.693571    
## carrierUA    -4.90557    0.38340 -12.795  < 2e-16 ***
## carrierUS   -12.43204    0.43216 -28.767  < 2e-16 ***
## carrierVX    -4.02855    0.63644  -6.330 2.46e-10 ***
## carrierWN     1.25021    0.49683   2.516 0.011858 *  
## carrierYV     3.37925    1.74606   1.935 0.052947 .  
## originJFK    -0.38387    0.23214  -1.654 0.098213 .  
## originLGA    -1.54708    0.21363  -7.242 4.44e-13 ***
## month        -0.23726    0.02045 -11.604  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 39.96 on 328502 degrees of freedom
##   (8255 observations deleted due to missingness)
## Multiple R-squared:  0.01256,    Adjusted R-squared:  0.01251 
## F-statistic: 232.2 on 18 and 328502 DF,  p-value: < 2.2e-16
ggplot(modelo_data, aes(x = as.factor(month), y = dep_delay, group = 1)) +
  geom_line(stat = "summary", fun = "mean", linetype = "solid", size = 1) +
  labs(title = "Promedio del Retraso de Salida en función del Mes",
       x = "Mes",
       y = "Promedio de Retraso de Salida")
## 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.
## Warning: Removed 8255 rows containing non-finite outside the scale range
## (`stat_summary()`).

Análisis Retrasos

Aquí ponemos lo que nos falta de poner par lo de retrasos….

Retraso por tipo de avión

# Retraso por tipo de avión
retraso_por_avion <- flights %>%
  left_join(planes, by = "tailnum") %>%
  group_by(type) %>%
  summarize(avg_delay = mean(dep_delay, na.rm = TRUE))

# Gráfico de barras para retraso por tipo de avión
ggplot(retraso_por_avion, aes(x = type, y = avg_delay)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(title = "Retraso Promedio por Tipo de Avión",
       x = "Tipo de Avión",
       y = "Retraso Promedio") +
  theme_minimal()

Retraso por día de la semana

# Retraso por día de la semana
retraso_por_dia_semana <- flights %>%
  mutate(weekday = weekdays(as.Date(paste(year, month, day, sep = "-")))) %>%
  group_by(weekday) %>%
  summarize(avg_delay = mean(dep_delay, na.rm = TRUE))

# Ordenar días de la semana
retraso_por_dia_semana$weekday <- factor(retraso_por_dia_semana$weekday, levels = c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"))

# Gráfico de barras para retraso por día de la semana
ggplot(retraso_por_dia_semana, aes(x = weekday, y = avg_delay)) +
  geom_bar(stat = "identity", fill = "blue") +
  labs(title = "Retraso Promedio por Dia de la Semana",
       x = "Dia de la Semana",
       y = "Retraso Promedio") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Retraso por hora del día

flights$hour <- as.integer(flights$hour) 
mean_delay_per_hour <- aggregate(dep_delay ~ hour, flights, mean)
ggplot(data = mean_delay_per_hour, aes(x = hour, y = dep_delay)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(x = "Hora del día", y = "Retraso promedio (minutos)", 
       title = "Retraso promedio por hora del día") +
  theme_minimal() +
  theme(plot.title = element_text(hjust = 0.5))

# Gráfica atraso por origen
ggplot(atraso_por_origen, aes(x=origin, y=tiempo_atraso_promedio)) +
  geom_bar(stat="identity", fill="lightblue1") +
  theme_minimal() +
  labs(title="Atraso promedio por origen", x="Origen", y="Tiempo de atraso promedio")

# Gráfica atraso por carrier
ggplot(atraso_por_carrier, aes(x=carrier, y=tiempo_atraso_promedio)) +
  geom_bar(stat="identity", fill="cadetblue3") +
  theme_minimal() +
  labs(title="Atraso promedio por carrier", x="Carrier", y="Tiempo de atraso promedio")

# Gráfica de atraso por mes
ggplot(atraso_por_mes, aes(x=month, y=tiempo_atraso_promedio)) +
  geom_line(group=1, colour="darkslategray3") +
  theme_minimal() +
  labs(title="Atraso promedio por mes", x="Mes", y="Tiempo de atraso promedio")

flights_filtered <- flights %>%
  mutate(flights = ifelse(dep_delay > 0, "Delayed", "Not Delayed")) %>% 
  group_by(month, flights) %>%
  summarise(count = n()) %>%
  mutate(percent = count / sum(count) * 100)
## `summarise()` has grouped output by 'month'. You can override using the
## `.groups` argument.
ggplot(flights_filtered, aes(x = factor(month), y = count, fill = flights)) +
  geom_bar(stat = "identity", position = "stack") + 
  scale_fill_manual(values = c("seashell2", "rosybrown2")) +
  labs(title = "Número de vuelos por mes con y sin retraso",
       x = "Mes",
       y = "Número de vuelos",
       fill = "Retraso") +
  theme_minimal()

Análisis del Clima

Retraso por clima

flights_weather<- merge(weather, flights)
flights_weather %>%
  group_by(humid) %>%
  summarise(delay = mean(dep_delay, na.rm = TRUE)) %>%
  ggplot(aes(x = humid, y = delay)) +
  labs(x = "Humedad relativa", y = "Retraso promedio (minutos)", fill = "Aeoropuerto") +
  ggtitle("Retraso promedio por humedad relativa") +
  geom_line() + geom_point()+ theme(plot.title= element_text(hjust=0.5))
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_line()`).
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).

flights_weather %>%
  group_by(temp) %>%
  summarise(delay = mean(dep_delay, na.rm = TRUE)) %>%
  ggplot(aes(x = temp, y = delay)) +
  labs(x = "Temperatura", y = "Retraso promedio (minutos)", fill = "Aeoropuerto") +
  ggtitle("Retraso promedio por Temperatura") +
  geom_point() +
  geom_smooth()+ theme(plot.title= element_text(hjust=0.5))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_smooth()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_point()`).

flights_weather %>%
  group_by(wind_speed) %>%
  summarise(delay = mean(dep_delay, na.rm = TRUE)) %>%
  ggplot(aes(x = wind_speed, y = delay)) +
  labs(x = "Velocidad del Viento", y = "Retraso promedio (minutos)") +
  ggtitle("Retraso promedio por Velocidad del Viento") +
  geom_smooth()+ theme(plot.title= element_text(hjust=0.5))
## `geom_smooth()` using method = 'loess' and formula = 'y ~ x'
## Warning: Removed 1 row containing non-finite outside the scale range
## (`stat_smooth()`).

flights_weather %>%
  group_by(wind_dir) %>%
  summarise(delay = mean(dep_delay, na.rm = TRUE)) %>%
  ggplot(aes(x = wind_dir, y = delay)) +
  labs(x = "Dirección del Viento", y = "Retraso promedio (minutos)") +
  ggtitle("Retraso promedio por Dirección del Viento") +
  geom_bar(stat = "identity") + 
  theme(plot.title=element_text(hjust=0.5))
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_bar()`).

flights_weather %>%
  group_by(visib) %>%
  summarise(delay = mean(dep_delay, na.rm = TRUE)) %>%
  ggplot(aes(x = visib, y = delay)) +
  labs(x = "Visibilidad", y = "Retraso promedio (minutos)") +
  ggtitle("Retraso promedio por Visibilidad en el aire") +
  geom_line() + 
  theme(plot.title=element_text(hjust=0.5))

Conclusiones de retrasos

En esta actividad de manera grupal, determinamos el por qué se retrasan los vuelos en los aeropuertos de Nueva York. Se obtuvo información muy interesante a través de los diferentes análisis de la base de datos.

En primera instancia se obtuvo el atraso por origen, en donde nos mostró el tiempo de atraso promedio en cada uno de los tres aeropuertos disponibles, dando como resultado que el aeropuerto con mayor atraso en promedio es el EWR. El siguiente análisis fue el atraso por Carrier, en donde se obtuvo el atraso promedio por aerolínea; 9E (Endevoir Air) obtuvo el mayor resultado en atraso promedio.

Despúes nos enfocamos más en el mes en el que había mayores retrasos, dando como resultado temporadas altas para viajar, por ejemplo en primer lugar del mes con mayor retraso se encontraba Julio, aproximadamente solo por un minuto mayor a Junio, y a este le seguía diciembre en el tercer puesto. Si tomamos en cuenta que muchas personas viajan en dichas temporados por el verano y las fiestas decembrinas, lo que ocasiona que haya mayor cantidad de personas en movilidad en aeropuertos, podría ser un importante factor del por qué los vuelos se retrasan más en dichas temporadas.

Por último, realizamos un modelo del promedio del retraso de salida en función del mes, lo que nos muestra con mayor claridad, que las temporadas altas de viajes son un factor que influye en los retrasos generados en los aeropuertos de Nueva York.

Ejercicios de evidencia en clase

Extra 1. 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          : int [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)
# Date: fecha (en R va año-mes-día)
# POSIXct: formato fecha y hora

Extra 2. ¿Cuál es la clase de “flights” y que 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úmweos enteros
# 3. complex: Números complejos
# 4. character: carácteres
# 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

Extra 3. ¿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

Extra 4. 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 <int>, 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 <int>, minute <dbl>, time_hour <dttm>
# Si quisieramos 7 renglones: head(flights,7)

Compromiso ético y ciudadano

El valor de la integridad, según las Naciones Unidas, viene de la práctica de ser una persona honesta, que se adhiere a sus valores y que la toma de decisiones es sistemáticamente positiva. La integridad es la forma de actuar de acuerdo a los principios, a diferencia de la honestidad que es el acto de ser veraz. (Naciones Unidas)

Reflexión Personal: Nancy Marroquín

  • Reflexión personal: El respeto y la honestidad forman parte de los valores que trato de representar en mi día a día. En cualquie tipo de proyecto en el que participo, busco que este se lleve a cabo de manera más tranparente, fomentando la comunicación y la escucha activa. En el mundo de los negocios fomentar estos valores tan importantes, son clave para el éxito de las empresas. El actua de manera honesta y con respeto hacia los demás, te permite tener un mejor desarrollo personal y profesional.
    Si nos enfocamos más, hacia la parte de análisis de datos y el uso de datos de las empresas, el repeto y la honestidad, no son los únicos valores que se promueven, sino que también la confianza, el compromiso y la integridad. Al trabajar con información de la empresas es necesario tener mucho cuidado cómo es que se utiliza y cuál es su propósito. De esta manera es posible generar una mejor toma de decisiones repecto al uso y desarrollo de dichos datos.

Reflexión Personal: Kevin Meza

  • Reflexión personal: kevin

Reflexión Personal: Adrián Morales

  • Reflexión personal: adrián

Reflexión Personal: Karla López

  • Reflexión personal: karla

(usar al menos 3 bibliografías aquí)

Conclusión General

Aqui se pone la conclusión de todo….

Bibliografías

Aqui se pone las bibliografías….

LS0tCnRpdGxlOiAnRXZpZGVuY2lhIEZpbmFsOiBBbmFsw610aWNhIERlc2NyaXB0aXZhIHwgRXh0cmFjY2nDs24sIE1hbmlwdWxhY2nDs24gZSBJbnRlZ3JhY2nDs24gZGUgRGF0b3MnCmF1dGhvcjogIk5hbmN5IE1hcnJvcXXDrW4gLSBBMDExOTg1NTMsIEFkcmnDoW4gTW9yYWxlcyAtIEEwMTcyMjUzMiwgS2V2aW4gTWV6YSAtIEEwMDgzNjExMywgS2FybGEgTMOzcGV6IC0gQTAwMjI3NDExIgpkYXRlOiAiMjAyNC0wMy0wNCIKb3V0cHV0OiAKICBodG1sX2RvY3VtZW50OgogICAgdG9jOiBUUlVFCiAgICB0b2NfZmxvYXQ6IFRSVUUKICAgIGNvZGVfZG93bmxvYWQ6IFRSVUUKICAgIHRoZW1lOiBjb3NtbwotLS0KIVtdKEM6XFxVc2Vyc1xcbGVub3ZvXFxEb3dubG9hZHNcXGxsZWdhci1hZXJvcHVlcnRvLW51ZXZhLXlvcmstNC5qcGcpCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkNvbnRleHRvPC9zcGFuPiAKRWwgcGFxdWV0ZSAqKm55Y2ZsaWdodHMxMyoqIGNvbnRpZW5lIGluZm9ybWFjacOzbiBzb3JlIHRvZG9zIGxvcyB2dWVsZXMgcXVlIHBhcnRpZXJvbiBkZXNkZSBOdWV2YSBZb3JrKEVXUiwgSkZMLCBMR0EpIGVuIGRlc3Rpbm9zIGEgbG9zIEVzdGFkb3MgVW5pZG9zIGVuIDIwMTMuIEZ1ZXJvbiAzMzYsNzc2IHZ1ZWxvcyBlbiB0b3RhbC4gUGFyYSBheXVkYXIgYSBjb21wcmVuZGVyIGxhcyBjYXVzYXMgZGUgbG9zIHJldHJhc29zLCB0YW1iacOpbiBpbmNsdXllIG90cm9zIGNvbmp1bnRvcyBkZSBkYXRvcyDDunRpbGVzLiAgCgpFc3RlIHBhcXVldGUgaW5jbHV5ZSBsYXMgc2lndWllbnRlcyB0YWJsYXM6CgorIGZsaWdodHMgPSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzYWxpZXJvbiBkZSBOVWV2YSBZb3JrIGVuIGVsIDIwMTMgIAorIHdlYXRoZXIgPSBkYXRvcyBtZXRlcmVvbMOzZ2ljb3MgcG9yIGhvcmEgZGUgY2FkYSBhZXJvcHVlcnRvICAKKyBwbGFuZXMgPSBpbmZvcm1hY2nDs24gZGUgY29uc3RydWNjacOzbiBkZSBjYWRhIGF2acOzbiAgCisgYWlycG9ydHMgPSBub21icmVzIHkgdWJsaWNhY2lvbmVzIGRlIGFlcm9wdWVydG9zICAKKyBhaXJsaW5lcyA9IHJlbGFjacOzbiBlbnRyZSBub21icmVzIHkgY8OzZGlnb3MgZGUgbGFzIGFlcm9sw61uZWFzICAKCkZ1ZW50ZToKW09yaWdlbiBkZSBsb3MgZGF0b3NdKGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnL3dlYi9wYWNrYWdlcy9ueWNmbGlnaHRzMTMvbnljZmxpZ2h0czEzLnBkZikKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+UmVwb3J0ZSBFamVjdXRpdm88L3NwYW4+IApFbiBlc3RhIGV2aWRlbmNpYSBzZSB0cmFiYWrDsyBjb24gZWwgcGFxdWV0ZSAqKm55Y2ZsaWdodHMqKiwgZWwgY3XDoWwgbm9zIHBlcm1pdGnDsyBhbmFsaXphciBpbmZvcm1hY2nDs24gYWNlcmNhIGRlIGxvcyB2dWVsb3MsIGRlc3Rpbm9zLCBhZXJvbMOtbmVhcywgcmV0cmFzb3MgZW50cmUgb3Ryb3MsIHJlZ2lzdHJhZG9zIGVuIGxvcyBhZXJvcHVlcnRvcyBkZSBOdWV2YSBZb3JrIGVuIGVsIDIwMTMuIFNlIHV0aWxpemFyb24gbGFzIGZ1bmNpb25lcyBtw6FzIGNvbXVuZXMgZGVsIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8sIGVsIGN1YWwgZXMgZWwgcHJpbWVyIHBhc28gcGFyYSBjdWFscXVpZXIgdHJhYmFqbyBkZSBtYW5pcHVsYWNpw7NuIGRlIGRhdG9zLiAgCgpMYSBzaXR1YWNpw7NuIHByb2JsZW1hIHF1ZSBzZSBidXNjYWJhIHJlc29sdmVyIGVzIHNhYmVyIGVsIHBvciBxdcOpIGxvcyB2dWVsb3Mgc2UgcmV0cmFzYW4sIHlhIHNlYSBlbiBsYSBwYXJ0aWRhIG8gZW4gbGEgbGxlZ2FkYSwgZW4gbG9zIGFlcm9wdWVydG9zIGVuIE51ZXZhIFlvcmsuIENvbiBsYSBpbmZvcm1hY2nDs24gYnJpbmRhZGEgZW4gbGFzIGJhc2VzIGRlIGRhdG9zLCBzZSBwdWRvIHJlYWxpemFyIHVuIGFuw6FsaXNpcyB0b21hbmRvIGVuIGN1ZW50YSBkaWZlcmVudGVzIHZhcmlhYmxlcywgeWEgc2VhIGVsIGNsaW1hLCBlbCB0aXBvIGRlIGF2acOzbiBxdWUgc2UgdXRpbGl6YWJhLCBsYSBhZXJvbMOtbmVhLCBlbCBkw61hIGRlIGxhIHNlbWFuYSwgbGFzIHRlbXBvcmFkYXMgdmFjYWNpb25hbGVzIGUgaW5jbHVzbyBoYXN0YSBlbCBob3JhcmlvIGRlbCBkw61hLiBBbCBhbmFsaXphciBlc3RhIGluZm9ybWFjacOzbiBzZSBvYnR1dmllcm9uIGRhdG9zLCBxdWUgbm9zIHBlcm1pdGlyw61hbiBldmFsdWFyIGN1w6FsIGVzIGVsIHZlcmRhZGVybyBtb3Rpdm8gcG9yIGVsIGN1YWwgbG9zIHZ1ZWxvcyBzZSByZXRyYXNhbi4gCgpQYXJhIGVzdGUgcHJveWVjdG8gc2UgdXRpbGl6YXJvbiBkaWZlcmVudGVzIHBhcXVldGVzIHkgbGlicmVyw61hcywgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkluc3RhbGFyIHBhcXVldGVzIHkgbGxhbWFyIGxpYnJlcsOtYXM8L3NwYW4+CmBgYHtyIHdhcm5pbmc9RkFMU0V9CiNpbnN0YWxsLnBhY2thZ2VzKCJueWNmbGlnaHQxMyIpCmxpYnJhcnkobnljZmxpZ2h0czEzKQojaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikKbGlicmFyeSh0aWR5dmVyc2UpCiNpbnN0YWxsLnBhY2thZ2VzKCJkcGx5ciIpCmxpYnJhcnkoZHBseXIpCiNpbnN0YWxsLnBhY2thZ2VzKCJnZ3Bsb3QyIikKbGlicmFyeShnZ3Bsb3QyKQpkYXRhKCJmbGlnaHRzIikKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkd1YXJkYXIgYmFzZSBkZSBkYXRvczwvc3Bhbj4gCmBgYHtyfQpmbGlnaHRzIDwtIGZsaWdodHMKd2VhdGhlciA8LSB3ZWF0aGVyCnBsYW5lcyA8LSBwbGFuZXMKYWlycG9ydHMgPC0gYWlycG9ydHMKYWlybGluZXMgPC0gYWlybGluZXMKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlJlbGFjacOzbiBlbnRyZSBsYXMgYmFzZXMgZGUgZGF0b3M8L3NwYW4+IAohW10oQzpcXFVzZXJzXFxsZW5vdm9cXERvd25sb2Fkc1xccmVsYXRpb25hbC1ueWNmbGlnaHRzLnBuZykKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPlJlbGFjacOzbiBleGlzdGVudGU8L3NwYW4+IApgYGB7cn0KZGYgPC0gbWVyZ2UoZmxpZ2h0cyxhaXJsaW5lcywgYnk9ImNhcnJpZXIiKQpkZiA8LSBsZWZ0X2pvaW4oZGYscGxhbmVzLCBieT0idGFpbG51bSIpCmRmIDwtIGxlZnRfam9pbihkZix3ZWF0aGVyLCBieT1jKCJvcmlnaW4iLCJ0aW1lX2hvdXIiKSkKYGBgCgoKCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkRhdGEgV3JhbmdsaW5nPC9zcGFuPiAKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij4xLiBGdW5jaW9uZXMgYsOhc2ljYXMgZGUgbWFuZWpvIGRlIGRhdG9zPC9zcGFuPiAKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5TZWxlY3Q8L3NwYW4+IApMYSBmdW5jacOzbiAqc2VsZWN0KiBzaXJ2ZSBwYXJhIHNlbGVjY2lvbmFyIGNvbHVtbm9zIGRlIHVuIHRhYmxlICgqZGF0YSBmcmFtZSopLgpgYGB7cn0KZGYxIDwtIGZsaWdodHMgJT4lIHNlbGVjdChjYXJyaWVyLCBmbGlnaHQpICMgU2VsZWNjacOzbiBkZSBjb2x1bW5hcyBlc3BlY8OtZmljYXMKZGYyIDwtIGZsaWdodHMgJT4lIHNlbGVjdChjYXJyaWVyOmRpc3RhbmNlKSAjIFNlbGVjY2nDs24gZGUgcmFuZ28gZGUgY29sdW1uYXMKZGYzIDwtIGZsaWdodHMgJT4lIHNlbGVjdCgtY2FycmllciwgLWZsaWdodCkgIyBFbGltaW5hciBjb2x1bW5hcyBlc3BlY8OtZmljYXMKZGY0IDwtIGZsaWdodHMgJT4lIHNlbGVjdCgtY2FycmllcjogLWZsaWdodCkgIyBFbGltaW5hciByYW5nbyBkZSBjb2x1bW5hcwpkZjUgPC0gZmxpZ2h0cyAlPiUgc2VsZWN0KGFlcm9saW5lYSA9IGNhcnJpZXIpICMgU2VsZWNjaW9uYSB1bmEgY29sdW1uYSB5IGxlIGNhbWJpYSBlbCBub21icmUKZGY2IDwtIGZsaWdodHMgJT4lIHJlbmFtZShhZXJvbGluZWEgPSBjYXJyaWVyKSAjIENhbWJpYSBlbCBub21icmUgZGUgdW5hIGNvbHVtbmEKYGBgCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPkZpbHRlcjwvc3Bhbj4gCkxhIGZ1bmNpw7NuICpGaWx0ZXIqIHNpcnZlIHBhcmEgc2VsZWNjaW9uYXIgcmVuZ2xvbmVzIGRlIHVuIHRhYmxhKCpkYXRhIGZyYW1lKikuCmBgYHtyfQpkZjcgPC0gZmxpZ2h0cyAlPiUgZmlsdGVyKGRlcF9kZWxheSA+PTUwMCkgIyBFeHRyYWUgcmVuZ2xvbmVzIHF1ZSBjdW1wbGFuIGNvbmRpY2nDs24KIyBDb25kaWNpb25hbGVzOiBJZ3VhbCA9PSwgRGVzaWd1YWwgPSE9LCBNYXlvciBxdWUgPiwgTWF5b3IgbyBpZ3VhbCBxdWUgPj0sIE1lbm9yIG8gaWd1YWwgcXVlIDw9CiMgT3BlcmFkb3JlcyBsw7NnaWNvczogQU5EICYsIE9SIHwsIE5PVCAhCmRmOCA8LSBmbGlnaHRzICU+JSBmaWx0ZXIoZGVwX2RlbGF5ID49NTAwLCBkZXBfZGVsYXkgPD02MDApICMgRXh0cmFlIHJlbmdsb25lcyBxdWUgY3VtcGxhbiBjb24gZG9zIGNvbmRpY2lvbmVzCmRmOSA8LSBmbGlnaHRzICU+JSBzbGljZSgxMDAwOiAxMDk5KSAjIEV4dHJhZSBsb3MgbsO6bWVyb3MgZGUgbG9zIHJlbmdsb25lcyBpbmRpY2Fkb3MsIHNpbiBpbXBvcnRhciBzdXMgdmFsb3JlcwpgYGAKCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+RGlzdGluY3Q8L3NwYW4+IApMYSBmdW5jacOzbiAqZGlzdGluY3QqIHNpcnZlIHBhcmEgZWxpbWluYXIgcmVuZ2xvbmVzIGR1cGxpY2Fkb3MuCmBgYHtyfQpkZjEwIDwtIGRpc3RpbmN0KGZsaWdodHMpICMgRGVqYXIgc29sbyBsb3MgcmVuZ2xvbmVzIGRpZmVyZW50ZXMsIGJvcnJhIHRvZG9zIGxvcyByZXBldGlkb3MuCmBgYAoKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5NZXJnZTwvc3Bhbj4gCkxhIGZ1bmNpw7NuICptZXJnZSogc2lydmUgcGFyYSBqdW50YXIgYmFzZXMgZGUgZGF0b3MuCmBgYHtyfQpiZGdyYW5kZSA8LSBtZXJnZShmbGlnaHRzLCBhaXJsaW5lcywgYnk9ImNhcnJpZXIiKQpiZGdyYW5kZTIgPC0gbWVyZ2UoYmRncmFuZGUscGxhbmVzLCBieT0idGFpbG51bSIpCmBgYAoKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5NdXRhdGU8L3NwYW4+IApgYGB7cn0KYmRncmFuZGUzIDwtIG11dGF0ZShiZGdyYW5kZTIsIGRpc3RfbXRzID0gZGlzdGFuY2UqMS42MDkpCiNBZ3JlZ2EgdmFyaWFibGVzIG51ZXZhcyBjYWx1bGFkYXMgYSBwYXJ0aXIgZGUgdmFyaWFibGVzIGV4aXN0ZW50ZXMgZW4gbGEgYmFzZSBkZSBkYXRvcy4KYGBgCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPkVqZXJjaWNpb3M8L3NwYW4+IAoxLiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgdHV2aWVyb24gdW4gYXRyYXNvIGVuIGxsZWdhZGEgZGUgMiBob3JhcyBvIG3DoXMuCmBgYHtyfQplamVyY2ljaW8xIDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGFycl9kZWxheT49MTIwKQpgYGAKCjIuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBsbGVnYXJvbiBhIEhvdXN0b24gKElBTiBPIEhPVSkKYGBge3J9CmVqZXJjaWNpbzIgPC0gYmRncmFuZGUyICU+JSBmaWx0ZXIoZGVzdD09ICJJQUgiIHwgZGVzdCA9PSAiSE9VIikKYGBgCgozLiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBvcGVyYWRvcyBwb3IgVW5pdGVkLCBBbWVyaWNhbiBvIERlbHRhLgpgYGB7cn0KZWplcmNpY2lvMyA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihjYXJyaWVyICVpbiUgYygiVUEiLCAiQUEiLCAiREwiKSkKYGBgCgo0LiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgZGVzcGVnYXJvbiBlbiBKdWxpbywgQWdvc3RvIG8gU2VwdGllbWJyZQpgYGB7cn0KZWplcmNpY2lvNCA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihtb250aCAlaW4lIGMoNywgOCwgOSkpCmVqZXJjaWNpbzRhIDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKG1vbnRoID09IDcgfCBtb250aCA9PSA4IHwgbW9udGggPT0gOSkgCmBgYAoKNS4gRW5jdWVudHJhIHRvZG9zIGxvcyB2dWVsb3MgcXVlIGFycml2YXJvbiBtw6FzIGRlIDIgaG9yYXMgdGFyZGUsIHBlcm8gbm8gZGVzcGVnYXJvbiB0YXJkZS4KYGBge3J9CmVqZXJjaWNpbzUgPC0gYmRncmFuZGUyICU+JSBmaWx0ZXIoYXJyX2RlbGF5PjEyMCAmIGRlcF90aW1lID09IHNjaGVkX2RlcF90aW1lKQplamVyY2ljaW81YSA8LSBiZGdyYW5kZTIgJT4lIGZpbHRlcihhcnJfZGVsYXk+MTIwICYgZGVwX2RlbGF5PD0wKQpgYGAKCjYuIEVuY3VlbnRyYSB0b2RvcyBsb3MgdnVlbG9zIHF1ZSBzZSByZXRyYXNhcm9uIGFsIG1lbm9zIDEgaG9yYSwgcGVybyBxdWUgbGxlZ2Fyb24gYW50ZXMgMzAgbWludXRvcyBvIG3DoXMuCmBgYHtyfQplamVyY2ljaW82IDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGRlcF9kZWxheT49NjAgJiBhcnJfZGVsYXk8PS0zMCkKYGBgCgo3LiBFbmN1ZW50cmEgdG9kb3MgbG9zIHZ1ZWxvcyBxdWUgc2FsaWVyb24gZW50cmUgbGEgbWVkaWFub2NoZSB5IGxhcyA2IGEubS4KYGBge3J9CmVqZXJjaWNpbzcgPC0gYmRncmFuZGUyICU+JSBmaWx0ZXIoZGVwX3RpbWUgJWluJSBjKCIyNDAwIiwgIjEwMCIsICIyMDAiLCAiMzAwIiwgIjQwMCIsICI1MDAiLCAiNjAwIikpCmVqZXJjaWNpbzdhIDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGRlcF90aW1lPT0yNDAwIHwgZGVwX3RpbWU8PTYwMCkgI0NPUlJFQ1RBCmVqZXJjaWNpbzdiIDwtIGJkZ3JhbmRlMiAlPiUgZmlsdGVyKGhvdXIgJWluJSBjKCIwIiwgIjEiLCAiMiIsICIzIiwgIjQiLCAiNSIsICI2IikpCmBgYAoKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5BcnJhbmdlPC9zcGFuPiAKU2ltaWxhciBhIGZpbHRlciAoKSBwZXJvIGVuIGx1Z2FyIGRlIHNlbGVjY2lvbmFyIHJlbmdsb25lcywgbG9zIG9yZGVuYSBkZSBtZW5vciBhIG1heW9yLgpgYGB7cn0KZGYxMSA8LSBhcnJhbmdlKGJkZ3JhbmRlMiwgeWVhci54LCBtb250aCwgZGF5KQpgYGAKClBhcmEgYWNvbW9kYXIgZGUgbWF5b3IgYSBtZW5vci4KYGBge3J9CmRmMTIgPC0gYXJyYW5nZShiZGdyYW5kZTIsIHllYXIueCwgZGVzYyhtb250aCksIGRheSkKYGBgCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPlN1bW1hcml6ZTwvc3Bhbj4gCkNvbGFwc2EgdW5hIHRhYmxhIGEgdW4gc8OzbG8gcmVuZ2zDs24KYGBge3J9CiMgT2J0w6luIGVsIHJldHJhc28gcHJvbWVkaW8gZGUgc2FsaWRhIGRlIGRlc3BlZ3VlIGRlIHRvZG9zIGxvcyB2dWVsb3MKc3VtbWFyaXplKGJkZ3JhbmRlMiwgbWVhbihkZXBfZGVsYXksIG5hLnJtPVRSVUUpKQpgYGAKCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+R3JvdXAgYnk8L3NwYW4+IApBZ3J1cGEgdGFibGEgYmFzYWRvIGVuIGFsZ3VuYXMgY29sdW1uYXMuCmBgYHtyfQojIE9idGVuZXIgZWwgcmV0cmFzbyBwcm9tZWRpbyBkZSBkZXNwZWd1ZSBwb3IgZMOtYQpwb3JfZGlhIDwtIGdyb3VwX2J5KGJkZ3JhbmRlMiwgeWVhci54LCBtb250aCwgZGF5KQpzdW1tYXJpemUocG9yX2RpYSwgbWVhbihkZXBfZGVsYXksIG5hLnJtPVRSVUUpKQpgYGAKCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+RXZpZGVuY2lhOiBQYXJ0ZSAxPC9zcGFuPiAKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij4xLiBDYXJnYXIgZW4gbWVtb3JpYSBsYSB0YWJsYSAiZmxpZ2h0cyIgeSBtb3N0cmFyIHN1IGNvbnRlbmlkbzwvc3Bhbj4gCmBgYHtyfQojIExhIGNhcmdhIGEgbWVtb3JpYSBzZSBoaXpvIGVuIGVsIHBhc28gYW50ZXJpb3IsIGNvbnN1bHRhIGRlIGRhdGFmcmFtZSBwYXJhIHJlY29yZGFyIHN1IGNvbnRlbmlkby4KdmlldyhmbGlnaHRzKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+Mi4gRGF0b3MgZGVzY3JpcHRpdm9zIGRlICJmbGlnaHRzIjwvc3Bhbj4gCmBgYHtyfQojIElkZW50aWZpY2EgbGEgbWVkaWEgZGUgbGFzIGRpc3RhbmNpYXMgcmVjb3JyaWRhcyBlbiBtaWxsYXMuCnN1bW1hcnkoZmxpZ2h0cykKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPjMuIENyaXRlcmlvcyBwYXJhIGVuY29udHJhciBhZXJvbMOtbmVhczwvc3Bhbj4gCmBgYHtyfQojQ3JlYSB1biBudWV2byBkYXRhIGZyYW1lIHF1ZSBmaWx0cmUgc29sYW1lbnRlIGEgbGFzIGFlb3Jsw61uZWFzIHF1ZSBoYW4gcmVjb3JyaWRvIHVuYSBkaXN0YW5jaWEgc3VwZXJpb3IgYSBsYSBtZWRpYSwgc2UgZGVzZWFuIHZlciBsb3MgY2FtcG9zIGNhcnJpZXIsIGRpc3RhbmNlLCBvcmlnaW4sIGRlc3QgZW4gZm9ybWEgZGVzY2VuZGVudGUgcG9yIGRpc3RhbmNlLgoKI0NyaXRlcmlvIDE6IHNlIHNlbGVjY2lvbmEgbGFzIHZhcmlhYmxlcy4KQ3JpdGVyaW8xIDwtIGZsaWdodHMgJT4lIHNlbGVjdChjYXJyaWVyLCBkaXN0YW5jZSwgb3JpZ2luLCBkZXN0KQoKI0NyaXRlcmlvIDI6IHNlIGZpbHRyYW4gYSBsYXMgYWVyb2xpbmVhcyBxdWUgdGVuZ2FuIHVuYSBtZWRpYSBzdXBlcmlvciBhIDEwNDAgZW4gbWlsbGFzIHJlY29ycmlkYXMuIApDcml0ZXJpbzIgPC0gQ3JpdGVyaW8xICU+JSBmaWx0ZXIoZGlzdGFuY2UgPjEwNDApCgojQ3JpdGVyaW8gMzogc2Ugb3JkZW5hIGVuIGRlc2NlbmRlbnRlIHBvciBsYSBkaXN0YW5jaWEgcmVjb3JyaWRhIApDcml0ZXJpbzMgPC0gQ3JpdGVyaW8yICU+JSBhcnJhbmdlKGRlc2MoZGlzdGFuY2UpKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+NC4gU3VtYSB5IE1lZGlhIGRlIGxhcyBkaXN0YW5jaWFzIHJlY29ycmlkYXM8L3NwYW4+IApgYGB7cn0KIyBTZSBlbmN1ZW50cmEgbGEgc3VtYSB5IGxhIG1lZGlhIGRlIGxhcyBkaXN0YW5jaWFzIHJlY29ycmlkYXMgcG9yIGNhcnJpZXIsIGVsaW1pbmEgbG9zIE5B4oCZUyBlIGludGVycHJldGEgcXVlIHNpZ25pZmljYSBsYSBzdW1hIHkgbGEgbWVkaWEgZGUgbGFzIGRpc3RhbmNpYXMgcmVjb3JyaWRhcy4KCkNyaXRlcmlvNCA8LSBDcml0ZXJpbzMgJT4lIGdyb3VwX2J5KGNhcnJpZXIsb3JpZ2luLGRlc3QpICU+JSAgCiAgc3VtbWFyaXplKGRpc3RhbmNlc3VtYT1zdW0oZGlzdGFuY2UsIG5hLnJtPVRSVUUpLCBkaXN0YW5jZXByb21lZGlvPW1lYW4oZGlzdGFuY2UsIG5hLnJtPVRSVUUpKQoKIyBQb3N0ZXJpb3JtZW50ZSwgc2Ugb3JkZW5hIGRlIGZvcm1hIGRlc2NlbmRlbnRlIGVuIGJhc2UgYSBsYSBkaXN0YW5jaWEgcmVjb3JyaWRhLgpEZXNjZW5kZW50ZSA8LSBDcml0ZXJpbzQgJT4lIGFycmFuZ2UoY2FycmllcixkaXN0YW5jZXN1bWEpCmBgYAoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij41LiBJbnRlcnByZXRhY2lvbmVzOiBQYXJ0ZSAxPC9zcGFuPiAKQXF1w60gc2UgZXNjcmliZSBsYSBpbnRlcnByZXRhY2nDs24uLi4uLgoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij42LiBJZGVudGlmaWNhciBhZXJvbMOtbmVhcyBsw61kZXJlcyBlbiBsb3MgYWVyb3B1ZXJ0b3M8L3NwYW4+CmBgYHtyfQojRW4gZXN0YSBwYXJ0ZSBzZSBpZGVudGlmaWNhIHNpIGxhcyBhZXJvbMOtbmVhcyBsw61kZXJlcyBzb24gbGFzIG1pc21hcyBlbiBsb3MgdHJlcyBhZXJvcHVlcnRvcyBjdXlvIG9yaWdlbiBlcyBOdWV2YSBZb3JrIHlhIHNlYSBlbCBKb2huIEYuIEtlbm5lZHkgKEpGSyksIGVsIGRlIExhR3VhcmRpYSAoTEdBKSBvIGVsIGRlIE5ld2FyayBMaWJlcnR5IChFV1IpLiBTZSBnZW5lcmEgdW4gZGF0YWZyYW1lIHBhcmEgY2FkYSBhZXJvcHVlcnRvLgoKQWVyb3B1ZXJ0b19KRksgPSBEZXNjZW5kZW50ZSAlPiUgZmlsdGVyKG9yaWdpbiA9PSAiSkZLIikgICU+JSBhcnJhbmdlKGNhcnJpZXIsIGRlc2MoZGlzdGFuY2VzdW1hKSkKQWVyb3B1ZXJ0b19MR0EgPSBEZXNjZW5kZW50ZSAlPiUgZmlsdGVyKG9yaWdpbiA9PSAiTEdBIikgICU+JSBhcnJhbmdlKGNhcnJpZXIsIGRlc2MoZGlzdGFuY2VzdW1hKSkKQWVyb3B1ZXJ0b19FV1IgPSBEZXNjZW5kZW50ZSAlPiUgZmlsdGVyKG9yaWdpbiA9PSAiRVdSIikgICU+JSBhcnJhbmdlKGNhcnJpZXIsIGRlc2MoZGlzdGFuY2VzdW1hKSkKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPjcuIENvbmNsdXNpw7NuOiBQYXJ0ZSAxPC9zcGFuPgpBcXXDrSBzZSBlc2NyaWJlIGxhIGNvbmNsdXNpw7NuIGRlIGxhIHBhcnRlIDEgZGUgbGEgZXZpZGVuY2lhCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkV2aWRlbmNpYTogUGFydGUgMjwvc3Bhbj4gCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPjEuIENvbnN1bHRhIGRlbCBkYXRhZnJhbWU8L3NwYW4+CmBgYHtyfQojQWwgY29uc3VsdGFyL2xsYW1hciBlbCBEYXRhRnJhbWUgbm9zIHBlcm1pdGUgdmlzdWFsaXphciBsYSBiYXNlIGRlIGRhdG9zICpmbGlnaHRzKi4KdmlldyhmbGlnaHRzKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+Mi4gSW5mb3JtYWNpw7NuIGRlIGNhZGEgdnVlbG88L3NwYW4+CmBgYHtyfQojU2UgbmVjZXNpdGEgc2FiZXIgZGUgY2FkYSB2dWVsbywgbGEgYWVyb2zDrW5lYSwgZWwgYWVyb3B1ZXJ0byBkZSBvcmlnZW4geSBlbCBhZXJvcHVlcnRvIGRlc3Rpbm8KdnVlbG9zIDwtIGZsaWdodHMgJT4lIHNlbGVjdChjYXJyaWVyLCBvcmlnaW4sIGRlc3QpCgojRGUgbGEgY29uc3VsdGEgYW50ZXJpb3Igc2UgcmVxdWllcmUgc2FiZXIgZWwgbm9tYnJlIGRlIGxhIGFlcm9sw61uZWEKYWVyb2zDrW5lYSA8LSB2dWVsb3MgJT4lIGxlZnRfam9pbiAoYWlybGluZXMsIGJ5ID0gImNhcnJpZXIiKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+My4gQ2FudGlkYWQgZGUgdnVlbG9zIHBvciBkZXN0aW5vPC9zcGFuPgpgYGB7cn0gCiNEZSBsYSBjb25zdWx0YSBhbnRlcmlvciBzZSByZXF1aWVyZSBzYWJlciBlbCBub21icmUgZGUgbGEgYWVyb2zDrW5lYSAoRkFMVEEpCgojZGVzdG5vbSA8LSBtdXRhdGUodnVlbG9zX2NhbnRpZGFkLCBhaXJsaW5lcykKc3VtbWFyeV9kZWxheSA8LSBkZiAlPiUKICBncm91cF9ieShkZXN0KSAlPiUKICBzdW1tYXJpc2UoYXZnX2RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHRvdGFsX2ZsaWdodHMgPSBuKCksCiAgICAgICAgICAgIHRvdGFsX2RlbGF5ZWRfZmxpZ2h0cyA9IHN1bShkZXBfZGVsYXkgPiAwLCBuYS5ybSA9IFRSVUUpLAogICAgICAgICAgICBwZXJjX2RlbGF5ZWRfZmxpZ2h0cyA9IHRvdGFsX2RlbGF5ZWRfZmxpZ2h0cyAvIHRvdGFsX2ZsaWdodHMgKiAxMDApCgpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+NC4gQWVyb2zDrW5lYXMgeSBEZXN0aW5vczogTWHDsWFuYSwgVGFyZGUsIE5vY2hlIHkgTWFkcnVnYWRhPC9zcGFuPgpgYGB7cn0KI1NlIG5lY2VzaXRhIGNvbm9jZXIgbGFzIGFlcm9sw61uZWFzIChjbGF2ZSB5IG5vbWJyZSkgeSBkZXN0aW5vcyBxdWUgdnVlbGFuIHBvciBsYSBNYcOxYW5hOiBkZSA2IGEgMTIsIFRhcmRlOiBkZSAxMiBhIDE5ICwgTm9jaGU6IGRlIDE5IGEgMjQgeSBNYWRydWdhZGEgZGUgMjQgYSA2LgoKdHVybm9fY2FycmllciA8LSBmbGlnaHRzICU+JSBzZWxlY3QgKGNhcnJpZXIsIGRlc3QsIHNjaGVkX2RlcF90aW1lKSAlPiUgbGVmdF9qb2luIChhaXJsaW5lcywgYnkgPSAiY2FycmllciIpCgp0dXJub19NVE5NPC0gbXV0YXRlKHR1cm5vX2NhcnJpZXIsIGNsYXNfaG9yYXJpbyA9IGlmZWxzZShzY2hlZF9kZXBfdGltZSAlaW4lIDYwMDoxMTU5LCJNYcOxYW5hIixpZmVsc2Uoc2NoZWRfZGVwX3RpbWUgJWluJSAxMjAwOjE4NTksIlRhcmRlIixpZmVsc2Uoc2NoZWRfZGVwX3RpbWUgJWluJSAxOTAwOjI0MDAsIk5vY2hlIiwgIk1hZHJ1Z2FkYSIpKSkpCmBgYAoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij41LiBDYW50aWRhZCBkZSB2dWVsb3M6IE1hw7FhbmEsIFRhcmRlIHkgTm9jaGU8L3NwYW4+CmBgYHtyfQojU2UgcHJlc2VudGEgbGEgY2FudGlkYWQgZGUgdnVlbG9zIHBvciBhZXJvbMOtbmVhIHkgZGVzdGlubyBxdWUgaGF5IGVuIGNhZGEgdHVybm8sIHlhIHNlYSBlbiBsYSBtYcOxYW5hLCB0YXJkZSwgbm9jaGUgbyBtYWRydWdhZGEuCgpjYW50aWRhZF90dXJub19NVE5NIDwtIHR1cm5vX01UTk0gJT4lIGdyb3VwX2J5KGNhcnJpZXIsIGRlc3QsIGNsYXNfaG9yYXJpbykgJT4lIGNvdW50KCkKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPjYuIERlc3Rpbm9zIGEgbG9zIHF1ZSB2dWVsYSBBbWVyaWNhbiBBaXJsaW5lcyBlbiBNYWRydWdhZGE8L3NwYW4+CmBgYHtyfQpBQV9kZXN0aW5vc19tYWQgPC0gdHVybm9fTVROTSAlPiUgc2VsZWN0KGNhcnJpZXIsbmFtZSwgZGVzdCxjbGFzX2hvcmFyaW8pICU+JSBmaWx0ZXIoY2FycmllciA9PSAiQUEiICYgY2xhc19ob3JhcmlvID09ICJNYWRydWdhZGEiKSAlPiUgZ3JvdXBfYnkoY2FycmllcixuYW1lLCBkZXN0LGNsYXNfaG9yYXJpbykKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPjcuIEF2aW9uZXMgcXVlIHV0aWxpemEgQW1lcmljYW4gQWlybGluZXM8L3NwYW4+CmBgYHtyfQojU2UgcHJlc2VudGEgbGEgYWVyb2zDrW5lYSwgdGlwbywgbW90b3IsIG7Dum1lcm8gZGUgYXNpZW50b3MgeSBsYSBjYW50aWRhZCBkZSB2dWVsb3MgcXVlIHNlIGhhbiByZWFsaXphZG8gY29uIGNhZGEgdW5vIGRlIGxvcyBhdmlvbmVzLgpBQV9hdmlvbmVzIDwtIGZsaWdodHMgJT4lIGxlZnRfam9pbihwbGFuZXMsIGJ5ID0gInRhaWxudW0iKSAlPiUgc2VsZWN0KGNhcnJpZXIsIHR5cGUsIGVuZ2luZSwgc2VhdHMpICU+JSBmaWx0ZXIoY2FycmllciA9PSAiQUEiLCAhaXMubmEodHlwZSkpICU+JSBncm91cF9ieShjYXJyaWVyLHR5cGUsZW5naW5lLHNlYXRzKSAlPiUgY291bnQoKQpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+OC4gSW50ZXJwcmV0YWNpb25lczogUGFydGUgMjwvc3Bhbj4KQXF1w60gc2UgZXNjcmliZSBsYSBpbnRlcnByZXRhY2nDs24uLi4uLgoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij45LiBWaXN1YWxpemFjacOzbiBkZSBEYXRvczwvc3Bhbj4KVmlzdWFsaXphY2lvbmVzIGRlIGxhIGFlcm9sw61uZWEgQW1lcmljYW4gQWlybGluZXMgcGFyYSBsb3MgZWplY3V0aXZvcyBjb24gbGFzIHNpZ3VpZW50ZXMgY2FyYWN0ZXLDrXN0aWNhcy4gRGVudHJvIGRlIGxhcyBhZXJvbMOtbmVhcyBlbCByZXRyYXNvIHRhbnRvIGVuIGxhIGhvcmEgZGUgcGFydGlkYSBjb21vIGVuIGxhIGhvcmEgZGUgbGxlZ2FkYSBhIHN1IGRlc3Rpbm8gdmFuIGdlbmVyYW5kbyBpbmRpY2Fkb3JlcyBuZWdhdGl2b3MuCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPlZ1ZWxvcyBjb24gcmV0cmFzbyBlbiBpZGEgeSByZWdyZXNvPC9zcGFuPgpgYGB7cn0KI1Z1ZWxvcyBkZSBBbWVyaWNhbiBBaXJsaW5lcyBxdWUgc2kgdGllbmVuIHJldHJhc28gZW4gbGEgcGFydGlkYSB0YW1iacOpbiB0aWVuZW4gcmV0cmFzbyBlbiBsYSBob3JhIGRlIGxsZWdhZGEuCgp2dWVsb3NfYWEgPC0gZmxpZ2h0cyAlPiUgZmlsdGVyKGNhcnJpZXIgPT0gIkFBIikKcmV0cmFzb3BhcnRpZGEgPC0gbXV0YXRlKHZ1ZWxvc19hYSwgZGVwX2RlbGF5ID0gZGVwX3RpbWUgLSBzY2hlZF9kZXBfdGltZSkKcmV0cmFzb2xsZWdhZGEgPC0gbXV0YXRlKHZ1ZWxvc19hYSwgYXJyX2RlbGF5ID0gYXJyX3RpbWUgLSBzY2hlZF9hcnJfdGltZSkKcGFydGlkYUFBcmV0cmFzb3MgPC0gZmlsdGVyKHJldHJhc29sbGVnYWRhLCBkZXBfZGVsYXkgPiAwKQpsbGVnYWRhQUFyZXRyYXNvcyA8LSBmaWx0ZXIocmV0cmFzb2xsZWdhZGEsIGFycl9kZWxheSA+IDApCkFBcmV0cmFzb3NfbHAgPC0gaW50ZXJzZWN0KHBhcnRpZGFBQXJldHJhc29zLCBsbGVnYWRhQUFyZXRyYXNvcykKZ2dwbG90KEFBcmV0cmFzb3NfbHAsIGFlcyh4ID0gZGVwX2RlbGF5LCB5ID0gYXJyX2RlbGF5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgbGFicyh4ID0gIlJldHJhc28gZW4gbGEgcGFydGlkYSkiLCB5ID0gIlJldHJhc28gZW4gbGEgbGxlZ2FkYSIpICsKICB0aGVtZV92b2lkKCkKYGBgCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPlRlbmRlbmNpYSBkZSBsYSB0ZW1wZXJhdHVyYTwvc3Bhbj4KYGBge3J9CiNUZW5kZW5jaWEgZGUgbGEgdGVtcGVyYXR1cmEgZHVyYW50ZSBsb3MgcHJpbWVyb3MgMTUgZMOtYXMgZGVsIG1lcyBkZSBFbmVybyBlbiBsb3MgdnVlbG9zIHF1ZSBwYXJ0ZW4gZGVsIGFlcm9wdWVydG8g4oCcTmV3YXJrLCBFV1LigJ0sIHNlIHV0aWxpemEgdW5hIGdyw6FmaWNhIGRlIGzDrW5lYS4KCkVXUmVuZXJvMTUgPC0gd2VhdGhlciAlPiUgZmlsdGVyKG9yaWdpbiA9PSAiRVdSIiwgbW9udGggPT0gMSwgZGF5IDw9IDE1KQpFV1JlbmVybzE1VGVtcCA8LSBzZWxlY3QoRVdSZW5lcm8xNSwgZGF5LCB0ZW1wKQoKRVdSZW5lcm8xNVRlbXBQcm9tIDwtIEVXUmVuZXJvMTVUZW1wICU+JSBncm91cF9ieShkYXkpICU+JSBzdW1tYXJpc2UocHJvbWVkaW90ZW1wID0gbWVhbih0ZW1wLCBuYS5ybT1UUlVFKSkKCmdncGxvdChFV1JlbmVybzE1VGVtcFByb20sIGFlcyh4ID0gZGF5LCB5ID0gcHJvbWVkaW90ZW1wKSkgKwogIGdlb21fbGluZSgpICsKICBsYWJzKHggPSAiRGlhIiwgeSA9ICJUZW1wZXJhdHVyYSAowrBDKSIpICsKICB0aGVtZV92b2lkKCkKYGBgCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPlRlbXBlcmF0dXJhIG3DoXMgZnJlY3VlbnRlIGVuIGNlbHNpdXM8L3NwYW4+CmBgYHtyfQojVmlzdWFsaXphIGxhIHRlbXBlcmF0dXJhIG3DoXMgZnJlY3VlbnRlIGVuIGxvcyBwcmltZXJvcyAxNSBkw61hcyBkZWwgbWVzIGRlIEVuZXJvLCB1dGlsaXphciB1biBoaXN0cm9ncmFtYS4KZGF0b3NfZW5lcm8gPC0gZGYgJT4lCiAgZmlsdGVyKG1vbnRoLnggPT0gMSwgZGF5LnggPD0gMTUpCgojRkFMVEEgQ09OVkVSVElSIEEgQ0VMU0lVUwpkYXRvc19lbmVyb19jZWxzaXVzIDwtIG11dGF0ZShkYXRvc19lbmVybywgY2Vsc2l1cz0odGVtcC0zMikqKDUvOSkpCgoKIyBDcmVhciBlbCBoaXN0b2dyYW1hIGRlIHRlbXBlcmF0dXJhCmdncGxvdChkYXRvc19lbmVybywgYWVzKHggPSB0ZW1wKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNSwgY29sb3IgPSAid2hpdGUiLCBmaWxsID0gInNreWJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJIaXN0b2dyYW1hIGRlIFRlbXBlcmF0dXJhIGVuIGxvcyBQcmltZXJvcyAxNSBEaWFzIGRlIEVuZXJvIiwKICAgICAgIHggPSAiVGVtcGVyYXR1cmEiLCB5ID0gIkZyZWN1ZW5jaWEiKSArCiAgdGhlbWVfbWluaW1hbCgpCgpgYGAKYGBge3J9CmRhdG9zX2VuZXJvIDwtIGRmICU+JQogIGZpbHRlcihtb250aC54ID09IDEsIGRheS54IDw9IDE1KQoKI0NPTlZFUlRJUiBBIENFTFNJVVMKZGF0b3NfZW5lcm9fY2Vsc2l1cyA8LSBtdXRhdGUoZGF0b3NfZW5lcm8sIGNlbHNpdXM9KHRlbXAtMzIpKig1LzkpKQoKIyBDcmVhciBlbCBoaXN0b2dyYW1hIGRlIHRlbXBlcmF0dXJhCmdncGxvdChkYXRvc19lbmVyb19jZWxzaXVzLCBhZXMoeCA9IGNlbHNpdXMpKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSA1LCBjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAic2t5Ymx1ZSIpICsKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbWEgZGUgVGVtcGVyYXR1cmEgZW4gbG9zIFByaW1lcm9zIDE1IERpYXMgZGUgRW5lcm8iLAogICAgICAgeCA9ICJUZW1wZXJhdHVyYSAowrBDKSIsIHkgPSAiRnJlY3VlbmNpYSIpICsKICB0aGVtZV9taW5pbWFsKCkKCmBgYAoKCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPkZhY2V0czwvc3Bhbj4KYGBge3J9CiNVdGlsaXphIEZhY2V0cyBwYXJhIG9ic2VydmFyIGPDs21vIHZhcsOtYSBsYSB0ZW1wZXJhdHVyYSBlbiBjYWRhIG1lcyBlbiDDqWwgaGlzdG9ncmFtYSBkZWwgcHVudG8gYW50ZXJpb3IKZGF0b3MgPC0gZGYgJT4lCiAgc2VsZWN0KG1vbnRoLngsIHRlbXApCgojRkFMVEEgQ09OVkVSVElSIEEgQ0VMU0lVUwoKZ2dwbG90KGRhdG9zLCBhZXMoeCA9IHRlbXApKSArCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAzLCBjb2xvciA9ICJ3aGl0ZSIsIGZpbGwgPSAic2t5Ymx1ZSIpICsKICBmYWNldF93cmFwKH5tb250aC54LCBucm93ID0gMykgKyAgIyBGYWNldGFyIHBvciBtZXMsIGNvbiAzIHBhbmVsZXMgcG9yIGZpbGEKICBsYWJzKHRpdGxlID0gIkhpc3RvZ3JhbWEgZGUgVGVtcGVyYXR1cmEgcG9yIE1lcyIsCiAgICAgICB4ID0gIlRlbXBlcmF0dXJhIiwgeSA9ICJGcmVjdWVuY2lhIikgKwogIHRoZW1lX21pbmltYWwoKQpgYGAKCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+VnVlbG9zIHF1ZSBzYWxpZXJvbiBkZSBOdWV2YSBZb3JrIGVuIGVsIDIwMTM8L3NwYW4+CmBgYHtyfQojU2UgcHJlc2VudGFuIGVsIG7Dum1lcm8gZGUgdnVlbG9zIHF1ZSBzYWxpZXJvbiBkZSBOdWV2YSBZb3JrIGVuIDIwMTMgcG9yIGFlcm9sw61uZWEgeSBjb24gbGFzIDEwIGFlcm9sw61uZXMgY29uIG3DoXMgdnVlbG9zIHNlIHJlYWxpemEgdW5hIGdyw6FmaWNhIGRlIGJhcnJhcy4KdnVlbG9zX2NhbnRpZGFkMiA8LSBmbGlnaHRzICU+JSBzZWxlY3QgKGNhcnJpZXIsIGRlc3QpICU+JSBjb3VudChjYXJyaWVyKQp2dWVsb3Nfb3JkZW4gPC0gYXJyYW5nZSh2dWVsb3NfY2FudGlkYWQyLCBkZXNjKG4pKQpoZWFkKHZ1ZWxvc19vcmRlbiwgMTApCgpncmFmaWNvX2JhcnJhcyA8LSBnZ3Bsb3QoaGVhZCh2dWVsb3Nfb3JkZW4sIDEwKSwgYWVzKHggPSBjYXJyaWVyLCB5ID0gbikpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIGxhYnMoeCA9ICJBZXJvbGluZWEiLCB5ID0gIkNhbnRpZGFkIGRlIFZ1ZWxvcyIpCmdyYWZpY29fYmFycmFzCgpgYGAKCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+R3JhZmljYSBkZSBwaWU8L3NwYW4+CmBgYHtyfQpncmFmaWNvX3Bhc3RlbCA8LSBncmFmaWNvX2JhcnJhcyArCiAgY29vcmRfcG9sYXIoInkiLCBzdGFydCA9IDApCmdyYWZpY29fcGFzdGVsCmBgYAoKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5SZWxhY2nDs24gRmxpZ2h0cyBhbmQgQWlycG9ydHM8L3NwYW4+CmBgYHtyfQojUmVsYWNpb25hIGVsIGRhdGEgZnJhbWUgZmxpZ2h0cyBjb24gZWwgZGF0YSBmcmFtZSBhaXJwb3J0cyBhIHRyYXbDqXMgZGVsIGNhbXBvIGRlc3Rpbm8gwr9jw7NtbyBsb2dyYXIgZXN0YXMgcmVsYWNpb25lcz8KZGYgPC0gbWVyZ2UoZmxpZ2h0cyxhaXJsaW5lcywgYnk9ImNhcnJpZXIiKQpkZiA8LSBsZWZ0X2pvaW4oZGYscGxhbmVzLCBieT0idGFpbG51bSIpCmRmIDwtIGxlZnRfam9pbihkZix3ZWF0aGVyLCBieT1jKCJvcmlnaW4iLCJ0aW1lX2hvdXIiKSkKCiNFc3RhcyByZWxhY2lvbmVzIHNlIGxvZ3JhbiBhIHRyYXbDqXMgZGVsIHVzbyBkZSBmdW5jaW9uZXMgY29tbyBtZXJnZSB5IGxlZnRfam9pbixxdWUgcGVybWl0ZW4gZW5jb250cmEgbGFzIHJlbGFjaW9uZXMgZW50cmUgbG9zIGRpZmVyZW50ZXMgZGF0YSBmcmFtZXMuIEVzdGUgcGFzbyBzZSByZWFsaXrDsyBhbCBpbmljbyBkZWwgcHJvZ3JhbWEgcGFyYSBlbCBkZXNhcnJvbGxvIGRlIGxvcyBvdHJvcyBwdW50b3MgZGUgYW7DoWxpc2lzLgpgYGAKCiMjIyA8c3BhbiBzdHlsZT0iY29sb3I6IGdyZWVuOyI+VmlzdWFsaXphY2lvbmVzIEZsaWdodHMgYW5kIEFpcnBvcnRzPC9zcGFuPgpgYGB7cn0KI1Zpc3VhbGl6YWNpb25lcyBkZSBGbGlnaHRzCgojIEdyw6FmaWNvIGRlIEJhcnJhcwpnZ3Bsb3QoZGF0YSA9IHZ1ZWxvc19jYW50aWRhZDIsIGFlcyh4ID0gY2FycmllciwgeSA9IG4pKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBsYWJzKHRpdGxlID0gIkNhbnRpZGFkIGRlIFZ1ZWxvcyBwb3IgQWVyb2zDrW5lYSIsCiAgICAgICB4ID0gIkFlcm9sw61uZWEiLAogICAgICAgeSA9ICJDYW50aWRhZCBkZSBWdWVsb3MiKSArCiAgdGhlbWVfbWluaW1hbCgpCgojR3LDoWZpY28gZGUgUGFzdGVsCmdncGxvdChkYXRhID0gdnVlbG9zX2NhbnRpZGFkMiwgYWVzKHggPSAiIiwgeSA9IG4sIGZpbGwgPSBjYXJyaWVyKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDEpICsKICBjb29yZF9wb2xhcigieSIpICsKICBsYWJzKHRpdGxlID0gIlByb3BvcmNpw7NuIGRlIFZ1ZWxvcyBwb3IgQWVyb2zDrW5lYSIsCiAgICAgICB4ID0gTlVMTCwKICAgICAgIHkgPSBOVUxMKSArCiAgdGhlbWVfdm9pZCgpCgojR3LDoWZpY28gZGUgVGVuZGVuY2lhCmdncGxvdChkYXRhID0gRVdSZW5lcm8xNVRlbXBQcm9tLCBhZXMoeCA9IGRheSwgeSA9IHByb21lZGlvdGVtcCkpICsKICBnZW9tX2xpbmUoKSArCiAgbGFicyh0aXRsZSA9ICJUZW5kZW5jaWEgZGUgVGVtcGVyYXR1cmEgZW4gRW5lcm8iLAogICAgICAgeCA9ICJEw61hIiwKICAgICAgIHkgPSAiVGVtcGVyYXR1cmEgKMKwQykiKSArCiAgdGhlbWVfbWluaW1hbCgpCmBgYAoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij4xMC4gQ29uY2x1c2nDs246IFBhcnRlIDI8L3NwYW4+CkFxdcOtIHNlIHBvbmUgbGEgY29uY2x1c2nDs24gZGUgbGEgcGFydGUgMiBkZSBsYSBldmlkZW5jaWEuLi4uLgoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij7Cv1BvciBxdcOpIHNlIHJldHJhc2FuIGxvcyB2dWVsb3MgZW4gTnVldmEgWW9yaz88L3NwYW4+CkludGVycHJldGFjacOzbjogYSBjb250aW51YWNpw7NuIHNlIHByZXNlbnRhLi4uLi5mYWx0YSBwb25lciBncsOhZmljYXMgYXF1w60KYGBge3J9CiNBdHJhc29zIGRlIG9yaWdlbiwgY2FycmllciB5IG1lcy4KYXRyYXNvX3Bvcl9vcmlnZW4gPC0gZmxpZ2h0cyAlPiUgZ3JvdXBfYnkob3JpZ2luKSAlPiUgc3VtbWFyaXNlKHRpZW1wb19hdHJhc29fcHJvbWVkaW8gPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkKCmF0cmFzb19wb3JfY2FycmllciA8LSBmbGlnaHRzICU+JSBncm91cF9ieShjYXJyaWVyKSAlPiUgc3VtbWFyaXNlKHRpZW1wb19hdHJhc29fcHJvbWVkaW8gPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkKCmF0cmFzb19wb3JfbWVzIDwtIGZsaWdodHMgJT4lIGdyb3VwX2J5KG1vbnRoKSAlPiUgc3VtbWFyaXNlKHRpZW1wb19hdHJhc29fcHJvbWVkaW8gPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkKCiMgUmVzdW1lbiBwb3Igb3JpZ2VuCnN1bW1hcnlfYnlfb3JpZ2luIDwtIGZsaWdodHMgJT4lIGdyb3VwX2J5KG9yaWdpbikgJT4lIHN1bW1hcml6ZShNZWRpYV9EZXBfRGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwKTWVkaWFuYV9EZXBfRGVsYXkgPSBtZWRpYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpLCBNaW5fRGVwX0RlbGF5ID0gbWluKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwgTWF4X0RlcF9EZWxheSA9IG1heChkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpCgojIFJlc3VtZW4gcG9yIGFlcm9sw61uZWEKc3VtbWFyeV9ieV9jYXJyaWVyIDwtIGZsaWdodHMgJT4lIGdyb3VwX2J5KGNhcnJpZXIpICU+JSBzdW1tYXJpemUoTWVkaWFfRGVwX0RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICBNZWRpYW5hX0RlcF9EZWxheSA9IG1lZGlhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICBNaW5fRGVwX0RlbGF5ID0gbWluKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwKICAgIE1heF9EZXBfRGVsYXkgPSBtYXgoZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKQoKIyBDYWxjdWxhciByZXN1bWVuIGVzdGFkw61zdGljbyBwb3IgZGVzdGlubwpzdW1tYXJ5X2J5X2Rlc3QgPC0gZmxpZ2h0cyAlPiUKICBncm91cF9ieShkZXN0KSAlPiUKICBzdW1tYXJpemUoTWVkaWFfRGVwX0RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICBNZWRpYW5hX0RlcF9EZWxheSA9IG1lZGlhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSksCiAgICBNaW5fRGVwX0RlbGF5ID0gbWluKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSwKICAgIE1heF9EZXBfRGVsYXkgPSBtYXgoZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKQoKIyBDcmVhciB1biBjb25qdW50byBkZSBkYXRvcyBjb21iaW5hbmRvIGxhcyB2YXJpYWJsZXMgZGUgaW50ZXLDqXMKbW9kZWxvX2RhdGEgPC0gZmxpZ2h0cyAlPiUKICBzZWxlY3QoZGVwX2RlbGF5LCBjYXJyaWVyLCBvcmlnaW4sIG1vbnRoKQoKIyBBanVzdGFyIGVsIG1vZGVsbyBkZSByZWdyZXNpw7NuIGxpbmVhbAptb2RlbG8gPC0gbG0oZGVwX2RlbGF5IH4gY2FycmllciArIG9yaWdpbiArIG1vbnRoLCBkYXRhID0gbW9kZWxvX2RhdGEpCgojIFJlc3VtZW4gZGVsIG1vZGVsbwpzdW1tYXJ5KG1vZGVsbykKCmdncGxvdChtb2RlbG9fZGF0YSwgYWVzKHggPSBhcy5mYWN0b3IobW9udGgpLCB5ID0gZGVwX2RlbGF5LCBncm91cCA9IDEpKSArCiAgZ2VvbV9saW5lKHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgbGluZXR5cGUgPSAic29saWQiLCBzaXplID0gMSkgKwogIGxhYnModGl0bGUgPSAiUHJvbWVkaW8gZGVsIFJldHJhc28gZGUgU2FsaWRhIGVuIGZ1bmNpw7NuIGRlbCBNZXMiLAogICAgICAgeCA9ICJNZXMiLAogICAgICAgeSA9ICJQcm9tZWRpbyBkZSBSZXRyYXNvIGRlIFNhbGlkYSIpCmBgYAoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5BbsOhbGlzaXMgUmV0cmFzb3M8L3NwYW4+CkFxdcOtIHBvbmVtb3MgbG8gcXVlIG5vcyBmYWx0YSBkZSBwb25lciBwYXIgbG8gZGUgcmV0cmFzb3MuLi4uCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPlJldHJhc28gcG9yIHRpcG8gZGUgYXZpw7NuPC9zcGFuPgpgYGB7cn0KIyBSZXRyYXNvIHBvciB0aXBvIGRlIGF2acOzbgpyZXRyYXNvX3Bvcl9hdmlvbiA8LSBmbGlnaHRzICU+JQogIGxlZnRfam9pbihwbGFuZXMsIGJ5ID0gInRhaWxudW0iKSAlPiUKICBncm91cF9ieSh0eXBlKSAlPiUKICBzdW1tYXJpemUoYXZnX2RlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpCgojIEdyw6FmaWNvIGRlIGJhcnJhcyBwYXJhIHJldHJhc28gcG9yIHRpcG8gZGUgYXZpw7NuCmdncGxvdChyZXRyYXNvX3Bvcl9hdmlvbiwgYWVzKHggPSB0eXBlLCB5ID0gYXZnX2RlbGF5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgbGFicyh0aXRsZSA9ICJSZXRyYXNvIFByb21lZGlvIHBvciBUaXBvIGRlIEF2acOzbiIsCiAgICAgICB4ID0gIlRpcG8gZGUgQXZpw7NuIiwKICAgICAgIHkgPSAiUmV0cmFzbyBQcm9tZWRpbyIpICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgoKIyMjIDxzcGFuIHN0eWxlPSJjb2xvcjogZ3JlZW47Ij5SZXRyYXNvIHBvciBkw61hIGRlIGxhIHNlbWFuYTwvc3Bhbj4KYGBge3J9CiMgUmV0cmFzbyBwb3IgZMOtYSBkZSBsYSBzZW1hbmEKcmV0cmFzb19wb3JfZGlhX3NlbWFuYSA8LSBmbGlnaHRzICU+JQogIG11dGF0ZSh3ZWVrZGF5ID0gd2Vla2RheXMoYXMuRGF0ZShwYXN0ZSh5ZWFyLCBtb250aCwgZGF5LCBzZXAgPSAiLSIpKSkpICU+JQogIGdyb3VwX2J5KHdlZWtkYXkpICU+JQogIHN1bW1hcml6ZShhdmdfZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkKCiMgT3JkZW5hciBkw61hcyBkZSBsYSBzZW1hbmEKcmV0cmFzb19wb3JfZGlhX3NlbWFuYSR3ZWVrZGF5IDwtIGZhY3RvcihyZXRyYXNvX3Bvcl9kaWFfc2VtYW5hJHdlZWtkYXksIGxldmVscyA9IGMoIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiLCAiU2F0dXJkYXkiLCAiU3VuZGF5IikpCgojIEdyw6FmaWNvIGRlIGJhcnJhcyBwYXJhIHJldHJhc28gcG9yIGTDrWEgZGUgbGEgc2VtYW5hCmdncGxvdChyZXRyYXNvX3Bvcl9kaWFfc2VtYW5hLCBhZXMoeCA9IHdlZWtkYXksIHkgPSBhdmdfZGVsYXkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAiYmx1ZSIpICsKICBsYWJzKHRpdGxlID0gIlJldHJhc28gUHJvbWVkaW8gcG9yIERpYSBkZSBsYSBTZW1hbmEiLAogICAgICAgeCA9ICJEaWEgZGUgbGEgU2VtYW5hIiwKICAgICAgIHkgPSAiUmV0cmFzbyBQcm9tZWRpbyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCgpgYGAKCgojIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBncmVlbjsiPlJldHJhc28gcG9yIGhvcmEgZGVsIGTDrWE8L3NwYW4+CgoKYGBge3J9CmZsaWdodHMkaG91ciA8LSBhcy5pbnRlZ2VyKGZsaWdodHMkaG91cikgCm1lYW5fZGVsYXlfcGVyX2hvdXIgPC0gYWdncmVnYXRlKGRlcF9kZWxheSB+IGhvdXIsIGZsaWdodHMsIG1lYW4pCmdncGxvdChkYXRhID0gbWVhbl9kZWxheV9wZXJfaG91ciwgYWVzKHggPSBob3VyLCB5ID0gZGVwX2RlbGF5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArCiAgbGFicyh4ID0gIkhvcmEgZGVsIGTDrWEiLCB5ID0gIlJldHJhc28gcHJvbWVkaW8gKG1pbnV0b3MpIiwgCiAgICAgICB0aXRsZSA9ICJSZXRyYXNvIHByb21lZGlvIHBvciBob3JhIGRlbCBkw61hIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmBgYAoKYGBge3J9CiMgR3LDoWZpY2EgYXRyYXNvIHBvciBvcmlnZW4KZ2dwbG90KGF0cmFzb19wb3Jfb3JpZ2VuLCBhZXMoeD1vcmlnaW4sIHk9dGllbXBvX2F0cmFzb19wcm9tZWRpbykpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGZpbGw9ImxpZ2h0Ymx1ZTEiKSArCiAgdGhlbWVfbWluaW1hbCgpICsKICBsYWJzKHRpdGxlPSJBdHJhc28gcHJvbWVkaW8gcG9yIG9yaWdlbiIsIHg9Ik9yaWdlbiIsIHk9IlRpZW1wbyBkZSBhdHJhc28gcHJvbWVkaW8iKQoKIyBHcsOhZmljYSBhdHJhc28gcG9yIGNhcnJpZXIKZ2dwbG90KGF0cmFzb19wb3JfY2FycmllciwgYWVzKHg9Y2FycmllciwgeT10aWVtcG9fYXRyYXNvX3Byb21lZGlvKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IiwgZmlsbD0iY2FkZXRibHVlMyIpICsKICB0aGVtZV9taW5pbWFsKCkgKwogIGxhYnModGl0bGU9IkF0cmFzbyBwcm9tZWRpbyBwb3IgY2FycmllciIsIHg9IkNhcnJpZXIiLCB5PSJUaWVtcG8gZGUgYXRyYXNvIHByb21lZGlvIikKCiMgR3LDoWZpY2EgZGUgYXRyYXNvIHBvciBtZXMKZ2dwbG90KGF0cmFzb19wb3JfbWVzLCBhZXMoeD1tb250aCwgeT10aWVtcG9fYXRyYXNvX3Byb21lZGlvKSkgKwogIGdlb21fbGluZShncm91cD0xLCBjb2xvdXI9ImRhcmtzbGF0ZWdyYXkzIikgKwogIHRoZW1lX21pbmltYWwoKSArCiAgbGFicyh0aXRsZT0iQXRyYXNvIHByb21lZGlvIHBvciBtZXMiLCB4PSJNZXMiLCB5PSJUaWVtcG8gZGUgYXRyYXNvIHByb21lZGlvIikKCmBgYAoKCmBgYHtyfQpmbGlnaHRzX2ZpbHRlcmVkIDwtIGZsaWdodHMgJT4lCiAgbXV0YXRlKGZsaWdodHMgPSBpZmVsc2UoZGVwX2RlbGF5ID4gMCwgIkRlbGF5ZWQiLCAiTm90IERlbGF5ZWQiKSkgJT4lIAogIGdyb3VwX2J5KG1vbnRoLCBmbGlnaHRzKSAlPiUKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JQogIG11dGF0ZShwZXJjZW50ID0gY291bnQgLyBzdW0oY291bnQpICogMTAwKQoKZ2dwbG90KGZsaWdodHNfZmlsdGVyZWQsIGFlcyh4ID0gZmFjdG9yKG1vbnRoKSwgeSA9IGNvdW50LCBmaWxsID0gZmxpZ2h0cykpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAic3RhY2siKSArIAogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoInNlYXNoZWxsMiIsICJyb3N5YnJvd24yIikpICsKICBsYWJzKHRpdGxlID0gIk7Dum1lcm8gZGUgdnVlbG9zIHBvciBtZXMgY29uIHkgc2luIHJldHJhc28iLAogICAgICAgeCA9ICJNZXMiLAogICAgICAgeSA9ICJOw7ptZXJvIGRlIHZ1ZWxvcyIsCiAgICAgICBmaWxsID0gIlJldHJhc28iKSArCiAgdGhlbWVfbWluaW1hbCgpCgpgYGAKCgoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5BbsOhbGlzaXMgZGVsIENsaW1hPC9zcGFuPgpSZXRyYXNvIHBvciBjbGltYQpgYGB7cn0KZmxpZ2h0c193ZWF0aGVyPC0gbWVyZ2Uod2VhdGhlciwgZmxpZ2h0cykKYGBgCgpgYGB7cn0KZmxpZ2h0c193ZWF0aGVyICU+JQogIGdyb3VwX2J5KGh1bWlkKSAlPiUKICBzdW1tYXJpc2UoZGVsYXkgPSBtZWFuKGRlcF9kZWxheSwgbmEucm0gPSBUUlVFKSkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gaHVtaWQsIHkgPSBkZWxheSkpICsKICBsYWJzKHggPSAiSHVtZWRhZCByZWxhdGl2YSIsIHkgPSAiUmV0cmFzbyBwcm9tZWRpbyAobWludXRvcykiLCBmaWxsID0gIkFlb3JvcHVlcnRvIikgKwogIGdndGl0bGUoIlJldHJhc28gcHJvbWVkaW8gcG9yIGh1bWVkYWQgcmVsYXRpdmEiKSArCiAgZ2VvbV9saW5lKCkgKyBnZW9tX3BvaW50KCkrIHRoZW1lKHBsb3QudGl0bGU9IGVsZW1lbnRfdGV4dChoanVzdD0wLjUpKQpgYGAKCmBgYHtyfQpmbGlnaHRzX3dlYXRoZXIgJT4lCiAgZ3JvdXBfYnkodGVtcCkgJT4lCiAgc3VtbWFyaXNlKGRlbGF5ID0gbWVhbihkZXBfZGVsYXksIG5hLnJtID0gVFJVRSkpICU+JQogIGdncGxvdChhZXMoeCA9IHRlbXAsIHkgPSBkZWxheSkpICsKICBsYWJzKHggPSAiVGVtcGVyYXR1cmEiLCB5ID0gIlJldHJhc28gcHJvbWVkaW8gKG1pbnV0b3MpIiwgZmlsbCA9ICJBZW9yb3B1ZXJ0byIpICsKICBnZ3RpdGxlKCJSZXRyYXNvIHByb21lZGlvIHBvciBUZW1wZXJhdHVyYSIpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fc21vb3RoKCkrIHRoZW1lKHBsb3QudGl0bGU9IGVsZW1lbnRfdGV4dChoanVzdD0wLjUpKQpgYGAKCgpgYGB7cn0KZmxpZ2h0c193ZWF0aGVyICU+JQogIGdyb3VwX2J5KHdpbmRfc3BlZWQpICU+JQogIHN1bW1hcmlzZShkZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB3aW5kX3NwZWVkLCB5ID0gZGVsYXkpKSArCiAgbGFicyh4ID0gIlZlbG9jaWRhZCBkZWwgVmllbnRvIiwgeSA9ICJSZXRyYXNvIHByb21lZGlvIChtaW51dG9zKSIpICsKICBnZ3RpdGxlKCJSZXRyYXNvIHByb21lZGlvIHBvciBWZWxvY2lkYWQgZGVsIFZpZW50byIpICsKICBnZW9tX3Ntb290aCgpKyB0aGVtZShwbG90LnRpdGxlPSBlbGVtZW50X3RleHQoaGp1c3Q9MC41KSkKYGBgCmBgYHtyfQpmbGlnaHRzX3dlYXRoZXIgJT4lCiAgZ3JvdXBfYnkod2luZF9kaXIpICU+JQogIHN1bW1hcmlzZShkZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB3aW5kX2RpciwgeSA9IGRlbGF5KSkgKwogIGxhYnMoeCA9ICJEaXJlY2Npw7NuIGRlbCBWaWVudG8iLCB5ID0gIlJldHJhc28gcHJvbWVkaW8gKG1pbnV0b3MpIikgKwogIGdndGl0bGUoIlJldHJhc28gcHJvbWVkaW8gcG9yIERpcmVjY2nDs24gZGVsIFZpZW50byIpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKyAKICB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChoanVzdD0wLjUpKQoKYGBgCmBgYHtyfQpmbGlnaHRzX3dlYXRoZXIgJT4lCiAgZ3JvdXBfYnkodmlzaWIpICU+JQogIHN1bW1hcmlzZShkZWxheSA9IG1lYW4oZGVwX2RlbGF5LCBuYS5ybSA9IFRSVUUpKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSB2aXNpYiwgeSA9IGRlbGF5KSkgKwogIGxhYnMoeCA9ICJWaXNpYmlsaWRhZCIsIHkgPSAiUmV0cmFzbyBwcm9tZWRpbyAobWludXRvcykiKSArCiAgZ2d0aXRsZSgiUmV0cmFzbyBwcm9tZWRpbyBwb3IgVmlzaWJpbGlkYWQgZW4gZWwgYWlyZSIpICsKICBnZW9tX2xpbmUoKSArIAogIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF90ZXh0KGhqdXN0PTAuNSkpCgpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+Q29uY2x1c2lvbmVzIGRlIHJldHJhc29zPC9zcGFuPgpFbiBlc3RhIGFjdGl2aWRhZCBkZSBtYW5lcmEgZ3J1cGFsLCBkZXRlcm1pbmFtb3MgZWwgcG9yIHF1w6kgc2UgcmV0cmFzYW4gbG9zIHZ1ZWxvcyBlbiBsb3MgYWVyb3B1ZXJ0b3MgZGUgTnVldmEgWW9yay4gU2Ugb2J0dXZvIGluZm9ybWFjacOzbiBtdXkgaW50ZXJlc2FudGUgYSB0cmF2w6lzIGRlIGxvcyBkaWZlcmVudGVzIGFuw6FsaXNpcyBkZSBsYSBiYXNlIGRlIGRhdG9zLiAgCgpFbiBwcmltZXJhIGluc3RhbmNpYSBzZSBvYnR1dm8gZWwgYXRyYXNvIHBvciBvcmlnZW4sIGVuIGRvbmRlIG5vcyBtb3N0csOzIGVsIHRpZW1wbyBkZSBhdHJhc28gcHJvbWVkaW8gZW4gY2FkYSB1bm8gZGUgbG9zIHRyZXMgYWVyb3B1ZXJ0b3MgZGlzcG9uaWJsZXMsIGRhbmRvIGNvbW8gcmVzdWx0YWRvIHF1ZSBlbCBhZXJvcHVlcnRvIGNvbiBtYXlvciBhdHJhc28gZW4gcHJvbWVkaW8gZXMgZWwgKipFV1IqKi4gRWwgc2lndWllbnRlIGFuw6FsaXNpcyBmdWUgZWwgYXRyYXNvIHBvciBDYXJyaWVyLCBlbiBkb25kZSBzZSBvYnR1dm8gZWwgYXRyYXNvIHByb21lZGlvIHBvciBhZXJvbMOtbmVhOyA5RSAoKkVuZGV2b2lyIEFpciopIG9idHV2byBlbCBtYXlvciByZXN1bHRhZG8gZW4gYXRyYXNvIHByb21lZGlvLiAgCgpEZXNww7plcyBub3MgZW5mb2NhbW9zIG3DoXMgZW4gZWwgbWVzIGVuIGVsIHF1ZSBoYWLDrWEgbWF5b3JlcyByZXRyYXNvcywgZGFuZG8gY29tbyByZXN1bHRhZG8gdGVtcG9yYWRhcyBhbHRhcyBwYXJhIHZpYWphciwgcG9yIGVqZW1wbG8gZW4gcHJpbWVyIGx1Z2FyIGRlbCBtZXMgY29uIG1heW9yIHJldHJhc28gc2UgZW5jb250cmFiYSBKdWxpbywgYXByb3hpbWFkYW1lbnRlIHNvbG8gcG9yIHVuIG1pbnV0byBtYXlvciBhIEp1bmlvLCB5IGEgZXN0ZSBsZSBzZWd1w61hIGRpY2llbWJyZSBlbiBlbCB0ZXJjZXIgcHVlc3RvLiBTaSB0b21hbW9zIGVuIGN1ZW50YSBxdWUgbXVjaGFzIHBlcnNvbmFzIHZpYWphbiBlbiBkaWNoYXMgdGVtcG9yYWRvcyBwb3IgZWwgdmVyYW5vIHkgbGFzIGZpZXN0YXMgZGVjZW1icmluYXMsIGxvIHF1ZSBvY2FzaW9uYSBxdWUgaGF5YSBtYXlvciBjYW50aWRhZCBkZSBwZXJzb25hcyBlbiBtb3ZpbGlkYWQgZW4gYWVyb3B1ZXJ0b3MsIHBvZHLDrWEgc2VyIHVuIGltcG9ydGFudGUgZmFjdG9yIGRlbCBwb3IgcXXDqSBsb3MgdnVlbG9zIHNlIHJldHJhc2FuIG3DoXMgZW4gZGljaGFzIHRlbXBvcmFkYXMuICAKClBvciDDumx0aW1vLCByZWFsaXphbW9zIHVuIG1vZGVsbyBkZWwgcHJvbWVkaW8gZGVsIHJldHJhc28gZGUgc2FsaWRhIGVuIGZ1bmNpw7NuIGRlbCBtZXMsIGxvIHF1ZSBub3MgbXVlc3RyYSBjb24gbWF5b3IgY2xhcmlkYWQsIHF1ZSBsYXMgdGVtcG9yYWRhcyBhbHRhcyBkZSB2aWFqZXMgc29uIHVuIGZhY3RvciBxdWUgaW5mbHV5ZSBlbiBsb3MgcmV0cmFzb3MgZ2VuZXJhZG9zIGVuIGxvcyBhZXJvcHVlcnRvcyBkZSBOdWV2YSBZb3JrLgoKIyA8c3BhbiBzdHlsZT0iY29sb3I6IGJsdWU7Ij5FamVyY2ljaW9zIGRlIGV2aWRlbmNpYSBlbiBjbGFzZTwvc3Bhbj4gCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPkV4dHJhIDEuIENvbnN1bHRhIGxhIGVzdHJ1Y3R1cmEgZGUgImZsaWdodHMiPC9zcGFuPiAKYGBge3J9CnN0cihmbGlnaHRzKQojIGludDogZW50ZXJvIChzaW4gZGVjaW1hbGVzKQojIG51bTogbnVtw6lyaWNvIChjb24gZGVjaW1hbGVzKQojIGNocjogY2FyYWN0w6lyIChsZXRyYXMpCiMgRGF0ZTogZmVjaGEgKGVuIFIgdmEgYcOxby1tZXMtZMOtYSkKIyBQT1NJWGN0OiBmb3JtYXRvIGZlY2hhIHkgaG9yYQpgYGAKCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+RXh0cmEgMi4gwr9DdcOhbCBlcyBsYSBjbGFzZSBkZSAiZmxpZ2h0cyIgeSBxdWUgc2lnbmlmaWNhPzwvc3Bhbj4gCmBgYHtyfQpjbGFzcyhmbGlnaHRzKQoKIyBMYXMgNSBjbGFzZXMgZGUgb2JqZXRvcyBzb246CiMgMS4gbnVtZXJpYzogTsO6bWVybyByZWFsIG8gZGVjaW1hbGVzLgojIDIuIGludGVnZXI6IE7Dum13ZW9zIGVudGVyb3MKIyAzLiBjb21wbGV4OiBOw7ptZXJvcyBjb21wbGVqb3MKIyA0LiBjaGFyYWN0ZXI6IGNhcsOhY3RlcmVzCiMgNS4gbG9naWNhbDogVFJVRSBPIEZBTFNFCgojIExhcyA0IGNsYXNlcyBkZSBvYmpldG9zIGNvbXB1ZXN0b3Mgc29uOgojIDEuIGxpc3Q6IGxpc3RhCiMgMi4gbWF0cml4OiBtYXRyaXoKIyAzLiBhcnJheTogY29sZWNjacOzbiBkZSBvYmpldG9zCiMgNC4gZGF0YS5mcmFtZTogYmFzZSBkZSBkYXRvcwoKYGBgCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+RXh0cmEgMy4gwr9DdcOhbnRhcyBjb2x1bW5hcyB5IHJlbmdsb25lcyB0aWVuZSAiZmxpZ2h0cyI/IMK/Q3XDoWwgZXMgc3UgZGltZW5zacOzbj88L3NwYW4+IApgYGB7cn0KIyBOw7ptZXJvIGRlIGNvbHVtbmFzCm5jb2woZmxpZ2h0cykKIyBOw7ptZXJvIGRlIHJlbmdsb25lcwpucm93KGZsaWdodHMpCiMgRGltZW5zacOzbgpkaW0oZmxpZ2h0cykKYGBgCgojIyA8c3BhbiBzdHlsZT0iY29sb3I6IHB1cnBsZTsiPkV4dHJhIDQuIE11ZXN0cmEgbG9zIHByaW1lcm9zIDYgcmVuZ2xvbmVzIGRlICJmbGlnaHRzIi4gVGFtYmnDqW4gbG9zIMO6bHRpbW9zIDYuPC9zcGFuPiAKYGBge3J9CmhlYWQoZmxpZ2h0cykKdGFpbChmbGlnaHRzKQojIFNpIHF1aXNpZXJhbW9zIDcgcmVuZ2xvbmVzOiBoZWFkKGZsaWdodHMsNykKYGBgCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkNvbXByb21pc28gw6l0aWNvIHkgY2l1ZGFkYW5vPC9zcGFuPiAKRWwgdmFsb3IgZGUgbGEgaW50ZWdyaWRhZCwgc2Vnw7puIGxhcyBOYWNpb25lcyBVbmlkYXMsIHZpZW5lIGRlIGxhIHByw6FjdGljYSBkZSBzZXIgdW5hIHBlcnNvbmEgaG9uZXN0YSwgcXVlIHNlIGFkaGllcmUgYSBzdXMgdmFsb3JlcyB5IHF1ZSBsYSB0b21hIGRlIGRlY2lzaW9uZXMgZXMgc2lzdGVtw6F0aWNhbWVudGUgcG9zaXRpdmEuIExhIGludGVncmlkYWQgZXMgbGEgZm9ybWEgZGUgYWN0dWFyIGRlIGFjdWVyZG8gYSBsb3MgcHJpbmNpcGlvcywgYSBkaWZlcmVuY2lhIGRlIGxhIGhvbmVzdGlkYWQgcXVlIGVzIGVsIGFjdG8gZGUgc2VyIHZlcmF6LiAoTmFjaW9uZXMgVW5pZGFzKQoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5SZWZsZXhpw7NuIFBlcnNvbmFsOiBOYW5jeSBNYXJyb3F1w61uPC9zcGFuPiAKLSBSZWZsZXhpw7NuIHBlcnNvbmFsOiBFbCByZXNwZXRvIHkgbGEgaG9uZXN0aWRhZCBmb3JtYW4gcGFydGUgZGUgbG9zIHZhbG9yZXMgcXVlIHRyYXRvIGRlIHJlcHJlc2VudGFyIGVuIG1pIGTDrWEgYSBkw61hLiBFbiBjdWFscXVpZSB0aXBvIGRlIHByb3llY3RvIGVuIGVsIHF1ZSBwYXJ0aWNpcG8sIGJ1c2NvIHF1ZSBlc3RlIHNlIGxsZXZlIGEgY2FibyBkZSBtYW5lcmEgbcOhcyB0cmFucGFyZW50ZSwgZm9tZW50YW5kbyBsYSBjb211bmljYWNpw7NuIHkgbGEgZXNjdWNoYSBhY3RpdmEuIEVuIGVsIG11bmRvIGRlIGxvcyBuZWdvY2lvcyBmb21lbnRhciBlc3RvcyB2YWxvcmVzIHRhbiBpbXBvcnRhbnRlcywgc29uIGNsYXZlIHBhcmEgZWwgw6l4aXRvIGRlIGxhcyBlbXByZXNhcy4gRWwgYWN0dWEgZGUgbWFuZXJhIGhvbmVzdGEgeSBjb24gcmVzcGV0byBoYWNpYSBsb3MgZGVtw6FzLCB0ZSBwZXJtaXRlIHRlbmVyIHVuIG1lam9yIGRlc2Fycm9sbG8gcGVyc29uYWwgeSBwcm9mZXNpb25hbC4gIApTaSBub3MgZW5mb2NhbW9zIG3DoXMsIGhhY2lhIGxhIHBhcnRlIGRlIGFuw6FsaXNpcyBkZSBkYXRvcyB5IGVsIHVzbyBkZSBkYXRvcyBkZSBsYXMgZW1wcmVzYXMsIGVsIHJlcGV0byB5IGxhIGhvbmVzdGlkYWQsIG5vIHNvbiBsb3Mgw7puaWNvcyB2YWxvcmVzIHF1ZSBzZSBwcm9tdWV2ZW4sIHNpbm8gcXVlIHRhbWJpw6luIGxhIGNvbmZpYW56YSwgZWwgY29tcHJvbWlzbyB5IGxhIGludGVncmlkYWQuIEFsIHRyYWJhamFyIGNvbiBpbmZvcm1hY2nDs24gZGUgbGEgZW1wcmVzYXMgZXMgbmVjZXNhcmlvIHRlbmVyIG11Y2hvIGN1aWRhZG8gY8OzbW8gZXMgcXVlIHNlIHV0aWxpemEgeSBjdcOhbCBlcyBzdSBwcm9ww7NzaXRvLiBEZSBlc3RhIG1hbmVyYSBlcyBwb3NpYmxlIGdlbmVyYXIgdW5hIG1lam9yIHRvbWEgZGUgZGVjaXNpb25lcyByZXBlY3RvIGFsIHVzbyB5IGRlc2Fycm9sbG8gZGUgZGljaG9zIGRhdG9zLgoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5SZWZsZXhpw7NuIFBlcnNvbmFsOiBLZXZpbiBNZXphPC9zcGFuPiAKLSBSZWZsZXhpw7NuIHBlcnNvbmFsOiBrZXZpbgoKIyMgPHNwYW4gc3R5bGU9ImNvbG9yOiBwdXJwbGU7Ij5SZWZsZXhpw7NuIFBlcnNvbmFsOiBBZHJpw6FuIE1vcmFsZXM8L3NwYW4+IAotIFJlZmxleGnDs24gcGVyc29uYWw6IGFkcmnDoW4KCiMjIDxzcGFuIHN0eWxlPSJjb2xvcjogcHVycGxlOyI+UmVmbGV4acOzbiBQZXJzb25hbDogS2FybGEgTMOzcGV6PC9zcGFuPiAKLSBSZWZsZXhpw7NuIHBlcnNvbmFsOiBrYXJsYQoKCih1c2FyIGFsIG1lbm9zIDMgYmlibGlvZ3JhZsOtYXMgYXF1w60pCgojIDxzcGFuIHN0eWxlPSJjb2xvcjogYmx1ZTsiPkNvbmNsdXNpw7NuIEdlbmVyYWw8L3NwYW4+IApBcXVpIHNlIHBvbmUgbGEgY29uY2x1c2nDs24gZGUgdG9kby4uLi4KCiMgPHNwYW4gc3R5bGU9ImNvbG9yOiBibHVlOyI+QmlibGlvZ3JhZsOtYXM8L3NwYW4+IApBcXVpIHNlIHBvbmUgbGFzIGJpYmxpb2dyYWbDrWFzLi4uLgoKCg==