Grupo 601

Profesor David Saucedo

Alumna:

Avril Lobato Delgado A00833113

library(ggplot2)
library(dplyr)
library(readxl)
library(tidyr)
library(lubridate)
library(purrr)
library(plotly)
library(forecast)
library(readxl)
library(DataExplorer)
library(dplyr)
library(ggplot2)
library(tm)
library(wordcloud)
library(cluster)
library(factoextra) 
library(gridExtra)
library(purrr)
library(pROC)
library(rpart)
library(rpart.plot)
library(e1071)
library(ggpubr)
library(dlookr)
library(zoo)
library(caret)
library(stats)
library(tseries)
library(readr)
library(vars)
library(syuzhet)
library(kableExtra)
library(plotly)
library(scales)
library(readxl)

Introducción

  • ¿Qué es un análisis exploratorio de los datos? El análisis exploratorio de datos (EDA) es una metodología para comprender, examinar y visualizar la estructura y características de un conjunto de datos antes de aplicar modelos, análisis y/o algoritmos estadísticos más avanzados. El objetivo principal es resumir y descubrir características relevantes de los datos mediante técnicas gráficas y estadísticas descriptivas, para obtener información inicial y detectar posibles patrones, tendencias, anomalías o relaciones que puedan ser relevantes para el problema en cuestión.

  • ¿Cómo contribuye el análisis exploratorio de los datos a mejorar el proceso y los resultados de analítica descriptiva? El análisis exploratorio de datos contribuye a mejorar el proceso y los resultados de la analítica descriptiva mediante la identificación de patrones y tendencias lo que ayuda a comprender mejor el fenómeno que están representando y a generar hipótesis sobre posibles relaciones entre las variables. Asimismo, se detectan anomalías y errores puesto que se distinguen valores atípicos, errores de entrada o inconsistencias en los datos que deben ser corregidos antes de realizar análisis avanzados. De igual manera, al explorar la relación entre variables, es más sencillo seleccionar las variables más relevantes para incluir en análisis posteriores, lo que permite simplificar el modelo y mejorar su interpretabilidad. Inclusive, a través de visualizaciones se muestran relaciones entre variables que pueden ser exploradas más a fondo en análisis posteriores para formular y comprobar ciertas hipótesis. Igualmente, el EDA permite examinar la distribución de las variables, lo que funciona para determinar si los supuestos de ciertos modelos estadísticos son válidos y a elegir las técnicas adecuadas para estos.

Antecedentes de la Empresa FORM

Visión:

En 2033 seremos una de las cinco mejores compañías de México que generan valor dentro de la cadena de suministro de las industrias que más valoran la forma en la que se protegen y trasladan las cosas.

Misión:

Transformar nuestro entorno y resolver retos industriales de nuestros clientes a través de la colaboración, provocando nuevas oportunidades que potencian nuestro modelo de negocio, para alcanzar nuestros ideales.

Objetivos estratégicos:

  • Sustentabilidad colaborativa: Fomentar el uso de materiales de bajo impacto ambiental mientras optimizamos los recursos sin desperdiciar.

  • Efectividad colaborativa: Cumplir en tiempo y forma participando proactivamente.

  • Integridad colaborativa: Actitud de honestidad y transparencia dentro de todos nuestros procesos.

  • Innovación colaborativa: Constante búsqueda de nuevas y mejores formas de solucionar a través del ingenio y la experimentación.

  • Calidad colaborativa: Sin comprometer nuestros tiempos, cuidamos cada detalle, desde el espacio de trabajo hasta nuestro producto final.

  • Flexibilidad colaborativa: Siempre encontraremos el como sí, anticipándonos a las adversidades apoyados de la multidisciplina.

Contexto de la Industria

Automotriz

Industria Norteamericana

Con base en las gráficas presentes se muestra el Panorama Actual en EUA:

  • La industria automotriz en EE. UU. se enfrenta a una serie de desafíos, como la escasez de chips, el aumento de los precios de los materiales y la inflación; lo cual se visualiza ante diferencia de ventas con producción.

De igual manera, se muestra tendencia en el incremento de las ventas totales de vehículos en EE. UU. en los próximos años, impulsadas por la recuperación económica y la demanda de vehículos nuevos.

df <- read_xlsx("C:\\Users\\AVRIL\\Documents\\Automotriz_ALD.xlsx")
colnames(df)[5] <- "Total_domestic_sales"

df <- na.omit(df)
df <- unique(df)

df$Año <- as.numeric(as.character(df$Año))

plot_ly(df, x = ~Año) %>%
  add_lines(y = ~Production_total, name = "Producción Total", line = list(color = "blue")) %>%
  add_lines(y = ~Total_domestic_sales, name = "Ventas Totales", line = list(color = "red")) %>%
  layout(title = "<b>Industria Automotriz en USA - Producción Total vs Ventas Totales</b>",
         xaxis = list(title = "Año"),
         yaxis = list(title = "Cantidad"),
         legend = list(orientation = "h", x = 0.5, y = -0.2))  # Mover la leyenda a la parte inferior y centrarla

Industria Mexicana

La exportación de vehículos desde México se da a una variedad de puntos, considerando principalmente países en Asia y Europa. Esto permite determinar el papel importante que cumple México en la industria automotriz y su comercialización a países extranjeros reconocidos, siendo el principal Arabia Saudita.

dfaz1 <-read_excel("C:\\Users\\AVRIL\\Documents\\mx_exportacion_vehiculos_pais_destino.xlsx")

dfaz1 <- dfaz1 %>%
  rename(País_destino = `País destino`)

# Filtrar los datos para obtener solo las exportaciones de autos para el año 2023
df_2023 <- filter(dfaz1, Año == 2023)


# Calcular el total de exportaciones de autos a cada país destino
exportaciones_por_pais <- df_2023 %>%
  group_by(País_destino) %>%
  summarise(Total_exportaciones = sum(Cantidad)) %>%
  arrange(desc(Total_exportaciones)) %>%
  top_n(5)

# Crear el gráfico de barras
ggplot(exportaciones_por_pais, aes(y = reorder(País_destino, Total_exportaciones), x = Total_exportaciones, fill = Total_exportaciones)) +
  geom_bar(stat = "identity") +
  labs(title = "Top 5 de países destino para exportaciones de autos de México en 2023",
       y = "País Destino",
       x = "Cantidad de Exportaciones") +
  scale_fill_gradient(low = "#F4AC88", high = "#FF5400") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20,face = "bold"),
        axis.title = element_text(size = 15))+
  guides(fill = FALSE)

Las principales empresas que realizan exportaciones desde México corresponden a General Motors, Nissan y Ford. Esto muestra que el sector más destacado lo conforman principalmente empresas americanas (y 1 japonesa), siendo un aspecto relevante debido a la existencia de choques culturales con las compañías coreanas y chinas acorde al actual dueño de Form, Felipe. Determinando de esta forma, la posibilidad de mantener buenas relaciones con los principales líderes en exportación en México, con una mayor facilidad.

# Calcular el total de exportaciones de autos para cada marca
exportaciones_por_marca <- df_2023 %>%
  group_by(Marca) %>%
  summarise(Total_exportaciones = sum(Cantidad)) %>%
  arrange(desc(Total_exportaciones)) %>%
  top_n(5)

# Crear el gráfico de barras horizontal para las 10 marcas más exportadas
ggplot(exportaciones_por_marca, aes(y = reorder(Marca, Total_exportaciones), x = Total_exportaciones, fill = Total_exportaciones)) +
  geom_bar(stat = "identity") +
  labs(title = "Top 5 de marcas más exportadas de autos de México en 2023",
       y = "Marca",
       x = "Cantidad de Exportaciones") +
  scale_fill_gradient(low = "#F4AC88", high = "#FF5400") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20,face = "bold"),
        axis.title = element_text(size = 15))+
  guides(fill = FALSE)

Entre los vehículos que hacen uso de combustible alternativo (o complementario) a la gasolina destacan principalmente los híbridos no enchufables, representando los híbridos enchufables la más baja proporción de ventas en el mercado mexicano. Asimismo, los principales estados donde ocurrieron mayores ventas de este tipo de vehículos fueron Ciudad de México, Estado de México y Nuevo León, siendo algunos de los principales centros económicos que destacaron como pioneros en la integración de este tipo de vehículos. Esto genera una oportunidad para Form para la atención de este mercado ampliamente presente en su Estado de origen, pudiendo complementar sus operaciones al ofrecer el uso de sus soluciones de cartón para embalaje.

# Vehículos Eléctricos
dfve <- read.csv("C:\\Users\\AVRIL\\Documents\\mx_venta_vehiculos_hibridos_electricos_2023.csv")
dfve <- dfve[dfve$ID_ENTIDAD != 99, ]

# Crear un vector con los nombres reales de los estados
nombres_estados <- c("Aguascalientes", "Baja California", "Baja California Sur", "Campeche", "Coahuila", "Colima", "Chiapas", "Chihuahua", "Ciudad de México", "Durango", "Guanajuato", "Guerrero", "Hidalgo", "Jalisco", "Estado de México", "Michoacán", "Morelos", "Nayarit", "Nuevo León", "Oaxaca", "Puebla", "Querétaro", "Quintana Roo", "San Luis Potosí", "Sinaloa", "Sonora", "Tabasco", "Tamaulipas", "Tlaxcala", "Veracruz", "Yucatán", "Zacatecas")

# Crear un data frame con los ID_ENTIDAD y los nombres de los estados
estados_df <- data.frame(ID_ENTIDAD = 1:32, ESTADO = nombres_estados)

# Unir los data frames usando la función merge
dfve <- merge(dfve, estados_df, by = "ID_ENTIDAD", all.x = TRUE)

ventas_por_estado <- dfve %>%
  group_by(ESTADO) %>%
  summarise(Total_ventas_electricos = sum(VEH_ELECTR),
            Total_ventas_hibridos = sum(VEH_HIBRIDAS),
            Total_ventas_hibridos_enchufables = sum(VEH_HIBRIDAS_PLUGIN))


ventas_por_estado_long <- ventas_por_estado %>%
  pivot_longer(cols = c(Total_ventas_electricos, Total_ventas_hibridos, Total_ventas_hibridos_enchufables),
               names_to = "Tipo de Vehículo",
               values_to = "Total de Ventas")


# Seleccionar los 10 principales estados con las mayores ventas totales
top5_estados <- ventas_por_estado %>%
  slice_max(order_by = Total_ventas_electricos + Total_ventas_hibridos + Total_ventas_hibridos_enchufables, n = 5)

# Filtrar ventas_por_estado_long para incluir solo los 10 principales estados
ventas_top10 <- ventas_por_estado_long %>%
  filter(ESTADO %in% top5_estados$ESTADO)

# Crear el gráfico de barras mostrando las ventas divididas por tipo de vehículo para los 10 principales estados
ggplot(ventas_top10, aes(y = reorder(ESTADO, `Total de Ventas`), x = `Total de Ventas`, fill = `Tipo de Vehículo`)) +
  geom_bar(stat = "identity", position = "stack") +
  labs(title = "Top 5 de estados con ventas de vehículos en México en 2023",
       y = "Estado",
       x = "Total de Ventas",
       fill = "") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17),
        legend.position = "top")  

La industria automotriz en México presenta mayor producción local que importaciones, lo cual remarca la relevancia de la industria automotriz en México, siendo también considerable la cantidad unidades exportadas. Es importante destacar el descenso en la producción local debido a la pandemia por COVID-19 en el 2020, así como también su recuperación en años posteriores, siendo un buen indicativo para el futuro de la industria automotriz en el país.

dfaz2 <- mx_automotive_industry <- read_excel("C:\\Users\\AVRIL\\Documents\\mx_automotive_industry.xlsx", sheet = 1)


# Métricas de la Industria Automotriz en México
plot_ly(data = dfaz2, x = ~year) %>%
  add_lines(y = ~total_local_production, color = I("blue"), name = "Producción Local") %>%
  add_lines(y = ~total_exports, color = I("green"), name = "Exportaciones") %>%
  add_lines(y = ~total_imports, color = I("red"), name = "Importaciones") %>%
  layout(title = list(text = "<b>Evolución de métricas de Industria Automotriz en México</b>"),
         xaxis = list(title = "Año"),
         yaxis = list(title = "Valor"),
         legend = list(x = 0.5, y = 1))

Autopartes

Industria Norteamericana

En relación al Panorama Actual de la industria de Autopartes en EUA se preveé que el promedio de nuevos pedidos de fabricantes: vehículos de motor y repuestos (AMVPNO) desde 1995 hasta 2023 ha sido mayor en el periodo de invierno donde jerárquicamente los meses con mayores ventas son: Enero, Diciembre, Noviembre, Octubre y Spetiembre; lo cual representa cierta estacionalidad en este periodo y una estimación mayor de producción antes de Septiembre.

Predicción de Nuevos pedidos de fabricantes: vehículos de motor y repuestos (AMVPNO) para 2025

En relación al Panorama Actual se muestra:

  • A partir del año 2020, se observa una estabilización en las ventas, lo que podría ser un indicio de maduración del mercado.

  • La industria de autopartes en EE. UU. ha experimentado un crecimiento constante en los últimos años, con un valor de mercado de aproximadamente $892 mil millones en 2022. Dicho crecimiento se ha visto impulsado por una serie de factores, como el aumento de la producción de vehículos en EUA, la creciente demanda de vehículos eléctricos e híbridos; y un mayor enfoque en la seguridad y las características tecnológicas en los vehículos.

Por lo tanto, las tendencias de mayor fuerza en esta industria son:

  • Crecimiento de industria impulsado por factores como el aumento del parque automotor, mayor demanda de vehículos usados y el desarrollo de nuevas tecnologías automotrices.

  • Se espera que la competencia en la industria nacional e internacional se intensifique, con la entrada de nuevos competidores, especialmente de países asiáticos.

  • Nuevas oportunidades ante el auge de vehículos eléctricos por ende, la innovación será clave para el éxito de las empresas en la industria de autopartes, ya que permitirá desarrollar productos y servicios más eficientes y competitivos.

df2 <- read_xls("C:\\Users\\AVRIL\\Documents\\Autopartes_ALD.xls")
df2 <- na.omit(df2)
df2 <- unique(df2)

df2$observation_date = as.Date(df2$observation_date)

#Promedio de Nuevos pedidos de fabricantes: vehículos de motor y repuestos (AMVPNO) 
df2$Mes <- format(df2$observation_date, "%m")

#Predicción de Nuevos pedidos de fabricantes: vehículos de motor y repuestos (AMVPNO) para 2025
ts_ventas <- ts(df2$AMVPNO, frequency = 12, start = c(1992, 1))

df_ts_ventas <- data.frame(Año = as.Date(time(ts_ventas)), Ventas = as.numeric(ts_ventas))
plot_ly(df_ts_ventas, x = ~Año, y = ~Ventas, type = 'scatter', mode = 'lines', name = 'Ventas', color="orange") %>%
  layout(title = "<b>Histórico de Ventas de Autopartes en Estados Unidos</b>",
         xaxis = list(title = "Año"),
         yaxis = list(title = "Ventas"))
# Ajustar el modelo de series de tiempo automáticamente
modelo <- auto.arima(ts_ventas)

# Generar predicciones hasta el cierre del año 2025 (36 meses más allá de los datos existentes)
predicciones <- forecast(modelo, h = 23)
predicciones
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2024       61033.07 58054.83 64011.32 56478.24 65587.91
## Feb 2024       61363.02 57090.37 65635.68 54828.56 67897.48
## Mar 2024       61494.39 56753.76 66235.02 54244.22 68744.56
## Apr 2024       61596.43 56581.21 66611.66 53926.31 69266.56
## May 2024       61698.47 56422.93 66974.02 53630.22 69766.73
## Jun 2024       61800.52 56276.90 67324.13 53352.87 70248.16
## Jul 2024       61902.56 56141.55 67663.57 53091.85 70713.26
## Aug 2024       62004.60 56015.60 67993.60 52845.21 71163.99
## Sep 2024       62106.64 55898.01 68315.27 52611.36 71601.92
## Oct 2024       62208.68 55787.93 68629.43 52389.00 72028.37
## Nov 2024       62310.73 55684.65 68936.80 52177.01 72444.44
## Dec 2024       62412.77 55587.53 69238.00 51974.47 72851.07
## Jan 2025       62514.81 55496.06 69533.55 51780.57 73249.05
## Feb 2025       62616.85 55409.79 69823.91 51594.61 73639.10
## Mar 2025       62718.89 55328.32 70109.47 51415.98 74021.80
## Apr 2025       62820.93 55251.29 70390.58 51244.16 74397.71
## May 2025       62922.98 55178.40 70667.55 51078.67 74767.28
## Jun 2025       63025.02 55109.38 70940.66 50919.09 75130.95
## Jul 2025       63127.06 55043.97 71210.15 50765.04 75489.07
## Aug 2025       63229.10 54981.97 71476.23 50616.20 75842.00
## Sep 2025       63331.14 54923.16 71739.12 50472.25 76190.04
## Oct 2025       63433.18 54867.38 71998.99 50332.91 76533.46
## Nov 2025       63535.23 54814.45 72256.00 50197.95 76872.51
plot(predicciones, main = "Predicciones de Ventas hasta 2025", xlab = "Año", ylab = "Ventas")

Industria Mexicana

Es posible observar que las principales plantas de autopartes en México durante el 2022 se concentraron en Coahuila y Puebla, destacando como los estados con mayor valor comercial en exportaciones. Ante esto es necesario considerar la cercanía de Coahuila con Nuevo León, estado en el que está presente la planta de Form. Esto supone una ventaja al mantener cercanía en uno de los puntos clave de la industria de autopartes en el país.

Al hacer la comparación entre el valor comercial del 2021 con el 2022, Coahuila vuelve a destacar como el estado con mayor valor total en la suma de ambos años. Esto reafirma lo mencionado en el punto anterior, siendo Coahuila un punto estrátegico en la industria de autopartes y la ventaja que eso representa para Form al estar próximo. Sin embargo, esto también tiene una consideración importante, siendo que a pesar de mantener el valor más elevado durante ambos años, este fue el mismo, es decir, no hubo un crecimiento, a diferencia de Puebla, en el cual sí hubo un crecimiento considerable con respecto al año previo, pero igualmente es un comportamiento favorable comparando con el resto de estados, en los cuales hubo decrecimiento.

dfap1 <- read.csv("C:\\Users\\AVRIL\\Documents\\mex_exports_autoparts.csv")

df_2021_2022 <- subset(dfap1, year %in% c(2021, 2022))

# Agrupar los datos por estado y año, y calcular el total del valor comercial para cada estado en cada año
state_trade <- df_2021_2022 %>%
  group_by(State, year) %>%
  summarise(total_trade = sum(trade_value))

# Seleccionar los 10 estados con el valor comercial más alto en ambos años
top10_states <- state_trade %>%
  group_by(year) %>%
  top_n(8, total_trade) %>%
  arrange(year, desc(total_trade))

# Crear el gráfico de barras
ggplot(top10_states, aes(x = reorder(State, total_trade), y = total_trade, fill = factor(year))) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Comparación de valor comercial entre 2021 y 2022 (Top 8 estados)",
       x = "Estado",
       y = "Valor Comercial Total",
       fill = "Año") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17),
        axis.text = element_text(size = 12))

Finalmente, en la industria de autopartes en México a lo largo del tiempo se observó un impacto considerable debido a la pandemia por COVID-19 en 2020, sin embargo esta tuvo una recuperación considerable en años posteriores. Asimismo, se identificó que el valor de la producción local es mayor al de las importaciones de otros países. Esto muestra la magnitud de la importancia de la producción de autopartes como una industria sólida en el país.

dfap2 <- mx_automotive_industry <- read_excel("C:\\Users\\AVRIL\\Documents\\mx_automotive_industry.xlsx", sheet = "mx_autoparts_market")

# Crear el gráfico de líneas
plot_ly(dfap2, x = ~year) %>%
  add_lines(y = ~total_local_production, color = I("blue"), name = "Producción Local") %>%
  add_lines(y = ~total_exports, color = I("green"), name = "Exportaciones") %>%
  add_lines(y = ~total_imports, color = I("red"), name = "Importaciones") %>%
  layout(title = list(text = "<b>Evolución de métricas de Autopartes en México</b>"),
         xaxis = list(title = "Año"),
         yaxis = list(title = "Valor"),
         legend = list(x = 0.5, y = 1))

Carton

Industria Norteamericana

Las siguientes dos gráficas, muestran que el Panorama Actual de la industria del cartón tiene como competencia la fabricación de fibra y papel donde este último es el primero en percibir mayores ingresos anuales. A pesar de esto se visualiza que:

  • La industria del cartón en Estados Unidos ha experimentado un crecimiento constante en los últimos años puesto que, entre 2012 y 2022, los ingresos anuales de la industria aumentaron en un 50%.

  • El crecimiento se ha desacelerado ligeramente en los últimos años, pero se espera que continúe en el futuro.

df3 <- read_xlsx("C:\\Users\\AVRIL\\Documents\\Carton_ALD.xlsx")
df3 <- na.omit(df3)
df3 <- unique(df3)

df3$Año <- as.numeric(df3$Año)

#Promedio de ingresos por año
ggplot(df3, aes(x = Año)) +
  geom_bar(aes(y = paper_mills, fill = "Paper"), stat = "identity", position = "dodge") +
  geom_bar(aes(y = pulp_mills, fill = "Pulp"), stat = "identity", position = "dodge") +
  geom_bar(aes(y = paperboard_mills, fill = "Paperboard"), stat = "identity", position = "dodge") +
  labs(title = "Ingresos de la industria de las fábricas de pulpa, papel y cartón en EE. UU. de 2012 a 2024",
       x = "Año",
       y = "Miles de millones de dólares estadounidenses",
       fill = "Tipo") +
  scale_fill_manual(values = c("Paper" = "red", "Pulp" = "lightblue", "Paperboard" = "green")) +
  theme_minimal()+
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17))

Industria Mexicana

El valor comercial total de las importaciones de productos de cartón en México obtuvó el 2do valor más alto entre los países de América, superado únicamente por Estados Unidos. Esto permite comprobar la demanda en empresas con sede en México por soluciones de cartón.

dfcm <- read.csv("C:\\Users\\AVRIL\\Documents\\ImportersBoxes2020_2021.csv")

# Filtrar Países de Norte América
df_north_america <- subset(dfcm, Continent == "North America")

# Obtener el top 5 de países con mayor trade value
top5_tradevalue <- df_north_america %>%
  arrange(desc(Trade.Value)) %>%
  head(5)

# Crear el gráfico de barras comparando el valor comercial en América del Norte para el top 5 de países
ggplot(top5_tradevalue, aes(x = reorder(Country, Trade.Value), y = Trade.Value, fill = Country)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = comma(Trade.Value)), vjust = -0.5, size = 8, color = "black") +
  labs(title = "Top 5 de países en valor comercial de cajas en América del Norte en 2021",
       x = "País",
       y = "Valor Comercial") +
  scale_y_continuous(labels = comma) +  # Formatear los números en el eje y
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 20),
        axis.title = element_text(size = 18),
        axis.text = element_text(size = 18),
        legend.position = "none")

El crecimiento anual entre 2020 y 2021 en el valor comercial del cartón en México se destacó con el tercer valor más alto entre los países en América. Este dato, junto con lo mencionado anteriormente, sugiere un aumento positivo en la demanda de estas soluciones, lo que remarca la relevancia de las operaciones de Form. Sin embargo, es importante tener en cuenta que en ambos casos (valor total y crecimiento), México es superado por Estados Unidos, lo cual es comprensible dada la potencia comercial que representa Estados Unidos.

# Obtener el top 5 de países con mayor crecimiento en valor
top5_tradegrowth <- df_north_america %>%
  arrange(desc(Trade.Value.Growth.Value)) %>%
  head(5)

# Crear el gráfico de barras comparando el valor del crecimiento del valor comercial en América del Norte para el top 5 de países
ggplot(top5_tradegrowth, aes(x = reorder(Country, Trade.Value.Growth.Value), y = Trade.Value.Growth.Value, fill = Country)) +
  geom_bar(stat = "identity") +
  geom_text(aes(label = comma(Trade.Value.Growth.Value)), vjust = -0.5, size = 8, color = "black") +
  labs(title = "Top 5 de Países con Mayor Crecimiento de Valor Comercial de Cajas en América del Norte en 2021",
       x = "País",
       y = "Crecimiento del Valor Comercial") +
  scale_y_continuous(labels = comma) +  # Formatear los números en el eje y
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 18),
        axis.title = element_text(size = 20),
        axis.text = element_text(size = 18),
        legend.position = "none")

FODA Cruzado

PESTLE

Político

  • Acuerdos comerciales: Los tratados comerciales entre México y EE.UU., como el T-MEC, influyen directamente en las operaciones de nearshoring, facilitando o dificultando el comercio.

  • Regulaciones de importación/exportación: Cambios en las políticas pueden afectar la eficiencia y costos de las operaciones transfronterizas.

Económico

  • Nearshoring y relocalización: El aumento de empresas relocalizando su producción cerca de EE.UU. para reducir costos y tiempos de envío puede ser una oportunidad para FORM.

  • Tipo de cambio: Fluctuaciones entre el peso mexicano y el dólar estadounidense pueden impactar los costos y precios de los productos.

Social

  • Sostenibilidad y conciencia ambiental: Una creciente preocupación por el medio ambiente podría impulsar la demanda de empaques sostenibles.

  • Preferencias del consumidor: Tendencias hacia productos locales y de menor impacto ambiental pueden afectar las decisiones de compra.

Tecnológico

  • Innovaciones en materiales y procesos de empaque: Avances tecnológicos que permitan mejorar la eficiencia, reducir costos o incrementar la sostenibilidad pueden ser clave.

  • Digitalización y automatización: La integración de tecnologías digitales en la cadena de suministro puede mejorar la eficiencia operativa.

Ecológico

  • Gestión de residuos y reciclaje: La presión para mejorar la sostenibilidad de los empaques puede llevar a buscar materiales más ecológicos.

  • Huella de carbono: La necesidad de reducir las emisiones de CO2 podría influir en las decisiones de logística y producción.

Estrategias a seguir en el corto plazo

  • Innovación en empaques sostenibles: Desarrollar y promocionar soluciones de empaque que sean tanto funcionales como ambientalmente responsables, anticipándose a las tendencias del mercado y regulaciones. Esto puede incluir la investigación en materiales biodegradables o reciclables, y procesos de producción más eficientes.

  • Digitalización y mejora de la eficiencia operativa: Invertir en tecnología para la automatización de procesos y la digitalización de la cadena de suministro. Esto no solo puede mejorar la eficiencia operativa, sino también ofrecer mejor transparencia y trazabilidad, aspectos cada vez más valorados por los clientes.

  • Expansión de mercado y diversificación: Aunque la empresa tiene una presencia fuerte en San Antonio, explorar nuevos mercados en EE.UU. y otros países podría ser estratégico. Diversificar la cartera de productos para atender a otras industrias además de la automotriz también puede ayudar a mitigar riesgos y aprovechar nuevas oportunidades de nearshoring.

Definición de la Situación Problema

Situación Problema 1: Actualmente FORM tiene como reto la incertidumbre de la demanda para su predicción y eficiencia operatia, puesto que FORM tiene interés en prever la producción para anticipar la demanda diaria de sus proveedores. Esto permitirá planificar con precisión y satisfacer eficientemente los pedidos en tiempo y forma. Cabe destacar que para dicho análisis también se busca evaluar el impacto del Nearshoring en esta situación, con el fin de determinar cómo dicho efecto ayuda y/o afecta a la empresa a alcanzar sus objetivos y, por ende, generar estrategias efectivas.

Situación Problema 2: Asimismo, FORM se enfrenta a la alta rotación de empleados, que afecta a la empresa de manera generalizada. A pesar de implementar diversas medidas y herramientas en áreas como prestaciones y condiciones laborales, los empleados tienden a dejar sus puestos poco después de comenzar su contrato. Ante esta situación, la empresa busca comprender este comportamiento y desarrollar estrategias para mejorar la retención de su personal con el fin de evitar efectos a mediano y largo plazo como el aumento de costos, deterioro de cultura empresarial, etc.

Análisis Exploratorio de Datos (EDA)

FORM RH FJ2024

Limpieza y organización

# Leer y observar el archivo
rh_alt <- read_excel("C:\\Users\\AVRIL\\Documents\\Datos_FORM_RH_FJ2024.xlsx")
str(rh_alt)
## tibble [606 × 10] (S3: tbl_df/tbl/data.frame)
##  $ Fecha de nacimiento: POSIXct[1:606], format: "1985-08-18" "1969-06-27" ...
##  $ HOY                : POSIXct[1:606], format: "2024-04-06" "2024-04-06" ...
##  $ Género             : chr [1:606] "Femenino" "Masculino" "Masculino" "Femenino" ...
##  $ Fecha de Alta      : POSIXct[1:606], format: "2017-02-20" "2017-12-01" ...
##  $ Puesto             : chr [1:606] "Costurera" "Gestor" "Chofer" "Lider" ...
##  $ Dpto               : chr [1:606] "Costura" "Embarques" "Embarques" "Produccion Cartón Mdl" ...
##  $ SD                 : chr [1:606] "152.86" "176.72" "176.72" "144.45" ...
##  $ Municipio          : chr [1:606] "San Nicolas De Los G" "Monterrey" "Pesqueria" "Apodaca" ...
##  $ Estado             : chr [1:606] "Nuevo León" "Nuevo León" "Nuevo León" "Nuevo León" ...
##  $ Estado Civil       : chr [1:606] "Casado" "Casado" "Casado" "Soltero" ...
# Asignar nombres de columnas
colnames(rh_alt)<-c('fecha_nacimiento','fecha_actual','genero', 'fecha_alta','puesto','depto','salario_diario','mpio','estado','estado_civil')

# Reemplazar valores erróneos en la base de datos
rh_alt$estado_civil[rh_alt$estado_civil == "Soltera"] <- "Soltero"
rh_alt$estado_civil[rh_alt$estado_civil == "Casada"] <- "Casado"
rh_alt$estado_civil[rh_alt$estado_civil == "casado"] <- "Casado"
rh_alt$estado_civil[rh_alt$estado_civil == "Divorciada"] <- "Divorciado"
rh_alt$estado_civil[rh_alt$estado_civil == "Viuda"] <- "Viudo"

rh_alt$puesto[rh_alt$puesto == "Ayudante de embarques"] <- "Ayudante de Embarques"
rh_alt$puesto[rh_alt$puesto == "Ayud. De Embarques"] <- "Ayudante de Embarques"
rh_alt$puesto[rh_alt$puesto == "Auxiliar de Embarques"] <- "Ayudante de Embarques"
rh_alt$puesto[rh_alt$puesto == "Ayudante de soldador"] <- "Ayudante de Soldador"
rh_alt$puesto[rh_alt$puesto == "Ayu. De Soldador"] <- "Ayudante de Soldador"
rh_alt$puesto[rh_alt$puesto == "Ay. General"] <- "Ayudante General"
rh_alt$puesto[rh_alt$puesto == "Ayudante general"] <- "Ayudante General"
rh_alt$puesto[rh_alt$puesto == "Ayu. De Pintor"] <- "Ayudante de Pintor"
rh_alt$puesto[rh_alt$puesto == "Ayudante De Pintor"] <- "Ayudante de Pintor"
rh_alt$puesto[rh_alt$puesto == "Ayudante general-Cedis"] <- "Ayudante general CEDIS"
rh_alt$puesto[rh_alt$puesto == "Inspectora de Calidad"] <- "Calidad"
rh_alt$puesto[rh_alt$puesto == "Inspector de calidad"] <- "Calidad"
rh_alt$puesto[rh_alt$puesto == "Inspectora De Calidad"] <- "Calidad"
rh_alt$puesto[rh_alt$puesto == "Materialista"] <- "Materiales"
rh_alt$puesto[rh_alt$puesto == "Operador Sierra"] <- "Operador de Sierra"
rh_alt$puesto[rh_alt$puesto == "Materialista"] <- "Materiales"
rh_alt$puesto[rh_alt$puesto == "Costurera"] <- "Costura"
rh_alt$puesto[rh_alt$puesto == "Costurero"] <- "Costura"

rh_alt$estado[rh_alt$estado == "Nuevo Leon"] <- "Nuevo León"

rh_alt$mpio[rh_alt$mpio == "Ramoz Arizpe"] <- "Ramos Arizpe"
rh_alt$mpio[rh_alt$mpio == "San Nicolas De Los G"] <- "San Nicolas de los Garza"
rh_alt$mpio[rh_alt$mpio == "San Nicolas"] <- "San Nicolas de los Garza"

rh_alt$depto[rh_alt$depto == "Cedis"] <- "CEDIS"
rh_alt$depto[rh_alt$depto == "Ehs"] <- "EHS"
rh_alt$depto[rh_alt$depto == "Produccion Cartón MC"] <- "Producción Cartón MC"
rh_alt$depto[rh_alt$depto == "Produccion Cartón Mdl"] <- "Produccion Cartón MDL"
rh_alt$depto[rh_alt$depto == "Producción Retorn"] <- "Produccion Retornable"
rh_alt$depto[rh_alt$depto == "Paileria"] <- "Paileria y Pintura"
rh_alt <- rh_alt %>%
  mutate(depto = ifelse(is.na(depto), "Área No Definida", depto))

# Convertir fechas en formato de fecha
rh_alt$fecha_nacimiento<-as.Date(rh_alt$fecha_nacimiento,format="%m/%d/%Y") 
rh_alt$fecha_actual<-as.Date(rh_alt$fecha_actual,format="%m/%d/%Y") 

# Crear columna edad
edad<-as.numeric(difftime(rh_alt$fecha_actual, rh_alt$fecha_nacimiento, units = "days") / 365)
rh_alt$edad<-edad

# Reemplazar outliers
mediana_edad <- median(rh_alt$edad, na.rm = TRUE)
rh_alt$edad <- ifelse(rh_alt$edad < 10, mediana_edad, rh_alt$edad)

# Conversión a factores
rh_alt$genero<-as.factor(rh_alt$genero)
rh_alt$puesto<-as.factor(rh_alt$puesto)
rh_alt$depto<-as.factor(rh_alt$depto)
rh_alt$mpio<-as.factor(rh_alt$mpio)
rh_alt$estado<-as.factor(rh_alt$estado)
rh_alt$estado_civil<-as.factor(rh_alt$estado_civil)
rh_alt$salario_diario<-as.numeric(rh_alt$salario_diario)

summary(rh_alt)
##  fecha_nacimiento      fecha_actual              genero   
##  Min.   :1962-12-29   Min.   :2024-04-06   Femenino :335  
##  1st Qu.:1983-12-04   1st Qu.:2024-04-06   Masculino:271  
##  Median :1994-03-22   Median :2024-04-06                  
##  Mean   :1991-08-17   Mean   :2024-04-06                  
##  3rd Qu.:2000-08-06   3rd Qu.:2024-04-06                  
##  Max.   :2022-10-31   Max.   :2024-04-06                  
##                                                           
##    fecha_alta                                       puesto   
##  Min.   :2017-02-20 00:00:00.00   Ayudante General     :497  
##  1st Qu.:2023-01-10 00:00:00.00   Costura              : 15  
##  Median :2023-06-15 12:00:00.00   Soldador             : 15  
##  Mean   :2023-04-15 08:54:39.21   Calidad              : 14  
##  3rd Qu.:2023-09-11 00:00:00.00   Montacarguista       : 12  
##  Max.   :2024-03-07 00:00:00.00   Ayudante de Embarques:  7  
##                                   (Other)              : 46  
##                    depto     salario_diario                        mpio    
##  Área No Definida     :371   Min.   :144.4   Apodaca                 :418  
##  Produccion Cartón MDL: 55   1st Qu.:217.6   Pesqueria               : 75  
##  Producción Cartón MC : 40   Median :217.6   Juarez                  : 58  
##  Paileria y Pintura   : 26   Mean   :211.2   Guadalupe               : 25  
##  Materiales           : 18   3rd Qu.:217.6   Ramos Arizpe            : 18  
##  Produccion Retornable: 18   Max.   :261.2   San Nicolas de los Garza:  3  
##  (Other)              : 78                   (Other)                 :  9  
##         estado         estado_civil      edad      
##  Coahuila  : 19   Casado     :162   Min.   :18.43  
##  Nuevo León:587   Divorciado :  2   1st Qu.:23.77  
##                   Soltero    :280   Median :30.08  
##                   Union Libre:159   Mean   :32.71  
##                   Unión libre:  1   3rd Qu.:40.37  
##                   Viudo      :  2   Max.   :61.31  
## 

Clusters

# Dataset para kmeans
rh_edad<-rh_alt %>% 
  dplyr::select(genero,estado_civil,salario_diario,edad)

rh_edad_norm<-scale(rh_edad[3:4]) # Escalar variables para evitar sesgo

# Calcular cantidad adecuada de clusters utilizando el método de wss
set.seed(123)
wss <- function(k) {
  kmeans(rh_edad_norm, k, nstart = 10 )$tot.withinss
}
k.values <- 1:15
wss_values <- map_dbl(k.values, wss)
plot(k.values, wss_values,
     type="b", pch = 19, frame = FALSE, 
     xlab="Number of clusters K",
     ylab="Total within-clusters sum of squares")

# Creación de clusters mediante kmeans
set.seed(123)
edad_cluster<-kmeans(rh_edad_norm,3)

# Gráfica de clusters resultantes
fviz_cluster(edad_cluster, geom = "point", data = rh_edad_norm) + ggtitle("Clusters de Bajas en Form")

# Añadir el cluster al Dataframe
rh_clusters <- rh_alt %>%
  mutate(Cluster = edad_cluster$cluster) 

# Observar características del cluster
rh_clusters %>%
  mutate(Cluster = edad_cluster$cluster) %>%
  group_by(Cluster) %>%
  summarise(max_edad = max(edad), mean_salario_diario = mean(salario_diario, na.rm = TRUE))
## # A tibble: 3 × 3
##   Cluster max_edad mean_salario_diario
##     <int>    <dbl>               <dbl>
## 1       1     54.4                178.
## 2       2     61.3                218.
## 3       3     37.1                222.
# Crear etiquetas de los clusters
rh_clusters <- rh_clusters %>%
  mutate(Cluster_Name = case_when(
    Cluster == 1 ~ "Adulto",
    Cluster == 2 ~ "Adulto Mayor",
    Cluster == 3 ~ "Joven",
    TRUE ~ as.factor(Cluster)
  ))

Gráficas

Tras haber realizado un proceso de clusterización por medio del algoritmo de K-means, se asignaron a la base de datos de bajas de rh para observar la composición de cada uno en base a determinadas características de los empleados que abandonan.

Se determina que la mayor parte de los empleados adultos que abandonaron son jovenes solteros o en unión libre, lo cual supone que tienen una mayor libertad e independencia para explorar otras oportunidades laborales al no existir un comrpomiso formal o familiar. A diferencia de esto, se puede observar que los adultos mayores que abandonan son en su mayoría casados, pudiendo implicar que esta característica no impacta en su decisión.

ggplot(rh_clusters, aes(x = estado_civil, fill = Cluster_Name)) +
  geom_bar(position = "dodge", alpha = 0.7) +
  labs(title = "Estado Civil por Cluster de Bajas en Form",
       x = "Estado Civil",
       y = "Count") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17),
        axis.text = element_text(size = 15))

Se puede observar que los miembros del clúster adulto suelen tener un menor salario que los demás, lo cual puede tener una influencia en su razón para abandonar. Sin embargo, al comparar los clusters joven y adulto mayor, se observa tienen diferencias mínimas en su salario.

ggplot(rh_clusters, aes(x = edad, y = salario_diario, color = Cluster_Name)) +
  geom_point() +
  labs(title = "Salario Diario vs. Edad por Cluster de Bajas en Form",
       x = "Edad",
       y = "Salario Diario") +
  theme_minimal()+
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17),
        axis.text = element_text(size = 15))

Tanto el cluster de adultos mayores como el de jóvenes que abandonan están mayormente compuestos por mujeres, lo cual puede suponer un problema en el clima organizacional percibido por estas, así como una posible falta de oportunidades de crecimiento (particularmente en el cluster jóven), entre otras situaciones. Esta situación parece no influir sobre el cluster de adultos, estando compuesto de manera igual por ambos géneros.

# Gráfico de Barras Apiladas de Género por Cluster_Name
ggplot(rh_clusters, aes(x = Cluster_Name, fill = genero)) +
  geom_bar(position = "dodge", alpha = 0.7) +
  labs(title = "Distribución de Género por Cluster de Bajas en Form",
       x = "Cluster_Name",
       y = "Count") +
  theme_minimal()+
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17),
        axis.text = element_text(size = 15))

La mayor parte de los miembros de cada clúster proviene de Apodaca, esto pues es el municipio donde está presente la planta de Form, asi que es necesario reconocer que Apodaca contiene el 70% de parques industriales del estado de Nuevo León, por lo cual existe una variedad de plantas productivas cercanas. Esto otorga mayor libertad a los empleados a renunciar y explorar otras oportunidades sin implicar un impacto significativo en su rutina diaria respecto a los traslados.

# Crear el gráfico de barras apiladas municipio
ggplot(rh_clusters, aes(x = Cluster_Name, fill = mpio)) +
  geom_bar(position = "stack", alpha = 0.7) +
  labs(title = "Distribución de Municipio por Cluster de Bajas en Form",
       x = "Cluster_Name",
       y = "Count") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17),
        axis.text = element_text(size = 15))

El departamento con mayor abandono en cada uno de los clusters corresponde al de Área No Identificad (compuesto mayormente del puesto de ayudante general), seguidos del de Producción Cartón MDL y MC, implicando una posible insatisfacción con las tareas particulares del puesto de ayudante general (predominante), pudiendo ser por la demanda de trabajo, la repetición continua de tareas o el clima laboral particular de este puesto. De acuerdo a lo comentado por Felipe, no existe una capacitación hacia estos sino la necesidad de aprendizaje visual por los nuevos empleados hacia los compañeros ya experimentados. Esto puede suponer dificultades para la adaptación al puesto, lo que guiaría a una temprana recesión por parte de estos.

ggplot(rh_clusters, aes(x = Cluster_Name, fill = depto)) +
  geom_bar(position = "dodge", alpha = 0.7) +
  ggtitle("Puestos de Colaboradores por Cluster") +
  theme_minimal() +
  theme(axis.text.y = element_text(hjust = 1, size= 18, face = "bold"),
        plot.title = element_text(size = 20, face = "bold"),
        axis.title = element_text(size = 15),
        legend.title = element_text(size = 16, face = "bold"),
        legend.text = element_text(size = 17),
        axis.text = element_text(size = 15))

FORM Encuesta Clima Organizacional Otoño 2023

Limpieza y organización

Diseñar y organizar base(s) de datos a partir de la información y datos seleccionados.

df<- read_excel("C:\\Users\\AVRIL\\Documents\\Encuesta_Datos_FORM_Fall2023.xlsx")

# Nombres, tipo y registros de las variables
str(df)
## tibble [106 × 23] (S3: tbl_df/tbl/data.frame)
##  $ Encuesta                                                                                                                 : num [1:106] 1 2 3 4 5 6 7 8 9 10 ...
##  $ Puesto de trabajo - Selected Choice                                                                                      : chr [1:106] "Administrativo" "Costurera" "Ayudante general" "Ayudante general" ...
##  $ Puesto de trabajo - Otro - Text                                                                                          : chr [1:106] NA NA NA NA ...
##  $ Antiguedad en la empresa - Meses                                                                                         : num [1:106] 9 36 4 2 1 36 36 36 36 1 ...
##  $ ¿Cuál fue la principal razón por la que entraste a este trabajo?                                                         : chr [1:106] "Por el salario" "Otro" "Ubicación de la empresa" "Ubicación de la empresa" ...
##  $ 1 - Considero que el salario que recibo es bueno para el trabajo que realizo                                             : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente en desacuerdo" "Totalmente de acuerdo" ...
##  $ 2 - Mis prestaciones son algo que hace que me quede en la empresa                                                        : chr [1:106] "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ 3 - La jornada laboral no es excesiva                                                                                    : chr [1:106] "Totalmente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ 4 - FORM me ha ofrecido las herramientas necesarias para mi desempeño y aprendizaje                                      : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ 5 - Que haga mucho frío o calor en mi área de trabajo no es algo que me moleste                                          : chr [1:106] "Medianamente en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Ni de acuerdo ni en desacuerdo" "Medianamente de acuerdo" ...
##  $ 6 - Mi nivel de estrés durante la jornada laboral es bajo                                                                : chr [1:106] "Totalmente de acuerdo" "Medianamente en desacuerdo" "Totalmente en desacuerdo" "Totalmente de acuerdo" ...
##  $ 7 - Me puedo transportar de forma segura de mi casa a mi trabajo y no me cuesta demasiado esfuerzo llegar                : chr [1:106] "Medianamente de acuerdo" "Medianamente en desacuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ 8 - Mi zona de trabajo es cómoda y segura para hacer mis actividades                                                     : chr [1:106] "Totalmente de acuerdo" "Medianamente de acuerdo" "Medianamente de acuerdo" "Totalmente de acuerdo" ...
##  $ 9 - Es muy probable que siga trabajando en FORM en un futuro                                                             : chr [1:106] "Medianamente de acuerdo" "Totalmente de acuerdo" "Totalmente en desacuerdo" "Medianamente de acuerdo" ...
##  $ ¿Has experimentado situaciones de conflicto, acoso  o que te hayan hecho sentir inseguro durante tu tiempo en la empresa?: chr [1:106] "No" "No" "Si" "No" ...
##  $ En 3 palabras o menos ¿Qué aspectos de tu puesto actual te resultan menos satisfactorios?                                : chr [1:106] "cotización ante imss, fecha de pago, comer a las 3pm" "Ninguno" "mucho trabajo, estrés" "Todo bien" ...
##  $ ¿Cómo te sientes en FORM?                                                                                                : chr [1:106] "agusto, feliz" "Bien" "cómoda, no satisfecha" "Tranquila y contenta" ...
##  $ Edad                                                                                                                     : chr [1:106] "30" "54" "21" "20" ...
##  $ Género                                                                                                                   : chr [1:106] "Femenino" "Femenino" "Femenino" "Femenino" ...
##  $ Estado civil                                                                                                             : chr [1:106] "Unión libre" "Casado" "Soltero" "Casado" ...
##  $ Municipio de residencia                                                                                                  : chr [1:106] "Apodaca" "Apodaca" "Apodaca" "Apodaca" ...
##  $ Nivel de escolaridad                                                                                                     : chr [1:106] "Licenciatura" "Primaria" "Preparatoria" "Preparatoria" ...
##  $ Número de dependientes económicos (personas que dependen de ti)                                                          : num [1:106] 0 0 0 0 0 2 1 0 0 2 ...
# Eliminar columna ID "Encuestas"
df$Encuesta <- NULL

# Actualizar nombre de columnas para que sea más manejable  
colnames(df) <- c("puesto_de_trabajo", "puesto_de_trabajo_otro", "meses_antigüedad", "razon_trabajar_form", "escala_salario_justo", "escala_percepcion_prestaciones", "perpcepcion_peso_negativo_jornada", "percepcion_deserrollo_personal_form", "percepcion_comodidad_clima_area", "percepcion_estres_bajo", "percepcion_facilidad_traslado", "percepcion_comodidad_area_trabajo", "percepcion_probabilidad_seguir_form", "situaciones_acoso", "opinion_malos_aspectos", "opinion_trabajar_forms", "edad", "género", "estado_civil", "municipio", "nivel_escolaridad", "num_dependientes_económicos")

  
# Eliminar columna "puesto_trabajo_otro"
df$puesto_de_trabajo_otro <- NULL

# Cambiar variables cateóricas a factor
df$puesto_de_trabajo <- as.factor(df$puesto_de_trabajo)
df$razon_trabajar_form <- as.factor(df$razon_trabajar_form)
df$situaciones_acoso <- as.factor(df$situaciones_acoso)
df[, 17:20] <- lapply(df[, 17:20], as.factor)


# Cambiar etiqueta erronea en variable percepcion_facilidad_traslado
df$percepcion_facilidad_traslado[df$percepcion_facilidad_traslado == "Totalmende en desacuerdo"] <- "Totalmente en desacuerdo"

# Transformación de variables (5 a 13) de escala ordinal a valor numérico
niveles <- c("Totalmente en desacuerdo", "Medianamente en desacuerdo", 
             "Ni de acuerdo ni en desacuerdo", "Medianamente de acuerdo", 
             "Totalmente de acuerdo")
valores <- c(1, 2, 3, 4, 5)
df[, 4:12] <- lapply(df[, 4:12], function(x) {
  match(x, niveles)
})

# Cambiar formato incorrecto en edad
df$edad[df$edad == "30 años"] <- "30"
df$edad <- as.numeric(df$edad)

# Extraer variables de texto libre
df_sentiment <- df[,14:15]

# Eliminar variables texto dataframe original
df$opinion_malos_aspectos <- NULL
df$opinion_trabajar_forms <- NULL

Visualizar en R los primeros 6 renglones de la nueva base de datos.

head(df)
## # A tibble: 6 × 19
##   puesto_de_trabajo meses_antigüedad razon_trabajar_form    escala_salario_justo
##   <fct>                        <dbl> <fct>                                 <int>
## 1 Administrativo                   9 Por el salario                            5
## 2 Costurera                       36 Otro                                      4
## 3 Ayudante general                 4 Ubicación de la empre…                    2
## 4 Ayudante general                 2 Ubicación de la empre…                    5
## 5 Ayudante general                 1 Ubicación de la empre…                    3
## 6 Ayudante general                36 Razones personales                        4
## # ℹ 15 more variables: escala_percepcion_prestaciones <int>,
## #   perpcepcion_peso_negativo_jornada <int>,
## #   percepcion_deserrollo_personal_form <int>,
## #   percepcion_comodidad_clima_area <int>, percepcion_estres_bajo <int>,
## #   percepcion_facilidad_traslado <int>,
## #   percepcion_comodidad_area_trabajo <int>,
## #   percepcion_probabilidad_seguir_form <int>, situaciones_acoso <fct>, …

Glosario de las variables en la base de datos:

  • puesto_de_trabajo: Puesto actual en el que labora el empleado.

  • meses_antigüedad: Número de meses que el empleado ha laborado en la empresa.

  • razon_trabajar_form: Motivo por el cual los empleados decidieron trabajar en Form.

  • escala_salario_justo: Escala 1-5 (menor a mayor) sobre que tan justo se percibe el salario recibido por el trabajo realizado.

  • escala_percepcion_prestaciones: Escala 1-5 (menor a mayor) sobre que tan adecuadas se perciben las prestaciones recibidas.

  • perpcepcion_peso_negativo_jornada: Escala 1-5 (menor a mayor) sobre que tan ardua se siente la jornada laboral.

  • percepcion_deserrollo_personal_form: Escala 1-5 (menor a mayor) sobre que tanta influencia de Form se percibe en el desarrollo de habilidades profesionales.

  • percepcion_comodidad_clima_area: Escala 1-5 (menor a mayor) sobre que tan agradable se percibe el ambiente de trabajo.

  • percepcion_estres_bajo: Escala 1-5 (menor a mayor) sobre que la percepción de que el estrés laboral es bajo.

  • percepcion_facilidad_traslado: Escala 1-5 (menor a mayor) sobre que tan fácil y accesible es llegar de su casa a la planta y viceversa.

  • percepcion_comodidad_area_trabajo: Escala 1-5 (menor a mayor) sobre que tan agradable se percibe el espacio en el que se trabaja.

  • percepcion_probabilidad_seguir_form: Escala 1-5 (menor a mayor) sobre la confianza que se siente en continuar trabajando en Form en el largo plazo.

  • situaciones_acoso: Si se ha experimentado al menos una situación que haya hecho sentir incómoda a la persona.

  • edad: Número de años de la persona.

  • género: Género de la persona.

  • estado_civil: Estado civil de la persona.

  • municipio: Municipio de residencia de la persona.

  • nivel_escolaridad: Último grado de escolaridad cursado por la persona.

  • num_dependientes_económicos: El número de personas que dependen económicamente de la persona.

Estadísticos descriptivos

Hallazgos acorde a medidas descriptivas y de distribución:

  • Percepción_facilidad_traslado: Existe un rango intercuartílico relativamente amplio, lo que indica que a algunos empleados les resulta muy fácil trasladarse (en torno a 60) mientras que a otros les resulta difícil (en torno a 20).

  • Percepción_comodidad_área_trabajo: La mediana de empleados percibe un nivel de comodidad en su área de trabajo de alrededor de 30, con algunos empleados que encuentran su área de trabajo muy cómoda (alrededor de 60) y otros que la encuentran incómoda (alrededor de 10).

  • Percepcion_desarrollo_personal: La mediana de los empleados percibe pocas oportunidades de desarrollo personal (10 personas). Sin embargo, algunos empleados ven muchas oportunidades (alrededor de 30) mientras que otros ven muy pocas (alrededor de 0).

  • Num_dependientes_económicos: Algunos empleados tienen muchas personas a su cargo (cerca de 5) mientras que otros no tienen ninguna (en torno a 0).

  • Meses_antigüedad: La mediana es de 3 meses de antigüedad. Sin embargo, algunos empleados son muy nuevos (alrededor de 0 meses) mientras que otros llevan mucho tiempo en la empresa (alrededor de 20 meses).

  • Escala_salario_justo: La mediana de los empleados cree que su salario es justo (en torno a 3). Hay un rango intercuartílico relativamente pequeño, lo que implica que la mayoría de los empleados creen que su salario es relativamente justo (entre 2 y 4).

  • Escala_percepcion_prestaciones: La mediana de los empleados percibe las prestaciones de forma positiva (en torno a 3). No obstante, la mayoría de los empleados tienen una percepción neutra de las prestaciones (entre 2 y 4).

  • Percepcion_peso_negativo_jornada: La mediana de los empleados percibe un peso negativo de su jornada laboral (en torno a 2). Aunque, la mayoría de los empleados tienen una percepción neutra del peso de la jornada laboral.

  • Percepción_comodidad_clima_área: La mediana de los empleados percibe un nivel de comodidad neutro en su clima laboral. Sin embargo, existe un rango intercuartílico amplio, lo que implica que algunos empleados encuentran el clima cómodo (en torno a 4) mientras que otros lo encuentran incómodo (en torno a 0).

  • Percepcion_estres_bajo: La mediana de los empleados percibe un nivel moderado de estrés (en torno a 2); incluso la mayoría de los empleados tienen una percepción neutra del estrés.

summary(df)
##         puesto_de_trabajo meses_antigüedad              razon_trabajar_form
##  Ayudante general:46      Min.   : 1.00    Ambiente de trabajo    :13      
##  Otro            :25      1st Qu.: 1.00    Otro                   :21      
##  Administrativo  :17      Median : 9.00    Por el salario         :19      
##  Costurera       : 7      Mean   :14.08    Prestaciones           : 2      
##  Supervisor      : 6      3rd Qu.:34.50    Razones personales     :19      
##  Limpieza        : 2      Max.   :36.00    Ubicación de la empresa:32      
##  (Other)         : 3                                                       
##  escala_salario_justo escala_percepcion_prestaciones
##  Min.   :1.000        Min.   :1.000                 
##  1st Qu.:3.000        1st Qu.:2.000                 
##  Median :4.000        Median :4.000                 
##  Mean   :3.792        Mean   :3.274                 
##  3rd Qu.:5.000        3rd Qu.:5.000                 
##  Max.   :5.000        Max.   :5.000                 
##                                                     
##  perpcepcion_peso_negativo_jornada percepcion_deserrollo_personal_form
##  Min.   :1.00                      Min.   :1.000                      
##  1st Qu.:4.00                      1st Qu.:3.000                      
##  Median :5.00                      Median :5.000                      
##  Mean   :4.16                      Mean   :3.877                      
##  3rd Qu.:5.00                      3rd Qu.:5.000                      
##  Max.   :5.00                      Max.   :5.000                      
##                                                                       
##  percepcion_comodidad_clima_area percepcion_estres_bajo
##  Min.   :1.000                   Min.   :1.000         
##  1st Qu.:1.000                   1st Qu.:3.000         
##  Median :3.000                   Median :4.000         
##  Mean   :3.123                   Mean   :3.679         
##  3rd Qu.:5.000                   3rd Qu.:5.000         
##  Max.   :5.000                   Max.   :5.000         
##                                                        
##  percepcion_facilidad_traslado percepcion_comodidad_area_trabajo
##  Min.   :1.000                 Min.   :1.000                    
##  1st Qu.:4.000                 1st Qu.:4.000                    
##  Median :5.000                 Median :5.000                    
##  Mean   :4.009                 Mean   :4.311                    
##  3rd Qu.:5.000                 3rd Qu.:5.000                    
##  Max.   :5.000                 Max.   :5.000                    
##                                                                 
##  percepcion_probabilidad_seguir_form           situaciones_acoso
##  Min.   :1.000                       No                 :89     
##  1st Qu.:3.000                       Prefiero no decirlo: 1     
##  Median :5.000                       Si                 :16     
##  Mean   :4.038                                                  
##  3rd Qu.:5.000                                                  
##  Max.   :5.000                                                  
##                                                                 
##       edad             género        estado_civil     municipio 
##  Min.   :18.00   Femenino :69   Casado     :38    Apodaca  :77  
##  1st Qu.:25.25   Masculino:37   Divorciado : 1    Guadalupe: 4  
##  Median :33.50                  Soltero    :47    Juárez   :12  
##  Mean   :35.62                  Unión libre:20    Monterrey: 3  
##  3rd Qu.:45.00                                    Otro     : 6  
##  Max.   :68.00                                    Pesquería: 4  
##                                                                 
##     nivel_escolaridad num_dependientes_económicos
##  Licenciatura:24      Min.   :0.000              
##  Otro        : 3      1st Qu.:0.000              
##  Preparatoria:27      Median :1.000              
##  Primaria    : 9      Mean   :1.085              
##  Secundaria  :43      3rd Qu.:2.000              
##                       Max.   :3.000              
## 
edad <- ggplot(data = df, aes(x = edad)) + 
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) + 
  geom_density()

percepcion_facilidad_traslado <- ggplot(data = df, aes(x = percepcion_facilidad_traslado)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) + 
  geom_density()

percepcion_comodidad_area_trabajo <- ggplot(data = df, aes(x = percepcion_comodidad_area_trabajo)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) + 
  geom_density()

percepcion_deserrollo_personal_form <- ggplot(data = df, aes(x = percepcion_deserrollo_personal_form)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) + 
  geom_density()

num_dependientes_economicos <- ggplot(data = df, aes(x = num_dependientes_económicos)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) +
  geom_density()

meses_antiguedad <- ggplot(data = df, aes(x = meses_antigüedad)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) + 
  geom_density()

escala_salario_justo <- ggplot(data = df, aes(x = escala_salario_justo)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) +geom_density()

escala_percepcion_prestaciones <- ggplot(data = df, aes(x = escala_percepcion_prestaciones)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) +geom_density()

perpcepcion_peso_negativo_jornada <- ggplot(data = df, aes(x = perpcepcion_peso_negativo_jornada)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) +geom_density()

percepcion_comodidad_clima_area <- ggplot(data = df, aes(x = percepcion_comodidad_clima_area)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) +geom_density()

percepcion_estres_bajo <- ggplot(data = df, aes(x = percepcion_estres_bajo)) +
  geom_histogram( color = "red", fill = "blue", alpha = 0.1) +geom_density()

ggarrange(
  edad, percepcion_facilidad_traslado, percepcion_comodidad_area_trabajo, percepcion_deserrollo_personal_form,
  num_dependientes_economicos, meses_antiguedad, escala_salario_justo,
  escala_percepcion_prestaciones, perpcepcion_peso_negativo_jornada,
  percepcion_comodidad_clima_area, percepcion_estres_bajo,
  ncol = 3, nrow = 4
)

Medidas de dispersión

df_numeric <- df %>%
  select_if(is.numeric)

dispersion_sd <- sapply(df_numeric, sd)
print(dispersion_sd)
##                    meses_antigüedad                escala_salario_justo 
##                           14.471448                            1.336071 
##      escala_percepcion_prestaciones   perpcepcion_peso_negativo_jornada 
##                            1.552467                            1.258395 
## percepcion_deserrollo_personal_form     percepcion_comodidad_clima_area 
##                            1.559627                            1.722141 
##              percepcion_estres_bajo       percepcion_facilidad_traslado 
##                            1.397598                            1.508675 
##   percepcion_comodidad_area_trabajo percepcion_probabilidad_seguir_form 
##                            1.221733                            1.279319 
##                                edad         num_dependientes_económicos 
##                           12.160399                            1.096470
#Rango de cada columna
dispersion_range <- sapply(df_numeric, range)
print(dispersion_range)
##      meses_antigüedad escala_salario_justo escala_percepcion_prestaciones
## [1,]                1                    1                              1
## [2,]               36                    5                              5
##      perpcepcion_peso_negativo_jornada percepcion_deserrollo_personal_form
## [1,]                                 1                                   1
## [2,]                                 5                                   5
##      percepcion_comodidad_clima_area percepcion_estres_bajo
## [1,]                               1                      1
## [2,]                               5                      5
##      percepcion_facilidad_traslado percepcion_comodidad_area_trabajo
## [1,]                             1                                 1
## [2,]                             5                                 5
##      percepcion_probabilidad_seguir_form edad num_dependientes_económicos
## [1,]                                   1   18                           0
## [2,]                                   5   68                           3
#Rango intercuartílico de cada columna
dispersion_iqr <- sapply(df_numeric, IQR)
print(dispersion_iqr)
##                    meses_antigüedad                escala_salario_justo 
##                               33.50                                2.00 
##      escala_percepcion_prestaciones   perpcepcion_peso_negativo_jornada 
##                                3.00                                1.00 
## percepcion_deserrollo_personal_form     percepcion_comodidad_clima_area 
##                                2.00                                4.00 
##              percepcion_estres_bajo       percepcion_facilidad_traslado 
##                                2.00                                1.00 
##   percepcion_comodidad_area_trabajo percepcion_probabilidad_seguir_form 
##                                1.00                                2.00 
##                                edad         num_dependientes_económicos 
##                               19.75                                2.00
outlier_ratio <- dispersion_sd / dispersion_iqr

# Columna con la proporción más alta
max_outlier_column <- names(outlier_ratio)[which.max(outlier_ratio)]

print(outlier_ratio)
##                    meses_antigüedad                escala_salario_justo 
##                           0.4319835                           0.6680354 
##      escala_percepcion_prestaciones   perpcepcion_peso_negativo_jornada 
##                           0.5174889                           1.2583950 
## percepcion_deserrollo_personal_form     percepcion_comodidad_clima_area 
##                           0.7798133                           0.4305351 
##              percepcion_estres_bajo       percepcion_facilidad_traslado 
##                           0.6987989                           1.5086751 
##   percepcion_comodidad_area_trabajo percepcion_probabilidad_seguir_form 
##                           1.2217334                           0.6396596 
##                                edad         num_dependientes_económicos 
##                           0.6157164                           0.5482349
print(paste("La variable con más outliers es:", max_outlier_column))
## [1] "La variable con más outliers es: percepcion_facilidad_traslado"
plot_boxplot(df_numeric, by="percepcion_probabilidad_seguir_form")

Gráficos de patrones

Hallazgos acorde a correlaciones:

  • Edad: La edad parece ser un factor importante que afecta la comodidad y el estrés de los empleados en el trabajo; donde a mayor edad, los empleados experimentan menor comodidad en el área de trabajo, menor facilidad de traslado y mayor estrés laboral.

  • Antigüedad: La antigüedad se asocia con una mayor satisfacción con el salario y las prestaciones; por ende, a mayor antigüedad en la empresa, los empleados perciben un salario más justo y mejores prestaciones.

  • Clima laboral: Un mejor clima laboral se relaciona con una mayor comodidad en el área de trabajo y una mayor facilidad de traslado.

  • Dependientes económicos: Tener más dependientes económicos puede afectar negativamente la probabilidad de que los empleados continúen en la empresa.

  • Desarrollo personal: Una mayor percepción de desarrollo personal en la empresa puede aumentar la probabilidad de que los empleados continúen siendo parte de la organización.

  • Prestaciones: Una mejor percepción de las prestaciones puede reducir la percepción negativa del impacto de la jornada laboral en la vida personal.

# Gráfico de correlación
plot_correlation(df_numeric)

# Gráfico de dispersión
plot_histogram(df)

#Grafico scatterplot
plot(df_numeric)

#Grafico normalidad
plot_normality(df)

Text Mining

Aspectos Negativos de Form

A través de la exploración de la columna de texto libre sobre aquellos aspectos menos atractivos de Form, se pudo comprobar que los aspectos que tienen un mayor impacto negativo sobre los empleados fueron las altas temperaturas, las compensaciones recibidas tanto en salario como prestaciones, así como la percepción de las actividades laborales (incluyendo el sábado) que resulta en estrés. Igualmente, esto último puede reflejarse en el análisis de sentimientos, relacionando estos aspectos con la ansiedad (anticipation), como la 3ra emoción predominante.

texto_negativo <- df_sentiment$opinion_malos_aspectos

# Crear un Corpus con los comentarios
corpus <- Corpus(VectorSource(texto_negativo))

# Limpiar el texto
corpus <- tm_map(corpus, content_transformer(tolower))       # Convertir a minúsculas
corpus <- tm_map(corpus, removePunctuation)                  # Eliminar puntuación
corpus <- tm_map(corpus, removeNumbers)                      # Eliminar números
corpus <- tm_map(corpus, removeWords, stopwords("spanish"))  # Eliminar stopwords en español
corpus <- tm_map(corpus, removeWords, c("bien", "ninguno"))             # Eliminar palabra "bien"


# Crear la matriz término-documento
tdm <- TermDocumentMatrix(corpus)
m <- as.matrix(tdm)       #Cuenta las veces que aparece cada palabra por renglón


frecuencia <- sort(rowSums(m), decreasing = TRUE) #Cuenta la frecuencia de cada palabra en el texto completo

frecuencia_df <- data.frame(word=names(frecuencia), freq=frecuencia) # Convierte la frecuencia en un data frame

# Top 10 Palabras
ggplot(head(frecuencia_df, 10), aes(x = reorder(word, -freq), y = freq)) +
  geom_bar(stat = "identity", fill = "lightblue")+
  labs(x= "Palabra", y = "Frecuencia", title = "Top 10 Palabras Negativas de Form")+
  geom_text(aes(label = freq), vjust = -0.5) +
  ylim(0,10)+
  theme_minimal()+
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 18),
        axis.title = element_text(size = 20),
        axis.text = element_text(size = 18),
        legend.position = "none")

# Nube de Palabras
set.seed(123)
wordcloud(words= frecuencia_df$word, freq=frecuencia_df$freq, min.freq = 2, random.order = FALSE, colors = brewer.pal(8, "Spectral"))

# Análisis de Sentimientos
texto_palabras <- get_tokens(corpus)
emociones_df <- get_nrc_sentiment(texto_palabras, language = "spanish")
emociones_prop <- colSums(prop.table(emociones_df[1:8]))
emociones_df <- data.frame(Emocion = names(emociones_prop), Proporcion = emociones_prop)
ggplot(emociones_df, aes(x = Emocion, y = Proporcion, fill = Emocion)) +
  geom_bar(stat = "identity") +
  labs(title = "Distribución de emociones en los comentarios negativos de FORM",
       x = "Emoción",
       y = "Proporción") +
  theme_minimal() +  # Estilo minimalista
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 18),
        axis.title = element_text(size = 20),
        axis.text = element_text(size = 18),
        legend.position = "none")

Opinión de Form

Al analizar la opinión general de los empleados de Form, se obtienen resultados positivos, los cuales mencionan una percepción agradable y cómoda sobre la empresa, destacando aspectos como el ambiente laboral y la oportunidad de crecimiento. Asimismo, mediante el análisis de sentimientos se observa que estos comentarios están relacionados en su mayoría con emociones de felicidad y confianza.

texto_positivo <- df_sentiment$opinion_trabajar_forms

# Crear un Corpus con los comentarios
corpus <- Corpus(VectorSource(texto_positivo))

# Limpiar el texto
corpus <- tm_map(corpus, content_transformer(tolower))        # Convertir a minúsculas
corpus <- tm_map(corpus, removePunctuation)                   # Eliminar puntuación
corpus <- tm_map(corpus, removeNumbers)                       # Eliminar números
corpus <- tm_map(corpus, removeWords, stopwords("spanish"))   # Eliminar stopwords en español
corpus <- tm_map(corpus, removeWords, c("bien"))              # Eliminar palabra "bien"

# Crear la matriz término-documento
tdm <- TermDocumentMatrix(corpus) 
m <- as.matrix(tdm) #Cuenta las veces que aparece cada palabra por renglón


frecuencia <- sort(rowSums(m), decreasing = TRUE) 
frecuencia_df <- data.frame(word=names(frecuencia), freq=frecuencia)

# Gráfica Top 10 Palabras
ggplot(head(frecuencia_df, 10), aes(x = reorder(word, -freq), y = freq)) +
  geom_bar(stat = "identity", fill = "lightblue")+
  labs(x= "Palabra", y = "Frecuencia", title = "Top 10 Palabras Positivas de Form")+
  geom_text(aes(label = freq), vjust = -0.5) +
  ylim(0,15) +
  theme_minimal() +  # Estilo minimalista
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 18),
        axis.title = element_text(size = 20),
        axis.text = element_text(size = 18),
        legend.position = "none")

# Nube de Palabras
set.seed(123)
wordcloud(words= frecuencia_df$word, freq=frecuencia_df$freq, min.freq = 2, random.order = FALSE, colors = brewer.pal(8, "PRGn"))

# Análisis de Sentimientos
texto_palabras <- get_tokens(texto_positivo)
emociones_df <- get_nrc_sentiment(texto_palabras, language = "spanish")
emociones_prop <- colSums(prop.table(emociones_df[1:8]))
emociones_df <- data.frame(Emocion = names(emociones_prop), Proporcion = emociones_prop)
ggplot(emociones_df, aes(x = Emocion, y = Proporcion, fill = Emocion)) +
  geom_bar(stat = "identity") +
  labs(title = "Distribución de emociones en los comentarios de FORM",
       x = "Emoción",
       y = "Proporción")  +
  theme_minimal() +  # Estilo minimalista
  theme(axis.text.x = element_text(angle = 45, hjust = 1),
        plot.title = element_text(face = "bold", size = 18),
        axis.title = element_text(size = 20),
        axis.text = element_text(size = 18),
        legend.position = "none")

Modelos de Predicción

Se determina que es más probable que los empleados de FORM que sean mujeres y tengan una percepción positiva tanto de su salario como de sus prestaciones tienen alta probabilidad de permanecer en la empresa. Por lo tanto, establecer estrategias de retención para este segmento generaría un mayor sentido de pertenencia a la compañía. Asimismo, se requiere establecer alternativas de atracción y retención enfocadas en mejorar la percepción del salario y prestaciones que ofrece la empresa como una ventaja competitiva en comparación con otras compañías del sector, especialmente en la ubicación de Apodaca.

Preparación de datos para modelos:

df_models <- df %>% mutate(percepcion_probabilidad_seguir_form = ifelse(percepcion_probabilidad_seguir_form < 3, "no seguir", "si seguir"))

frecuencia_seguirform <- table(df_models$percepcion_probabilidad_seguir_form)
frecuencia_seguirform
## 
## no seguir si seguir 
##        14        92
set.seed(123)
df_models$percepcion_probabilidad_seguir_form <- as.factor(df_models$percepcion_probabilidad_seguir_form)
sample <- createDataPartition(y = df_models$percepcion_probabilidad_seguir_form, p=0.7, list=F)
train  <- df_models[sample, ]
test   <- df_models[-sample, ]

a) Regresion logistica

El primer modelo construido corresponde a la regresión logística, empleando variables como el número de dependientes económicos, la edad, las distintas percepciones sobre Form, los meses de antigüedad y el género.

set.seed(123)
formula <- percepcion_probabilidad_seguir_form ~ num_dependientes_económicos + edad + percepcion_comodidad_area_trabajo + percepcion_facilidad_traslado + percepcion_estres_bajo + percepcion_comodidad_clima_area + percepcion_deserrollo_personal_form + perpcepcion_peso_negativo_jornada + escala_percepcion_prestaciones + escala_salario_justo + meses_antigüedad + género

model_glm <- glm(formula, family = "binomial", data = train)
summary(model_glm)
## 
## Call:
## glm(formula = formula, family = "binomial", data = train)
## 
## Coefficients:
##                                     Estimate Std. Error z value Pr(>|z|)  
## (Intercept)                         -2.10375    3.68543  -0.571   0.5681  
## num_dependientes_económicos         -0.16856    0.71556  -0.236   0.8138  
## edad                                 0.08846    0.08021   1.103   0.2701  
## percepcion_comodidad_area_trabajo    0.29968    0.60336   0.497   0.6194  
## percepcion_facilidad_traslado       -0.35084    0.55057  -0.637   0.5240  
## percepcion_estres_bajo              -0.33029    0.51703  -0.639   0.5229  
## percepcion_comodidad_clima_area     -0.78769    0.41672  -1.890   0.0587 .
## percepcion_deserrollo_personal_form  1.26752    0.68996   1.837   0.0662 .
## perpcepcion_peso_negativo_jornada   -0.01763    0.45721  -0.039   0.9692  
## escala_percepcion_prestaciones       0.88876    0.58006   1.532   0.1255  
## escala_salario_justo                -0.38422    0.60744  -0.633   0.5270  
## meses_antigüedad                     0.11741    0.06923   1.696   0.0899 .
## géneroMasculino                     -1.31964    1.61401  -0.818   0.4136  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 58.901  on 74  degrees of freedom
## Residual deviance: 25.694  on 62  degrees of freedom
## AIC: 51.694
## 
## Number of Fisher Scoring iterations: 8
varImp(model_glm)
##                                        Overall
## num_dependientes_económicos         0.23555712
## edad                                1.10286472
## percepcion_comodidad_area_trabajo   0.49668732
## percepcion_facilidad_traslado       0.63722380
## percepcion_estres_bajo              0.63883115
## percepcion_comodidad_clima_area     1.89019331
## percepcion_deserrollo_personal_form 1.83708562
## perpcepcion_peso_negativo_jornada   0.03855666
## escala_percepcion_prestaciones      1.53219319
## escala_salario_justo                0.63252556
## meses_antigüedad                    1.69600213
## géneroMasculino                     0.81761680

El modelo demuestra tener un desempeño inicial adecuado, prediciendo acertadamente el 83.87% de los casos en que un empleado tiene una percepción de continuar o no en la empresa.. Este resultado es relevante debido a que tiene un kappa del .3515, es decir, no es una predicción aleatoria.

prediccion_glm <- predict(model_glm, test, type = "response")

confusion_glm <- confusionMatrix(as.factor(ifelse(prediccion_glm>0.5, "si seguir", "no seguir")), test$percepcion_probabilidad_seguir_form, positive = "no seguir")
print(confusion_glm)
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  no seguir si seguir
##   no seguir         2         3
##   si seguir         2        24
##                                           
##                Accuracy : 0.8387          
##                  95% CI : (0.6627, 0.9455)
##     No Information Rate : 0.871           
##     P-Value [Acc > NIR] : 0.7966          
##                                           
##                   Kappa : 0.3515          
##                                           
##  Mcnemar's Test P-Value : 1.0000          
##                                           
##             Sensitivity : 0.50000         
##             Specificity : 0.88889         
##          Pos Pred Value : 0.40000         
##          Neg Pred Value : 0.92308         
##              Prevalence : 0.12903         
##          Detection Rate : 0.06452         
##    Detection Prevalence : 0.16129         
##       Balanced Accuracy : 0.69444         
##                                           
##        'Positive' Class : no seguir       
## 

Mediante la curva ROC para el modelo logístico, se reafirma el punto anterior, pues al resultar en un AUC con valor de 0.86, se determina que la predicción del modelo es mejor que una predicción aleatoria.

#  Curva ROC y valor de AUC
## Obtener las puntuaciones de probabilidad
prediccion_prob_glm <- predict(model_glm, test, type = "response")

## Generar la curva ROC
roc_obj_glm <- roc(test$percepcion_probabilidad_seguir_form, as.numeric(prediccion_prob_glm))

## Dibujar la curva ROC
plot.roc(roc_obj_glm, main = "Curva ROC", col = "blue")

## Calcular el AUC
auc_glm <- pROC::auc(roc_obj_glm)
auc_glm
## Area under the curve: 0.8611

b) Naive Bayes

El modelo de Naive Bayes demuestra igualmente, tener un desempeño inicial adecuado, prediciendo acertadamente el 80.65% de los casos en que un empleado tiene una percepción de continuar o no en la empresa. Este resultado es relevante debido a que tiene un kappa del 0.2901 (mayor a 0), es decir, no es una predicción aleatoria.

modelo_nb <- naiveBayes(formula, data = train)

# Matriz de Confusión
prediccion_nb <- predict(modelo_nb, test)
confusion_nb <- confusionMatrix(prediccion_nb, test$percepcion_probabilidad_seguir_form,positive = "no seguir")
print(confusion_nb)
## Confusion Matrix and Statistics
## 
##            Reference
## Prediction  no seguir si seguir
##   no seguir         2         4
##   si seguir         2        23
##                                           
##                Accuracy : 0.8065          
##                  95% CI : (0.6253, 0.9255)
##     No Information Rate : 0.871           
##     P-Value [Acc > NIR] : 0.9040          
##                                           
##                   Kappa : 0.2901          
##                                           
##  Mcnemar's Test P-Value : 0.6831          
##                                           
##             Sensitivity : 0.50000         
##             Specificity : 0.85185         
##          Pos Pred Value : 0.33333         
##          Neg Pred Value : 0.92000         
##              Prevalence : 0.12903         
##          Detection Rate : 0.06452         
##    Detection Prevalence : 0.19355         
##       Balanced Accuracy : 0.67593         
##                                           
##        'Positive' Class : no seguir       
## 

El punto anterior se reafirmar mediante la curva ROC del modelo bayesiano, obteniendo un AUC de 0.76 (mayor a .5), determinando nuevamente que el modelo es mejor a una predicción aleatoria.

#  Curva ROC y valor de AUC
## Obtener las puntuaciones de probabilidad
prediccion_prob_nb <- predict(modelo_nb, test, type = "raw")

## Si el resultado es una matriz, selecciona la columna que corresponde a la clase 'Yes' o '1'
prediccion_prob_true_nb <- prediccion_prob_nb[, "no seguir"]

## Generar la curva ROC
roc_obj_nb <- roc(test$percepcion_probabilidad_seguir_form, prediccion_prob_true_nb)

## Dibujar la curva ROC
plot.roc(roc_obj_nb, main="Curva ROC", col="blue")

## Calcular el AUC
auc_nb <- pROC::auc(roc_obj_nb)
auc_nb
## Area under the curve: 0.7685

Debido a la falta de significancia en las variables del modelo logístico, considerando el buen desempeño del modelo de Naive Bayes, en conjunto con su principio de independencia, se analizarán sus resultados a través de las tablas de probabilidad condicional y distribución para determinar el impacto de las variables independientes sobre la percepción de continuar o no trabajando en Form.

  • Los empleados de género femenino tienen mayor probabilidad de considerar seguir trabajando en Form.

  • Los empleados de mayor edad tienen mayor probabilidad de considerar seguir trabajando en Form.

  • Los empleados que han trabajado por un periodo más largo tienen mayor probabilidad de considerar seguir trabajando en Form.

  • Los empleados que perciben su salario y prestaciones como más justos, tienen mayor probabilidad de considerar seguir trabajando en Form.

  • Los empleados que perciben su nivel de estrés como bajo, tienen mayor probabilidad de considerar seguir trabajando en Form.

  • Los empleados que perciben buena facilidad de traslado, tienen mayor probabilidad de considerar seguir trabajando en Form.

## Tablas de Probabilidad Condicional (FACTORES/CATEGORIAS)
barplot(modelo_nb$tables$género, legend.text = TRUE, beside = TRUE, col = c("black", "lightgray"), main = "Género")

## Tablas de Media y Desviación Estándar para Variables Continuas (NUMEROS)

barplot(modelo_nb$tables$edad, legend.text = TRUE, beside = TRUE, col = c("black", "lightgray"), names.arg = c("Media", "Desviación estándar"), main = "Edad")

barplot(modelo_nb$tables$meses_antigüedad, legend.text = TRUE, beside = TRUE, col = c("black", "lightgray"), names.arg = c("Media", "Desviación estándar"), main = "Meses")

barplot(modelo_nb$tables$escala_salario_justo, legend.text = TRUE, beside = TRUE, col = c("black", "lightgray"), names.arg = c("Media", "Desviación estándar"), main = "Salario justo")

barplot(modelo_nb$tables$escala_percepcion_prestaciones, legend.text = TRUE, beside = TRUE, col = c("black", "lightgray"), names.arg = c("Media", "Desviación estándar"), main = "Prestaciones")

barplot(modelo_nb$tables$percepcion_estres_bajo, legend.text = TRUE, beside = TRUE, col = c("black", "lightgray"), names.arg = c("Media", "Desviación estándar"), main = "Percepción estrés bajo")

barplot(modelo_nb$tables$percepcion_facilidad_traslado, legend.text = TRUE, beside = TRUE, col = c("black", "lightgray"), names.arg = c("Media", "Desviación estándar"), main = "Percepción facilidad de traslado")

Nearshoring

IED - Vector Autoregressive Model

Limpieza y Transformación de Variables

# Cargar Base de Datos
nearshoring_data <- read.csv("C:\\Users\\AVRIL\\Documents\\nearshoring_data.csv")

# Tipos de Variables
summary(nearshoring_data)
##       Año         IED_Flujos    Exportaciones      Empleo         
##  Min.   :1997   Min.   : 8374   Min.   : 9088   Length:26         
##  1st Qu.:2003   1st Qu.:21367   1st Qu.:13260   Class :character  
##  Median :2010   Median :27698   Median :21188   Mode  :character  
##  Mean   :2010   Mean   :26770   Mean   :23601                     
##  3rd Qu.:2016   3rd Qu.:32183   3rd Qu.:31601                     
##  Max.   :2022   Max.   :48354   Max.   :46478                     
##   Educación         Salario_Diario    Innovación        Inseguridad_Robo
##  Length:26          Min.   : 24.30   Length:26          Min.   :120.5   
##  Class :character   1st Qu.: 41.97   Class :character   1st Qu.:148.3   
##  Mode  :character   Median : 54.48   Mode  :character   Median :181.8   
##                     Mean   : 65.16                      Mean   :185.4   
##                     3rd Qu.: 72.31                      3rd Qu.:209.9   
##                     Max.   :172.87                      Max.   :314.8   
##  Inseguridad_Homicidio Tipo_de_Cambio    Peso_Nominal   
##  Length:26             Min.   : 8.064   Min.   : 83228  
##  Class :character      1st Qu.:10.752   1st Qu.:237047  
##  Mode  :character      Median :13.016   Median :344938  
##                        Mean   :13.910   Mean   :393485  
##                        3rd Qu.:18.489   3rd Qu.:629635  
##                        Max.   :20.664   Max.   :703096  
##  Pesos_Nom__divididos_INPC Pesos_actuales_MXN Densidad_Carretera
##  Min.   :2108              Min.   :210849     Min.   :0.05205   
##  1st Qu.:3684              1st Qu.:368434     1st Qu.:0.05954   
##  Median :4971              Median :497116     Median :0.06989   
##  Mean   :4936              Mean   :493603     Mean   :0.07106   
##  3rd Qu.:5788              3rd Qu.:578789     3rd Qu.:0.08275   
##  Max.   :7542              Max.   :754160     Max.   :0.09020   
##  Densidad_Población CO2_Emisiones      PIB_Per_Cápita        INPC       
##  Min.   :47.44      Length:26          Min.   :126739   Min.   : 33.28  
##  1st Qu.:52.78      Class :character   1st Qu.:130964   1st Qu.: 56.15  
##  Median :58.09      Mode  :character   Median :136845   Median : 73.35  
##  Mean   :57.33                         Mean   :138550   Mean   : 75.17  
##  3rd Qu.:61.39                         3rd Qu.:146148   3rd Qu.: 91.29  
##  Max.   :65.60                         Max.   :153236   Max.   :126.48
nearshoring_data$Empleo <- as.numeric(nearshoring_data$Empleo)
nearshoring_data$Educación <- as.numeric(nearshoring_data$Educación)
nearshoring_data$Innovación <- as.numeric(nearshoring_data$Innovación)
nearshoring_data$Inseguridad_Homicidio <- as.numeric(nearshoring_data$Inseguridad_Homicidio)
nearshoring_data$Empleo <- as.numeric(nearshoring_data$Empleo)
nearshoring_data$CO2_Emisiones <- as.numeric(nearshoring_data$CO2_Emisiones)
nearshoring_data$CO2_Emisiones <- as.numeric(nearshoring_data$CO2_Emisiones)

# Imputar la Media a Valores Nulos
nearshoring_data <- na.aggregate(nearshoring_data, FUN = median)


# Conversión a Números Reales
nearshoring_data$IED_Flujos_Reales <- ((nearshoring_data$IED_Flujos  * nearshoring_data$Tipo_de_Cambio) / nearshoring_data$INPC)*100

# Eliminar columnas innecesarias
nearshoring_data <- subset(nearshoring_data, select = -c(IED_Flujos))

# Verificar los resultados
head(nearshoring_data)
##    Año Exportaciones Empleo Educación Salario_Diario Innovación
## 1 1997      9087.616  96.53  7.197968          24.30   11.30141
## 2 1998      9875.065  96.53  7.311587          31.91   11.37221
## 3 1999     10990.013  96.53  7.427924          31.91   12.45897
## 4 2000     12482.963  97.83  7.560000          35.12   13.14556
## 5 2001     11300.439  97.36  7.678270          37.57   13.46812
## 6 2002     11923.099  97.66  7.803418          39.74   12.79893
##   Inseguridad_Robo Inseguridad_Homicidio Tipo_de_Cambio Peso_Nominal
## 1         266.5065             14.554142         8.0640     97942.12
## 2         314.7762             14.319399         9.9395     83228.40
## 3         272.8936             12.641071         9.5222    132932.94
## 4         216.9808             10.857846         9.5997    175181.93
## 5         214.5269             10.249509         9.1692    275600.31
## 6         197.8004              9.938719        10.3613    249699.11
##   Pesos_Nom__divididos_INPC Pesos_actuales_MXN Densidad_Carretera
## 1                  2942.983           294298.3         0.05205217
## 2                  2108.491           210849.1         0.05295475
## 3                  2998.340           299834.0         0.05501698
## 4                  3626.379           362637.9         0.05522774
## 5                  5464.476           546447.6         0.05646070
## 6                  4683.914           468391.4         0.05758828
##   Densidad_Población CO2_Emisiones PIB_Per_Cápita     INPC IED_Flujos_Reales
## 1           47.43650      3.675330       127570.1 33.27987          294298.3
## 2           48.76163      3.853045       126738.8 39.47297          210849.1
## 3           49.48089      3.686918       129164.7 44.33552          299834.0
## 4           50.57930      3.874147       130874.9 48.30767          362637.9
## 5           51.27675      3.811393       128083.4 50.43490          546447.6
## 6           51.95311      3.824969       128205.9 53.30993          468391.4

Seleccionar variables más importantes para la construcción del modelo VAR

# Extraer variables más importantes con modelo OLS
ols_model <- lm(IED_Flujos_Reales ~., nearshoring_data)
summary(ols_model)
## 
## Call:
## lm(formula = IED_Flujos_Reales ~ ., data = nearshoring_data)
## 
## Residuals:
##        Min         1Q     Median         3Q        Max 
## -6.341e-05 -2.019e-05 -1.932e-06  2.728e-05  7.014e-05 
## 
## Coefficients: (1 not defined because of singularities)
##                             Estimate Std. Error    t value Pr(>|t|)    
## (Intercept)               -2.083e-02  2.041e-01 -1.020e-01  0.92097    
## Año                        1.530e-05  1.024e-04  1.490e-01  0.88453    
## Exportaciones             -8.321e-09  2.575e-08 -3.230e-01  0.75392    
## Empleo                    -3.374e-05  4.738e-05 -7.120e-01  0.49448    
## Educación                  3.178e-04  2.696e-04  1.179e+00  0.26873    
## Salario_Diario             8.107e-07  5.648e-06  1.440e-01  0.88904    
## Innovación                 2.076e-05  3.014e-05  6.890e-01  0.50834    
## Inseguridad_Robo          -2.507e-06  8.103e-07 -3.094e+00  0.01284 *  
## Inseguridad_Homicidio      2.542e-05  9.037e-06  2.813e+00  0.02027 *  
## Tipo_de_Cambio             8.803e-06  2.146e-05  4.100e-01  0.69125    
## Peso_Nominal              -6.801e-11  1.362e-09 -5.000e-02  0.96127    
## Pesos_Nom__divididos_INPC  1.000e+02  1.044e-07  9.577e+08  < 2e-16 ***
## Pesos_actuales_MXN                NA         NA         NA       NA    
## Densidad_Carretera         1.189e-02  1.752e-02  6.790e-01  0.51440    
## Densidad_Población        -2.991e-04  9.844e-05 -3.038e+00  0.01406 *  
## CO2_Emisiones              8.872e-04  2.326e-04  3.814e+00  0.00413 ** 
## PIB_Per_Cápita             2.466e-09  1.158e-08  2.130e-01  0.83613    
## INPC                       4.048e-05  1.465e-05  2.763e+00  0.02201 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 5.959e-05 on 9 degrees of freedom
## Multiple R-squared:      1,  Adjusted R-squared:      1 
## F-statistic: 9.102e+18 on 16 and 9 DF,  p-value: < 2.2e-16
varImp(ols_model)
##                                Overall
## Año                       1.494041e-01
## Exportaciones             3.232116e-01
## Empleo                    7.120496e-01
## Educación                 1.178724e+00
## Salario_Diario            1.435226e-01
## Innovación                6.887545e-01
## Inseguridad_Robo          3.094160e+00
## Inseguridad_Homicidio     2.813158e+00
## Tipo_de_Cambio            4.102052e-01
## Peso_Nominal              4.993176e-02
## Pesos_Nom__divididos_INPC 9.576816e+08
## Densidad_Carretera        6.787070e-01
## Densidad_Población        3.038013e+00
## CO2_Emisiones             3.813951e+00
## PIB_Per_Cápita            2.129191e-01
## INPC                      2.762858e+00

Visualización Individual de cada Variable

IED_FLujos_ts<-ts(nearshoring_data$IED_Flujos_Reales,start=c(1997, 1),end=c(2022, 1),frequency=1)
InseguridadRobo_ts<-ts(nearshoring_data$Inseguridad_Robo,start=c(1997, 1),end=c(2022, 1),frequency=1)
InseguridadHomicidio_ts<-ts(nearshoring_data$Inseguridad_Homicidio,start=c(1997, 1),end=c(2022, 1),frequency=1)
Educacion_ts <- ts(nearshoring_data$Educación,start=c(1997, 1),end=c(2022, 1),frequency=1)
Innovacion_ts <- ts(nearshoring_data$Innovación,start=c(1997, 1),end=c(2022, 1),frequency=1)
DensidadPoblacion_ts <- ts(nearshoring_data$Densidad_Población,start=c(1997, 1),end=c(2022, 1),frequency=1)
CO2_ts <- ts(nearshoring_data$CO2_Emisiones,start=c(1997, 1),end=c(2022, 1),frequency=1)


autoplot(IED_FLujos_ts)

autoplot(InseguridadRobo_ts)

autoplot(InseguridadHomicidio_ts)

autoplot(Educacion_ts)

autoplot(Innovacion_ts)

autoplot(DensidadPoblacion_ts)

autoplot(CO2_ts)

Construir Modelo VAR

Los resultados del modelo para la variable IED_Flujos_Reales muestran capturar el 34% de su variabilidad (R-ajustada), sin embargo el estadístico F muestra que esta relación no es significativa (p-value > 0.05). Asimismo, los resultados muestran en su mayoría que valores mayores de las variables explicativas en periodos anteriores conducen a disminuir el valor actual de los flujos de IED, exceptuando las innovaciones y la educación. Es decir, valores elevados en periodos previos para estos últimos casos, contribuyen a aumentar los flujos de IED. Asimismo, es importante reconocer que ninguno de los valores se muestra significativo tampoco (p-value > 0.05).

data_ts <- cbind(nearshoring_data$IED_Flujos_Reales, nearshoring_data$Inseguridad_Robo, nearshoring_data$Inseguridad_Homicidio, nearshoring_data$Educación, nearshoring_data$Innovación, nearshoring_data$Densidad_Población, nearshoring_data$CO2_Emisiones)
colnames(data_ts) <- c("IED_Flujos_Reales", "Inseguridad_Robo","Inseguridad_Homicidio", "Educación", "Innovación", "Densidad_Población", "CO2_emisiones")

#data_ts_diff <- log(data_ts+.0000000001)
VAR_model <- VAR(data_ts, p = 2, type = "const")
summary(VAR_model)
## 
## VAR Estimation Results:
## ========================= 
## Endogenous variables: IED_Flujos_Reales, Inseguridad_Robo, Inseguridad_Homicidio, Educación, Innovación, Densidad_Población, CO2_emisiones 
## Deterministic variables: const 
## Sample size: 24 
## Log Likelihood: -323.468 
## Roots of the characteristic polynomial:
## 1.095 1.095 1.011 0.8566 0.8566 0.8202 0.8202 0.7582 0.7198 0.7198 0.4667 0.4667 0.3963 0.3963
## Call:
## VAR(y = data_ts, p = 2, type = "const")
## 
## 
## Estimation results for equation IED_Flujos_Reales: 
## ================================================== 
## IED_Flujos_Reales = IED_Flujos_Reales.l1 + Inseguridad_Robo.l1 + Inseguridad_Homicidio.l1 + Educación.l1 + Innovación.l1 + Densidad_Población.l1 + CO2_emisiones.l1 + IED_Flujos_Reales.l2 + Inseguridad_Robo.l2 + Inseguridad_Homicidio.l2 + Educación.l2 + Innovación.l2 + Densidad_Población.l2 + CO2_emisiones.l2 + const 
## 
##                            Estimate Std. Error t value Pr(>|t|)
## IED_Flujos_Reales.l1     -5.779e-01  3.565e-01  -1.621    0.139
## Inseguridad_Robo.l1       4.488e+02  1.526e+03   0.294    0.775
## Inseguridad_Homicidio.l1 -1.520e+04  2.553e+04  -0.595    0.566
## Educación.l1              9.420e+04  1.514e+05   0.622    0.549
## Innovación.l1             8.970e+04  6.474e+04   1.386    0.199
## Densidad_Población.l1    -1.269e+05  1.496e+05  -0.848    0.419
## CO2_emisiones.l1          2.016e+05  3.315e+05   0.608    0.558
## IED_Flujos_Reales.l2      1.995e-01  4.166e-01   0.479    0.643
## Inseguridad_Robo.l2       1.735e+03  1.596e+03   1.087    0.305
## Inseguridad_Homicidio.l2 -4.630e+03  1.928e+04  -0.240    0.816
## Educación.l2              2.764e+04  1.984e+05   0.139    0.892
## Innovación.l2            -3.907e+04  5.300e+04  -0.737    0.480
## Densidad_Población.l2     1.665e+05  1.226e+05   1.358    0.208
## CO2_emisiones.l2         -4.215e+05  3.201e+05  -1.317    0.220
## const                    -2.354e+06  2.307e+06  -1.020    0.334
## 
## 
## Residual standard error: 105400 on 9 degrees of freedom
## Multiple R-Squared: 0.7423,  Adjusted R-squared: 0.3415 
## F-statistic: 1.852 on 14 and 9 DF,  p-value: 0.1774 
## 
## 
## Estimation results for equation Inseguridad_Robo: 
## ================================================= 
## Inseguridad_Robo = IED_Flujos_Reales.l1 + Inseguridad_Robo.l1 + Inseguridad_Homicidio.l1 + Educación.l1 + Innovación.l1 + Densidad_Población.l1 + CO2_emisiones.l1 + IED_Flujos_Reales.l2 + Inseguridad_Robo.l2 + Inseguridad_Homicidio.l2 + Educación.l2 + Innovación.l2 + Densidad_Población.l2 + CO2_emisiones.l2 + const 
## 
##                            Estimate Std. Error t value Pr(>|t|)
## IED_Flujos_Reales.l1     -2.713e-05  8.881e-05  -0.305    0.767
## Inseguridad_Robo.l1       6.472e-01  3.800e-01   1.703    0.123
## Inseguridad_Homicidio.l1 -2.267e-01  6.358e+00  -0.036    0.972
## Educación.l1             -1.659e+00  3.771e+01  -0.044    0.966
## Innovación.l1             1.426e+00  1.613e+01   0.088    0.931
## Densidad_Población.l1     1.969e+01  3.727e+01   0.528    0.610
## CO2_emisiones.l1          6.420e+01  8.257e+01   0.777    0.457
## IED_Flujos_Reales.l2      2.268e-05  1.038e-04   0.219    0.832
## Inseguridad_Robo.l2       5.111e-01  3.975e-01   1.286    0.231
## Inseguridad_Homicidio.l2 -2.060e+00  4.802e+00  -0.429    0.678
## Educación.l2             -2.618e+01  4.942e+01  -0.530    0.609
## Innovación.l2             1.152e+01  1.320e+01   0.873    0.406
## Densidad_Población.l2    -1.169e+01  3.054e+01  -0.383    0.711
## CO2_emisiones.l2         -4.651e+00  7.973e+01  -0.058    0.955
## const                    -6.378e+02  5.746e+02  -1.110    0.296
## 
## 
## Residual standard error: 26.24 on 9 degrees of freedom
## Multiple R-Squared: 0.8041,  Adjusted R-squared: 0.4994 
## F-statistic: 2.639 on 14 and 9 DF,  p-value: 0.07357 
## 
## 
## Estimation results for equation Inseguridad_Homicidio: 
## ====================================================== 
## Inseguridad_Homicidio = IED_Flujos_Reales.l1 + Inseguridad_Robo.l1 + Inseguridad_Homicidio.l1 + Educación.l1 + Innovación.l1 + Densidad_Población.l1 + CO2_emisiones.l1 + IED_Flujos_Reales.l2 + Inseguridad_Robo.l2 + Inseguridad_Homicidio.l2 + Educación.l2 + Innovación.l2 + Densidad_Población.l2 + CO2_emisiones.l2 + const 
## 
##                            Estimate Std. Error t value Pr(>|t|)  
## IED_Flujos_Reales.l1     -1.024e-06  4.597e-06  -0.223   0.8287  
## Inseguridad_Robo.l1       4.133e-02  1.967e-02   2.102   0.0649 .
## Inseguridad_Homicidio.l1  4.790e-01  3.291e-01   1.456   0.1795  
## Educación.l1             -5.888e-01  1.952e+00  -0.302   0.7698  
## Innovación.l1            -1.237e+00  8.347e-01  -1.482   0.1726  
## Densidad_Población.l1     4.459e+00  1.929e+00   2.312   0.0461 *
## CO2_emisiones.l1         -4.245e+00  4.274e+00  -0.993   0.3466  
## IED_Flujos_Reales.l2     -1.139e-05  5.371e-06  -2.120   0.0631 .
## Inseguridad_Robo.l2       2.174e-02  2.057e-02   1.057   0.3182  
## Inseguridad_Homicidio.l2 -4.574e-01  2.485e-01  -1.840   0.0988 .
## Educación.l2              5.524e+00  2.558e+00   2.160   0.0591 .
## Innovación.l2             1.972e+00  6.832e-01   2.886   0.0180 *
## Densidad_Población.l2    -3.466e+00  1.581e+00  -2.193   0.0560 .
## CO2_emisiones.l2          1.735e+00  4.126e+00   0.420   0.6841  
## const                    -8.954e+01  2.974e+01  -3.011   0.0147 *
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Residual standard error: 1.358 on 9 degrees of freedom
## Multiple R-Squared: 0.9867,  Adjusted R-squared: 0.966 
## F-statistic:  47.7 on 14 and 9 DF,  p-value: 1.067e-06 
## 
## 
## Estimation results for equation Educación: 
## ========================================== 
## Educación = IED_Flujos_Reales.l1 + Inseguridad_Robo.l1 + Inseguridad_Homicidio.l1 + Educación.l1 + Innovación.l1 + Densidad_Población.l1 + CO2_emisiones.l1 + IED_Flujos_Reales.l2 + Inseguridad_Robo.l2 + Inseguridad_Homicidio.l2 + Educación.l2 + Innovación.l2 + Densidad_Población.l2 + CO2_emisiones.l2 + const 
## 
##                            Estimate Std. Error t value Pr(>|t|)  
## IED_Flujos_Reales.l1      9.409e-07  6.852e-07   1.373   0.2030  
## Inseguridad_Robo.l1       3.531e-03  2.932e-03   1.204   0.2591  
## Inseguridad_Homicidio.l1  6.197e-04  4.906e-02   0.013   0.9902  
## Educación.l1              4.180e-01  2.910e-01   1.437   0.1847  
## Innovación.l1            -1.629e-02  1.244e-01  -0.131   0.8987  
## Densidad_Población.l1     7.558e-02  2.876e-01   0.263   0.7986  
## CO2_emisiones.l1          8.652e-01  6.371e-01   1.358   0.2076  
## IED_Flujos_Reales.l2      1.024e-06  8.007e-07   1.278   0.2331  
## Inseguridad_Robo.l2       7.513e-03  3.067e-03   2.449   0.0368 *
## Inseguridad_Homicidio.l2 -9.187e-02  3.705e-02  -2.480   0.0350 *
## Educación.l2              6.506e-02  3.813e-01   0.171   0.8683  
## Innovación.l2            -1.634e-01  1.019e-01  -1.604   0.1432  
## Densidad_Población.l2     9.209e-02  2.357e-01   0.391   0.7050  
## CO2_emisiones.l2          3.338e-01  6.151e-01   0.543   0.6005  
## const                    -9.023e+00  4.434e+00  -2.035   0.0723 .
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Residual standard error: 0.2025 on 9 degrees of freedom
## Multiple R-Squared: 0.9563,  Adjusted R-squared: 0.8884 
## F-statistic: 14.08 on 14 and 9 DF,  p-value: 0.0001932 
## 
## 
## Estimation results for equation Innovación: 
## =========================================== 
## Innovación = IED_Flujos_Reales.l1 + Inseguridad_Robo.l1 + Inseguridad_Homicidio.l1 + Educación.l1 + Innovación.l1 + Densidad_Población.l1 + CO2_emisiones.l1 + IED_Flujos_Reales.l2 + Inseguridad_Robo.l2 + Inseguridad_Homicidio.l2 + Educación.l2 + Innovación.l2 + Densidad_Población.l2 + CO2_emisiones.l2 + const 
## 
##                            Estimate Std. Error t value Pr(>|t|)
## IED_Flujos_Reales.l1     -1.172e-06  2.833e-06  -0.414    0.689
## Inseguridad_Robo.l1       1.045e-02  1.212e-02   0.862    0.411
## Inseguridad_Homicidio.l1 -2.924e-01  2.029e-01  -1.441    0.183
## Educación.l1             -1.030e+00  1.203e+00  -0.856    0.414
## Innovación.l1             4.092e-01  5.145e-01   0.795    0.447
## Densidad_Población.l1     6.284e-01  1.189e+00   0.528    0.610
## CO2_emisiones.l1          5.402e-01  2.634e+00   0.205    0.842
## IED_Flujos_Reales.l2      8.894e-07  3.311e-06   0.269    0.794
## Inseguridad_Robo.l2       9.992e-03  1.268e-02   0.788    0.451
## Inseguridad_Homicidio.l2  1.168e-02  1.532e-01   0.076    0.941
## Educación.l2              1.440e+00  1.577e+00   0.914    0.385
## Innovación.l2            -4.196e-01  4.211e-01  -0.996    0.345
## Densidad_Población.l2    -2.219e-01  9.744e-01  -0.228    0.825
## CO2_emisiones.l2          8.059e-01  2.544e+00   0.317    0.759
## const                    -1.766e+01  1.833e+01  -0.963    0.361
## 
## 
## Residual standard error: 0.8373 on 9 degrees of freedom
## Multiple R-Squared: 0.7131,  Adjusted R-squared: 0.2667 
## F-statistic: 1.598 on 14 and 9 DF,  p-value: 0.2424 
## 
## 
## Estimation results for equation Densidad_Población: 
## =================================================== 
## Densidad_Población = IED_Flujos_Reales.l1 + Inseguridad_Robo.l1 + Inseguridad_Homicidio.l1 + Educación.l1 + Innovación.l1 + Densidad_Población.l1 + CO2_emisiones.l1 + IED_Flujos_Reales.l2 + Inseguridad_Robo.l2 + Inseguridad_Homicidio.l2 + Educación.l2 + Innovación.l2 + Densidad_Población.l2 + CO2_emisiones.l2 + const 
## 
##                            Estimate Std. Error t value Pr(>|t|)  
## IED_Flujos_Reales.l1      8.171e-07  1.067e-06   0.766   0.4635  
## Inseguridad_Robo.l1       3.020e-04  4.567e-03   0.066   0.9487  
## Inseguridad_Homicidio.l1  4.072e-03  7.642e-02   0.053   0.9587  
## Educación.l1             -1.021e-01  4.533e-01  -0.225   0.8269  
## Innovación.l1            -1.504e-01  1.938e-01  -0.776   0.4576  
## Densidad_Población.l1     1.112e+00  4.480e-01   2.482   0.0349 *
## CO2_emisiones.l1         -1.618e+00  9.924e-01  -1.630   0.1375  
## IED_Flujos_Reales.l2     -1.118e-06  1.247e-06  -0.897   0.3932  
## Inseguridad_Robo.l2      -6.592e-06  4.777e-03  -0.001   0.9989  
## Inseguridad_Homicidio.l2 -8.481e-02  5.771e-02  -1.469   0.1758  
## Educación.l2              3.107e-01  5.939e-01   0.523   0.6135  
## Innovación.l2            -9.514e-02  1.587e-01  -0.600   0.5635  
## Densidad_Población.l2    -5.020e-02  3.671e-01  -0.137   0.8942  
## CO2_emisiones.l2          4.945e-01  9.582e-01   0.516   0.6182  
## const                     4.482e+00  6.907e+00   0.649   0.5326  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## 
## Residual standard error: 0.3154 on 9 degrees of freedom
## Multiple R-Squared: 0.9984,  Adjusted R-squared: 0.9958 
## F-statistic: 391.6 on 14 and 9 DF,  p-value: 9.151e-11 
## 
## 
## Estimation results for equation CO2_emisiones: 
## ============================================== 
## CO2_emisiones = IED_Flujos_Reales.l1 + Inseguridad_Robo.l1 + Inseguridad_Homicidio.l1 + Educación.l1 + Innovación.l1 + Densidad_Población.l1 + CO2_emisiones.l1 + IED_Flujos_Reales.l2 + Inseguridad_Robo.l2 + Inseguridad_Homicidio.l2 + Educación.l2 + Innovación.l2 + Densidad_Población.l2 + CO2_emisiones.l2 + const 
## 
##                            Estimate Std. Error t value Pr(>|t|)
## IED_Flujos_Reales.l1     -5.199e-07  3.843e-07  -1.353    0.209
## Inseguridad_Robo.l1      -2.041e-03  1.644e-03  -1.241    0.246
## Inseguridad_Homicidio.l1 -6.944e-03  2.751e-02  -0.252    0.806
## Educación.l1              1.691e-01  1.632e-01   1.036    0.327
## Innovación.l1            -5.344e-02  6.978e-02  -0.766    0.463
## Densidad_Población.l1     4.973e-02  1.613e-01   0.308    0.765
## CO2_emisiones.l1          1.251e-01  3.573e-01   0.350    0.734
## IED_Flujos_Reales.l2     -6.829e-07  4.490e-07  -1.521    0.163
## Inseguridad_Robo.l2      -1.371e-03  1.720e-03  -0.797    0.446
## Inseguridad_Homicidio.l2  3.580e-03  2.078e-02   0.172    0.867
## Educación.l2              1.854e-02  2.138e-01   0.087    0.933
## Innovación.l2             1.946e-02  5.712e-02   0.341    0.741
## Densidad_Población.l2    -6.054e-02  1.322e-01  -0.458    0.658
## CO2_emisiones.l2          1.720e-01  3.450e-01   0.499    0.630
## const                     3.512e+00  2.487e+00   1.412    0.191
## 
## 
## Residual standard error: 0.1136 on 9 degrees of freedom
## Multiple R-Squared: 0.8408,  Adjusted R-squared: 0.5931 
## F-statistic: 3.395 on 14 and 9 DF,  p-value: 0.03547 
## 
## 
## 
## Covariance matrix of residuals:
##                       IED_Flujos_Reales Inseguridad_Robo Inseguridad_Homicidio
## IED_Flujos_Reales             1.110e+10        6.446e+05            7528.47472
## Inseguridad_Robo              6.446e+05        6.888e+02              18.16607
## Inseguridad_Homicidio         7.528e+03        1.817e+01               1.84523
## Educación                     1.328e+04        9.145e-01              -0.12689
## Innovación                    2.620e+04        5.288e+00              -0.37343
## Densidad_Población           -1.294e+04        5.792e-01               0.10822
## CO2_emisiones                -6.840e+03       -4.171e-02               0.04558
##                        Educación Innovación Densidad_Población CO2_emisiones
## IED_Flujos_Reales      1.328e+04  2.620e+04         -1.294e+04    -6.840e+03
## Inseguridad_Robo       9.145e-01  5.288e+00          5.792e-01    -4.171e-02
## Inseguridad_Homicidio -1.269e-01 -3.734e-01          1.082e-01     4.558e-02
## Educación              4.101e-02  1.100e-01         -4.927e-03    -1.131e-02
## Innovación             1.100e-01  7.011e-01          1.093e-01    -3.192e-02
## Densidad_Población    -4.927e-03  1.093e-01          9.950e-02     5.201e-03
## CO2_emisiones         -1.131e-02 -3.192e-02          5.201e-03     1.290e-02
## 
## Correlation matrix of residuals:
##                       IED_Flujos_Reales Inseguridad_Robo Inseguridad_Homicidio
## IED_Flujos_Reales                1.0000          0.23309                0.0526
## Inseguridad_Robo                 0.2331          1.00000                0.5096
## Inseguridad_Homicidio            0.0526          0.50956                1.0000
## Educación                        0.6225          0.17207               -0.4613
## Innovación                       0.2970          0.24062               -0.3283
## Densidad_Población              -0.3895          0.06997                0.2526
## CO2_emisiones                   -0.5717         -0.01399                0.2955
##                       Educación Innovación Densidad_Población CO2_emisiones
## IED_Flujos_Reales       0.62249     0.2970           -0.38947      -0.57166
## Inseguridad_Robo        0.17207     0.2406            0.06997      -0.01399
## Inseguridad_Homicidio  -0.46130    -0.3283            0.25257       0.29546
## Educación               1.00000     0.6488           -0.07713      -0.49171
## Innovación              0.64878     1.0000            0.41380      -0.33571
## Densidad_Población     -0.07713     0.4138            1.00000       0.14520
## CO2_emisiones          -0.49171    -0.3357            0.14520       1.00000
VAR_model_residuals <- data.frame(residuals(VAR_model))

Prueba ADF

Comentario: Al obtener un p-value mayor a 0.05, no se rechaza la hipotésis nula, por lo que no es estacionario.

adf.test(VAR_model_residuals$IED_Flujos_Reales)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  VAR_model_residuals$IED_Flujos_Reales
## Dickey-Fuller = -2.9795, Lag order = 2, p-value = 0.1993
## alternative hypothesis: stationary

Prueba Box-Ljung

Comentario: Al obtener un p-value mayor a 0.05, no se rechaza la hipotésis nula, por lo que no hay evidencia suficiente para rechazar la hipótesis nula, lo que sugiere que los residuos son independientes en el tiempo (es decir, no hay autocorrelación significativa en los residuos).

Box.test(VAR_model_residuals$IED_Flujos_Reales, lag = 1, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  VAR_model_residuals$IED_Flujos_Reales
## X-squared = 3.093, df = 1, p-value = 0.07863

Forecast Años (2023 a 2027)

De acuerdo a la predicción del modelo VAR considerando las variables de Inseguridad_Robo, Inseguridad_Homocidio, Educación, Innovación, Densidad de Población y Emisiones de CO2, la inversión extranjera aumentará en 2023-2025, implicando la posible llegada del Nearshoring a México.

# Predicción para los siguientes 5 periodos
forecast_var <- predict(VAR_model, n.ahead = 5, ci = 0.95)
print(forecast_var)
## $IED_Flujos_Reales
##          fcst    lower     upper       CI
## [1,] 679071.9 472560.2  885583.7 206511.7
## [2,] 945926.3 681680.4 1210172.3 264246.0
## [3,] 876913.4 597928.1 1155898.6 278985.2
## [4,] 975301.1 680691.1 1269911.0 294610.0
## [5,] 880087.3 566958.6 1193216.0 313128.7
## 
## $Inseguridad_Robo
##          fcst     lower    upper       CI
## [1,] 139.0026  87.56386 190.4414 51.43877
## [2,] 178.4376 112.83425 244.0410 65.60336
## [3,] 239.4771 160.26714 318.6870 79.20993
## [4,] 288.9116 200.27919 377.5441 88.63244
## [5,] 293.1862 202.35990 384.0125 90.82629
## 
## $Inseguridad_Homicidio
##          fcst    lower    upper        CI
## [1,] 14.88182 12.21942 17.54422  2.662403
## [2,] 15.76456 10.81427 20.71485  4.950291
## [3,] 22.35452 15.10353 29.60550  7.250983
## [4,] 38.51716 28.77466 48.25967  9.742507
## [5,] 51.91323 40.15613 63.67034 11.757106
## 
## $Educación
##           fcst     lower     upper        CI
## [1,]  8.292997  7.896102  8.689892 0.3968948
## [2,]  9.482927  8.958817 10.007037 0.5241096
## [3,] 10.279152  9.590625 10.967679 0.6885266
## [4,] 10.964642 10.177749 11.751534 0.7868930
## [5,] 11.541229 10.690334 12.392124 0.8508951
## 
## $Innovación
##          fcst     lower    upper       CI
## [1,] 15.47487 13.833766 17.11597 1.641102
## [2,] 17.21466 15.225872 19.20345 1.988789
## [3,] 15.94986 13.842973 18.05674 2.106884
## [4,] 15.14525 12.675598 17.61491 2.469655
## [5,] 12.33944  9.429624 15.24925 2.909813
## 
## $Densidad_Población
##          fcst    lower    upper        CI
## [1,] 65.87577 65.25754 66.49401 0.6182330
## [2,] 66.66732 65.79697 67.53767 0.8703505
## [3,] 67.64033 66.63758 68.64307 1.0027421
## [4,] 68.77211 67.61861 69.92561 1.1535021
## [5,] 70.27890 69.02417 71.53364 1.2547353
## 
## $CO2_emisiones
##          fcst    lower    upper        CI
## [1,] 4.034558 3.811976 4.257140 0.2225821
## [2,] 3.759601 3.463986 4.055216 0.2956150
## [3,] 3.576053 3.218478 3.933629 0.3575758
## [4,] 3.396823 2.970887 3.822758 0.4259354
## [5,] 3.212011 2.755855 3.668167 0.4561558
fanchart(forecast_var, names = "IED_Flujos_Reales", main = "Pronóstico de Flujos de IED en México (VAR)", 
         xlab = "Periodo", ylab = "IED Flujos Reales")

IED en México

# Cargando los datos de flujos de IED
ied_flujos <- read.csv("C:\\Users\\AVRIL\\Documents\\IED_Flujos.csv")
summary(ied_flujos)
##       Año         Trimestre      IED_Flujos     Tipo_Cambio         INPC       
##  Min.   :1999   Min.   :1.00   Min.   : 1341   Min.   : 9.02   Min.   : 41.39  
##  1st Qu.:2005   1st Qu.:1.75   1st Qu.: 4351   1st Qu.:10.85   1st Qu.: 58.66  
##  Median :2010   Median :2.50   Median : 6238   Median :13.01   Median : 75.05  
##  Mean   :2010   Mean   :2.50   Mean   : 7036   Mean   :14.08   Mean   : 76.96  
##  3rd Qu.:2016   3rd Qu.:3.25   3rd Qu.: 8053   3rd Qu.:18.46   3rd Qu.: 92.71  
##  Max.   :2022   Max.   :4.00   Max.   :22794   Max.   :23.51   Max.   :126.48

Visualizar la serie de tiempo (números reales)

# Crear una nueva columna para los flujos en números reales
ied_flujos$IED_Numero_Real <- ((ied_flujos$IED_Flujos * ied_flujos$Tipo_Cambio) / ied_flujos$INPC)*100

# Obtener los últimos 20 valores del pronóstico (5 años)
ultimos_valores <- tail(ied_flujos$IED_Numero_Real, 20)

# Calcular el promedio de los últimos 20 valores (5 años)
promedio_flujos <- mean(ultimos_valores)

# Convertir a serie de tiempo
ied_flujos <- ts(ied_flujos$IED_Numero_Real, start = c(min(ied_flujos$Año), 1), frequency = 4)

plot(ied_flujos)

Análisis de series de tiempo de flujos de IED

ADF Test

Comentario: Con un valor de p de 0.02, se puede rechazar la hipótesis nula de que se tiene una raíz unitaria, lo que significa que es estacionaria.

#Prueba de estacionariedad (ADF Test)
adf_test <- adf.test(ied_flujos, alternative = "stationary")
adf_test
## 
##  Augmented Dickey-Fuller Test
## 
## data:  ied_flujos
## Dickey-Fuller = -3.831, Lag order = 4, p-value = 0.02051
## alternative hypothesis: stationary

Box-Ljung Test y ACF Plot

Comentario: Con un valor de p de 0.9449, no hay evidencia suficiente para rechazar la hipótesis nula, lo que sugiere que los residuos son independientes en el tiempo (es decir, no hay autocorrelación significativa en los residuos).

Box.test(ied_flujos, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  ied_flujos
## X-squared = 0.0047773, df = 1, p-value = 0.9449
acf(ied_flujos)

Estimación SARIMA

De acuerdo a la función auto.arima, los parámetros del modelo fueron optimizados con los valores (0,0,0)(0,1,2), esto indica parámetros diferentes a 0 únicamente en el componente estacional. En este componente posee 0 autoregresiones, 1 diferencia, y 2 promedios móvil, generando así un modelo SARIMA con mejor desempeño que otros modelos, teniendo un RMSE de 53,266 y un AIC de 2276.

auto_arima_model <- auto.arima(ied_flujos)
summary(auto_arima_model)
## Series: ied_flujos 
## ARIMA(0,0,0)(0,1,2)[4] 
## 
## Coefficients:
##          sma1    sma2
##       -0.7624  0.1890
## s.e.   0.1118  0.1203
## 
## sigma^2 = 3.026e+09:  log likelihood = -1134.95
## AIC=2275.89   AICc=2276.16   BIC=2283.46
## 
## Training set error measures:
##                    ME     RMSE      MAE       MPE     MAPE      MASE
## Training set 6346.076 53266.06 35483.89 -13.21456 34.96835 0.7572764
##                     ACF1
## Training set -0.07016946
arimamodel <- arima(ied_flujos, order = c(0,1,0))
summary(arimamodel)
## 
## Call:
## arima(x = ied_flujos, order = c(0, 1, 0))
## 
## 
## sigma^2 estimated as 1.011e+10:  log likelihood = -1229.04,  aic = 2460.08
## 
## Training set error measures:
##                     ME   RMSE      MAE       MPE     MAPE      MASE       ACF1
## Training set -577.3496 100018 70315.79 -27.61468 63.36953 0.9895955 -0.3927458

Diagnósticos del Modelo

checkresiduals(auto_arima_model)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,0)(0,1,2)[4]
## Q* = 2.3579, df = 6, p-value = 0.884
## 
## Model df: 2.   Total lags used: 8

Predicciones del modelo

De acuerdo a lo visto por el pronóstico del modelo sarima para los siguiente 8 periodos (2024 y 2025), se pueden observar picos tanto positivos como negativos en los flujos de IED, subiendo y bajando el promedio de los últimos 5 años, lo cual hace incierta la llegada del Nearshoring a México.

# Predicciones para 4 trimestres del 2023, 2024 y 2025
forecast_arima <- forecast(auto_arima_model, h=14) # h es el número de periodos a pronosticar
forecast_arima
##         Point Forecast      Lo 80    Hi 80       Lo 95    Hi 95
## 2023 Q1      331742.27 261240.336 402244.2 223918.8660 439565.7
## 2023 Q2      128644.44  58142.506 199146.4  20821.0363 236467.8
## 2023 Q3       83032.63  12530.693 153534.6 -24790.7769 190856.0
## 2023 Q4       52832.71 -17669.222 123334.6 -54990.6925 160656.1
## 2024 Q1      343630.00 271165.571 416094.4 232805.2214 454454.8
## 2024 Q2      127831.42  55366.996 200295.8  17006.6462 238656.2
## 2024 Q3       77119.44   4655.013 149583.9 -33705.3366 187944.2
## 2024 Q4       44531.82 -27932.603 116996.2 -66292.9527 155356.6
## 2025 Q1      343630.00 265171.625 422088.4 223638.2720 463621.7
## 2025 Q2      127831.42  49373.050 206289.8   7839.6968 247823.1
## 2025 Q3       77119.44  -1338.933 155577.8 -42872.2860 197111.2
## 2025 Q4       44531.82 -33926.549 122990.2 -75459.9020 164523.5
## 2026 Q1      343630.00 259604.172 427655.8 215123.5876 472136.4
## 2026 Q2      127831.42  43805.597 211857.2   -674.9876 256337.8
# Crear el gráfico
grafico <- autoplot(forecast_arima) + 
  labs(title = "Pronóstico de flujos de IED en México", x = "Periodo", y = "Flujos de IED")

# Agregar la línea del promedio al gráfico
grafico_con_promedio <- grafico +
  geom_hline(yintercept = promedio_flujos, linetype = "dashed", color = "red")

# Mostrar el gráfico
print(grafico_con_promedio)

IED Fabricación de Papel y Cartón

Visualizar la serie de tiempo (números reales)

# Cargando los datos de flujos de IED
ied_flujos <- read_excel("C:\\Users\\AVRIL\\Documents\\ied_carton_papel_2023.xlsx")
summary(ied_flujos)
##       Year        Quarter          IED_Fab_Carton_Papel  Tipo_Cambio    
##  Min.   :1999   Length:99          Min.   :-61.305      Min.   : 9.016  
##  1st Qu.:2005   Class :character   1st Qu.: -2.874      1st Qu.:10.858  
##  Median :2011   Mode  :character   Median :  8.999      Median :13.012  
##  Mean   :2011                      Mean   : 13.198      Mean   :14.191  
##  3rd Qu.:2017                      3rd Qu.: 22.506      3rd Qu.:18.271  
##  Max.   :2023                      Max.   :317.684      Max.   :23.512  
##       INPC       
##  Min.   : 41.39  
##  1st Qu.: 58.77  
##  Median : 75.72  
##  Mean   : 78.53  
##  3rd Qu.: 95.53  
##  Max.   :130.12
ied_flujos$Tipo_Cambio <- as.numeric(ied_flujos$Tipo_Cambio)
# Crear una nueva columna para los flujos en números reales
ied_flujos$IED_Fab_Carton_Papel_Numero_Real <- ((ied_flujos$IED_Fab_Carton_Papel  * ied_flujos$Tipo_Cambio) / ied_flujos$INPC)*100

# Obtener los últimos 20 valores del pronóstico (5 años)
ultimos_valores <- tail(ied_flujos$IED_Fab_Carton_Papel_Numero_Real, 20)

# Calcular el promedio de los últimos 20 valores (5 años)
promedio_flujos <- mean(ultimos_valores)


# Convertir a serie de tiempo
ied_flujos <- ts(ied_flujos$IED_Fab_Carton_Papel_Numero_Real, start = c(min(ied_flujos$Year), 1), frequency = 4)

plot(ied_flujos)

Análisis de series de tiempo de flujos de IED

ADF Test

Comentario: Con un valor de p de 0.01, se puede rechazar la hipótesis nula de que se tiene una raíz unitaria, lo que significa que es estacionaria.

#Prueba de estacionariedad (ADF Test)
adf_test <- adf.test(ied_flujos, alternative = "stationary")
adf_test
## 
##  Augmented Dickey-Fuller Test
## 
## data:  ied_flujos
## Dickey-Fuller = -4.3846, Lag order = 4, p-value = 0.01
## alternative hypothesis: stationary

Box-Ljung Test y ACF Plot

Comentario: Con un valor de p de 0.5739, no hay evidencia suficiente para rechazar la hipótesis nula, lo que sugiere que los residuos son independientes en el tiempo (es decir, no hay autocorrelación significativa en los residuos).

Box.test(ied_flujos, type = "Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  ied_flujos
## X-squared = 0.31621, df = 1, p-value = 0.5739
acf(ied_flujos)

Estimación SARIMA

De acuerdo a la función auto.arima, los parámetros del modelo fueron optimizados con los valores (0,0,0)(2,0,0), esto indica parámetros diferentes a 0 únicamente en el componente estacional. En este componente posee 2 autoregresiones, 0 diferencias, y 0 promedios móvil, generando así un modelo SARIMA con mejor desempeño que otros modelos, teniendo un RMSE de 708 y un AIC de 1589

auto_arima_model <- auto.arima(ied_flujos)
summary(auto_arima_model)
## Series: ied_flujos 
## ARIMA(0,0,0)(2,0,0)[4] with non-zero mean 
## 
## Coefficients:
##         sar1    sar2      mean
##       0.1779  0.2418  231.3254
## s.e.  0.0977  0.0975  117.4993
## 
## sigma^2 = 517050:  log likelihood = -790.52
## AIC=1589.05   AICc=1589.47   BIC=1599.43
## 
## Training set error measures:
##                   ME    RMSE      MAE       MPE     MAPE      MASE        ACF1
## Training set 6.74125 708.083 372.0405 -20.35875 346.8635 0.7589269 -0.02059353
arimamodel <- arima(ied_flujos, order = c(0,1,0))
summary(arimamodel)
## 
## Call:
## arima(x = ied_flujos, order = c(0, 1, 0))
## 
## 
## sigma^2 estimated as 1184680:  log likelihood = -824.32,  aic = 1650.64
## 
## Training set error measures:
##                    ME     RMSE      MAE      MPE     MAPE      MASE       ACF1
## Training set 15.84571 1082.919 600.1467 323.1185 498.6854 0.9899225 -0.4903256

Diagnósticos del Modelo

checkresiduals(auto_arima_model)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(0,0,0)(2,0,0)[4] with non-zero mean
## Q* = 3.1275, df = 6, p-value = 0.7927
## 
## Model df: 2.   Total lags used: 8

Predicciones del modelo

De acuerdo a lo visto por el pronóstico del modelo sarima para los siguiente 8 periodos (2024 y 2025), se puede observar únicamente un pico tanto positivo en los flujos de IED para la industria de cartón y papel que sobresale del promedio de los últimos 5 años, lo cual determina que no estaría presente el efecto del Nearshoring en esta industria en México (de acuerdo al modelo).

# Predicciones para 4 trimestres del 2024 y 2025
forecast_arima <- forecast(auto_arima_model, h=9) # h es el número de periodos a pronosticar
forecast_arima
##         Point Forecast     Lo 80     Hi 80      Lo 95    Hi 95
## 2023 Q4     118.270285 -803.2444 1039.7849 -1291.0647 1527.605
## 2024 Q1      63.172193 -858.3425  984.6868 -1346.1628 1472.507
## 2024 Q2     428.659314 -492.8553 1350.1740  -980.6757 1837.994
## 2024 Q3     257.420841 -664.0938 1178.9355 -1151.9142 1666.756
## 2024 Q4       7.801776 -928.1791  943.7827 -1423.6575 1439.261
## 2025 Q1     197.496264 -738.4847 1133.4772 -1233.9630 1628.956
## 2025 Q2     312.299567 -623.6814 1248.2805 -1119.1597 1743.759
## 2025 Q3     218.929689 -717.0512 1154.9106 -1212.5296 1650.389
## 2025 Q4     164.229054 -805.0733 1133.5314 -1318.1910 1646.649
# Crear el gráfico
grafico <- autoplot(forecast_arima) + 
  labs(title = "Pronóstico de flujos de IED en la Industria de Cartón y Papel en México", x = "Periodo", y = "Flujos de IED")

# Agregar la línea del promedio al gráfico
grafico_con_promedio <- grafico +
  geom_hline(yintercept = promedio_flujos, linetype = "dashed", color = "red")

# Mostrar el gráfico
print(grafico_con_promedio)

Pronóstico de Ventas de FORM (Cantidad de $)

Cargar TimeSeries Dataset

# Dataset de Ventas de Forms
df_ventas <- read_excel("C:\\Users\\AVRIL\\Documents\\FORM - Ventas.xlsx")  
df_ventas <- head(df_ventas, -3) # Eliminar últimos 3 periodos incompletos
head(df_ventas)
## # A tibble: 6 × 7
##     Ano Mes      Total Total_carton Total_retornable Servicios Muestras
##   <dbl> <chr>    <dbl>        <dbl>            <dbl>     <dbl>    <dbl>
## 1  2020 Ene   6059791.            0                0         0        0
## 2  2020 Feb   6643181.            0                0         0        0
## 3  2020 Mar   8368674.            0                0         0        0
## 4  2020 Abr   4925778.            0                0         0        0
## 5  2020 May   2235669.            0                0         0        0
## 6  2020 Jun   7842003.            0                0         0        0
summary(df_ventas)
##       Ano           Mes                Total           Total_carton    
##  Min.   :2020   Length:33          Min.   : 2235669   Min.   :      0  
##  1st Qu.:2020   Class :character   1st Qu.: 6358278   1st Qu.:      0  
##  Median :2021   Mode  :character   Median : 7872345   Median :5055607  
##  Mean   :2021                      Mean   : 7858459   Mean   :3860008  
##  3rd Qu.:2022                      3rd Qu.: 9219847   3rd Qu.:6295172  
##  Max.   :2022                      Max.   :12285123   Max.   :8873296  
##  Total_retornable    Servicios          Muestras      
##  Min.   :      0   Min.   :      0   Min.   :   0.00  
##  1st Qu.:      0   1st Qu.:      0   1st Qu.:   0.00  
##  Median : 803742   Median :      0   Median :   0.00  
##  Mean   :1261055   Mean   : 133844   Mean   :  74.99  
##  3rd Qu.:1993289   3rd Qu.:  40000   3rd Qu.:   0.00  
##  Max.   :5304410   Max.   :1375979   Max.   :2474.59
df_ventas <- df_ventas %>% dplyr::select(Ano, Mes, Total)

# Iniciar conversión a Formato de Time Series
meses <- c("Ene", "Feb", "Mar", "Abr", "May", "Jun", "Jul", "Ago", "Sep", "Oct", "Nov", "Dic")
df_ventas$Mes <- factor(df_ventas$Mes, levels = meses)

# Combinar la columna Ano con la columna Mes
df_ventas$Fecha <- as.Date(paste(df_ventas$Ano, as.numeric(df_ventas$Mes), "01", sep = "-"))
df_ventas <- df_ventas %>%
  dplyr::select(Fecha, Total)

# Crear la time series
df_ventas <- ts(df_ventas$Total, start = c(min(year(df_ventas$Fecha)), 1), frequency = 12)

Graficar serie de tiempo

plot(df_ventas, main="Serie de tiempo", ylab="Precio", col="red")

# Descomponer la serie de tiempo en sus componentes
Porcomponente <- stats::decompose(df_ventas)

tend <- Porcomponente$trend 
estac <- Porcomponente$seasonal 
error <- Porcomponente$random 
plot(Porcomponente)

Prueba de Estacionariedad - ADF test

Al obtener un valor de p-value=0.6462; no se rechaza la hipotésis nula, por lo que es posible decir que NO es estacionaria.

adf_test <- adf.test(df_ventas)
print(adf_test)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  df_ventas
## Dickey-Fuller = -1.8104, Lag order = 3, p-value = 0.6462
## alternative hypothesis: stationary

Prueba de Autocorrelación - Box-Ljung Test y ACF plot

El p-value resultante es: 0.01477. Por lo que al analizarlo, se determina que es posible rechazar la hipótesis nula, por lo que se dice que Hay autocorrelación serial.

# Prueba de Box-Ljung
box_ljung_test <- Box.test( df_ventas, type = "Ljung-Box")
print(box_ljung_test)
## 
##  Box-Ljung test
## 
## data:  df_ventas
## X-squared = 5.9438, df = 1, p-value = 0.01477
# Plot ACF
acf_plot <- acf(df_ventas, main = "Función de Autocorrelación (ACF) de Ventas")

Estimación de modelo

Para realizar el pronósitico de las ventas mensuales de Form se empleó el método de suavización exponencial, considerando un alpha de 0.99, es decir, otorgando un mayor peso a los valores más recientes que a los datos históricos. Esto implica que para prever las ventas mensuales de Form, las predicciones reflejarán de manera más precisa las tendencias recientes en las ventas.

modelo_expsmooth <- HoltWinters(df_ventas, alpha = 0.99) 
modelo_expsmooth
## Holt-Winters exponential smoothing with trend and additive seasonal component.
## 
## Call:
## HoltWinters(x = df_ventas, alpha = 0.99)
## 
## Smoothing parameters:
##  alpha: 0.99
##  beta : 0
##  gamma: 1
## 
## Coefficients:
##            [,1]
## a   12406683.50
## b      45417.64
## s1   -477921.08
## s2  -1396969.64
## s3   3101872.80
## s4    208552.22
## s5   2095374.61
## s6   1544632.18
## s7   -811668.75
## s8    706601.75
## s9  -2733150.23
## s10 -2118022.84
## s11   746162.03
## s12  -829155.51

Diagnósticos del Modelo

checkresiduals(modelo_expsmooth)

## 
##  Ljung-Box test
## 
## data:  Residuals from HoltWinters
## Q* = 14.824, df = 4, p-value = 0.005081
## 
## Model df: 0.   Total lags used: 4

Predicciones del modelo

Al realizar el pronóstico base mediante el modelo de suavización exponencial, este resultó en una tendencia creciente en las ventas futuras de Form a través de los siguientes meses. Sin embargo es necesario considerar la diferencia entre la línea trazada del pronóstico, y el sombreado del error, existiendo una incertidumbre considerable considerando los intervalores de confianza del 80 y 95, pudiendo no ser un pronóstico certero para medir el desempeño futuro con exactitud, y debería complementarse con otros factores.

predicciones <- forecast(modelo_expsmooth, h = 18)  # Predicción de 18 periodos (meses) hacia adelante
print(predicciones)
##          Point Forecast      Lo 80    Hi 80      Lo 95    Hi 95
## Oct 2022       11974180 8630764.47 15317596  6860867.2 17087493
## Nov 2022       11100549 6395827.58 15805271  3905298.4 18295800
## Dec 2022       15644809 9892385.20 21397233  6847235.9 24442383
## Jan 2023       12796906 6160163.17 19433649  2646883.6 22946929
## Feb 2023       14729146 7312790.31 22145502  3386808.6 26071484
## Mar 2023       14223822 6102349.16 22345294  1803101.4 26644542
## Apr 2023       11912938 3142858.96 20683018 -1499740.6 25325617
## May 2023       13476626 4102712.16 22850541  -859538.3 27812791
## Jun 2023       10082292  141153.03 20023431 -5121368.1 25285952
## Jul 2023       10742837  265135.89 21220538 -5281424.1 26767098
## Aug 2023       13652440 2664346.07 24640533 -3152399.3 30457278
## Sep 2023       12122540  646731.38 23598348 -5428194.6 29673274
## Oct 2023       12519192  566258.89 24472125 -5761241.5 30799625
## Nov 2023       11645561 -757204.23 24048326 -7322831.5 30613953
## Dec 2023       16189821 3352977.13 29026665 -3442437.5 35822079
## Jan 2024       13341918   85201.36 26598635 -6932480.5 33616316
## Feb 2024       15274158 1610464.78 28937851 -5622657.5 36170973
## Mar 2024       14768833  709939.61 28827727 -6732389.1 36270056
# Graficar las predicciones
plot(predicciones, main = "Predicciones de Ventas de Form")

Pronóstico de Ventas de FORM (Cantidad de Producción)

Cargar TimeSeries Dataset

# Dataset de Ventas de Forms
df <- read_excel("C:\\Users\\AVRIL\\Documents\\Datos_FORM_Ventas_FJ2024 (1).xlsx")

# Remover columnas innecesarias
df_ventas <- df[, !names(df) %in% c("Folio_Factura", "No_Cliente", "Ref_cliente", "Estado")]

# Convertir variables categóricas a factores
df_ventas$Producto <- as.factor(df_ventas$Producto)
df_ventas$Cliente <- as.factor(df_ventas$Cliente)
df_ventas$Categoria_Producto <- as.factor(df_ventas$Categoria_Producto)

# Convertir la columna Fecha a formato de fecha
df_ventas$Fecha <- as.Date(df_ventas$Fecha)

# Resumen del dataframe
summary(df_ventas)
##      Fecha                                                          Cliente    
##  Min.   :2021-01-04   Stabilus                                          :6655  
##  1st Qu.:2021-06-04   GRUPO ANTOLIN SALTILLO, S. de R.L de C.V.         :2022  
##  Median :2022-05-09   PO LIGHTING MEXICO                                :1820  
##  Mean   :2022-05-10   DENSO MEXICO                                      :1693  
##  3rd Qu.:2023-03-03   TOKAI RIKA MEXICO                                 :1458  
##  Max.   :2023-12-22   YANFENG INTERNATIONAL AUTOMOTIVE TECHNOLOGY MEXICO:1147  
##                       (Other)                                           :1768  
##                                                                                  Producto    
##  [MX989402-0020] 19419. Toyota. MCV. Pallet                                          :  419  
##  [TR14085 KIT 95161] KIT 95161                                                       :  210  
##  [MX989002-0020-1] CAJA EMPTY MCV - 19638 V.I                                        :  187  
##  [429296 AS 30 99 0000 00 000 INSERTO - INSERT TMC 150 TESLA] 14783. TMC150. Inserto.:  179  
##  [939308 FS 30 99 0000 00 000 CARTÓN - BOX 939308 SIZE 48"] 48’’. Caja Terminada.    :  179  
##  [TR12440 TAPA P558] 18842. P558. Tapa.                                              :  177  
##  (Other)                                                                             :15212  
##     Cantidad                                                 Categoria_Producto
##  Min.   :    1.0   Cartón / Producto Terminado (Cartón)               :10427   
##  1st Qu.:   30.0   Cartón / Kit (Cartón)                              : 3752   
##  Median :   80.0   Cartón / Producto Comercialización (Cartón)        : 1097   
##  Mean   :  360.6   Retornable / Producto Terminado (Retornable)       :  841   
##  3rd Qu.:  250.0   Servicios                                          :  411   
##  Max.   :36220.0   Retornable / Producto Comercialización (Retornable):   26   
##                    (Other)                                            :    9
# Extraer Mes y Año de la fecha
df_ventas <- df_ventas %>%
  mutate(Mes_Año = format(Fecha, "%m-%Y"))  %>% # Combinar Mes y Año en una sola columna
  arrange(Fecha)
  
# Convertir Mes_Año a factor para ordenar adecuadamente
df_ventas$Mes_Año <- factor(df_ventas$Mes_Año, levels = unique(df_ventas$Mes_Año))

# Agrupar por Cliente, Mes_Año y calcular la suma de ventas mensuales
df_ventas_agrupado <- df_ventas %>%
  group_by(Mes_Año, Cliente) %>%
  summarise(Total_Ventas = sum(Cantidad))

# Ver el resultado
head(df_ventas_agrupado)
## # A tibble: 6 × 3
## # Groups:   Mes_Año [1]
##   Mes_Año Cliente                                        Total_Ventas
##   <fct>   <fct>                                                 <dbl>
## 1 01-2021 DENSO MEXICO                                             70
## 2 01-2021 GRUPO ABC DE MEXICO SA DE CV                            279
## 3 01-2021 GRUPO ANTOLIN SALTILLO, S. de R.L de C.V.            145049
## 4 01-2021 HELLA AUTOMOTIVE MEXICO                                  86
## 5 01-2021 IACNA MEXICO V S DE RL DE CV                            109
## 6 01-2021 JOHNSON CONTROLS ENTERPRISES MEXICO, SRL DE CV           42
# Calcular las ventas totales por producto
ventas_por_cliente <- df_ventas %>%
  group_by(Cliente) %>%
  summarise(Ventas = sum(Cantidad)) %>%
  arrange(desc(Ventas)) %>%
  top_n(10)

# Gráfico de barras de los productos con mayores ventas
ggplot(ventas_por_cliente, aes(x = reorder(Cliente, Ventas), y = Ventas)) +
  geom_bar(stat = "identity", fill = "orange") +
  labs(x = "Cliente", y = "Ventas", title = "Top 10 de Cliente con mayores ventas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Calcular las ventas totales por producto
ventas_por_producto <- df_ventas %>%
  group_by(Producto) %>%
  summarise(Ventas = sum(Cantidad)) %>%
  arrange(desc(Ventas)) %>%
  top_n(5)

# Gráfico de barras de los productos con mayores ventas
ggplot(ventas_por_producto, aes(x = reorder(Producto, Ventas), y = Ventas)) +
  geom_bar(stat = "identity", fill = "skyblue") +
  labs(x = "Producto", y = "Ventas", title = "Top 5 de productos con mayores ventas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

# Calcular las ventas totales por categoría de producto
ventas_por_categoria <- df_ventas %>%
  group_by(Categoria_Producto) %>%
  summarise(Ventas = sum(Cantidad)) %>%
  arrange(desc(Ventas)) %>%
  top_n(5)
  
# Gráfico de barras de las categorías de productos con mayores ventas
ggplot(ventas_por_categoria, aes(x = reorder(Categoria_Producto, Ventas), y = Ventas)) +
  geom_bar(stat = "identity", fill = "lightgreen") +
  labs(x = "Categoría de Producto", y = "Ventas", title = "Categorías de productos con mayores ventas") +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

df_ventas_agrupado_total <- df_ventas %>%
  group_by(Mes_Año) %>%
  summarise(Total_Ventas = sum(Cantidad))

df_ventas_ts_total <- ts(df_ventas_agrupado_total$Total_Ventas, start = c(2021, 1), end = c(2023,12), frequency = 12)

# Graficar la serie de tiempo
plot(df_ventas_ts_total, main = "Serie de tiempo", ylab = "Cantidad", col = "blue")

# Realizar la descomposición de la serie de tiempo
Porcomponente1 <- stats::decompose(df_ventas_ts_total)

# Graficar las componentes
plot(Porcomponente1)

Prueba adf

Al tener un valor de p menor a 0.05, se rechaza la hipotésis nula, por lo que existe estacionariedad.

adf_test1 <- adf.test(df_ventas_ts_total)
print(adf_test1)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  df_ventas_ts_total
## Dickey-Fuller = -4.5932, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary

Prueba Box-Ljung

Al tener un valor de p menor a 0.05, se rechaza la hipotésis nula, por lo que existe autocorrelación serial

# Prueba de Box-Ljung
box_ljung_test1 <- Box.test(df_ventas_ts_total, type = "Ljung-Box")
print(box_ljung_test1)
## 
##  Box-Ljung test
## 
## data:  df_ventas_ts_total
## X-squared = 17.207, df = 1, p-value = 3.352e-05
# Plot ACF
acf_plot1 <- acf(df_ventas_ts_total, main = "Función de Autocorrelación (ACF) de Ventas")

Estimación del modelo

Dentro de la estimación del modelo, al utilizar la función auto.arima, los parámetros optimizados corresponden a 1 autocorrelacion, 0 diferencias y 0 promedios móviles, determinando un modelo con un AIC de 873 y RMSE de 40838.33.

modelo_arima1 <- auto.arima(df_ventas_ts_total)
summary(modelo_arima1)
## Series: df_ventas_ts_total 
## ARIMA(1,0,0) with non-zero mean 
## 
## Coefficients:
##          ar1       mean
##       0.7468  170341.61
## s.e.  0.1183   25033.96
## 
## sigma^2 = 1.766e+09:  log likelihood = -433.72
## AIC=873.43   AICc=874.18   BIC=878.18
## 
## Training set error measures:
##                     ME     RMSE      MAE       MPE     MAPE      MASE
## Training set -3459.526 40838.33 31931.35 -8.167996 21.44947 0.5004715
##                     ACF1
## Training set -0.08431919
modelo_sarima2 <- arima(df_ventas_ts_total, order = c(0,1,1), seasonal = c(0,1,1))
summary(modelo_sarima2)
## 
## Call:
## arima(x = df_ventas_ts_total, order = c(0, 1, 1), seasonal = c(0, 1, 1))
## 
## Coefficients:
##           ma1    sma1
##       -0.2704  0.0660
## s.e.   0.1843  0.2924
## 
## sigma^2 estimated as 2.684e+09:  log likelihood = -282.37,  aic = 570.74
## 
## Training set error measures:
##                    ME     RMSE     MAE      MPE     MAPE      MASE        ACF1
## Training set 6784.491 41408.93 25821.3 2.479361 17.34954 0.7707029 -0.09075112

Diagnósticos del Modelo

checkresiduals(modelo_arima1)

## 
##  Ljung-Box test
## 
## data:  Residuals from ARIMA(1,0,0) with non-zero mean
## Q* = 3.2269, df = 6, p-value = 0.7799
## 
## Model df: 1.   Total lags used: 7

Predicciones de Producción Mensuales Totales 2023 y 2024

Al predecir la producción mensual de Form mediante el modelo obtenido, los resultados no muestran seguir un patrón o tendencia bien definido, resultando en un pronóstico ligeramente creciente, pudiendo ser considerado parcialmente flat. Ante esto, es necesario analizar su comportamiento mediante enfoques alternativos. En este caso, a continuación se buscará pronosticar el comportamiento de la producción solicitada por los 3 principales clientes en Form.

predicciones1 <- forecast(modelo_arima1, h = 24)  # Predicción de 24 periodos (meses) hacia adelante
print(predicciones1)
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2024       124530.3 70676.60 178384.1 42168.15 206892.5
## Feb 2024       136128.2 68913.15 203343.2 33331.67 238924.7
## Mar 2024       144789.8 71168.42 218411.3 32195.60 257384.1
## Apr 2024       151258.7 74295.33 228222.0 33553.40 268963.9
## May 2024       156089.8 77324.05 234855.6 35627.97 276551.6
## Jun 2024       159697.9 79944.49 239451.3 37725.59 281670.2
## Jul 2024       162392.5 82093.53 242691.5 39585.82 285199.2
## Aug 2024       164404.9 83803.27 245006.6 41135.32 287674.6
## Sep 2024       165907.9 85137.89 246677.9 42380.82 289435.0
## Oct 2024       167030.4 86166.61 247894.1 43359.92 290700.8
## Nov 2024       167868.7 86952.66 248784.7 44118.32 291619.0
## Dec 2024       168494.7 87549.61 249439.8 44699.85 292289.6
## Jan 2025       168962.3 88000.93 249923.7 45142.58 292782.0
## Feb 2025       169311.5 88341.07 250281.9 45477.93 293145.1
## Mar 2025       169572.3 88596.82 250547.7 45730.99 293413.6
## Apr 2025       169767.0 88788.77 250745.3 45921.45 293612.6
## May 2025       169912.5 88932.65 250892.4 46064.51 293760.5
## Jun 2025       170021.1 89040.41 251001.9 46171.80 293870.5
## Jul 2025       170102.3 89121.06 251083.5 46252.19 293952.4
## Aug 2025       170162.9 89181.37 251144.4 46312.36 294013.4
## Sep 2025       170208.1 89226.47 251189.8 46357.38 294058.9
## Oct 2025       170241.9 89260.19 251223.6 46391.05 294092.8
## Nov 2025       170267.2 89285.38 251248.9 46416.22 294118.1
## Dec 2025       170286.0 89304.20 251267.8 46435.03 294137.0
# Graficar las predicciones
plot(predicciones1, main = "Predicciones de Ventas")

Definir Clientes Más Importantes para Form

Al realizar la suma de las ventas para cada uno de los clientes de Form, fue posible identificar a los clientes más sobresalientes. Para esta selección se busco observar la suma de sus compras a través de los tres años, determinando si existió o no compras del cliente para todos los años. De esta forma, los clientes seleccionados serían aquellos con las compras más altas, pero que también tuvieron relación comercial con la empresa en cada uno de los 3 años previos. Estos clientes son: Stabilus, HELLA Automotive Mexico, y Tokai Rika Mexico.

top_clientes <- df_ventas_agrupado %>%
  group_by(Cliente) %>%
  summarise(Total_Ventas = sum(Total_Ventas)) %>%
  top_n(5, Total_Ventas) %>%
  pull(Cliente)
df_ventas_agrupado <- df_ventas_agrupado %>%
  mutate(Año = substr(Mes_Año, 4, 7))
# Agrupar por Cliente y Año y calcular la suma de las ventas
df_ventas_agrupado_anual <- df_ventas_agrupado %>%
  group_by(Año, Cliente) %>%
  summarise(Total_Ventas = sum(Total_Ventas))
# Encontrar los tres principales clientes
top_clientes <- df_ventas_agrupado_anual %>%
  group_by(Cliente) %>%
  summarise(Total_Ventas = sum(Total_Ventas)) %>%
  top_n(5, Total_Ventas) %>%
  pull(Cliente)
# Filtrar los datos solo para los tres principales clientes
df_top_clientes <- df_ventas_agrupado_anual %>%
  filter(Cliente %in% top_clientes)
# Crear la gráfica de barras
ggplot(df_top_clientes, aes(x = Año, y = Total_Ventas, fill = Cliente)) +
  geom_bar(stat = "identity", position = "dodge") +
  labs(title = "Ventas de Form por Cliente y Año",
       x = "Año",
       y = "Total Ventas",
       fill = "Cliente") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 15),
        plot.title = element_text(face= "bold", size = 18))

# Filtrar los datos solo para los tres principales clientes
df_top_clientes <- df_ventas_agrupado %>%
  filter(Cliente %in% top_clientes)
# Crear Dataframe para cada Cliente Principal
Stabilus <- filter(df_ventas_agrupado, Cliente == "Stabilus")
HELLA <- filter(df_ventas_agrupado, Cliente == "HELLA AUTOMOTIVE MEXICO")
TOKAI <- filter(df_ventas_agrupado, Cliente == "TOKAI RIKA MEXICO")

Dataseries por Principales Clientes

df_ventas_ts1 <- ts(Stabilus$Total_Ventas, start = c(2021, 1), end = c(2023,12), frequency = 12)
df_ventas_ts2 <- ts(HELLA$Total_Ventas, start = c(2021, 1), end = c(2023,12), frequency = 12)
df_ventas_ts3 <- ts(TOKAI$Total_Ventas, start = c(2021, 1), end = c(2023,12), frequency = 12)
df_ventas_ts <- list(df_ventas_ts1, df_ventas_ts2, df_ventas_ts3)
for (i in 1:3) {
  cliente <- c("Stabilus", "HELLA AUTOMOTIVE MEXICO", "TOKAI RIKA MEXICO")[i] 
  plot(df_ventas_ts[[i]], main = paste("Serie de tiempo -", cliente), ylab = "Cantidad", col = "blue")
}

Porcomponente <- list()
# Realizar la descomposición estacional para cada serie de tiempo

for (i in 1:3) {
  cliente <- c("Stabilus", "HELLA AUTOMOTIVE MEXICO", "TOKAI RIKA MEXICO")[i]  
  Porcomponente[[i]] <- stats::decompose(df_ventas_ts[[i]])
}


# Trazar las componentes de la descomposición estacional para cada cliente

for (i in 1:3) {
  cliente <- c("Stabilus", "HELLA AUTOMOTIVE MEXICO", "TOKAI RIKA MEXICO")[i]  
  plot(Porcomponente[[i]])
  mtext(paste("Descomposición -", cliente), side = 3, line = 1, cex = 1)
}

Diagnósticos de Series de Tiempo - Por Cliente

Dickey Fuller

  • Stabilus: Al tener un valor de p mayor a 0.05, no se rechaza la hipotésis nula, por lo que no existe estacionariedad.

  • Hella: Al tener un valor de p mayor a 0.05, no se rechaza la hipotésis nula, por lo que no existe estacionariedad.

  • Tokai Rika: Al tener un valor de p mayor a 0.05, no se rechaza la hipotésis nula, por lo que no existe estacionariedad.

Box - Ljung

  • Stabilus: Al tener un valor de p mayor a 0.05, no se rechaza la hipotésis nula, por lo que no existe autocorrelación.

  • Hella: Al tener un valor de p menor a 0.05, se rechaza la hipotésis nula, por lo que existe autocorrelación.

  • Tokai Rika: Al tener un valor de p menor a 0.05, se rechaza la hipotésis nula, por lo que existe autocorrelación.

# Prueba de Dickey-Fuller para cada serie de tiempo
for (i in 1:3) {
  cliente <- c("Stabilus", "HELLA AUTOMOTIVE MEXICO", "TOKAI RIKA MEXICO")[i] 
  cat("Cliente:", cliente, "\n")
  adf_result <- adf.test(df_ventas_ts[[i]])
  print(adf_result)
  cat("\n")
}
## Cliente: Stabilus 
## 
##  Augmented Dickey-Fuller Test
## 
## data:  df_ventas_ts[[i]]
## Dickey-Fuller = -3.2052, Lag order = 3, p-value = 0.1042
## alternative hypothesis: stationary
## 
## 
## Cliente: HELLA AUTOMOTIVE MEXICO 
## 
##  Augmented Dickey-Fuller Test
## 
## data:  df_ventas_ts[[i]]
## Dickey-Fuller = -0.91304, Lag order = 3, p-value = 0.9372
## alternative hypothesis: stationary
## 
## 
## Cliente: TOKAI RIKA MEXICO 
## 
##  Augmented Dickey-Fuller Test
## 
## data:  df_ventas_ts[[i]]
## Dickey-Fuller = -0.87803, Lag order = 3, p-value = 0.9425
## alternative hypothesis: stationary
# Prueba de Box-Ljung para cada serie de tiempo
for (i in 1:3) {
  cliente <- c("Stabilus", "HELLA AUTOMOTIVE MEXICO", "TOKAI RIKA MEXICO")[i] 
  cat("Cliente:", cliente, "\n")
  box_ljung_test <- Box.test(df_ventas_ts[[i]], type = "Ljung-Box")
  print(box_ljung_test)
  cat("\n")
}
## Cliente: Stabilus 
## 
##  Box-Ljung test
## 
## data:  df_ventas_ts[[i]]
## X-squared = 0.34643, df = 1, p-value = 0.5561
## 
## 
## Cliente: HELLA AUTOMOTIVE MEXICO 
## 
##  Box-Ljung test
## 
## data:  df_ventas_ts[[i]]
## X-squared = 4.3405, df = 1, p-value = 0.03722
## 
## 
## Cliente: TOKAI RIKA MEXICO 
## 
##  Box-Ljung test
## 
## data:  df_ventas_ts[[i]]
## X-squared = 13.372, df = 1, p-value = 0.0002554
# Graficar la función de autocorrelación para cada serie de tiempo
for (i in 1:3) {
  cliente <- c("Stabilus", "HELLA AUTOMOTIVE MEXICO", "TOKAI RIKA MEXICO")[i]  
  cat("Cliente:", cliente, "\n")
  acf_plot <- acf(df_ventas_ts[[i]], plot = FALSE)  
  plot(acf_plot)  
  mtext(paste(cliente), side = 3, line = 1, cex = 1)
  cat("\n")
}
## Cliente: Stabilus

## 
## Cliente: HELLA AUTOMOTIVE MEXICO

## 
## Cliente: TOKAI RIKA MEXICO

Estimación del Modelo SARIMA

La estimación de los modelos para cada uno de los principales clientes se realizó con base en lo revisado previamente y los parámetros empleados se eligieron debio a que la serie temporal tiene ciertas características particulares que no son bien manejadas por los métodos automáticos como algunos cambios estructurales o con patrones relativamente complejos. Lo anterior se realizó con el fin de observar un comportamiento más definido y preciso a través de los meses. Por lo tanto, se optó por realizar un modelo estacional (SARIMA) para adaptarse al comportamiento entre meses. No obstante, a futuro se planea realizar otros modelos predictivos con el fin de optimizar los resultados obtenidos.

  • El ajuste de parámetros para la producción solicitada por Stabilus fue (0,0,1)(0,0,1), ajustando un modelo SARIMA, es decir, que considera el componente estacional, con 1 promedio móvil tanto en el componente order como en el seasonal.

  • El ajuste de parámetros para la producción solicitada por Hella Automotive fue (0,0,1)(0,0,1), ajustando un modelo SARIMA, es decir, que considera el componente estacional, con 1 promedio móvil tanto en el componente order como en el seasonal.

  • El ajuste de parámetros para la producción solicitada por Tokai Rika fue (0,1,0)(0,0,1), ajustando un modelo SARIMA, es decir, que considera el componente estacional, con 1 diferencia en el componente order, y 1 promedio móvil en el componente seasonal.

#Stabilus
# Ajustar el modelo ARIMA a la serie temporal
modelo_arima_ts1 <- arima(df_ventas_ts1, order = c(0, 0, 1), seasonal = c(0, 0, 1))
summary(modelo_arima_ts1)
## 
## Call:
## arima(x = df_ventas_ts1, order = c(0, 0, 1), seasonal = c(0, 0, 1))
## 
## Coefficients:
##          ma1    sma1  intercept
##       0.0683  0.3519  99831.964
## s.e.  0.1463  0.3252   5428.938
## 
## sigma^2 estimated as 5.99e+08:  log likelihood = -415.67,  aic = 839.34
## 
## Training set error measures:
##                    ME     RMSE      MAE       MPE     MAPE      MASE
## Training set 1277.278 24474.78 19850.74 -5.142236 21.26204 0.7211767
##                     ACF1
## Training set 0.007015912
#HELLA
# Ajustar el modelo ARIMA a la serie temporal
modelo_arima_ts2 <- arima(df_ventas_ts2, order = c(0, 0, 1), seasonal = c(0, 0, 1))
summary(modelo_arima_ts2)
## 
## Call:
## arima(x = df_ventas_ts2, order = c(0, 0, 1), seasonal = c(0, 0, 1))
## 
## Coefficients:
##          ma1     sma1  intercept
##       0.1623  -0.1710  16179.171
## s.e.  0.1450   0.1956   2351.459
## 
## sigma^2 estimated as 179166981:  log likelihood = -393.34,  aic = 794.68
## 
## Training set error measures:
##                     ME     RMSE      MAE       MPE     MAPE     MASE       ACF1
## Training set -429.8283 13385.33 10610.74 -1693.441 1721.395 1.041435 0.06032071
#TOKAI RIKA
# Ajustar el modelo ARIMA a la serie temporal
modelo_arima_ts3 <- arima(df_ventas_ts3, order = c(0, 1, 0), seasonal = c(0, 0, 1))
summary(modelo_arima_ts3)
## 
## Call:
## arima(x = df_ventas_ts3, order = c(0, 1, 0), seasonal = c(0, 0, 1))
## 
## Coefficients:
##         sma1
##       0.5580
## s.e.  0.3019
## 
## sigma^2 estimated as 3903297:  log likelihood = -317.44,  aic = 638.87
## 
## Training set error measures:
##                     ME     RMSE      MAE       MPE     MAPE      MASE
## Training set -21.20438 1948.043 1509.663 -22.24132 45.85809 0.8312205
##                    ACF1
## Training set -0.1317307

Predicciones Mensuales para los 3 Clientes principales 2023 y 2024

  • De acuerdo al modelo SARIMA, la producción solicitada por Stabilus tiene un patrón incremento y descenso, lo cual puede ser incierto para Form al ser su cliente principal. Ante esto, puede suponerse cierto nivel de riesgo, existiendo un decrecimiento considerable con respecto a su demanda al final de cada año.

  • De acuerdo al modelo SARIMA, la producción solicitada por Hella Automotive supondrá un comportamiento con ligero crecimiento, con un valle en Junio del 2025, continuando con la tendencia de crecimiento en los niveles de producción durante el resto del año.

  • De acuerdo al modelo ARIMA, la producción solicituda por Tokai Rika supondrá un comportamiento con ligero decrecimiento constante, con picos mínimos en comparación con el comportamiento del resto del año.

#Stabilus
# Realizar predicciones con el modelo ajustado
predicciones <- forecast(modelo_arima_ts1, h = 12)
predicciones
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2024      112339.66 80970.63 143708.7 64364.86 160314.4
## Feb 2024       98026.47 66584.51 129468.4 49940.15 146112.8
## Mar 2024      105922.52 74480.56 137364.5 57836.19 154008.8
## Apr 2024       93357.92 61915.96 124799.9 45271.59 141444.2
## May 2024      117341.28 85899.32 148783.2 69254.96 165427.6
## Jun 2024      119719.19 88277.23 151161.1 71632.86 167805.5
## Jul 2024      103757.82 72315.86 135199.8 55671.49 151844.1
## Aug 2024      110523.36 79081.40 141965.3 62437.03 158609.7
## Sep 2024       99769.99 68328.04 131212.0 51683.67 147856.3
## Oct 2024      102345.99 70904.03 133787.9 54259.67 150432.3
## Nov 2024      113015.67 81573.72 144457.6 64929.35 161102.0
## Dec 2024       85368.80 53926.85 116810.7 37282.49 133455.1
# Graficar las predicciones
plot(predicciones, main = "Predicciones de Ventas - STABILUS", xlab = "Tiempo", ylab = "Cantidad")

#HELLA
# Realizar predicciones con el modelo ajustado
predicciones <- forecast(modelo_arima_ts2, h = 12)
predicciones
##          Point Forecast      Lo 80    Hi 80      Lo 95    Hi 95
## Jan 2024       14356.60 -2797.3938 31510.60 -11878.172 40591.38
## Feb 2024       13753.73 -3624.7391 31132.19 -12824.343 40331.79
## Mar 2024       15401.96 -1976.5019 32780.43 -11176.106 41980.03
## Apr 2024       13863.66 -3514.8013 31242.13 -12714.405 40441.73
## May 2024       17810.09   431.6291 35188.56  -8767.975 44388.16
## Jun 2024       10421.16 -6957.3078 27799.62 -16156.911 36999.23
## Jul 2024       16962.60  -415.8650 34341.07  -9615.469 43540.67
## Aug 2024       16669.28  -709.1837 34047.75  -9908.787 43247.35
## Sep 2024       17152.33  -226.1320 34530.80  -9425.736 43730.40
## Oct 2024       17490.65   112.1816 34869.11  -9087.422 44068.72
## Nov 2024       16411.79  -966.6792 33790.25 -10166.283 42989.85
## Dec 2024       19219.12  1840.6518 36597.58  -7358.952 45797.19
# Graficar las predicciones
plot(predicciones, main = "Predicciones de Ventas - HELLA AUTOMOTIVE", xlab = "Tiempo", ylab = "Cantidad")

#TOKAI RIKA
# Realizar predicciones con el modelo ajustado
predicciones <- forecast(modelo_arima_ts3, h = 12)
predicciones
##          Point Forecast      Lo 80     Hi 80       Lo 95     Hi 95
## Jan 2024       4202.861  1643.9492  6761.772    289.3432  8116.378
## Feb 2024       4307.876   702.2457  7913.505  -1206.4595  9822.211
## Mar 2024       5189.544   778.9770  9600.112  -1555.8364 11934.925
## Apr 2024       4080.669 -1009.0897  9170.428  -3703.4452 11864.783
## May 2024       4344.536 -1343.8895 10032.961  -4355.1599 13044.231
## Jun 2024       3852.280 -2377.5445 10082.106  -5675.4147 13379.976
## Jul 2024       2831.773 -3896.0249  9559.570  -7457.5057 13121.051
## Aug 2024       2385.075 -4806.2945  9576.445  -8613.1756 13383.326
## Sep 2024       2952.464 -4674.3526 10579.281  -8711.7456 14616.674
## Oct 2024       2855.788 -5182.9226 10894.499  -9438.3591 15149.936
## Nov 2024       2961.073 -5469.4314 11391.578  -9932.2711 15854.418
## Dec 2024       2708.306 -6096.5765 11513.188 -10757.5995 16174.211
# Graficar las predicciones
plot(predicciones, main = "Predicciones de Ventas - TOKAI RIKA", xlab = "Tiempo", ylab = "Cantidad")

Principales Hallazgos

Situación Problema 1: Incertidumbre en demanda de la industria

  • El pronóstico de ventas de FORM, en términos monetarios, fue mediante el modelo de suavización exponencial, el cual resultó en una tendencia creciente en las ventas futuras a través de los siguientes meses. A pesar de esto, se presentan varios valles durante dicho periodo lo que implica cierto comportamiento en los clientes de la industria automotriz y sus derivados.

  • El pronóstico de ventas de FORM, en términos de cantidad de productos, determina que las ventas generales tendrán cierto decaimiento pero continuará con un aumento mensual. Esto se muestra con la predicción de los tres principales clientes claves de FORM que tienen presencia cada año en las ventas, ya que las tres empresas tienen un comportamiento que sube y baja pero se diferencia en la medida de ls picos y valles. De igual manera, se muestra que Stabilus tendrá una reducción en su nivel de ventas en 2025; además coinciden en que habrá en sus ventas del 2025 en comparación con años anteriores. Pero esto no implica que siga existiendo cierto aumento ligero conforme pasa cada periodo. Acorde a esto, se requiere establecer estrategias para reducir los efectos de esta dependencia y aprovechar el incremento de demanda generalizado.

Situación Problema 2: Alta rotación de personal

  • Existe un desafío de Retención en Empleados Jóvenes y Solteros, ya que el análisis de clustering revela que la mayoría de los empleados que abandonan Form resultó en 3 perfiles de edad. Esto permitió observar que la mayor parte de empleados que terminan su relación laboral en la empresa son jóvenes solteros o en unión libre, considerando la libertad brindada por las posibles oportunidades disponibles y la falta de un compromiso familiar (responsabilidad de la situación financiera de la familia). En estos perfiles de abadono, se identifica también el mayor abandono al residir en Apodaca (principal municipio de parques industriales) y ser mujeres jovenes (posiblemente buscando oportunidades de crecimiento).

  • La fuerza laboral de Form está conformada principalmente por empleados con las siguientes características: Mujeres, residentes de Apodaca, educación secundaria, con la principal razón para trabajar siendo la ubicación de la empresa.

  • El análisis de Text Mining sobre los comentarios de los empleados por medio de las frecuencias determinó que los principales factores negativos al trabajar en Form son: calor, salario, prestaciones y estrés. Asimismo, el Análisis de Sentimientos también relacionó que estos comentarios negativos tienen una relación con la principal emoción negativa siendo la ansiedad. Por lo tanto, se debe mejorar el bienestar laboral abordando estas preocupaciones por medio de la implementación de medidas para reducir el estrés, mejorar las condiciones de trabajo y ofrecer compensaciones competitivas.

  • El modelo más apropiado para analizar el abandono de los empleados en Form corresponde a Naive Bayes, debido a su capacidad de analizar cada factor de forma independiente, así como su desempeño considerable en las métricas. Accuracy:0. 80, Kappa: .29 y AUC: 0.77.

  • De acuerdo al modelo Naive Bayes, las variables explicativas estiman las siguientes cualidades para determinar la permanencia/retención de los empleados en Form: El empleado es mujer, está en una edad adulta (media 35), trabajó ya más de un año en la empresa (promedio 14 meses), considera que recibe una retribución justa de salario y prestaciones para sus labores realizadas, perciben su estrés bajo y una buena facilidad de traslado.

Relación de los resultados estimados de Nearshoring con las situaciones problemas.

El acontecimiento del Nearshoring será casi nulo en México, ya que se estima que ocurre pero en un nivel poco significativo para la industria en menor medida. Aunuqe existe cierta incertidumbre el respecto dependiendo ciertos factores externos políticos y económicos. Acorde a esto, se estima que tendrá un impacto negativo en la producción de empaques de cartón para autopartes en México y, por ende, en FORM, puesto que este efecto podría aumentar la rotación de empleados y disminuir la demanda de empaques de cartón. La probabilidad del aumento de la rotación de empleados sería más alta si FORM no ofrece condiciones de trabajo atractivas en relación a sus competidores y/o si no tiene un plan integral de crecimiento claro. Asimismo, acorde a las estimaciones de las ventas del top 3 de clientes de FORM junto con la predicción de ventas general de la empresa, se estima que habrá una cierto crecimiento en sus ventas de producto y monetarias lo que implica que la empresa sea más susceptible a las fluctuaciones en la demanda del mercado local; además de tener ciertas complicaciones con empresas internacionales con fuerte posicionamiento y/o que utilizan una estrategia de reducción de costos. Por lo tanto, se recomienda desarrollar planes de contingencia para adaptarse a diferentes escenarios y generar estrategias para mitigar la alta dependencia a los tres principales clientes ya que, representan aproximadamente el 70% de las ventas totales lo que implica graves afectaciones de rentabilidad a la empresa.

Referencias

LS0tDQp0aXRsZTogIkV2aWRlbmNpYSAxIg0Kc3VidGl0bGU6ICJDRDMwMDJDIEludGVsaWdlbmNpYSBBcnRpZmljaWFsIGNvbiBJbXBhY3RvIEVtcHJlc2FyaWFsIg0KYXV0aG9yOiAiQXZyaWwgTG9iYXRvIC0gRXF1aXBvIDEiDQpkYXRlOiAiMjAyNC0wMy0yMSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDoNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9kb3dubG9hZDogeWVzDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiBweWdtZW50cw0KLS0tDQoNCiFbXShodHRwczovL2NpdHJpcy11Yy5vcmcvd3AtY29udGVudC91cGxvYWRzLzIwMTkvMTAvVGVjLWRlLU1vbnRlcnJleS1sb2dvLWhvcml6b250YWwtYmx1ZS5wbmcpDQoNCjxkaXYgc3R5bGU9InRleHQtYWxpZ246IGNlbnRlciI+DQogIDxwPjxzdHJvbmc+R3J1cG8gNjAxPC9zdHJvbmc+PC9wPg0KICA8cD48c3Ryb25nPlByb2Zlc29yIERhdmlkIFNhdWNlZG88L3N0cm9uZz48L3A+DQo8L2Rpdj4NCg0KPGRpdiBzdHlsZT0idGV4dC1hbGlnbjogY2VudGVyIj4NCiAgPHA+PHN0cm9uZz5BbHVtbmE6PC9zdHJvbmc+PC9wPg0KDQogIEF2cmlsIExvYmF0byBEZWxnYWRvIEEwMDgzMzExMw0KIA0KPC9kaXY+DQoNCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoDQoJZWNobyA9IFRSVUUsDQoJbWVzc2FnZSA9IEZBTFNFLA0KCXdhcm5pbmcgPSBGQUxTRQ0KKQ0KYGBgDQoNCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkodGlkeXIpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHBsb3RseSkNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KHJlYWR4bCkNCmxpYnJhcnkoRGF0YUV4cGxvcmVyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkodG0pDQpsaWJyYXJ5KHdvcmRjbG91ZCkNCmxpYnJhcnkoY2x1c3RlcikNCmxpYnJhcnkoZmFjdG9leHRyYSkgDQpsaWJyYXJ5KGdyaWRFeHRyYSkNCmxpYnJhcnkocHVycnIpDQpsaWJyYXJ5KHBST0MpDQpsaWJyYXJ5KHJwYXJ0KQ0KbGlicmFyeShycGFydC5wbG90KQ0KbGlicmFyeShlMTA3MSkNCmxpYnJhcnkoZ2dwdWJyKQ0KbGlicmFyeShkbG9va3IpDQpsaWJyYXJ5KHpvbykNCmxpYnJhcnkoY2FyZXQpDQpsaWJyYXJ5KHN0YXRzKQ0KbGlicmFyeSh0c2VyaWVzKQ0KbGlicmFyeShyZWFkcikNCmxpYnJhcnkodmFycykNCmxpYnJhcnkoc3l1emhldCkNCmxpYnJhcnkoa2FibGVFeHRyYSkNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShzY2FsZXMpDQpsaWJyYXJ5KHJlYWR4bCkNCmBgYA0KDQoNCg0KIyAqKkludHJvZHVjY2nDs24qKg0KLSAqwr9RdcOpIGVzIHVuIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgbG9zIGRhdG9zPyoNCkVsIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgZGF0b3MgKEVEQSkgZXMgdW5hIG1ldG9kb2xvZ8OtYSBwYXJhIGNvbXByZW5kZXIsIGV4YW1pbmFyIHkgdmlzdWFsaXphciAgbGEgZXN0cnVjdHVyYSB5IGNhcmFjdGVyw61zdGljYXMgZGUgdW4gY29uanVudG8gZGUgZGF0b3MgYW50ZXMgZGUgYXBsaWNhciBtb2RlbG9zLCBhbsOhbGlzaXMgeS9vIGFsZ29yaXRtb3MgZXN0YWTDrXN0aWNvcyBtw6FzIGF2YW56YWRvcy4gRWwgb2JqZXRpdm8gcHJpbmNpcGFsIGVzIHJlc3VtaXIgeSBkZXNjdWJyaXIgY2FyYWN0ZXLDrXN0aWNhcyByZWxldmFudGVzIGRlIGxvcyBkYXRvcyBtZWRpYW50ZSB0w6ljbmljYXMgZ3LDoWZpY2FzIHkgZXN0YWTDrXN0aWNhcyBkZXNjcmlwdGl2YXMsIHBhcmEgb2J0ZW5lciBpbmZvcm1hY2nDs24gaW5pY2lhbCB5IGRldGVjdGFyIHBvc2libGVzIHBhdHJvbmVzLCB0ZW5kZW5jaWFzLCBhbm9tYWzDrWFzIG8gcmVsYWNpb25lcyBxdWUgcHVlZGFuIHNlciByZWxldmFudGVzIHBhcmEgZWwgcHJvYmxlbWEgZW4gY3Vlc3Rpw7NuLg0KDQotICrCv0PDs21vIGNvbnRyaWJ1eWUgZWwgYW7DoWxpc2lzIGV4cGxvcmF0b3JpbyBkZSBsb3MgZGF0b3MgYSBtZWpvcmFyIGVsIHByb2Nlc28geSBsb3MgcmVzdWx0YWRvcyBkZSBhbmFsw610aWNhIGRlc2NyaXB0aXZhPyoNCkVsIGFuw6FsaXNpcyBleHBsb3JhdG9yaW8gZGUgZGF0b3MgY29udHJpYnV5ZSBhIG1lam9yYXIgZWwgcHJvY2VzbyB5IGxvcyByZXN1bHRhZG9zIGRlIGxhIGFuYWzDrXRpY2EgZGVzY3JpcHRpdmEgbWVkaWFudGUgbGEgaWRlbnRpZmljYWNpw7NuIGRlIHBhdHJvbmVzIHkgdGVuZGVuY2lhcyBsbyBxdWUgYXl1ZGEgYSBjb21wcmVuZGVyIG1lam9yIGVsIGZlbsOzbWVubyBxdWUgZXN0w6FuIHJlcHJlc2VudGFuZG8geSBhIGdlbmVyYXIgaGlww7N0ZXNpcyBzb2JyZSBwb3NpYmxlcyByZWxhY2lvbmVzIGVudHJlIGxhcyB2YXJpYWJsZXMuIEFzaW1pc21vLCBzZSBkZXRlY3RhbiBhbm9tYWzDrWFzIHkgZXJyb3JlcyBwdWVzdG8gcXVlIHNlIGRpc3Rpbmd1ZW4gdmFsb3JlcyBhdMOtcGljb3MsIGVycm9yZXMgZGUgZW50cmFkYSBvIGluY29uc2lzdGVuY2lhcyBlbiBsb3MgZGF0b3MgcXVlIGRlYmVuIHNlciBjb3JyZWdpZG9zIGFudGVzIGRlIHJlYWxpemFyIGFuw6FsaXNpcyBhdmFuemFkb3MuIERlIGlndWFsIG1hbmVyYSwgYWwgZXhwbG9yYXIgbGEgcmVsYWNpw7NuIGVudHJlIHZhcmlhYmxlcywgZXMgbcOhcyBzZW5jaWxsbyBzZWxlY2Npb25hciBsYXMgdmFyaWFibGVzIG3DoXMgcmVsZXZhbnRlcyBwYXJhIGluY2x1aXIgZW4gYW7DoWxpc2lzIHBvc3RlcmlvcmVzLCBsbyBxdWUgcGVybWl0ZSBzaW1wbGlmaWNhciBlbCBtb2RlbG8geSBtZWpvcmFyIHN1IGludGVycHJldGFiaWxpZGFkLiBJbmNsdXNpdmUsIGEgdHJhdsOpcyBkZSB2aXN1YWxpemFjaW9uZXMgc2UgbXVlc3RyYW4gcmVsYWNpb25lcyBlbnRyZSB2YXJpYWJsZXMgcXVlIHB1ZWRlbiBzZXIgZXhwbG9yYWRhcyBtw6FzIGEgZm9uZG8gZW4gYW7DoWxpc2lzIHBvc3RlcmlvcmVzIHBhcmEgZm9ybXVsYXIgeSBjb21wcm9iYXIgY2llcnRhcyBoaXDDs3Rlc2lzLiBJZ3VhbG1lbnRlLCBlbCBFREEgcGVybWl0ZSBleGFtaW5hciBsYSBkaXN0cmlidWNpw7NuIGRlIGxhcyB2YXJpYWJsZXMsIGxvIHF1ZSBmdW5jaW9uYSBwYXJhIGRldGVybWluYXIgc2kgbG9zIHN1cHVlc3RvcyBkZSBjaWVydG9zIG1vZGVsb3MgZXN0YWTDrXN0aWNvcyBzb24gdsOhbGlkb3MgeSBhIGVsZWdpciBsYXMgdMOpY25pY2FzIGFkZWN1YWRhcyBwYXJhIGVzdG9zLiANCg0KDQoNCiMjICoqQW50ZWNlZGVudGVzIGRlIGxhIEVtcHJlc2EgRk9STSoqDQoNCioqVmlzacOzbioqOiANCg0K4oCdKkVuIDIwMzMgc2VyZW1vcyB1bmEgZGUgbGFzIGNpbmNvIG1lam9yZXMgY29tcGHDscOtYXMgZGUgTcOpeGljbyBxdWUgZ2VuZXJhbiB2YWxvciBkZW50cm8gZGUgbGEgY2FkZW5hIGRlIHN1bWluaXN0cm8gZGUgbGFzIGluZHVzdHJpYXMgcXVlIG3DoXMgdmFsb3JhbiBsYSBmb3JtYSBlbiBsYSBxdWUgc2UgcHJvdGVnZW4geSB0cmFzbGFkYW4gbGFzIGNvc2FzLirigJ0NCg0KKipNaXNpw7NuKio6IA0KDQrigJwqVHJhbnNmb3JtYXIgbnVlc3RybyBlbnRvcm5vIHkgcmVzb2x2ZXIgcmV0b3MgaW5kdXN0cmlhbGVzIGRlIG51ZXN0cm9zIGNsaWVudGVzIGEgdHJhdsOpcyBkZSBsYSBjb2xhYm9yYWNpw7NuLCBwcm92b2NhbmRvIG51ZXZhcyBvcG9ydHVuaWRhZGVzIHF1ZSBwb3RlbmNpYW4gbnVlc3RybyBtb2RlbG8gZGUgbmVnb2NpbywgcGFyYSBhbGNhbnphciBudWVzdHJvcyBpZGVhbGVzLirigJ0NCg0KKipPYmpldGl2b3MgZXN0cmF0w6lnaWNvcyoqOg0KDQoqIFN1c3RlbnRhYmlsaWRhZCBjb2xhYm9yYXRpdmE6ICpGb21lbnRhciBlbCB1c28gZGUgbWF0ZXJpYWxlcyBkZSBiYWpvIGltcGFjdG8gYW1iaWVudGFsIG1pZW50cmFzIG9wdGltaXphbW9zIGxvcyByZWN1cnNvcyBzaW4gZGVzcGVyZGljaWFyLioNCg0KKiBFZmVjdGl2aWRhZCBjb2xhYm9yYXRpdmE6ICpDdW1wbGlyIGVuIHRpZW1wbyB5IGZvcm1hIHBhcnRpY2lwYW5kbyBwcm9hY3RpdmFtZW50ZS4qDQoNCiogSW50ZWdyaWRhZCBjb2xhYm9yYXRpdmE6ICpBY3RpdHVkIGRlIGhvbmVzdGlkYWQgeSB0cmFuc3BhcmVuY2lhIGRlbnRybyBkZSB0b2RvcyBudWVzdHJvcyBwcm9jZXNvcy4qDQoNCiogSW5ub3ZhY2nDs24gY29sYWJvcmF0aXZhOiAqQ29uc3RhbnRlIGLDunNxdWVkYSBkZSBudWV2YXMgeSBtZWpvcmVzIGZvcm1hcyBkZSBzb2x1Y2lvbmFyIGEgdHJhdsOpcyBkZWwgaW5nZW5pbyB5IGxhIGV4cGVyaW1lbnRhY2nDs24uKg0KDQoqIENhbGlkYWQgY29sYWJvcmF0aXZhOiAqU2luIGNvbXByb21ldGVyIG51ZXN0cm9zIHRpZW1wb3MsIGN1aWRhbW9zIGNhZGEgZGV0YWxsZSwgZGVzZGUgZWwgZXNwYWNpbyBkZSB0cmFiYWpvIGhhc3RhIG51ZXN0cm8gcHJvZHVjdG8gZmluYWwuKg0KDQoqIEZsZXhpYmlsaWRhZCBjb2xhYm9yYXRpdmE6ICpTaWVtcHJlIGVuY29udHJhcmVtb3MgZWwgY29tbyBzw60sIGFudGljaXDDoW5kb25vcyBhIGxhcyBhZHZlcnNpZGFkZXMgYXBveWFkb3MgZGUgbGEgbXVsdGlkaXNjaXBsaW5hLioNCg0KDQojIyBDb250ZXh0byBkZSBsYSBJbmR1c3RyaWENCg0KIyMjIEF1dG9tb3RyaXogDQojIyMjIEluZHVzdHJpYSBOb3J0ZWFtZXJpY2FuYQ0KDQpDb24gYmFzZSBlbiBsYXMgZ3LDoWZpY2FzIHByZXNlbnRlcyBzZSBtdWVzdHJhIGVsICoqUGFub3JhbWEgQWN0dWFsIGVuIEVVQSoqOg0KDQoqIExhIGluZHVzdHJpYSBhdXRvbW90cml6IGVuIEVFLiBVVS4gc2UgZW5mcmVudGEgYSB1bmEgc2VyaWUgZGUgZGVzYWbDrW9zLCBjb21vIGxhIGVzY2FzZXogZGUgY2hpcHMsIGVsIGF1bWVudG8gZGUgbG9zIHByZWNpb3MgZGUgbG9zIG1hdGVyaWFsZXMgeSBsYSBpbmZsYWNpw7NuOyBsbyBjdWFsIHNlIHZpc3VhbGl6YSBhbnRlIGRpZmVyZW5jaWEgZGUgdmVudGFzIGNvbiBwcm9kdWNjacOzbi4NCg0KRGUgaWd1YWwgbWFuZXJhLCBzZSBtdWVzdHJhIHRlbmRlbmNpYSBlbiBlbCBpbmNyZW1lbnRvIGRlIGxhcyB2ZW50YXMgdG90YWxlcyBkZSB2ZWjDrWN1bG9zIGVuIEVFLiBVVS4gZW4gbG9zIHByw7N4aW1vcyBhw7FvcywgaW1wdWxzYWRhcyBwb3IgbGEgcmVjdXBlcmFjacOzbiBlY29uw7NtaWNhIHkgbGEgZGVtYW5kYSBkZSB2ZWjDrWN1bG9zIG51ZXZvcy4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZiA8LSByZWFkX3hsc3goIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcQXV0b21vdHJpel9BTEQueGxzeCIpDQpjb2xuYW1lcyhkZilbNV0gPC0gIlRvdGFsX2RvbWVzdGljX3NhbGVzIg0KDQpkZiA8LSBuYS5vbWl0KGRmKQ0KZGYgPC0gdW5pcXVlKGRmKQ0KDQpkZiRBw7FvIDwtIGFzLm51bWVyaWMoYXMuY2hhcmFjdGVyKGRmJEHDsW8pKQ0KDQpwbG90X2x5KGRmLCB4ID0gfkHDsW8pICU+JQ0KICBhZGRfbGluZXMoeSA9IH5Qcm9kdWN0aW9uX3RvdGFsLCBuYW1lID0gIlByb2R1Y2Npw7NuIFRvdGFsIiwgbGluZSA9IGxpc3QoY29sb3IgPSAiYmx1ZSIpKSAlPiUNCiAgYWRkX2xpbmVzKHkgPSB+VG90YWxfZG9tZXN0aWNfc2FsZXMsIG5hbWUgPSAiVmVudGFzIFRvdGFsZXMiLCBsaW5lID0gbGlzdChjb2xvciA9ICJyZWQiKSkgJT4lDQogIGxheW91dCh0aXRsZSA9ICI8Yj5JbmR1c3RyaWEgQXV0b21vdHJpeiBlbiBVU0EgLSBQcm9kdWNjacOzbiBUb3RhbCB2cyBWZW50YXMgVG90YWxlczwvYj4iLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkHDsW8iKSwNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJDYW50aWRhZCIpLA0KICAgICAgICAgbGVnZW5kID0gbGlzdChvcmllbnRhdGlvbiA9ICJoIiwgeCA9IDAuNSwgeSA9IC0wLjIpKSAgIyBNb3ZlciBsYSBsZXllbmRhIGEgbGEgcGFydGUgaW5mZXJpb3IgeSBjZW50cmFybGENCmBgYA0KDQojIyMjIEluZHVzdHJpYSBNZXhpY2FuYQ0KTGEgZXhwb3J0YWNpw7NuIGRlIHZlaMOtY3Vsb3MgZGVzZGUgTcOpeGljbyBzZSBkYSBhIHVuYSB2YXJpZWRhZCBkZSBwdW50b3MsIGNvbnNpZGVyYW5kbyBwcmluY2lwYWxtZW50ZSBwYcOtc2VzIGVuIEFzaWEgeSBFdXJvcGEuIEVzdG8gcGVybWl0ZSBkZXRlcm1pbmFyIGVsIHBhcGVsIGltcG9ydGFudGUgcXVlIGN1bXBsZSBNw6l4aWNvIGVuIGxhIGluZHVzdHJpYSBhdXRvbW90cml6IHkgc3UgY29tZXJjaWFsaXphY2nDs24gYSBwYcOtc2VzIGV4dHJhbmplcm9zIHJlY29ub2NpZG9zLCBzaWVuZG8gZWwgcHJpbmNpcGFsIEFyYWJpYSBTYXVkaXRhLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmYXoxIDwtcmVhZF9leGNlbCgiQzpcXFVzZXJzXFxBVlJJTFxcRG9jdW1lbnRzXFxteF9leHBvcnRhY2lvbl92ZWhpY3Vsb3NfcGFpc19kZXN0aW5vLnhsc3giKQ0KDQpkZmF6MSA8LSBkZmF6MSAlPiUNCiAgcmVuYW1lKFBhw61zX2Rlc3Rpbm8gPSBgUGHDrXMgZGVzdGlub2ApDQoNCiMgRmlsdHJhciBsb3MgZGF0b3MgcGFyYSBvYnRlbmVyIHNvbG8gbGFzIGV4cG9ydGFjaW9uZXMgZGUgYXV0b3MgcGFyYSBlbCBhw7FvIDIwMjMNCmRmXzIwMjMgPC0gZmlsdGVyKGRmYXoxLCBBw7FvID09IDIwMjMpDQoNCg0KIyBDYWxjdWxhciBlbCB0b3RhbCBkZSBleHBvcnRhY2lvbmVzIGRlIGF1dG9zIGEgY2FkYSBwYcOtcyBkZXN0aW5vDQpleHBvcnRhY2lvbmVzX3Bvcl9wYWlzIDwtIGRmXzIwMjMgJT4lDQogIGdyb3VwX2J5KFBhw61zX2Rlc3Rpbm8pICU+JQ0KICBzdW1tYXJpc2UoVG90YWxfZXhwb3J0YWNpb25lcyA9IHN1bShDYW50aWRhZCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoVG90YWxfZXhwb3J0YWNpb25lcykpICU+JQ0KICB0b3Bfbig1KQ0KDQojIENyZWFyIGVsIGdyw6FmaWNvIGRlIGJhcnJhcw0KZ2dwbG90KGV4cG9ydGFjaW9uZXNfcG9yX3BhaXMsIGFlcyh5ID0gcmVvcmRlcihQYcOtc19kZXN0aW5vLCBUb3RhbF9leHBvcnRhY2lvbmVzKSwgeCA9IFRvdGFsX2V4cG9ydGFjaW9uZXMsIGZpbGwgPSBUb3RhbF9leHBvcnRhY2lvbmVzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIlRvcCA1IGRlIHBhw61zZXMgZGVzdGlubyBwYXJhIGV4cG9ydGFjaW9uZXMgZGUgYXV0b3MgZGUgTcOpeGljbyBlbiAyMDIzIiwNCiAgICAgICB5ID0gIlBhw61zIERlc3Rpbm8iLA0KICAgICAgIHggPSAiQ2FudGlkYWQgZGUgRXhwb3J0YWNpb25lcyIpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiI0Y0QUM4OCIsIGhpZ2ggPSAiI0ZGNTQwMCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPSAxOCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpKw0KICBndWlkZXMoZmlsbCA9IEZBTFNFKQ0KDQoNCmBgYA0KDQoNCkxhcyBwcmluY2lwYWxlcyBlbXByZXNhcyBxdWUgcmVhbGl6YW4gZXhwb3J0YWNpb25lcyBkZXNkZSBNw6l4aWNvIGNvcnJlc3BvbmRlbiBhIEdlbmVyYWwgTW90b3JzLCBOaXNzYW4geSBGb3JkLiBFc3RvIG11ZXN0cmEgcXVlIGVsIHNlY3RvciBtw6FzIGRlc3RhY2FkbyBsbyBjb25mb3JtYW4gcHJpbmNpcGFsbWVudGUgZW1wcmVzYXMgYW1lcmljYW5hcyAoeSAxIGphcG9uZXNhKSwgc2llbmRvIHVuIGFzcGVjdG8gcmVsZXZhbnRlIGRlYmlkbyBhIGxhIGV4aXN0ZW5jaWEgZGUgY2hvcXVlcyBjdWx0dXJhbGVzIGNvbiBsYXMgY29tcGHDscOtYXMgY29yZWFuYXMgeSBjaGluYXMgYWNvcmRlIGFsIGFjdHVhbCBkdWXDsW8gZGUgRm9ybSwgRmVsaXBlLiBEZXRlcm1pbmFuZG8gZGUgZXN0YSBmb3JtYSwgbGEgcG9zaWJpbGlkYWQgZGUgbWFudGVuZXIgYnVlbmFzIHJlbGFjaW9uZXMgY29uIGxvcyBwcmluY2lwYWxlcyBsw61kZXJlcyBlbiBleHBvcnRhY2nDs24gZW4gTcOpeGljbywgY29uIHVuYSBtYXlvciBmYWNpbGlkYWQuICANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIENhbGN1bGFyIGVsIHRvdGFsIGRlIGV4cG9ydGFjaW9uZXMgZGUgYXV0b3MgcGFyYSBjYWRhIG1hcmNhDQpleHBvcnRhY2lvbmVzX3Bvcl9tYXJjYSA8LSBkZl8yMDIzICU+JQ0KICBncm91cF9ieShNYXJjYSkgJT4lDQogIHN1bW1hcmlzZShUb3RhbF9leHBvcnRhY2lvbmVzID0gc3VtKENhbnRpZGFkKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhUb3RhbF9leHBvcnRhY2lvbmVzKSkgJT4lDQogIHRvcF9uKDUpDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGhvcml6b250YWwgcGFyYSBsYXMgMTAgbWFyY2FzIG3DoXMgZXhwb3J0YWRhcw0KZ2dwbG90KGV4cG9ydGFjaW9uZXNfcG9yX21hcmNhLCBhZXMoeSA9IHJlb3JkZXIoTWFyY2EsIFRvdGFsX2V4cG9ydGFjaW9uZXMpLCB4ID0gVG90YWxfZXhwb3J0YWNpb25lcywgZmlsbCA9IFRvdGFsX2V4cG9ydGFjaW9uZXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGxhYnModGl0bGUgPSAiVG9wIDUgZGUgbWFyY2FzIG3DoXMgZXhwb3J0YWRhcyBkZSBhdXRvcyBkZSBNw6l4aWNvIGVuIDIwMjMiLA0KICAgICAgIHkgPSAiTWFyY2EiLA0KICAgICAgIHggPSAiQ2FudGlkYWQgZGUgRXhwb3J0YWNpb25lcyIpICsNCiAgc2NhbGVfZmlsbF9ncmFkaWVudChsb3cgPSAiI0Y0QUM4OCIsIGhpZ2ggPSAiI0ZGNTQwMCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPSAxOCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpKw0KICBndWlkZXMoZmlsbCA9IEZBTFNFKQ0KYGBgDQoNCkVudHJlIGxvcyB2ZWjDrWN1bG9zIHF1ZSBoYWNlbiB1c28gZGUgY29tYnVzdGlibGUgYWx0ZXJuYXRpdm8gKG8gY29tcGxlbWVudGFyaW8pIGEgbGEgZ2Fzb2xpbmEgZGVzdGFjYW4gcHJpbmNpcGFsbWVudGUgbG9zIGjDrWJyaWRvcyBubyBlbmNodWZhYmxlcywgcmVwcmVzZW50YW5kbyBsb3MgaMOtYnJpZG9zIGVuY2h1ZmFibGVzIGxhIG3DoXMgYmFqYSBwcm9wb3JjacOzbiBkZSB2ZW50YXMgZW4gZWwgbWVyY2FkbyBtZXhpY2Fuby4gQXNpbWlzbW8sIGxvcyBwcmluY2lwYWxlcyBlc3RhZG9zIGRvbmRlIG9jdXJyaWVyb24gbWF5b3JlcyB2ZW50YXMgZGUgZXN0ZSB0aXBvIGRlIHZlaMOtY3Vsb3MgZnVlcm9uIENpdWRhZCBkZSBNw6l4aWNvLCBFc3RhZG8gZGUgTcOpeGljbyB5IE51ZXZvIExlw7NuLCBzaWVuZG8gYWxndW5vcyBkZSBsb3MgcHJpbmNpcGFsZXMgY2VudHJvcyBlY29uw7NtaWNvcyBxdWUgZGVzdGFjYXJvbiBjb21vIHBpb25lcm9zIGVuIGxhIGludGVncmFjacOzbiBkZSBlc3RlIHRpcG8gZGUgdmVow61jdWxvcy4gRXN0byBnZW5lcmEgdW5hIG9wb3J0dW5pZGFkIHBhcmEgRm9ybSBwYXJhIGxhIGF0ZW5jacOzbiBkZSBlc3RlIG1lcmNhZG8gYW1wbGlhbWVudGUgcHJlc2VudGUgZW4gc3UgRXN0YWRvIGRlIG9yaWdlbiwgcHVkaWVuZG8gY29tcGxlbWVudGFyIHN1cyBvcGVyYWNpb25lcyBhbCBvZnJlY2VyIGVsIHVzbyBkZSBzdXMgc29sdWNpb25lcyBkZSBjYXJ0w7NuIHBhcmEgZW1iYWxhamUuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFZlaMOtY3Vsb3MgRWzDqWN0cmljb3MNCmRmdmUgPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcbXhfdmVudGFfdmVoaWN1bG9zX2hpYnJpZG9zX2VsZWN0cmljb3NfMjAyMy5jc3YiKQ0KZGZ2ZSA8LSBkZnZlW2RmdmUkSURfRU5USURBRCAhPSA5OSwgXQ0KDQojIENyZWFyIHVuIHZlY3RvciBjb24gbG9zIG5vbWJyZXMgcmVhbGVzIGRlIGxvcyBlc3RhZG9zDQpub21icmVzX2VzdGFkb3MgPC0gYygiQWd1YXNjYWxpZW50ZXMiLCAiQmFqYSBDYWxpZm9ybmlhIiwgIkJhamEgQ2FsaWZvcm5pYSBTdXIiLCAiQ2FtcGVjaGUiLCAiQ29haHVpbGEiLCAiQ29saW1hIiwgIkNoaWFwYXMiLCAiQ2hpaHVhaHVhIiwgIkNpdWRhZCBkZSBNw6l4aWNvIiwgIkR1cmFuZ28iLCAiR3VhbmFqdWF0byIsICJHdWVycmVybyIsICJIaWRhbGdvIiwgIkphbGlzY28iLCAiRXN0YWRvIGRlIE3DqXhpY28iLCAiTWljaG9hY8OhbiIsICJNb3JlbG9zIiwgIk5heWFyaXQiLCAiTnVldm8gTGXDs24iLCAiT2F4YWNhIiwgIlB1ZWJsYSIsICJRdWVyw6l0YXJvIiwgIlF1aW50YW5hIFJvbyIsICJTYW4gTHVpcyBQb3Rvc8OtIiwgIlNpbmFsb2EiLCAiU29ub3JhIiwgIlRhYmFzY28iLCAiVGFtYXVsaXBhcyIsICJUbGF4Y2FsYSIsICJWZXJhY3J1eiIsICJZdWNhdMOhbiIsICJaYWNhdGVjYXMiKQ0KDQojIENyZWFyIHVuIGRhdGEgZnJhbWUgY29uIGxvcyBJRF9FTlRJREFEIHkgbG9zIG5vbWJyZXMgZGUgbG9zIGVzdGFkb3MNCmVzdGFkb3NfZGYgPC0gZGF0YS5mcmFtZShJRF9FTlRJREFEID0gMTozMiwgRVNUQURPID0gbm9tYnJlc19lc3RhZG9zKQ0KDQojIFVuaXIgbG9zIGRhdGEgZnJhbWVzIHVzYW5kbyBsYSBmdW5jacOzbiBtZXJnZQ0KZGZ2ZSA8LSBtZXJnZShkZnZlLCBlc3RhZG9zX2RmLCBieSA9ICJJRF9FTlRJREFEIiwgYWxsLnggPSBUUlVFKQ0KDQp2ZW50YXNfcG9yX2VzdGFkbyA8LSBkZnZlICU+JQ0KICBncm91cF9ieShFU1RBRE8pICU+JQ0KICBzdW1tYXJpc2UoVG90YWxfdmVudGFzX2VsZWN0cmljb3MgPSBzdW0oVkVIX0VMRUNUUiksDQogICAgICAgICAgICBUb3RhbF92ZW50YXNfaGlicmlkb3MgPSBzdW0oVkVIX0hJQlJJREFTKSwNCiAgICAgICAgICAgIFRvdGFsX3ZlbnRhc19oaWJyaWRvc19lbmNodWZhYmxlcyA9IHN1bShWRUhfSElCUklEQVNfUExVR0lOKSkNCg0KDQp2ZW50YXNfcG9yX2VzdGFkb19sb25nIDwtIHZlbnRhc19wb3JfZXN0YWRvICU+JQ0KICBwaXZvdF9sb25nZXIoY29scyA9IGMoVG90YWxfdmVudGFzX2VsZWN0cmljb3MsIFRvdGFsX3ZlbnRhc19oaWJyaWRvcywgVG90YWxfdmVudGFzX2hpYnJpZG9zX2VuY2h1ZmFibGVzKSwNCiAgICAgICAgICAgICAgIG5hbWVzX3RvID0gIlRpcG8gZGUgVmVow61jdWxvIiwNCiAgICAgICAgICAgICAgIHZhbHVlc190byA9ICJUb3RhbCBkZSBWZW50YXMiKQ0KDQoNCiMgU2VsZWNjaW9uYXIgbG9zIDEwIHByaW5jaXBhbGVzIGVzdGFkb3MgY29uIGxhcyBtYXlvcmVzIHZlbnRhcyB0b3RhbGVzDQp0b3A1X2VzdGFkb3MgPC0gdmVudGFzX3Bvcl9lc3RhZG8gJT4lDQogIHNsaWNlX21heChvcmRlcl9ieSA9IFRvdGFsX3ZlbnRhc19lbGVjdHJpY29zICsgVG90YWxfdmVudGFzX2hpYnJpZG9zICsgVG90YWxfdmVudGFzX2hpYnJpZG9zX2VuY2h1ZmFibGVzLCBuID0gNSkNCg0KIyBGaWx0cmFyIHZlbnRhc19wb3JfZXN0YWRvX2xvbmcgcGFyYSBpbmNsdWlyIHNvbG8gbG9zIDEwIHByaW5jaXBhbGVzIGVzdGFkb3MNCnZlbnRhc190b3AxMCA8LSB2ZW50YXNfcG9yX2VzdGFkb19sb25nICU+JQ0KICBmaWx0ZXIoRVNUQURPICVpbiUgdG9wNV9lc3RhZG9zJEVTVEFETykNCg0KIyBDcmVhciBlbCBncsOhZmljbyBkZSBiYXJyYXMgbW9zdHJhbmRvIGxhcyB2ZW50YXMgZGl2aWRpZGFzIHBvciB0aXBvIGRlIHZlaMOtY3VsbyBwYXJhIGxvcyAxMCBwcmluY2lwYWxlcyBlc3RhZG9zDQpnZ3Bsb3QodmVudGFzX3RvcDEwLCBhZXMoeSA9IHJlb3JkZXIoRVNUQURPLCBgVG90YWwgZGUgVmVudGFzYCksIHggPSBgVG90YWwgZGUgVmVudGFzYCwgZmlsbCA9IGBUaXBvIGRlIFZlaMOtY3Vsb2ApKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJzdGFjayIpICsNCiAgbGFicyh0aXRsZSA9ICJUb3AgNSBkZSBlc3RhZG9zIGNvbiB2ZW50YXMgZGUgdmVow61jdWxvcyBlbiBNw6l4aWNvIGVuIDIwMjMiLA0KICAgICAgIHkgPSAiRXN0YWRvIiwNCiAgICAgICB4ID0gIlRvdGFsIGRlIFZlbnRhcyIsDQogICAgICAgZmlsbCA9ICIiKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0gMTgsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNyksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJ0b3AiKSAgDQoNCmBgYA0KDQoNCkxhIGluZHVzdHJpYSBhdXRvbW90cml6IGVuIE3DqXhpY28gcHJlc2VudGEgbWF5b3IgcHJvZHVjY2nDs24gbG9jYWwgcXVlIGltcG9ydGFjaW9uZXMsIGxvIGN1YWwgcmVtYXJjYSBsYSByZWxldmFuY2lhIGRlIGxhIGluZHVzdHJpYSBhdXRvbW90cml6IGVuIE3DqXhpY28sIHNpZW5kbyB0YW1iacOpbiBjb25zaWRlcmFibGUgbGEgY2FudGlkYWQgdW5pZGFkZXMgZXhwb3J0YWRhcy4gRXMgaW1wb3J0YW50ZSBkZXN0YWNhciBlbCBkZXNjZW5zbyBlbiBsYSBwcm9kdWNjacOzbiBsb2NhbCBkZWJpZG8gYSBsYSBwYW5kZW1pYSBwb3IgQ09WSUQtMTkgZW4gZWwgMjAyMCwgYXPDrSBjb21vIHRhbWJpw6luIHN1IHJlY3VwZXJhY2nDs24gZW4gYcOxb3MgcG9zdGVyaW9yZXMsIHNpZW5kbyB1biBidWVuIGluZGljYXRpdm8gcGFyYSBlbCBmdXR1cm8gZGUgbGEgaW5kdXN0cmlhIGF1dG9tb3RyaXogZW4gZWwgcGHDrXMuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZmF6MiA8LSBteF9hdXRvbW90aXZlX2luZHVzdHJ5IDwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcbXhfYXV0b21vdGl2ZV9pbmR1c3RyeS54bHN4Iiwgc2hlZXQgPSAxKQ0KDQoNCiMgTcOpdHJpY2FzIGRlIGxhIEluZHVzdHJpYSBBdXRvbW90cml6IGVuIE3DqXhpY28NCnBsb3RfbHkoZGF0YSA9IGRmYXoyLCB4ID0gfnllYXIpICU+JQ0KICBhZGRfbGluZXMoeSA9IH50b3RhbF9sb2NhbF9wcm9kdWN0aW9uLCBjb2xvciA9IEkoImJsdWUiKSwgbmFtZSA9ICJQcm9kdWNjacOzbiBMb2NhbCIpICU+JQ0KICBhZGRfbGluZXMoeSA9IH50b3RhbF9leHBvcnRzLCBjb2xvciA9IEkoImdyZWVuIiksIG5hbWUgPSAiRXhwb3J0YWNpb25lcyIpICU+JQ0KICBhZGRfbGluZXMoeSA9IH50b3RhbF9pbXBvcnRzLCBjb2xvciA9IEkoInJlZCIpLCBuYW1lID0gIkltcG9ydGFjaW9uZXMiKSAlPiUNCiAgbGF5b3V0KHRpdGxlID0gbGlzdCh0ZXh0ID0gIjxiPkV2b2x1Y2nDs24gZGUgbcOpdHJpY2FzIGRlIEluZHVzdHJpYSBBdXRvbW90cml6IGVuIE3DqXhpY288L2I+IiksDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiQcOxbyIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlZhbG9yIiksDQogICAgICAgICBsZWdlbmQgPSBsaXN0KHggPSAwLjUsIHkgPSAxKSkNCmBgYA0KDQojIyMgQXV0b3BhcnRlcw0KIyMjIyBJbmR1c3RyaWEgTm9ydGVhbWVyaWNhbmENCg0KRW4gcmVsYWNpw7NuIGFsICoqUGFub3JhbWEgQWN0dWFsKiogZGUgbGEgaW5kdXN0cmlhIGRlIEF1dG9wYXJ0ZXMgZW4gRVVBIHNlIHByZXZlw6kgcXVlIGVsIHByb21lZGlvIGRlIG51ZXZvcyBwZWRpZG9zIGRlIGZhYnJpY2FudGVzOiB2ZWjDrWN1bG9zIGRlIG1vdG9yIHkgcmVwdWVzdG9zIChBTVZQTk8pIGRlc2RlIDE5OTUgaGFzdGEgMjAyMyBoYSBzaWRvIG1heW9yIGVuIGVsIHBlcmlvZG8gZGUgaW52aWVybm8gZG9uZGUgamVyw6FycXVpY2FtZW50ZSBsb3MgbWVzZXMgY29uIG1heW9yZXMgdmVudGFzIHNvbjogRW5lcm8sIERpY2llbWJyZSwgTm92aWVtYnJlLCBPY3R1YnJlIHkgU3BldGllbWJyZTsgbG8gY3VhbCByZXByZXNlbnRhIGNpZXJ0YSBlc3RhY2lvbmFsaWRhZCBlbiBlc3RlIHBlcmlvZG8geSB1bmEgZXN0aW1hY2nDs24gbWF5b3IgZGUgcHJvZHVjY2nDs24gYW50ZXMgZGUgU2VwdGllbWJyZS4NCg0KDQoqKlByZWRpY2Npw7NuIGRlIE51ZXZvcyBwZWRpZG9zIGRlIGZhYnJpY2FudGVzOiB2ZWjDrWN1bG9zIGRlIG1vdG9yIHkgcmVwdWVzdG9zIChBTVZQTk8pIHBhcmEgMjAyNSoqDQoNCkVuIHJlbGFjacOzbiBhbCAqKlBhbm9yYW1hIEFjdHVhbCoqIHNlIG11ZXN0cmE6DQoNCiogQSBwYXJ0aXIgZGVsIGHDsW8gMjAyMCwgc2Ugb2JzZXJ2YSB1bmEgZXN0YWJpbGl6YWNpw7NuIGVuIGxhcyB2ZW50YXMsIGxvIHF1ZSBwb2Ryw61hIHNlciB1biBpbmRpY2lvIGRlIG1hZHVyYWNpw7NuIGRlbCBtZXJjYWRvLg0KDQoqIExhIGluZHVzdHJpYSBkZSBhdXRvcGFydGVzIGVuIEVFLiBVVS4gaGEgZXhwZXJpbWVudGFkbyB1biBjcmVjaW1pZW50byBjb25zdGFudGUgZW4gbG9zIMO6bHRpbW9zIGHDsW9zLCBjb24gdW4gdmFsb3IgZGUgbWVyY2FkbyBkZSBhcHJveGltYWRhbWVudGUgJDg5MiBtaWwgbWlsbG9uZXMgZW4gMjAyMi4gRGljaG8gY3JlY2ltaWVudG8gc2UgaGEgdmlzdG8gaW1wdWxzYWRvIHBvciB1bmEgc2VyaWUgZGUgZmFjdG9yZXMsIGNvbW8gZWwgYXVtZW50byBkZSBsYSBwcm9kdWNjacOzbiBkZSB2ZWjDrWN1bG9zIGVuIEVVQSwgbGEgY3JlY2llbnRlIGRlbWFuZGEgZGUgdmVow61jdWxvcyBlbMOpY3RyaWNvcyBlIGjDrWJyaWRvczsgeSB1biBtYXlvciBlbmZvcXVlIGVuIGxhIHNlZ3VyaWRhZCB5IGxhcyBjYXJhY3RlcsOtc3RpY2FzIHRlY25vbMOzZ2ljYXMgZW4gbG9zIHZlaMOtY3Vsb3MuDQoNClBvciBsbyB0YW50bywgbGFzICoqdGVuZGVuY2lhcyoqIGRlIG1heW9yIGZ1ZXJ6YSBlbiBlc3RhIGluZHVzdHJpYSBzb246DQoNCiogQ3JlY2ltaWVudG8gZGUgaW5kdXN0cmlhIGltcHVsc2FkbyBwb3IgZmFjdG9yZXMgY29tbyBlbCBhdW1lbnRvIGRlbCBwYXJxdWUgYXV0b21vdG9yLCBtYXlvciBkZW1hbmRhIGRlIHZlaMOtY3Vsb3MgdXNhZG9zIHkgZWwgZGVzYXJyb2xsbyBkZSBudWV2YXMgdGVjbm9sb2fDrWFzIGF1dG9tb3RyaWNlcy4NCg0KKiBTZSBlc3BlcmEgcXVlIGxhIGNvbXBldGVuY2lhIGVuIGxhIGluZHVzdHJpYSBuYWNpb25hbCBlIGludGVybmFjaW9uYWwgc2UgaW50ZW5zaWZpcXVlLCBjb24gbGEgZW50cmFkYSBkZSBudWV2b3MgY29tcGV0aWRvcmVzLCBlc3BlY2lhbG1lbnRlIGRlIHBhw61zZXMgYXNpw6F0aWNvcy4NCg0KKiBOdWV2YXMgb3BvcnR1bmlkYWRlcyBhbnRlIGVsIGF1Z2UgZGUgdmVow61jdWxvcyBlbMOpY3RyaWNvcyBwb3IgZW5kZSwgbGEgaW5ub3ZhY2nDs24gc2Vyw6EgY2xhdmUgcGFyYSBlbCDDqXhpdG8gZGUgbGFzIGVtcHJlc2FzIGVuIGxhIGluZHVzdHJpYSBkZSBhdXRvcGFydGVzLCB5YSBxdWUgcGVybWl0aXLDoSBkZXNhcnJvbGxhciBwcm9kdWN0b3MgeSBzZXJ2aWNpb3MgbcOhcyBlZmljaWVudGVzIHkgY29tcGV0aXRpdm9zLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGYyIDwtIHJlYWRfeGxzKCJDOlxcVXNlcnNcXEFWUklMXFxEb2N1bWVudHNcXEF1dG9wYXJ0ZXNfQUxELnhscyIpDQpkZjIgPC0gbmEub21pdChkZjIpDQpkZjIgPC0gdW5pcXVlKGRmMikNCg0KZGYyJG9ic2VydmF0aW9uX2RhdGUgPSBhcy5EYXRlKGRmMiRvYnNlcnZhdGlvbl9kYXRlKQ0KDQojUHJvbWVkaW8gZGUgTnVldm9zIHBlZGlkb3MgZGUgZmFicmljYW50ZXM6IHZlaMOtY3Vsb3MgZGUgbW90b3IgeSByZXB1ZXN0b3MgKEFNVlBOTykJDQpkZjIkTWVzIDwtIGZvcm1hdChkZjIkb2JzZXJ2YXRpb25fZGF0ZSwgIiVtIikNCg0KI1ByZWRpY2Npw7NuIGRlIE51ZXZvcyBwZWRpZG9zIGRlIGZhYnJpY2FudGVzOiB2ZWjDrWN1bG9zIGRlIG1vdG9yIHkgcmVwdWVzdG9zIChBTVZQTk8pIHBhcmEgMjAyNQ0KdHNfdmVudGFzIDwtIHRzKGRmMiRBTVZQTk8sIGZyZXF1ZW5jeSA9IDEyLCBzdGFydCA9IGMoMTk5MiwgMSkpDQoNCmRmX3RzX3ZlbnRhcyA8LSBkYXRhLmZyYW1lKEHDsW8gPSBhcy5EYXRlKHRpbWUodHNfdmVudGFzKSksIFZlbnRhcyA9IGFzLm51bWVyaWModHNfdmVudGFzKSkNCnBsb3RfbHkoZGZfdHNfdmVudGFzLCB4ID0gfkHDsW8sIHkgPSB+VmVudGFzLCB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0gJ2xpbmVzJywgbmFtZSA9ICdWZW50YXMnLCBjb2xvcj0ib3JhbmdlIikgJT4lDQogIGxheW91dCh0aXRsZSA9ICI8Yj5IaXN0w7NyaWNvIGRlIFZlbnRhcyBkZSBBdXRvcGFydGVzIGVuIEVzdGFkb3MgVW5pZG9zPC9iPiIsDQogICAgICAgICB4YXhpcyA9IGxpc3QodGl0bGUgPSAiQcOxbyIpLA0KICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIlZlbnRhcyIpKQ0KDQojIEFqdXN0YXIgZWwgbW9kZWxvIGRlIHNlcmllcyBkZSB0aWVtcG8gYXV0b23DoXRpY2FtZW50ZQ0KbW9kZWxvIDwtIGF1dG8uYXJpbWEodHNfdmVudGFzKQ0KDQojIEdlbmVyYXIgcHJlZGljY2lvbmVzIGhhc3RhIGVsIGNpZXJyZSBkZWwgYcOxbyAyMDI1ICgzNiBtZXNlcyBtw6FzIGFsbMOhIGRlIGxvcyBkYXRvcyBleGlzdGVudGVzKQ0KcHJlZGljY2lvbmVzIDwtIGZvcmVjYXN0KG1vZGVsbywgaCA9IDIzKQ0KcHJlZGljY2lvbmVzDQoNCnBsb3QocHJlZGljY2lvbmVzLCBtYWluID0gIlByZWRpY2Npb25lcyBkZSBWZW50YXMgaGFzdGEgMjAyNSIsIHhsYWIgPSAiQcOxbyIsIHlsYWIgPSAiVmVudGFzIikNCg0KYGBgDQoNCg0KIyMjIyBJbmR1c3RyaWEgTWV4aWNhbmENCkVzIHBvc2libGUgb2JzZXJ2YXIgcXVlIGxhcyBwcmluY2lwYWxlcyBwbGFudGFzIGRlIGF1dG9wYXJ0ZXMgZW4gTcOpeGljbyBkdXJhbnRlIGVsIDIwMjIgc2UgY29uY2VudHJhcm9uIGVuIENvYWh1aWxhIHkgUHVlYmxhLCBkZXN0YWNhbmRvIGNvbW8gbG9zIGVzdGFkb3MgY29uIG1heW9yIHZhbG9yIGNvbWVyY2lhbCBlbiBleHBvcnRhY2lvbmVzLiBBbnRlIGVzdG8gZXMgbmVjZXNhcmlvIGNvbnNpZGVyYXIgbGEgY2VyY2Fuw61hIGRlIENvYWh1aWxhIGNvbiBOdWV2byBMZcOzbiwgZXN0YWRvIGVuIGVsIHF1ZSBlc3TDoSBwcmVzZW50ZSBsYSBwbGFudGEgZGUgRm9ybS4gRXN0byBzdXBvbmUgdW5hIHZlbnRhamEgYWwgbWFudGVuZXIgY2VyY2Fuw61hIGVuIHVubyBkZSBsb3MgcHVudG9zIGNsYXZlIGRlIGxhIGluZHVzdHJpYSBkZSBhdXRvcGFydGVzIGVuIGVsIHBhw61zLg0KDQpBbCBoYWNlciBsYSBjb21wYXJhY2nDs24gZW50cmUgZWwgdmFsb3IgY29tZXJjaWFsIGRlbCAyMDIxIGNvbiBlbCAyMDIyLCBDb2FodWlsYSB2dWVsdmUgYSBkZXN0YWNhciBjb21vIGVsIGVzdGFkbyBjb24gbWF5b3IgdmFsb3IgdG90YWwgZW4gbGEgc3VtYSBkZSBhbWJvcyBhw7Fvcy4gRXN0byByZWFmaXJtYSBsbyBtZW5jaW9uYWRvIGVuIGVsIHB1bnRvIGFudGVyaW9yLCBzaWVuZG8gQ29haHVpbGEgdW4gcHVudG8gZXN0csOhdGVnaWNvIGVuIGxhIGluZHVzdHJpYSBkZSBhdXRvcGFydGVzIHkgbGEgdmVudGFqYSBxdWUgZXNvIHJlcHJlc2VudGEgcGFyYSBGb3JtIGFsIGVzdGFyIHByw7N4aW1vLiBTaW4gZW1iYXJnbywgZXN0byB0YW1iacOpbiB0aWVuZSB1bmEgY29uc2lkZXJhY2nDs24gaW1wb3J0YW50ZSwgc2llbmRvIHF1ZSBhIHBlc2FyIGRlIG1hbnRlbmVyIGVsIHZhbG9yIG3DoXMgZWxldmFkbyBkdXJhbnRlIGFtYm9zIGHDsW9zLCBlc3RlIGZ1ZSBlbCBtaXNtbywgZXMgZGVjaXIsIG5vIGh1Ym8gdW4gY3JlY2ltaWVudG8sIGEgZGlmZXJlbmNpYSBkZSBQdWVibGEsIGVuIGVsIGN1YWwgc8OtIGh1Ym8gdW4gY3JlY2ltaWVudG8gY29uc2lkZXJhYmxlIGNvbiByZXNwZWN0byBhbCBhw7FvIHByZXZpbywgcGVybyBpZ3VhbG1lbnRlIGVzIHVuIGNvbXBvcnRhbWllbnRvIGZhdm9yYWJsZSBjb21wYXJhbmRvIGNvbiBlbCByZXN0byBkZSBlc3RhZG9zLCBlbiBsb3MgY3VhbGVzIGh1Ym8gZGVjcmVjaW1pZW50by4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZmFwMSA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxBVlJJTFxcRG9jdW1lbnRzXFxtZXhfZXhwb3J0c19hdXRvcGFydHMuY3N2IikNCg0KZGZfMjAyMV8yMDIyIDwtIHN1YnNldChkZmFwMSwgeWVhciAlaW4lIGMoMjAyMSwgMjAyMikpDQoNCiMgQWdydXBhciBsb3MgZGF0b3MgcG9yIGVzdGFkbyB5IGHDsW8sIHkgY2FsY3VsYXIgZWwgdG90YWwgZGVsIHZhbG9yIGNvbWVyY2lhbCBwYXJhIGNhZGEgZXN0YWRvIGVuIGNhZGEgYcOxbw0Kc3RhdGVfdHJhZGUgPC0gZGZfMjAyMV8yMDIyICU+JQ0KICBncm91cF9ieShTdGF0ZSwgeWVhcikgJT4lDQogIHN1bW1hcmlzZSh0b3RhbF90cmFkZSA9IHN1bSh0cmFkZV92YWx1ZSkpDQoNCiMgU2VsZWNjaW9uYXIgbG9zIDEwIGVzdGFkb3MgY29uIGVsIHZhbG9yIGNvbWVyY2lhbCBtw6FzIGFsdG8gZW4gYW1ib3MgYcOxb3MNCnRvcDEwX3N0YXRlcyA8LSBzdGF0ZV90cmFkZSAlPiUNCiAgZ3JvdXBfYnkoeWVhcikgJT4lDQogIHRvcF9uKDgsIHRvdGFsX3RyYWRlKSAlPiUNCiAgYXJyYW5nZSh5ZWFyLCBkZXNjKHRvdGFsX3RyYWRlKSkNCg0KIyBDcmVhciBlbCBncsOhZmljbyBkZSBiYXJyYXMNCmdncGxvdCh0b3AxMF9zdGF0ZXMsIGFlcyh4ID0gcmVvcmRlcihTdGF0ZSwgdG90YWxfdHJhZGUpLCB5ID0gdG90YWxfdHJhZGUsIGZpbGwgPSBmYWN0b3IoeWVhcikpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgbGFicyh0aXRsZSA9ICJDb21wYXJhY2nDs24gZGUgdmFsb3IgY29tZXJjaWFsIGVudHJlIDIwMjEgeSAyMDIyIChUb3AgOCBlc3RhZG9zKSIsDQogICAgICAgeCA9ICJFc3RhZG8iLA0KICAgICAgIHkgPSAiVmFsb3IgQ29tZXJjaWFsIFRvdGFsIiwNCiAgICAgICBmaWxsID0gIkHDsW8iKSArDQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSwgc2l6ZT0gMTgsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwNCiAgICAgICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNiwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNyksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKQ0KYGBgDQoNCg0KRmluYWxtZW50ZSwgZW4gbGEgaW5kdXN0cmlhIGRlIGF1dG9wYXJ0ZXMgZW4gTcOpeGljbyBhIGxvIGxhcmdvIGRlbCB0aWVtcG8gc2Ugb2JzZXJ2w7MgdW4gaW1wYWN0byBjb25zaWRlcmFibGUgZGViaWRvIGEgbGEgcGFuZGVtaWEgcG9yIENPVklELTE5IGVuIDIwMjAsIHNpbiBlbWJhcmdvIGVzdGEgdHV2byB1bmEgcmVjdXBlcmFjacOzbiBjb25zaWRlcmFibGUgZW4gYcOxb3MgcG9zdGVyaW9yZXMuIEFzaW1pc21vLCBzZSBpZGVudGlmaWPDsyBxdWUgZWwgdmFsb3IgZGUgbGEgcHJvZHVjY2nDs24gbG9jYWwgZXMgbWF5b3IgYWwgZGUgbGFzIGltcG9ydGFjaW9uZXMgZGUgb3Ryb3MgcGHDrXNlcy4gRXN0byBtdWVzdHJhIGxhIG1hZ25pdHVkIGRlIGxhIGltcG9ydGFuY2lhIGRlIGxhIHByb2R1Y2Npw7NuIGRlIGF1dG9wYXJ0ZXMgY29tbyB1bmEgaW5kdXN0cmlhIHPDs2xpZGEgZW4gZWwgcGHDrXMuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGZhcDIgPC0gbXhfYXV0b21vdGl2ZV9pbmR1c3RyeSA8LSByZWFkX2V4Y2VsKCJDOlxcVXNlcnNcXEFWUklMXFxEb2N1bWVudHNcXG14X2F1dG9tb3RpdmVfaW5kdXN0cnkueGxzeCIsIHNoZWV0ID0gIm14X2F1dG9wYXJ0c19tYXJrZXQiKQ0KDQojIENyZWFyIGVsIGdyw6FmaWNvIGRlIGzDrW5lYXMNCnBsb3RfbHkoZGZhcDIsIHggPSB+eWVhcikgJT4lDQogIGFkZF9saW5lcyh5ID0gfnRvdGFsX2xvY2FsX3Byb2R1Y3Rpb24sIGNvbG9yID0gSSgiYmx1ZSIpLCBuYW1lID0gIlByb2R1Y2Npw7NuIExvY2FsIikgJT4lDQogIGFkZF9saW5lcyh5ID0gfnRvdGFsX2V4cG9ydHMsIGNvbG9yID0gSSgiZ3JlZW4iKSwgbmFtZSA9ICJFeHBvcnRhY2lvbmVzIikgJT4lDQogIGFkZF9saW5lcyh5ID0gfnRvdGFsX2ltcG9ydHMsIGNvbG9yID0gSSgicmVkIiksIG5hbWUgPSAiSW1wb3J0YWNpb25lcyIpICU+JQ0KICBsYXlvdXQodGl0bGUgPSBsaXN0KHRleHQgPSAiPGI+RXZvbHVjacOzbiBkZSBtw6l0cmljYXMgZGUgQXV0b3BhcnRlcyBlbiBNw6l4aWNvPC9iPiIpLA0KICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkHDsW8iKSwNCiAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJWYWxvciIpLA0KICAgICAgICAgbGVnZW5kID0gbGlzdCh4ID0gMC41LCB5ID0gMSkpDQpgYGANCg0KDQoNCiMjIyBDYXJ0b24NCiMjIyMgSW5kdXN0cmlhIE5vcnRlYW1lcmljYW5hDQpMYXMgc2lndWllbnRlcyBkb3MgZ3LDoWZpY2FzLCBtdWVzdHJhbiBxdWUgZWwgKipQYW5vcmFtYSBBY3R1YWwqKiBkZSBsYSBpbmR1c3RyaWEgZGVsIGNhcnTDs24gdGllbmUgY29tbyBjb21wZXRlbmNpYSBsYSBmYWJyaWNhY2nDs24gZGUgZmlicmEgeSBwYXBlbCBkb25kZSBlc3RlIMO6bHRpbW8gZXMgZWwgcHJpbWVybyBlbiBwZXJjaWJpciBtYXlvcmVzIGluZ3Jlc29zIGFudWFsZXMuIEEgcGVzYXIgZGUgZXN0byBzZSB2aXN1YWxpemEgcXVlOg0KDQoqIExhIGluZHVzdHJpYSBkZWwgY2FydMOzbiBlbiBFc3RhZG9zIFVuaWRvcyBoYSBleHBlcmltZW50YWRvIHVuIGNyZWNpbWllbnRvIGNvbnN0YW50ZSBlbiBsb3Mgw7psdGltb3MgYcOxb3MgcHVlc3RvIHF1ZSwgZW50cmUgMjAxMiB5IDIwMjIsIGxvcyBpbmdyZXNvcyBhbnVhbGVzIGRlIGxhIGluZHVzdHJpYSBhdW1lbnRhcm9uIGVuIHVuIDUwJS4NCg0KKiBFbCBjcmVjaW1pZW50byBzZSBoYSBkZXNhY2VsZXJhZG8gbGlnZXJhbWVudGUgZW4gbG9zIMO6bHRpbW9zIGHDsW9zLCBwZXJvIHNlIGVzcGVyYSBxdWUgY29udGluw7plIGVuIGVsIGZ1dHVyby4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmMyA8LSByZWFkX3hsc3goIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcQ2FydG9uX0FMRC54bHN4IikNCmRmMyA8LSBuYS5vbWl0KGRmMykNCmRmMyA8LSB1bmlxdWUoZGYzKQ0KDQpkZjMkQcOxbyA8LSBhcy5udW1lcmljKGRmMyRBw7FvKQ0KDQojUHJvbWVkaW8gZGUgaW5ncmVzb3MgcG9yIGHDsW8NCmdncGxvdChkZjMsIGFlcyh4ID0gQcOxbykpICsNCiAgZ2VvbV9iYXIoYWVzKHkgPSBwYXBlcl9taWxscywgZmlsbCA9ICJQYXBlciIpLCBzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSAiZG9kZ2UiKSArDQogIGdlb21fYmFyKGFlcyh5ID0gcHVscF9taWxscywgZmlsbCA9ICJQdWxwIiksIHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgZ2VvbV9iYXIoYWVzKHkgPSBwYXBlcmJvYXJkX21pbGxzLCBmaWxsID0gIlBhcGVyYm9hcmQiKSwgc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICBsYWJzKHRpdGxlID0gIkluZ3Jlc29zIGRlIGxhIGluZHVzdHJpYSBkZSBsYXMgZsOhYnJpY2FzIGRlIHB1bHBhLCBwYXBlbCB5IGNhcnTDs24gZW4gRUUuIFVVLiBkZSAyMDEyIGEgMjAyNCIsDQogICAgICAgeCA9ICJBw7FvIiwNCiAgICAgICB5ID0gIk1pbGVzIGRlIG1pbGxvbmVzIGRlIGTDs2xhcmVzIGVzdGFkb3VuaWRlbnNlcyIsDQogICAgICAgZmlsbCA9ICJUaXBvIikgKw0KICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCJQYXBlciIgPSAicmVkIiwgIlB1bHAiID0gImxpZ2h0Ymx1ZSIsICJQYXBlcmJvYXJkIiA9ICJncmVlbiIpKSArDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPSAxOCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE3KSkNCmBgYA0KDQoNCiMjIyMgSW5kdXN0cmlhIE1leGljYW5hDQoNCkVsIHZhbG9yIGNvbWVyY2lhbCB0b3RhbCBkZSBsYXMgaW1wb3J0YWNpb25lcyBkZSBwcm9kdWN0b3MgZGUgY2FydMOzbiBlbiBNw6l4aWNvIG9idHV2w7MgZWwgMmRvIHZhbG9yIG3DoXMgYWx0byBlbnRyZSBsb3MgcGHDrXNlcyBkZSBBbcOpcmljYSwgc3VwZXJhZG8gw7puaWNhbWVudGUgcG9yIEVzdGFkb3MgVW5pZG9zLiBFc3RvIHBlcm1pdGUgY29tcHJvYmFyIGxhIGRlbWFuZGEgZW4gZW1wcmVzYXMgY29uIHNlZGUgZW4gTcOpeGljbyBwb3Igc29sdWNpb25lcyBkZSBjYXJ0w7NuLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmY20gPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcSW1wb3J0ZXJzQm94ZXMyMDIwXzIwMjEuY3N2IikNCg0KIyBGaWx0cmFyIFBhw61zZXMgZGUgTm9ydGUgQW3DqXJpY2ENCmRmX25vcnRoX2FtZXJpY2EgPC0gc3Vic2V0KGRmY20sIENvbnRpbmVudCA9PSAiTm9ydGggQW1lcmljYSIpDQoNCiMgT2J0ZW5lciBlbCB0b3AgNSBkZSBwYcOtc2VzIGNvbiBtYXlvciB0cmFkZSB2YWx1ZQ0KdG9wNV90cmFkZXZhbHVlIDwtIGRmX25vcnRoX2FtZXJpY2EgJT4lDQogIGFycmFuZ2UoZGVzYyhUcmFkZS5WYWx1ZSkpICU+JQ0KICBoZWFkKDUpDQoNCiMgQ3JlYXIgZWwgZ3LDoWZpY28gZGUgYmFycmFzIGNvbXBhcmFuZG8gZWwgdmFsb3IgY29tZXJjaWFsIGVuIEFtw6lyaWNhIGRlbCBOb3J0ZSBwYXJhIGVsIHRvcCA1IGRlIHBhw61zZXMNCmdncGxvdCh0b3A1X3RyYWRldmFsdWUsIGFlcyh4ID0gcmVvcmRlcihDb3VudHJ5LCBUcmFkZS5WYWx1ZSksIHkgPSBUcmFkZS5WYWx1ZSwgZmlsbCA9IENvdW50cnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb21tYShUcmFkZS5WYWx1ZSkpLCB2anVzdCA9IC0wLjUsIHNpemUgPSA4LCBjb2xvciA9ICJibGFjayIpICsNCiAgbGFicyh0aXRsZSA9ICJUb3AgNSBkZSBwYcOtc2VzIGVuIHZhbG9yIGNvbWVyY2lhbCBkZSBjYWphcyBlbiBBbcOpcmljYSBkZWwgTm9ydGUgZW4gMjAyMSIsDQogICAgICAgeCA9ICJQYcOtcyIsDQogICAgICAgeSA9ICJWYWxvciBDb21lcmNpYWwiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKyAgIyBGb3JtYXRlYXIgbG9zIG7Dum1lcm9zIGVuIGVsIGVqZSB5DQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCkVsIGNyZWNpbWllbnRvIGFudWFsIGVudHJlIDIwMjAgeSAyMDIxIGVuIGVsIHZhbG9yIGNvbWVyY2lhbCBkZWwgY2FydMOzbiBlbiBNw6l4aWNvIHNlIGRlc3RhY8OzIGNvbiBlbCB0ZXJjZXIgdmFsb3IgbcOhcyBhbHRvIGVudHJlIGxvcyBwYcOtc2VzIGVuIEFtw6lyaWNhLiBFc3RlIGRhdG8sIGp1bnRvIGNvbiBsbyBtZW5jaW9uYWRvIGFudGVyaW9ybWVudGUsIHN1Z2llcmUgdW4gYXVtZW50byBwb3NpdGl2byBlbiBsYSBkZW1hbmRhIGRlIGVzdGFzIHNvbHVjaW9uZXMsIGxvIHF1ZSByZW1hcmNhIGxhIHJlbGV2YW5jaWEgZGUgbGFzIG9wZXJhY2lvbmVzIGRlIEZvcm0uIFNpbiBlbWJhcmdvLCBlcyBpbXBvcnRhbnRlIHRlbmVyIGVuIGN1ZW50YSBxdWUgZW4gYW1ib3MgY2Fzb3MgKHZhbG9yIHRvdGFsIHkgY3JlY2ltaWVudG8pLCBNw6l4aWNvIGVzIHN1cGVyYWRvIHBvciBFc3RhZG9zIFVuaWRvcywgbG8gY3VhbCBlcyBjb21wcmVuc2libGUgZGFkYSBsYSBwb3RlbmNpYSBjb21lcmNpYWwgcXVlIHJlcHJlc2VudGEgRXN0YWRvcyBVbmlkb3MuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBPYnRlbmVyIGVsIHRvcCA1IGRlIHBhw61zZXMgY29uIG1heW9yIGNyZWNpbWllbnRvIGVuIHZhbG9yDQp0b3A1X3RyYWRlZ3Jvd3RoIDwtIGRmX25vcnRoX2FtZXJpY2EgJT4lDQogIGFycmFuZ2UoZGVzYyhUcmFkZS5WYWx1ZS5Hcm93dGguVmFsdWUpKSAlPiUNCiAgaGVhZCg1KQ0KDQojIENyZWFyIGVsIGdyw6FmaWNvIGRlIGJhcnJhcyBjb21wYXJhbmRvIGVsIHZhbG9yIGRlbCBjcmVjaW1pZW50byBkZWwgdmFsb3IgY29tZXJjaWFsIGVuIEFtw6lyaWNhIGRlbCBOb3J0ZSBwYXJhIGVsIHRvcCA1IGRlIHBhw61zZXMNCmdncGxvdCh0b3A1X3RyYWRlZ3Jvd3RoLCBhZXMoeCA9IHJlb3JkZXIoQ291bnRyeSwgVHJhZGUuVmFsdWUuR3Jvd3RoLlZhbHVlKSwgeSA9IFRyYWRlLlZhbHVlLkdyb3d0aC5WYWx1ZSwgZmlsbCA9IENvdW50cnkpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBjb21tYShUcmFkZS5WYWx1ZS5Hcm93dGguVmFsdWUpKSwgdmp1c3QgPSAtMC41LCBzaXplID0gOCwgY29sb3IgPSAiYmxhY2siKSArDQogIGxhYnModGl0bGUgPSAiVG9wIDUgZGUgUGHDrXNlcyBjb24gTWF5b3IgQ3JlY2ltaWVudG8gZGUgVmFsb3IgQ29tZXJjaWFsIGRlIENhamFzIGVuIEFtw6lyaWNhIGRlbCBOb3J0ZSBlbiAyMDIxIiwNCiAgICAgICB4ID0gIlBhw61zIiwNCiAgICAgICB5ID0gIkNyZWNpbWllbnRvIGRlbCBWYWxvciBDb21lcmNpYWwiKSArDQogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKyAgIyBGb3JtYXRlYXIgbG9zIG7Dum1lcm9zIGVuIGVsIGVqZSB5DQogIHRoZW1lX21pbmltYWwoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE4KSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCg0KIyMgRk9EQSBDcnV6YWRvDQohW10oQzovVXNlcnMvQVZSSUwvRG9jdW1lbnRzL0ZPREFfRk9STS5wbmcpDQoNCiMjIFBFU1RMRQ0KIyMjIFBvbMOtdGljbw0KKiAqKkFjdWVyZG9zIGNvbWVyY2lhbGVzKio6IExvcyB0cmF0YWRvcyBjb21lcmNpYWxlcyBlbnRyZSBNw6l4aWNvIHkgRUUuVVUuLCBjb21vIGVsIFQtTUVDLCBpbmZsdXllbiBkaXJlY3RhbWVudGUgZW4gbGFzIG9wZXJhY2lvbmVzIGRlIG5lYXJzaG9yaW5nLCBmYWNpbGl0YW5kbyBvIGRpZmljdWx0YW5kbyBlbCBjb21lcmNpby4NCg0KKiAqKlJlZ3VsYWNpb25lcyBkZSBpbXBvcnRhY2nDs24vZXhwb3J0YWNpw7NuKio6IENhbWJpb3MgZW4gbGFzIHBvbMOtdGljYXMgcHVlZGVuIGFmZWN0YXIgbGEgZWZpY2llbmNpYSB5IGNvc3RvcyBkZSBsYXMgb3BlcmFjaW9uZXMgdHJhbnNmcm9udGVyaXphcy4NCg0KIyMjIEVjb27Ds21pY28NCiogKipOZWFyc2hvcmluZyB5IHJlbG9jYWxpemFjacOzbioqOiBFbCBhdW1lbnRvIGRlIGVtcHJlc2FzIHJlbG9jYWxpemFuZG8gc3UgcHJvZHVjY2nDs24gY2VyY2EgZGUgRUUuVVUuIHBhcmEgcmVkdWNpciBjb3N0b3MgeSB0aWVtcG9zIGRlIGVudsOtbyBwdWVkZSBzZXIgdW5hIG9wb3J0dW5pZGFkIHBhcmEgRk9STS4NCg0KKiAqKlRpcG8gZGUgY2FtYmlvKio6IEZsdWN0dWFjaW9uZXMgZW50cmUgZWwgcGVzbyBtZXhpY2FubyB5IGVsIGTDs2xhciBlc3RhZG91bmlkZW5zZSBwdWVkZW4gaW1wYWN0YXIgbG9zIGNvc3RvcyB5IHByZWNpb3MgZGUgbG9zIHByb2R1Y3Rvcy4NCg0KIyMjIFNvY2lhbA0KKiAqKlNvc3RlbmliaWxpZGFkIHkgY29uY2llbmNpYSBhbWJpZW50YWwqKjogVW5hIGNyZWNpZW50ZSBwcmVvY3VwYWNpw7NuIHBvciBlbCBtZWRpbyBhbWJpZW50ZSBwb2Ryw61hIGltcHVsc2FyIGxhIGRlbWFuZGEgZGUgZW1wYXF1ZXMgc29zdGVuaWJsZXMuDQoNCiogKipQcmVmZXJlbmNpYXMgZGVsIGNvbnN1bWlkb3IqKjogVGVuZGVuY2lhcyBoYWNpYSBwcm9kdWN0b3MgbG9jYWxlcyB5IGRlIG1lbm9yIGltcGFjdG8gYW1iaWVudGFsIHB1ZWRlbiBhZmVjdGFyIGxhcyBkZWNpc2lvbmVzIGRlIGNvbXByYS4NCg0KIyMjIFRlY25vbMOzZ2ljbw0KKiAqKklubm92YWNpb25lcyBlbiBtYXRlcmlhbGVzIHkgcHJvY2Vzb3MgZGUgZW1wYXF1ZSoqOiBBdmFuY2VzIHRlY25vbMOzZ2ljb3MgcXVlIHBlcm1pdGFuIG1lam9yYXIgbGEgZWZpY2llbmNpYSwgcmVkdWNpciBjb3N0b3MgbyBpbmNyZW1lbnRhciBsYSBzb3N0ZW5pYmlsaWRhZCBwdWVkZW4gc2VyIGNsYXZlLg0KDQoqICoqRGlnaXRhbGl6YWNpw7NuIHkgYXV0b21hdGl6YWNpw7NuKio6IExhIGludGVncmFjacOzbiBkZSB0ZWNub2xvZ8OtYXMgZGlnaXRhbGVzIGVuIGxhIGNhZGVuYSBkZSBzdW1pbmlzdHJvIHB1ZWRlIG1lam9yYXIgbGEgZWZpY2llbmNpYSBvcGVyYXRpdmEuDQoNCiMjIyBMZWdhbA0KKiAqKk5vcm1hdGl2YXMgYW1iaWVudGFsZXMqKjogTGVnaXNsYWNpb25lcyBtw6FzIGVzdHJpY3RhcyBzb2JyZSBtYXRlcmlhbGVzIGRlIGVtcGFxdWUgeSByZWNpY2xhamUgcHVlZGVuIHJlcXVlcmlyIGFkYXB0YWNpb25lcyBlbiBsb3MgcHJvY2Vzb3MgZGUgcHJvZHVjY2nDs24uDQoNCiogKipSZWd1bGFjaW9uZXMgbGFib3JhbGVzKio6IENhbWJpb3MgZW4gbGFzIGxleWVzIGxhYm9yYWxlcyB0YW50byBlbiBNw6l4aWNvIGNvbW8gZW4gRUUuVVUuIHB1ZWRlbiBpbmZsdWlyIGVuIGxvcyBjb3N0b3MgeSBvcGVyYWNpb25lcy4NCg0KIyMjIEVjb2zDs2dpY28NCiogKipHZXN0acOzbiBkZSByZXNpZHVvcyB5IHJlY2ljbGFqZSoqOiBMYSBwcmVzacOzbiBwYXJhIG1lam9yYXIgbGEgc29zdGVuaWJpbGlkYWQgZGUgbG9zIGVtcGFxdWVzIHB1ZWRlIGxsZXZhciBhIGJ1c2NhciBtYXRlcmlhbGVzIG3DoXMgZWNvbMOzZ2ljb3MuDQoNCiogKipIdWVsbGEgZGUgY2FyYm9ubyoqOiBMYSBuZWNlc2lkYWQgZGUgcmVkdWNpciBsYXMgZW1pc2lvbmVzIGRlIENPMiBwb2Ryw61hIGluZmx1aXIgZW4gbGFzIGRlY2lzaW9uZXMgZGUgbG9nw61zdGljYSB5IHByb2R1Y2Npw7NuLg0KDQojIyMgRXN0cmF0ZWdpYXMgYSBzZWd1aXIgZW4gZWwgY29ydG8gcGxhem8NCiogSW5ub3ZhY2nDs24gZW4gZW1wYXF1ZXMgc29zdGVuaWJsZXM6IERlc2Fycm9sbGFyIHkgcHJvbW9jaW9uYXIgc29sdWNpb25lcyBkZSBlbXBhcXVlIHF1ZSBzZWFuIHRhbnRvIGZ1bmNpb25hbGVzIGNvbW8gYW1iaWVudGFsbWVudGUgcmVzcG9uc2FibGVzLCBhbnRpY2lww6FuZG9zZSBhIGxhcyB0ZW5kZW5jaWFzIGRlbCBtZXJjYWRvIHkgcmVndWxhY2lvbmVzLiBFc3RvIHB1ZWRlIGluY2x1aXIgbGEgaW52ZXN0aWdhY2nDs24gZW4gbWF0ZXJpYWxlcyBiaW9kZWdyYWRhYmxlcyBvIHJlY2ljbGFibGVzLCB5IHByb2Nlc29zIGRlIHByb2R1Y2Npw7NuIG3DoXMgZWZpY2llbnRlcy4NCg0KKiBEaWdpdGFsaXphY2nDs24geSBtZWpvcmEgZGUgbGEgZWZpY2llbmNpYSBvcGVyYXRpdmE6IEludmVydGlyIGVuIHRlY25vbG9nw61hIHBhcmEgbGEgYXV0b21hdGl6YWNpw7NuIGRlIHByb2Nlc29zIHkgbGEgZGlnaXRhbGl6YWNpw7NuIGRlIGxhIGNhZGVuYSBkZSBzdW1pbmlzdHJvLiBFc3RvIG5vIHNvbG8gcHVlZGUgbWVqb3JhciBsYSBlZmljaWVuY2lhIG9wZXJhdGl2YSwgc2lubyB0YW1iacOpbiBvZnJlY2VyIG1lam9yIHRyYW5zcGFyZW5jaWEgeSB0cmF6YWJpbGlkYWQsIGFzcGVjdG9zIGNhZGEgdmV6IG3DoXMgdmFsb3JhZG9zIHBvciBsb3MgY2xpZW50ZXMuDQoNCiogRXhwYW5zacOzbiBkZSBtZXJjYWRvIHkgZGl2ZXJzaWZpY2FjacOzbjogQXVucXVlIGxhIGVtcHJlc2EgdGllbmUgdW5hIHByZXNlbmNpYSBmdWVydGUgZW4gU2FuIEFudG9uaW8sIGV4cGxvcmFyIG51ZXZvcyBtZXJjYWRvcyBlbiBFRS5VVS4geSBvdHJvcyBwYcOtc2VzIHBvZHLDrWEgc2VyIGVzdHJhdMOpZ2ljby4gRGl2ZXJzaWZpY2FyIGxhIGNhcnRlcmEgZGUgcHJvZHVjdG9zIHBhcmEgYXRlbmRlciBhIG90cmFzIGluZHVzdHJpYXMgYWRlbcOhcyBkZSBsYSBhdXRvbW90cml6IHRhbWJpw6luIHB1ZWRlIGF5dWRhciBhIG1pdGlnYXIgcmllc2dvcyB5IGFwcm92ZWNoYXIgbnVldmFzIG9wb3J0dW5pZGFkZXMgZGUgbmVhcnNob3JpbmcuDQoNCg0KIyAqKkRlZmluaWNpw7NuIGRlIGxhIFNpdHVhY2nDs24gUHJvYmxlbWEqKg0KDQoqKlNpdHVhY2nDs24gUHJvYmxlbWEgMSoqOiBBY3R1YWxtZW50ZSBGT1JNIHRpZW5lIGNvbW8gcmV0byBsYSAqKmluY2VydGlkdW1icmUgZGUgbGEgZGVtYW5kYSBwYXJhIHN1IHByZWRpY2Npw7NuIHkgZWZpY2llbmNpYSBvcGVyYXRpYSoqLCBwdWVzdG8gcXVlIEZPUk0gdGllbmUgaW50ZXLDqXMgZW4gcHJldmVyIGxhIHByb2R1Y2Npw7NuIHBhcmEgYW50aWNpcGFyIGxhIGRlbWFuZGEgZGlhcmlhIGRlIHN1cyBwcm92ZWVkb3Jlcy4gRXN0byBwZXJtaXRpcsOhIHBsYW5pZmljYXIgY29uIHByZWNpc2nDs24geSBzYXRpc2ZhY2VyIGVmaWNpZW50ZW1lbnRlIGxvcyBwZWRpZG9zIGVuIHRpZW1wbyB5IGZvcm1hLiBDYWJlIGRlc3RhY2FyIHF1ZSBwYXJhIGRpY2hvIGFuw6FsaXNpcyB0YW1iacOpbiBzZSBidXNjYSBldmFsdWFyIGVsIGltcGFjdG8gZGVsIE5lYXJzaG9yaW5nIGVuIGVzdGEgc2l0dWFjacOzbiwgY29uIGVsIGZpbiBkZSBkZXRlcm1pbmFyIGPDs21vIGRpY2hvIGVmZWN0byBheXVkYSB5L28gYWZlY3RhIGEgbGEgZW1wcmVzYSBhIGFsY2FuemFyIHN1cyBvYmpldGl2b3MgeSwgcG9yIGVuZGUsIGdlbmVyYXIgZXN0cmF0ZWdpYXMgZWZlY3RpdmFzLg0KDQoNCioqU2l0dWFjacOzbiBQcm9ibGVtYSAyKio6IEFzaW1pc21vLCBGT1JNIHNlIGVuZnJlbnRhIGEgKipsYSBhbHRhIHJvdGFjacOzbiBkZSBlbXBsZWFkb3MqKiwgcXVlIGFmZWN0YSBhIGxhIGVtcHJlc2EgZGUgbWFuZXJhIGdlbmVyYWxpemFkYS4gQSBwZXNhciBkZSBpbXBsZW1lbnRhciBkaXZlcnNhcyBtZWRpZGFzIHkgaGVycmFtaWVudGFzIGVuIMOhcmVhcyBjb21vIHByZXN0YWNpb25lcyB5IGNvbmRpY2lvbmVzIGxhYm9yYWxlcywgbG9zIGVtcGxlYWRvcyB0aWVuZGVuIGEgZGVqYXIgc3VzIHB1ZXN0b3MgcG9jbyBkZXNwdcOpcyBkZSBjb21lbnphciBzdSBjb250cmF0by4gQW50ZSBlc3RhIHNpdHVhY2nDs24sIGxhIGVtcHJlc2EgYnVzY2EgY29tcHJlbmRlciBlc3RlIGNvbXBvcnRhbWllbnRvIHkgZGVzYXJyb2xsYXIgZXN0cmF0ZWdpYXMgcGFyYSBtZWpvcmFyIGxhIHJldGVuY2nDs24gZGUgc3UgcGVyc29uYWwgY29uIGVsIGZpbiBkZSBldml0YXIgZWZlY3RvcyBhIG1lZGlhbm8geSBsYXJnbyBwbGF6byBjb21vIGVsIGF1bWVudG8gZGUgY29zdG9zLCBkZXRlcmlvcm8gZGUgY3VsdHVyYSBlbXByZXNhcmlhbCwgZXRjLg0KDQoNCiMgKipBbsOhbGlzaXMgRXhwbG9yYXRvcmlvIGRlIERhdG9zIChFREEpKioNCiMjIEZPUk0gUkggRkoyMDI0DQojIyMgTGltcGllemEgeSBvcmdhbml6YWNpw7NuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBMZWVyIHkgb2JzZXJ2YXIgZWwgYXJjaGl2bw0KcmhfYWx0IDwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcRGF0b3NfRk9STV9SSF9GSjIwMjQueGxzeCIpDQpzdHIocmhfYWx0KQ0KDQojIEFzaWduYXIgbm9tYnJlcyBkZSBjb2x1bW5hcw0KY29sbmFtZXMocmhfYWx0KTwtYygnZmVjaGFfbmFjaW1pZW50bycsJ2ZlY2hhX2FjdHVhbCcsJ2dlbmVybycsICdmZWNoYV9hbHRhJywncHVlc3RvJywnZGVwdG8nLCdzYWxhcmlvX2RpYXJpbycsJ21waW8nLCdlc3RhZG8nLCdlc3RhZG9fY2l2aWwnKQ0KDQojIFJlZW1wbGF6YXIgdmFsb3JlcyBlcnLDs25lb3MgZW4gbGEgYmFzZSBkZSBkYXRvcw0KcmhfYWx0JGVzdGFkb19jaXZpbFtyaF9hbHQkZXN0YWRvX2NpdmlsID09ICJTb2x0ZXJhIl0gPC0gIlNvbHRlcm8iDQpyaF9hbHQkZXN0YWRvX2NpdmlsW3JoX2FsdCRlc3RhZG9fY2l2aWwgPT0gIkNhc2FkYSJdIDwtICJDYXNhZG8iDQpyaF9hbHQkZXN0YWRvX2NpdmlsW3JoX2FsdCRlc3RhZG9fY2l2aWwgPT0gImNhc2FkbyJdIDwtICJDYXNhZG8iDQpyaF9hbHQkZXN0YWRvX2NpdmlsW3JoX2FsdCRlc3RhZG9fY2l2aWwgPT0gIkRpdm9yY2lhZGEiXSA8LSAiRGl2b3JjaWFkbyINCnJoX2FsdCRlc3RhZG9fY2l2aWxbcmhfYWx0JGVzdGFkb19jaXZpbCA9PSAiVml1ZGEiXSA8LSAiVml1ZG8iDQoNCnJoX2FsdCRwdWVzdG9bcmhfYWx0JHB1ZXN0byA9PSAiQXl1ZGFudGUgZGUgZW1iYXJxdWVzIl0gPC0gIkF5dWRhbnRlIGRlIEVtYmFycXVlcyINCnJoX2FsdCRwdWVzdG9bcmhfYWx0JHB1ZXN0byA9PSAiQXl1ZC4gRGUgRW1iYXJxdWVzIl0gPC0gIkF5dWRhbnRlIGRlIEVtYmFycXVlcyINCnJoX2FsdCRwdWVzdG9bcmhfYWx0JHB1ZXN0byA9PSAiQXV4aWxpYXIgZGUgRW1iYXJxdWVzIl0gPC0gIkF5dWRhbnRlIGRlIEVtYmFycXVlcyINCnJoX2FsdCRwdWVzdG9bcmhfYWx0JHB1ZXN0byA9PSAiQXl1ZGFudGUgZGUgc29sZGFkb3IiXSA8LSAiQXl1ZGFudGUgZGUgU29sZGFkb3IiDQpyaF9hbHQkcHVlc3RvW3JoX2FsdCRwdWVzdG8gPT0gIkF5dS4gRGUgU29sZGFkb3IiXSA8LSAiQXl1ZGFudGUgZGUgU29sZGFkb3IiDQpyaF9hbHQkcHVlc3RvW3JoX2FsdCRwdWVzdG8gPT0gIkF5LiBHZW5lcmFsIl0gPC0gIkF5dWRhbnRlIEdlbmVyYWwiDQpyaF9hbHQkcHVlc3RvW3JoX2FsdCRwdWVzdG8gPT0gIkF5dWRhbnRlIGdlbmVyYWwiXSA8LSAiQXl1ZGFudGUgR2VuZXJhbCINCnJoX2FsdCRwdWVzdG9bcmhfYWx0JHB1ZXN0byA9PSAiQXl1LiBEZSBQaW50b3IiXSA8LSAiQXl1ZGFudGUgZGUgUGludG9yIg0KcmhfYWx0JHB1ZXN0b1tyaF9hbHQkcHVlc3RvID09ICJBeXVkYW50ZSBEZSBQaW50b3IiXSA8LSAiQXl1ZGFudGUgZGUgUGludG9yIg0KcmhfYWx0JHB1ZXN0b1tyaF9hbHQkcHVlc3RvID09ICJBeXVkYW50ZSBnZW5lcmFsLUNlZGlzIl0gPC0gIkF5dWRhbnRlIGdlbmVyYWwgQ0VESVMiDQpyaF9hbHQkcHVlc3RvW3JoX2FsdCRwdWVzdG8gPT0gIkluc3BlY3RvcmEgZGUgQ2FsaWRhZCJdIDwtICJDYWxpZGFkIg0KcmhfYWx0JHB1ZXN0b1tyaF9hbHQkcHVlc3RvID09ICJJbnNwZWN0b3IgZGUgY2FsaWRhZCJdIDwtICJDYWxpZGFkIg0KcmhfYWx0JHB1ZXN0b1tyaF9hbHQkcHVlc3RvID09ICJJbnNwZWN0b3JhIERlIENhbGlkYWQiXSA8LSAiQ2FsaWRhZCINCnJoX2FsdCRwdWVzdG9bcmhfYWx0JHB1ZXN0byA9PSAiTWF0ZXJpYWxpc3RhIl0gPC0gIk1hdGVyaWFsZXMiDQpyaF9hbHQkcHVlc3RvW3JoX2FsdCRwdWVzdG8gPT0gIk9wZXJhZG9yIFNpZXJyYSJdIDwtICJPcGVyYWRvciBkZSBTaWVycmEiDQpyaF9hbHQkcHVlc3RvW3JoX2FsdCRwdWVzdG8gPT0gIk1hdGVyaWFsaXN0YSJdIDwtICJNYXRlcmlhbGVzIg0KcmhfYWx0JHB1ZXN0b1tyaF9hbHQkcHVlc3RvID09ICJDb3N0dXJlcmEiXSA8LSAiQ29zdHVyYSINCnJoX2FsdCRwdWVzdG9bcmhfYWx0JHB1ZXN0byA9PSAiQ29zdHVyZXJvIl0gPC0gIkNvc3R1cmEiDQoNCnJoX2FsdCRlc3RhZG9bcmhfYWx0JGVzdGFkbyA9PSAiTnVldm8gTGVvbiJdIDwtICJOdWV2byBMZcOzbiINCg0KcmhfYWx0JG1waW9bcmhfYWx0JG1waW8gPT0gIlJhbW96IEFyaXpwZSJdIDwtICJSYW1vcyBBcml6cGUiDQpyaF9hbHQkbXBpb1tyaF9hbHQkbXBpbyA9PSAiU2FuIE5pY29sYXMgRGUgTG9zIEciXSA8LSAiU2FuIE5pY29sYXMgZGUgbG9zIEdhcnphIg0KcmhfYWx0JG1waW9bcmhfYWx0JG1waW8gPT0gIlNhbiBOaWNvbGFzIl0gPC0gIlNhbiBOaWNvbGFzIGRlIGxvcyBHYXJ6YSINCg0KcmhfYWx0JGRlcHRvW3JoX2FsdCRkZXB0byA9PSAiQ2VkaXMiXSA8LSAiQ0VESVMiDQpyaF9hbHQkZGVwdG9bcmhfYWx0JGRlcHRvID09ICJFaHMiXSA8LSAiRUhTIg0KcmhfYWx0JGRlcHRvW3JoX2FsdCRkZXB0byA9PSAiUHJvZHVjY2lvbiBDYXJ0w7NuIE1DIl0gPC0gIlByb2R1Y2Npw7NuIENhcnTDs24gTUMiDQpyaF9hbHQkZGVwdG9bcmhfYWx0JGRlcHRvID09ICJQcm9kdWNjaW9uIENhcnTDs24gTWRsIl0gPC0gIlByb2R1Y2Npb24gQ2FydMOzbiBNREwiDQpyaF9hbHQkZGVwdG9bcmhfYWx0JGRlcHRvID09ICJQcm9kdWNjacOzbiBSZXRvcm4iXSA8LSAiUHJvZHVjY2lvbiBSZXRvcm5hYmxlIg0KcmhfYWx0JGRlcHRvW3JoX2FsdCRkZXB0byA9PSAiUGFpbGVyaWEiXSA8LSAiUGFpbGVyaWEgeSBQaW50dXJhIg0KcmhfYWx0IDwtIHJoX2FsdCAlPiUNCiAgbXV0YXRlKGRlcHRvID0gaWZlbHNlKGlzLm5hKGRlcHRvKSwgIsOBcmVhIE5vIERlZmluaWRhIiwgZGVwdG8pKQ0KDQojIENvbnZlcnRpciBmZWNoYXMgZW4gZm9ybWF0byBkZSBmZWNoYQ0KcmhfYWx0JGZlY2hhX25hY2ltaWVudG88LWFzLkRhdGUocmhfYWx0JGZlY2hhX25hY2ltaWVudG8sZm9ybWF0PSIlbS8lZC8lWSIpIA0KcmhfYWx0JGZlY2hhX2FjdHVhbDwtYXMuRGF0ZShyaF9hbHQkZmVjaGFfYWN0dWFsLGZvcm1hdD0iJW0vJWQvJVkiKSANCg0KIyBDcmVhciBjb2x1bW5hIGVkYWQNCmVkYWQ8LWFzLm51bWVyaWMoZGlmZnRpbWUocmhfYWx0JGZlY2hhX2FjdHVhbCwgcmhfYWx0JGZlY2hhX25hY2ltaWVudG8sIHVuaXRzID0gImRheXMiKSAvIDM2NSkNCnJoX2FsdCRlZGFkPC1lZGFkDQoNCiMgUmVlbXBsYXphciBvdXRsaWVycw0KbWVkaWFuYV9lZGFkIDwtIG1lZGlhbihyaF9hbHQkZWRhZCwgbmEucm0gPSBUUlVFKQ0KcmhfYWx0JGVkYWQgPC0gaWZlbHNlKHJoX2FsdCRlZGFkIDwgMTAsIG1lZGlhbmFfZWRhZCwgcmhfYWx0JGVkYWQpDQoNCiMgQ29udmVyc2nDs24gYSBmYWN0b3Jlcw0KcmhfYWx0JGdlbmVybzwtYXMuZmFjdG9yKHJoX2FsdCRnZW5lcm8pDQpyaF9hbHQkcHVlc3RvPC1hcy5mYWN0b3IocmhfYWx0JHB1ZXN0bykNCnJoX2FsdCRkZXB0bzwtYXMuZmFjdG9yKHJoX2FsdCRkZXB0bykNCnJoX2FsdCRtcGlvPC1hcy5mYWN0b3IocmhfYWx0JG1waW8pDQpyaF9hbHQkZXN0YWRvPC1hcy5mYWN0b3IocmhfYWx0JGVzdGFkbykNCnJoX2FsdCRlc3RhZG9fY2l2aWw8LWFzLmZhY3RvcihyaF9hbHQkZXN0YWRvX2NpdmlsKQ0KcmhfYWx0JHNhbGFyaW9fZGlhcmlvPC1hcy5udW1lcmljKHJoX2FsdCRzYWxhcmlvX2RpYXJpbykNCg0Kc3VtbWFyeShyaF9hbHQpDQpgYGANCg0KDQojIyMgQ2x1c3RlcnMNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIERhdGFzZXQgcGFyYSBrbWVhbnMNCnJoX2VkYWQ8LXJoX2FsdCAlPiUgDQogIGRwbHlyOjpzZWxlY3QoZ2VuZXJvLGVzdGFkb19jaXZpbCxzYWxhcmlvX2RpYXJpbyxlZGFkKQ0KDQpyaF9lZGFkX25vcm08LXNjYWxlKHJoX2VkYWRbMzo0XSkgIyBFc2NhbGFyIHZhcmlhYmxlcyBwYXJhIGV2aXRhciBzZXNnbw0KDQojIENhbGN1bGFyIGNhbnRpZGFkIGFkZWN1YWRhIGRlIGNsdXN0ZXJzIHV0aWxpemFuZG8gZWwgbcOpdG9kbyBkZSB3c3MNCnNldC5zZWVkKDEyMykNCndzcyA8LSBmdW5jdGlvbihrKSB7DQogIGttZWFucyhyaF9lZGFkX25vcm0sIGssIG5zdGFydCA9IDEwICkkdG90LndpdGhpbnNzDQp9DQprLnZhbHVlcyA8LSAxOjE1DQp3c3NfdmFsdWVzIDwtIG1hcF9kYmwoay52YWx1ZXMsIHdzcykNCnBsb3Qoay52YWx1ZXMsIHdzc192YWx1ZXMsDQogICAgIHR5cGU9ImIiLCBwY2ggPSAxOSwgZnJhbWUgPSBGQUxTRSwgDQogICAgIHhsYWI9Ik51bWJlciBvZiBjbHVzdGVycyBLIiwNCiAgICAgeWxhYj0iVG90YWwgd2l0aGluLWNsdXN0ZXJzIHN1bSBvZiBzcXVhcmVzIikNCg0KIyBDcmVhY2nDs24gZGUgY2x1c3RlcnMgbWVkaWFudGUga21lYW5zDQpzZXQuc2VlZCgxMjMpDQplZGFkX2NsdXN0ZXI8LWttZWFucyhyaF9lZGFkX25vcm0sMykNCg0KIyBHcsOhZmljYSBkZSBjbHVzdGVycyByZXN1bHRhbnRlcw0KZnZpel9jbHVzdGVyKGVkYWRfY2x1c3RlciwgZ2VvbSA9ICJwb2ludCIsIGRhdGEgPSByaF9lZGFkX25vcm0pICsgZ2d0aXRsZSgiQ2x1c3RlcnMgZGUgQmFqYXMgZW4gRm9ybSIpDQoNCiMgQcOxYWRpciBlbCBjbHVzdGVyIGFsIERhdGFmcmFtZQ0KcmhfY2x1c3RlcnMgPC0gcmhfYWx0ICU+JQ0KICBtdXRhdGUoQ2x1c3RlciA9IGVkYWRfY2x1c3RlciRjbHVzdGVyKSANCg0KIyBPYnNlcnZhciBjYXJhY3RlcsOtc3RpY2FzIGRlbCBjbHVzdGVyDQpyaF9jbHVzdGVycyAlPiUNCiAgbXV0YXRlKENsdXN0ZXIgPSBlZGFkX2NsdXN0ZXIkY2x1c3RlcikgJT4lDQogIGdyb3VwX2J5KENsdXN0ZXIpICU+JQ0KICBzdW1tYXJpc2UobWF4X2VkYWQgPSBtYXgoZWRhZCksIG1lYW5fc2FsYXJpb19kaWFyaW8gPSBtZWFuKHNhbGFyaW9fZGlhcmlvLCBuYS5ybSA9IFRSVUUpKQ0KDQojIENyZWFyIGV0aXF1ZXRhcyBkZSBsb3MgY2x1c3RlcnMNCnJoX2NsdXN0ZXJzIDwtIHJoX2NsdXN0ZXJzICU+JQ0KICBtdXRhdGUoQ2x1c3Rlcl9OYW1lID0gY2FzZV93aGVuKA0KICAgIENsdXN0ZXIgPT0gMSB+ICJBZHVsdG8iLA0KICAgIENsdXN0ZXIgPT0gMiB+ICJBZHVsdG8gTWF5b3IiLA0KICAgIENsdXN0ZXIgPT0gMyB+ICJKb3ZlbiIsDQogICAgVFJVRSB+IGFzLmZhY3RvcihDbHVzdGVyKQ0KICApKQ0KDQpgYGANCg0KIyMjIEdyw6FmaWNhcw0KDQpUcmFzIGhhYmVyIHJlYWxpemFkbyB1biBwcm9jZXNvIGRlIGNsdXN0ZXJpemFjacOzbiBwb3IgbWVkaW8gZGVsIGFsZ29yaXRtbyBkZSBLLW1lYW5zLCBzZSBhc2lnbmFyb24gYSBsYSBiYXNlIGRlIGRhdG9zIGRlIGJhamFzIGRlIHJoIHBhcmEgb2JzZXJ2YXIgbGEgY29tcG9zaWNpw7NuIGRlIGNhZGEgdW5vIGVuIGJhc2UgYSBkZXRlcm1pbmFkYXMgY2FyYWN0ZXLDrXN0aWNhcyBkZSBsb3MgZW1wbGVhZG9zIHF1ZSBhYmFuZG9uYW4uDQoNClNlIGRldGVybWluYSBxdWUgbGEgbWF5b3IgcGFydGUgZGUgbG9zIGVtcGxlYWRvcyBhZHVsdG9zIHF1ZSBhYmFuZG9uYXJvbiBzb24gam92ZW5lcyBzb2x0ZXJvcyBvIGVuIHVuacOzbiBsaWJyZSwgbG8gY3VhbCBzdXBvbmUgcXVlIHRpZW5lbiB1bmEgbWF5b3IgbGliZXJ0YWQgZSBpbmRlcGVuZGVuY2lhIHBhcmEgZXhwbG9yYXIgb3RyYXMgb3BvcnR1bmlkYWRlcyBsYWJvcmFsZXMgYWwgbm8gZXhpc3RpciB1biBjb21ycG9taXNvIGZvcm1hbCBvIGZhbWlsaWFyLiBBIGRpZmVyZW5jaWEgZGUgZXN0bywgc2UgcHVlZGUgb2JzZXJ2YXIgcXVlIGxvcyBhZHVsdG9zIG1heW9yZXMgcXVlIGFiYW5kb25hbiBzb24gZW4gc3UgbWF5b3LDrWEgY2FzYWRvcywgcHVkaWVuZG8gaW1wbGljYXIgcXVlIGVzdGEgY2FyYWN0ZXLDrXN0aWNhIG5vIGltcGFjdGEgZW4gc3UgZGVjaXNpw7NuLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZ2dwbG90KHJoX2NsdXN0ZXJzLCBhZXMoeCA9IGVzdGFkb19jaXZpbCwgZmlsbCA9IENsdXN0ZXJfTmFtZSkpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiLCBhbHBoYSA9IDAuNykgKw0KICBsYWJzKHRpdGxlID0gIkVzdGFkbyBDaXZpbCBwb3IgQ2x1c3RlciBkZSBCYWphcyBlbiBGb3JtIiwNCiAgICAgICB4ID0gIkVzdGFkbyBDaXZpbCIsDQogICAgICAgeSA9ICJDb3VudCIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPSAxOCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE3KSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpDQoNCmBgYA0KDQpTZSBwdWVkZSBvYnNlcnZhciBxdWUgbG9zIG1pZW1icm9zIGRlbCBjbMO6c3RlciBhZHVsdG8gc3VlbGVuIHRlbmVyIHVuIG1lbm9yIHNhbGFyaW8gcXVlIGxvcyBkZW3DoXMsIGxvIGN1YWwgcHVlZGUgdGVuZXIgdW5hIGluZmx1ZW5jaWEgZW4gc3UgcmF6w7NuIHBhcmEgYWJhbmRvbmFyLiBTaW4gZW1iYXJnbywgYWwgY29tcGFyYXIgbG9zIGNsdXN0ZXJzIGpvdmVuIHkgYWR1bHRvIG1heW9yLCBzZSBvYnNlcnZhIHRpZW5lbiBkaWZlcmVuY2lhcyBtw61uaW1hcyBlbiBzdSBzYWxhcmlvLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmdncGxvdChyaF9jbHVzdGVycywgYWVzKHggPSBlZGFkLCB5ID0gc2FsYXJpb19kaWFyaW8sIGNvbG9yID0gQ2x1c3Rlcl9OYW1lKSkgKw0KICBnZW9tX3BvaW50KCkgKw0KICBsYWJzKHRpdGxlID0gIlNhbGFyaW8gRGlhcmlvIHZzLiBFZGFkIHBvciBDbHVzdGVyIGRlIEJhamFzIGVuIEZvcm0iLA0KICAgICAgIHggPSAiRWRhZCIsDQogICAgICAgeSA9ICJTYWxhcmlvIERpYXJpbyIpICsNCiAgdGhlbWVfbWluaW1hbCgpKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9IDE4LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTcpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkNCmBgYA0KDQpUYW50byBlbCBjbHVzdGVyIGRlIGFkdWx0b3MgbWF5b3JlcyBjb21vIGVsIGRlIGrDs3ZlbmVzIHF1ZSBhYmFuZG9uYW4gZXN0w6FuIG1heW9ybWVudGUgY29tcHVlc3RvcyBwb3IgbXVqZXJlcywgbG8gY3VhbCBwdWVkZSBzdXBvbmVyIHVuIHByb2JsZW1hIGVuIGVsIGNsaW1hIG9yZ2FuaXphY2lvbmFsIHBlcmNpYmlkbyBwb3IgZXN0YXMsIGFzw60gY29tbyB1bmEgcG9zaWJsZSBmYWx0YSBkZSBvcG9ydHVuaWRhZGVzIGRlIGNyZWNpbWllbnRvIChwYXJ0aWN1bGFybWVudGUgZW4gZWwgY2x1c3RlciBqw7N2ZW4pLCBlbnRyZSBvdHJhcyBzaXR1YWNpb25lcy4gRXN0YSBzaXR1YWNpw7NuIHBhcmVjZSBubyBpbmZsdWlyIHNvYnJlIGVsIGNsdXN0ZXIgZGUgYWR1bHRvcywgZXN0YW5kbyBjb21wdWVzdG8gZGUgbWFuZXJhIGlndWFsIHBvciBhbWJvcyBnw6luZXJvcy4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEdyw6FmaWNvIGRlIEJhcnJhcyBBcGlsYWRhcyBkZSBHw6luZXJvIHBvciBDbHVzdGVyX05hbWUNCmdncGxvdChyaF9jbHVzdGVycywgYWVzKHggPSBDbHVzdGVyX05hbWUsIGZpbGwgPSBnZW5lcm8pKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgYWxwaGEgPSAwLjcpICsNCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIEfDqW5lcm8gcG9yIENsdXN0ZXIgZGUgQmFqYXMgZW4gRm9ybSIsDQogICAgICAgeCA9ICJDbHVzdGVyX05hbWUiLA0KICAgICAgIHkgPSAiQ291bnQiKSArDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxLCBzaXplPSAxOCwgZmFjZSA9ICJib2xkIiksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwLCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLA0KICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE2LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE3KSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSkpDQpgYGANCg0KDQpMYSBtYXlvciBwYXJ0ZSBkZSBsb3MgbWllbWJyb3MgZGUgY2FkYSBjbMO6c3RlciBwcm92aWVuZSBkZSBBcG9kYWNhLCBlc3RvIHB1ZXMgZXMgZWwgbXVuaWNpcGlvIGRvbmRlIGVzdMOhIHByZXNlbnRlIGxhIHBsYW50YSBkZSBGb3JtLCBhc2kgcXVlIGVzIG5lY2VzYXJpbyByZWNvbm9jZXIgcXVlIEFwb2RhY2EgY29udGllbmUgZWwgNzAlIGRlIHBhcnF1ZXMgaW5kdXN0cmlhbGVzIGRlbCBlc3RhZG8gZGUgTnVldm8gTGXDs24sIHBvciBsbyBjdWFsIGV4aXN0ZSB1bmEgdmFyaWVkYWQgZGUgcGxhbnRhcyBwcm9kdWN0aXZhcyBjZXJjYW5hcy4gRXN0byBvdG9yZ2EgbWF5b3IgbGliZXJ0YWQgYSBsb3MgZW1wbGVhZG9zIGEgcmVudW5jaWFyIHkgZXhwbG9yYXIgb3RyYXMgb3BvcnR1bmlkYWRlcyBzaW4gaW1wbGljYXIgdW4gaW1wYWN0byBzaWduaWZpY2F0aXZvIGVuIHN1IHJ1dGluYSBkaWFyaWEgcmVzcGVjdG8gYSBsb3MgdHJhc2xhZG9zLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBDcmVhciBlbCBncsOhZmljbyBkZSBiYXJyYXMgYXBpbGFkYXMgbXVuaWNpcGlvDQpnZ3Bsb3QocmhfY2x1c3RlcnMsIGFlcyh4ID0gQ2x1c3Rlcl9OYW1lLCBmaWxsID0gbXBpbykpICsNCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siLCBhbHBoYSA9IDAuNykgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgTXVuaWNpcGlvIHBvciBDbHVzdGVyIGRlIEJhamFzIGVuIEZvcm0iLA0KICAgICAgIHggPSAiQ2x1c3Rlcl9OYW1lIiwNCiAgICAgICB5ID0gIkNvdW50IikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9IDE4LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTcpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkNCg0KYGBgDQoNCkVsIGRlcGFydGFtZW50byBjb24gbWF5b3IgYWJhbmRvbm8gZW4gY2FkYSB1bm8gZGUgbG9zIGNsdXN0ZXJzIGNvcnJlc3BvbmRlIGFsIGRlIMOBcmVhIE5vIElkZW50aWZpY2FkIChjb21wdWVzdG8gbWF5b3JtZW50ZSBkZWwgcHVlc3RvIGRlIGF5dWRhbnRlIGdlbmVyYWwpLCBzZWd1aWRvcyBkZWwgZGUgUHJvZHVjY2nDs24gQ2FydMOzbiBNREwgeSBNQywgaW1wbGljYW5kbyB1bmEgcG9zaWJsZSBpbnNhdGlzZmFjY2nDs24gY29uIGxhcyB0YXJlYXMgcGFydGljdWxhcmVzIGRlbCBwdWVzdG8gZGUgYXl1ZGFudGUgZ2VuZXJhbCAocHJlZG9taW5hbnRlKSwgcHVkaWVuZG8gc2VyIHBvciBsYSBkZW1hbmRhIGRlIHRyYWJham8sIGxhIHJlcGV0aWNpw7NuIGNvbnRpbnVhIGRlIHRhcmVhcyBvIGVsIGNsaW1hIGxhYm9yYWwgcGFydGljdWxhciBkZSBlc3RlIHB1ZXN0by4gRGUgYWN1ZXJkbyBhIGxvIGNvbWVudGFkbyBwb3IgRmVsaXBlLCBubyBleGlzdGUgdW5hIGNhcGFjaXRhY2nDs24gaGFjaWEgZXN0b3Mgc2lubyBsYSBuZWNlc2lkYWQgZGUgYXByZW5kaXphamUgdmlzdWFsIHBvciBsb3MgbnVldm9zIGVtcGxlYWRvcyBoYWNpYSBsb3MgY29tcGHDsWVyb3MgeWEgZXhwZXJpbWVudGFkb3MuIEVzdG8gcHVlZGUgc3Vwb25lciBkaWZpY3VsdGFkZXMgcGFyYSBsYSBhZGFwdGFjacOzbiBhbCBwdWVzdG8sIGxvIHF1ZSBndWlhcsOtYSBhIHVuYSB0ZW1wcmFuYSByZWNlc2nDs24gcG9yIHBhcnRlIGRlIGVzdG9zLiANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpnZ3Bsb3QocmhfY2x1c3RlcnMsIGFlcyh4ID0gQ2x1c3Rlcl9OYW1lLCBmaWxsID0gZGVwdG8pKSArDQogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIiwgYWxwaGEgPSAwLjcpICsNCiAgZ2d0aXRsZSgiUHVlc3RvcyBkZSBDb2xhYm9yYWRvcmVzIHBvciBDbHVzdGVyIikgKw0KICB0aGVtZV9taW5pbWFsKCkgKw0KICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEsIHNpemU9IDE4LCBmYWNlID0gImJvbGQiKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjAsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAxNSksDQogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTYsIGZhY2UgPSAiYm9sZCIpLA0KICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTcpLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSkNCmBgYA0KDQoNCiMjIEZPUk0gRW5jdWVzdGEgQ2xpbWEgT3JnYW5pemFjaW9uYWwgT3Rvw7FvIDIwMjMgDQoNCiMjIyBMaW1waWV6YSB5IG9yZ2FuaXphY2nDs24NCg0KIyMjIyBEaXNlw7FhciB5IG9yZ2FuaXphciBiYXNlKHMpIGRlIGRhdG9zIGEgcGFydGlyIGRlIGxhIGluZm9ybWFjacOzbiB5IGRhdG9zIHNlbGVjY2lvbmFkb3MuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZjwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcRW5jdWVzdGFfRGF0b3NfRk9STV9GYWxsMjAyMy54bHN4IikNCg0KIyBOb21icmVzLCB0aXBvIHkgcmVnaXN0cm9zIGRlIGxhcyB2YXJpYWJsZXMNCnN0cihkZikNCg0KIyBFbGltaW5hciBjb2x1bW5hIElEICJFbmN1ZXN0YXMiDQpkZiRFbmN1ZXN0YSA8LSBOVUxMDQoNCiMgQWN0dWFsaXphciBub21icmUgZGUgY29sdW1uYXMgcGFyYSBxdWUgc2VhIG3DoXMgbWFuZWphYmxlICANCmNvbG5hbWVzKGRmKSA8LSBjKCJwdWVzdG9fZGVfdHJhYmFqbyIsICJwdWVzdG9fZGVfdHJhYmFqb19vdHJvIiwgIm1lc2VzX2FudGlnw7xlZGFkIiwgInJhem9uX3RyYWJhamFyX2Zvcm0iLCAiZXNjYWxhX3NhbGFyaW9fanVzdG8iLCAiZXNjYWxhX3BlcmNlcGNpb25fcHJlc3RhY2lvbmVzIiwgInBlcnBjZXBjaW9uX3Blc29fbmVnYXRpdm9fam9ybmFkYSIsICJwZXJjZXBjaW9uX2Rlc2Vycm9sbG9fcGVyc29uYWxfZm9ybSIsICJwZXJjZXBjaW9uX2NvbW9kaWRhZF9jbGltYV9hcmVhIiwgInBlcmNlcGNpb25fZXN0cmVzX2Jham8iLCAicGVyY2VwY2lvbl9mYWNpbGlkYWRfdHJhc2xhZG8iLCAicGVyY2VwY2lvbl9jb21vZGlkYWRfYXJlYV90cmFiYWpvIiwgInBlcmNlcGNpb25fcHJvYmFiaWxpZGFkX3NlZ3Vpcl9mb3JtIiwgInNpdHVhY2lvbmVzX2Fjb3NvIiwgIm9waW5pb25fbWFsb3NfYXNwZWN0b3MiLCAib3Bpbmlvbl90cmFiYWphcl9mb3JtcyIsICJlZGFkIiwgImfDqW5lcm8iLCAiZXN0YWRvX2NpdmlsIiwgIm11bmljaXBpbyIsICJuaXZlbF9lc2NvbGFyaWRhZCIsICJudW1fZGVwZW5kaWVudGVzX2Vjb27Ds21pY29zIikNCg0KICANCiMgRWxpbWluYXIgY29sdW1uYSAicHVlc3RvX3RyYWJham9fb3RybyINCmRmJHB1ZXN0b19kZV90cmFiYWpvX290cm8gPC0gTlVMTA0KDQojIENhbWJpYXIgdmFyaWFibGVzIGNhdGXDs3JpY2FzIGEgZmFjdG9yDQpkZiRwdWVzdG9fZGVfdHJhYmFqbyA8LSBhcy5mYWN0b3IoZGYkcHVlc3RvX2RlX3RyYWJham8pDQpkZiRyYXpvbl90cmFiYWphcl9mb3JtIDwtIGFzLmZhY3RvcihkZiRyYXpvbl90cmFiYWphcl9mb3JtKQ0KZGYkc2l0dWFjaW9uZXNfYWNvc28gPC0gYXMuZmFjdG9yKGRmJHNpdHVhY2lvbmVzX2Fjb3NvKQ0KZGZbLCAxNzoyMF0gPC0gbGFwcGx5KGRmWywgMTc6MjBdLCBhcy5mYWN0b3IpDQoNCg0KIyBDYW1iaWFyIGV0aXF1ZXRhIGVycm9uZWEgZW4gdmFyaWFibGUgcGVyY2VwY2lvbl9mYWNpbGlkYWRfdHJhc2xhZG8NCmRmJHBlcmNlcGNpb25fZmFjaWxpZGFkX3RyYXNsYWRvW2RmJHBlcmNlcGNpb25fZmFjaWxpZGFkX3RyYXNsYWRvID09ICJUb3RhbG1lbmRlIGVuIGRlc2FjdWVyZG8iXSA8LSAiVG90YWxtZW50ZSBlbiBkZXNhY3VlcmRvIg0KDQojIFRyYW5zZm9ybWFjacOzbiBkZSB2YXJpYWJsZXMgKDUgYSAxMykgZGUgZXNjYWxhIG9yZGluYWwgYSB2YWxvciBudW3DqXJpY28NCm5pdmVsZXMgPC0gYygiVG90YWxtZW50ZSBlbiBkZXNhY3VlcmRvIiwgIk1lZGlhbmFtZW50ZSBlbiBkZXNhY3VlcmRvIiwgDQogICAgICAgICAgICAgIk5pIGRlIGFjdWVyZG8gbmkgZW4gZGVzYWN1ZXJkbyIsICJNZWRpYW5hbWVudGUgZGUgYWN1ZXJkbyIsIA0KICAgICAgICAgICAgICJUb3RhbG1lbnRlIGRlIGFjdWVyZG8iKQ0KdmFsb3JlcyA8LSBjKDEsIDIsIDMsIDQsIDUpDQpkZlssIDQ6MTJdIDwtIGxhcHBseShkZlssIDQ6MTJdLCBmdW5jdGlvbih4KSB7DQogIG1hdGNoKHgsIG5pdmVsZXMpDQp9KQ0KDQojIENhbWJpYXIgZm9ybWF0byBpbmNvcnJlY3RvIGVuIGVkYWQNCmRmJGVkYWRbZGYkZWRhZCA9PSAiMzAgYcOxb3MiXSA8LSAiMzAiDQpkZiRlZGFkIDwtIGFzLm51bWVyaWMoZGYkZWRhZCkNCg0KIyBFeHRyYWVyIHZhcmlhYmxlcyBkZSB0ZXh0byBsaWJyZQ0KZGZfc2VudGltZW50IDwtIGRmWywxNDoxNV0NCg0KIyBFbGltaW5hciB2YXJpYWJsZXMgdGV4dG8gZGF0YWZyYW1lIG9yaWdpbmFsDQpkZiRvcGluaW9uX21hbG9zX2FzcGVjdG9zIDwtIE5VTEwNCmRmJG9waW5pb25fdHJhYmFqYXJfZm9ybXMgPC0gTlVMTA0KYGBgDQoNCiMjIyMgVmlzdWFsaXphciBlbiBSIGxvcyBwcmltZXJvcyA2IHJlbmdsb25lcyBkZSBsYSBudWV2YSBiYXNlIGRlIGRhdG9zLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmhlYWQoZGYpDQpgYGANCg0KIyMjIEdsb3NhcmlvIGRlIGxhcyB2YXJpYWJsZXMgZW4gbGEgYmFzZSBkZSBkYXRvczogDQoNCiogKnB1ZXN0b19kZV90cmFiYWpvKjogUHVlc3RvIGFjdHVhbCBlbiBlbCBxdWUgbGFib3JhIGVsIGVtcGxlYWRvLg0KDQoqICptZXNlc19hbnRpZ8O8ZWRhZCo6IE7Dum1lcm8gZGUgbWVzZXMgcXVlIGVsIGVtcGxlYWRvIGhhIGxhYm9yYWRvIGVuIGxhIGVtcHJlc2EuDQoNCiogKnJhem9uX3RyYWJhamFyX2Zvcm0qOiBNb3Rpdm8gcG9yIGVsIGN1YWwgbG9zIGVtcGxlYWRvcyBkZWNpZGllcm9uIHRyYWJhamFyIGVuIEZvcm0uDQoNCiogKmVzY2FsYV9zYWxhcmlvX2p1c3RvKjogRXNjYWxhIDEtNSAobWVub3IgYSBtYXlvcikgc29icmUgcXVlIHRhbiBqdXN0byBzZSBwZXJjaWJlIGVsIHNhbGFyaW8gcmVjaWJpZG8gcG9yIGVsIHRyYWJham8gcmVhbGl6YWRvLg0KDQoqICplc2NhbGFfcGVyY2VwY2lvbl9wcmVzdGFjaW9uZXMqOiBFc2NhbGEgMS01IChtZW5vciBhIG1heW9yKSBzb2JyZSBxdWUgdGFuIGFkZWN1YWRhcyBzZSBwZXJjaWJlbiBsYXMgcHJlc3RhY2lvbmVzIHJlY2liaWRhcy4NCg0KKiAqcGVycGNlcGNpb25fcGVzb19uZWdhdGl2b19qb3JuYWRhKjogRXNjYWxhIDEtNSAobWVub3IgYSBtYXlvcikgc29icmUgcXVlIHRhbiBhcmR1YSBzZSBzaWVudGUgbGEgam9ybmFkYSBsYWJvcmFsLg0KDQoqICpwZXJjZXBjaW9uX2Rlc2Vycm9sbG9fcGVyc29uYWxfZm9ybSo6IEVzY2FsYSAxLTUgKG1lbm9yIGEgbWF5b3IpIHNvYnJlIHF1ZSB0YW50YSBpbmZsdWVuY2lhIGRlIEZvcm0gc2UgcGVyY2liZSBlbiBlbCBkZXNhcnJvbGxvIGRlIGhhYmlsaWRhZGVzIHByb2Zlc2lvbmFsZXMuDQoNCiogKnBlcmNlcGNpb25fY29tb2RpZGFkX2NsaW1hX2FyZWEqOiBFc2NhbGEgMS01IChtZW5vciBhIG1heW9yKSBzb2JyZSBxdWUgdGFuIGFncmFkYWJsZSBzZSBwZXJjaWJlIGVsIGFtYmllbnRlIGRlIHRyYWJham8uDQoNCiogKnBlcmNlcGNpb25fZXN0cmVzX2Jham8qOiBFc2NhbGEgMS01IChtZW5vciBhIG1heW9yKSBzb2JyZSBxdWUgbGEgcGVyY2VwY2nDs24gZGUgcXVlIGVsIGVzdHLDqXMgbGFib3JhbCBlcyBiYWpvLg0KDQoqICpwZXJjZXBjaW9uX2ZhY2lsaWRhZF90cmFzbGFkbyo6IEVzY2FsYSAxLTUgKG1lbm9yIGEgbWF5b3IpIHNvYnJlIHF1ZSB0YW4gZsOhY2lsIHkgYWNjZXNpYmxlIGVzIGxsZWdhciBkZSBzdSBjYXNhIGEgbGEgcGxhbnRhIHkgdmljZXZlcnNhLg0KDQoqICpwZXJjZXBjaW9uX2NvbW9kaWRhZF9hcmVhX3RyYWJham8qOiBFc2NhbGEgMS01IChtZW5vciBhIG1heW9yKSBzb2JyZSBxdWUgdGFuIGFncmFkYWJsZSBzZSBwZXJjaWJlIGVsIGVzcGFjaW8gZW4gZWwgcXVlIHNlIHRyYWJhamEuDQoNCiogKnBlcmNlcGNpb25fcHJvYmFiaWxpZGFkX3NlZ3Vpcl9mb3JtKjogRXNjYWxhIDEtNSAobWVub3IgYSBtYXlvcikgc29icmUgbGEgY29uZmlhbnphIHF1ZSBzZSBzaWVudGUgZW4gY29udGludWFyIHRyYWJhamFuZG8gZW4gRm9ybSBlbiBlbCBsYXJnbyBwbGF6by4NCg0KKiAqc2l0dWFjaW9uZXNfYWNvc28qOiBTaSBzZSBoYSBleHBlcmltZW50YWRvIGFsIG1lbm9zIHVuYSBzaXR1YWNpw7NuIHF1ZSBoYXlhIGhlY2hvIHNlbnRpciBpbmPDs21vZGEgYSBsYSBwZXJzb25hLg0KDQoqICplZGFkKjogTsO6bWVybyBkZSBhw7FvcyBkZSBsYSBwZXJzb25hLg0KDQoqICpnw6luZXJvKjogR8OpbmVybyBkZSBsYSBwZXJzb25hLg0KDQoqICplc3RhZG9fY2l2aWwqOiBFc3RhZG8gY2l2aWwgZGUgbGEgcGVyc29uYS4NCg0KKiAqbXVuaWNpcGlvKjogTXVuaWNpcGlvIGRlIHJlc2lkZW5jaWEgZGUgbGEgcGVyc29uYS4NCg0KKiAqbml2ZWxfZXNjb2xhcmlkYWQqOiDDmmx0aW1vIGdyYWRvIGRlIGVzY29sYXJpZGFkIGN1cnNhZG8gcG9yIGxhIHBlcnNvbmEuDQoNCiogKm51bV9kZXBlbmRpZW50ZXNfZWNvbsOzbWljb3MqOiBFbCBuw7ptZXJvIGRlIHBlcnNvbmFzIHF1ZSBkZXBlbmRlbiBlY29uw7NtaWNhbWVudGUgZGUgbGEgcGVyc29uYS4NCg0KDQojIyMgRXN0YWTDrXN0aWNvcyBkZXNjcmlwdGl2b3MNCg0KSGFsbGF6Z29zIGFjb3JkZSBhIG1lZGlkYXMgZGVzY3JpcHRpdmFzIHkgZGUgZGlzdHJpYnVjacOzbjoNCg0KKiBQZXJjZXBjacOzbl9mYWNpbGlkYWRfdHJhc2xhZG86IEV4aXN0ZSB1biByYW5nbyBpbnRlcmN1YXJ0w61saWNvIHJlbGF0aXZhbWVudGUgYW1wbGlvLCBsbyBxdWUgaW5kaWNhIHF1ZSBhIGFsZ3Vub3MgZW1wbGVhZG9zIGxlcyByZXN1bHRhIG11eSBmw6FjaWwgdHJhc2xhZGFyc2UgKGVuIHRvcm5vIGEgNjApIG1pZW50cmFzIHF1ZSBhIG90cm9zIGxlcyByZXN1bHRhIGRpZsOtY2lsIChlbiB0b3JubyBhIDIwKS4NCg0KKiBQZXJjZXBjacOzbl9jb21vZGlkYWRfw6FyZWFfdHJhYmFqbzogTGEgbWVkaWFuYSBkZSBlbXBsZWFkb3MgcGVyY2liZSB1biBuaXZlbCBkZSBjb21vZGlkYWQgZW4gc3Ugw6FyZWEgZGUgdHJhYmFqbyBkZSBhbHJlZGVkb3IgZGUgMzAsIGNvbiBhbGd1bm9zIGVtcGxlYWRvcyBxdWUgZW5jdWVudHJhbiBzdSDDoXJlYSBkZSB0cmFiYWpvIG11eSBjw7Ntb2RhIChhbHJlZGVkb3IgZGUgNjApIHkgb3Ryb3MgcXVlIGxhIGVuY3VlbnRyYW4gaW5jw7Ntb2RhIChhbHJlZGVkb3IgZGUgMTApLg0KDQoqIFBlcmNlcGNpb25fZGVzYXJyb2xsb19wZXJzb25hbDogTGEgbWVkaWFuYSBkZSBsb3MgZW1wbGVhZG9zIHBlcmNpYmUgcG9jYXMgb3BvcnR1bmlkYWRlcyBkZSBkZXNhcnJvbGxvIHBlcnNvbmFsICgxMCBwZXJzb25hcykuIFNpbiBlbWJhcmdvLCBhbGd1bm9zIGVtcGxlYWRvcyB2ZW4gbXVjaGFzIG9wb3J0dW5pZGFkZXMgKGFscmVkZWRvciBkZSAzMCkgbWllbnRyYXMgcXVlIG90cm9zIHZlbiBtdXkgcG9jYXMgKGFscmVkZWRvciBkZSAwKS4gDQoNCiogTnVtX2RlcGVuZGllbnRlc19lY29uw7NtaWNvczogQWxndW5vcyBlbXBsZWFkb3MgdGllbmVuIG11Y2hhcyBwZXJzb25hcyBhIHN1IGNhcmdvIChjZXJjYSBkZSA1KSBtaWVudHJhcyBxdWUgb3Ryb3Mgbm8gdGllbmVuIG5pbmd1bmEgKGVuIHRvcm5vIGEgMCkuICANCg0KKiBNZXNlc19hbnRpZ8O8ZWRhZDogTGEgbWVkaWFuYSBlcyBkZSAzIG1lc2VzIGRlIGFudGlnw7xlZGFkLiBTaW4gZW1iYXJnbywgYWxndW5vcyBlbXBsZWFkb3Mgc29uIG11eSBudWV2b3MgKGFscmVkZWRvciBkZSAwIG1lc2VzKSBtaWVudHJhcyBxdWUgb3Ryb3MgbGxldmFuIG11Y2hvIHRpZW1wbyBlbiBsYSBlbXByZXNhIChhbHJlZGVkb3IgZGUgMjAgbWVzZXMpLiAgIA0KDQoqIEVzY2FsYV9zYWxhcmlvX2p1c3RvOiBMYSBtZWRpYW5hIGRlIGxvcyBlbXBsZWFkb3MgY3JlZSBxdWUgc3Ugc2FsYXJpbyBlcyBqdXN0byAoZW4gdG9ybm8gYSAzKS4gSGF5IHVuIHJhbmdvIGludGVyY3VhcnTDrWxpY28gcmVsYXRpdmFtZW50ZSBwZXF1ZcOxbywgbG8gcXVlIGltcGxpY2EgcXVlIGxhIG1heW9yw61hIGRlIGxvcyBlbXBsZWFkb3MgY3JlZW4gcXVlIHN1IHNhbGFyaW8gZXMgcmVsYXRpdmFtZW50ZSBqdXN0byAoZW50cmUgMiB5IDQpLiANCg0KKiBFc2NhbGFfcGVyY2VwY2lvbl9wcmVzdGFjaW9uZXM6IExhIG1lZGlhbmEgZGUgbG9zIGVtcGxlYWRvcyBwZXJjaWJlIGxhcyBwcmVzdGFjaW9uZXMgZGUgZm9ybWEgcG9zaXRpdmEgKGVuIHRvcm5vIGEgMykuIE5vIG9ic3RhbnRlLCBsYSBtYXlvcsOtYSBkZSBsb3MgZW1wbGVhZG9zIHRpZW5lbiB1bmEgcGVyY2VwY2nDs24gbmV1dHJhIGRlIGxhcyBwcmVzdGFjaW9uZXMgKGVudHJlIDIgeSA0KS4gIA0KDQoqIFBlcmNlcGNpb25fcGVzb19uZWdhdGl2b19qb3JuYWRhOiBMYSBtZWRpYW5hIGRlIGxvcyBlbXBsZWFkb3MgcGVyY2liZSB1biBwZXNvIG5lZ2F0aXZvIGRlIHN1IGpvcm5hZGEgbGFib3JhbCAoZW4gdG9ybm8gYSAyKS4gQXVucXVlLCBsYSBtYXlvcsOtYSBkZSBsb3MgZW1wbGVhZG9zIHRpZW5lbiB1bmEgcGVyY2VwY2nDs24gbmV1dHJhIGRlbCBwZXNvIGRlIGxhIGpvcm5hZGEgbGFib3JhbC4gICANCg0KKiBQZXJjZXBjacOzbl9jb21vZGlkYWRfY2xpbWFfw6FyZWE6IExhIG1lZGlhbmEgZGUgbG9zIGVtcGxlYWRvcyBwZXJjaWJlIHVuIG5pdmVsIGRlIGNvbW9kaWRhZCBuZXV0cm8gZW4gc3UgY2xpbWEgbGFib3JhbC4gU2luIGVtYmFyZ28sIGV4aXN0ZSB1biByYW5nbyBpbnRlcmN1YXJ0w61saWNvIGFtcGxpbywgbG8gcXVlIGltcGxpY2EgcXVlIGFsZ3Vub3MgZW1wbGVhZG9zIGVuY3VlbnRyYW4gZWwgY2xpbWEgY8OzbW9kbyAoZW4gdG9ybm8gYSA0KSBtaWVudHJhcyBxdWUgb3Ryb3MgbG8gZW5jdWVudHJhbiBpbmPDs21vZG8gKGVuIHRvcm5vIGEgMCkuICANCg0KKiBQZXJjZXBjaW9uX2VzdHJlc19iYWpvOiBMYSBtZWRpYW5hIGRlIGxvcyBlbXBsZWFkb3MgcGVyY2liZSB1biBuaXZlbCBtb2RlcmFkbyBkZSBlc3Ryw6lzIChlbiB0b3JubyBhIDIpOyBpbmNsdXNvIGxhIG1heW9yw61hIGRlIGxvcyBlbXBsZWFkb3MgdGllbmVuIHVuYSBwZXJjZXBjacOzbiBuZXV0cmEgZGVsIGVzdHLDqXMuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpzdW1tYXJ5KGRmKQ0KDQplZGFkIDwtIGdncGxvdChkYXRhID0gZGYsIGFlcyh4ID0gZWRhZCkpICsgDQogIGdlb21faGlzdG9ncmFtKCBjb2xvciA9ICJyZWQiLCBmaWxsID0gImJsdWUiLCBhbHBoYSA9IDAuMSkgKyANCiAgZ2VvbV9kZW5zaXR5KCkNCg0KcGVyY2VwY2lvbl9mYWNpbGlkYWRfdHJhc2xhZG8gPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSBwZXJjZXBjaW9uX2ZhY2lsaWRhZF90cmFzbGFkbykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oIGNvbG9yID0gInJlZCIsIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC4xKSArIA0KICBnZW9tX2RlbnNpdHkoKQ0KDQpwZXJjZXBjaW9uX2NvbW9kaWRhZF9hcmVhX3RyYWJham8gPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSBwZXJjZXBjaW9uX2NvbW9kaWRhZF9hcmVhX3RyYWJham8pKSArDQogIGdlb21faGlzdG9ncmFtKCBjb2xvciA9ICJyZWQiLCBmaWxsID0gImJsdWUiLCBhbHBoYSA9IDAuMSkgKyANCiAgZ2VvbV9kZW5zaXR5KCkNCg0KcGVyY2VwY2lvbl9kZXNlcnJvbGxvX3BlcnNvbmFsX2Zvcm0gPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSBwZXJjZXBjaW9uX2Rlc2Vycm9sbG9fcGVyc29uYWxfZm9ybSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oIGNvbG9yID0gInJlZCIsIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC4xKSArIA0KICBnZW9tX2RlbnNpdHkoKQ0KDQpudW1fZGVwZW5kaWVudGVzX2Vjb25vbWljb3MgPC0gZ2dwbG90KGRhdGEgPSBkZiwgYWVzKHggPSBudW1fZGVwZW5kaWVudGVzX2Vjb27Ds21pY29zKSkgKw0KICBnZW9tX2hpc3RvZ3JhbSggY29sb3IgPSAicmVkIiwgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjEpICsNCiAgZ2VvbV9kZW5zaXR5KCkNCg0KbWVzZXNfYW50aWd1ZWRhZCA8LSBnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IG1lc2VzX2FudGlnw7xlZGFkKSkgKw0KICBnZW9tX2hpc3RvZ3JhbSggY29sb3IgPSAicmVkIiwgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjEpICsgDQogIGdlb21fZGVuc2l0eSgpDQoNCmVzY2FsYV9zYWxhcmlvX2p1c3RvIDwtIGdncGxvdChkYXRhID0gZGYsIGFlcyh4ID0gZXNjYWxhX3NhbGFyaW9fanVzdG8pKSArDQogIGdlb21faGlzdG9ncmFtKCBjb2xvciA9ICJyZWQiLCBmaWxsID0gImJsdWUiLCBhbHBoYSA9IDAuMSkgK2dlb21fZGVuc2l0eSgpDQoNCmVzY2FsYV9wZXJjZXBjaW9uX3ByZXN0YWNpb25lcyA8LSBnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IGVzY2FsYV9wZXJjZXBjaW9uX3ByZXN0YWNpb25lcykpICsNCiAgZ2VvbV9oaXN0b2dyYW0oIGNvbG9yID0gInJlZCIsIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC4xKSArZ2VvbV9kZW5zaXR5KCkNCg0KcGVycGNlcGNpb25fcGVzb19uZWdhdGl2b19qb3JuYWRhIDwtIGdncGxvdChkYXRhID0gZGYsIGFlcyh4ID0gcGVycGNlcGNpb25fcGVzb19uZWdhdGl2b19qb3JuYWRhKSkgKw0KICBnZW9tX2hpc3RvZ3JhbSggY29sb3IgPSAicmVkIiwgZmlsbCA9ICJibHVlIiwgYWxwaGEgPSAwLjEpICtnZW9tX2RlbnNpdHkoKQ0KDQpwZXJjZXBjaW9uX2NvbW9kaWRhZF9jbGltYV9hcmVhIDwtIGdncGxvdChkYXRhID0gZGYsIGFlcyh4ID0gcGVyY2VwY2lvbl9jb21vZGlkYWRfY2xpbWFfYXJlYSkpICsNCiAgZ2VvbV9oaXN0b2dyYW0oIGNvbG9yID0gInJlZCIsIGZpbGwgPSAiYmx1ZSIsIGFscGhhID0gMC4xKSArZ2VvbV9kZW5zaXR5KCkNCg0KcGVyY2VwY2lvbl9lc3RyZXNfYmFqbyA8LSBnZ3Bsb3QoZGF0YSA9IGRmLCBhZXMoeCA9IHBlcmNlcGNpb25fZXN0cmVzX2Jham8pKSArDQogIGdlb21faGlzdG9ncmFtKCBjb2xvciA9ICJyZWQiLCBmaWxsID0gImJsdWUiLCBhbHBoYSA9IDAuMSkgK2dlb21fZGVuc2l0eSgpDQoNCmdnYXJyYW5nZSgNCiAgZWRhZCwgcGVyY2VwY2lvbl9mYWNpbGlkYWRfdHJhc2xhZG8sIHBlcmNlcGNpb25fY29tb2RpZGFkX2FyZWFfdHJhYmFqbywgcGVyY2VwY2lvbl9kZXNlcnJvbGxvX3BlcnNvbmFsX2Zvcm0sDQogIG51bV9kZXBlbmRpZW50ZXNfZWNvbm9taWNvcywgbWVzZXNfYW50aWd1ZWRhZCwgZXNjYWxhX3NhbGFyaW9fanVzdG8sDQogIGVzY2FsYV9wZXJjZXBjaW9uX3ByZXN0YWNpb25lcywgcGVycGNlcGNpb25fcGVzb19uZWdhdGl2b19qb3JuYWRhLA0KICBwZXJjZXBjaW9uX2NvbW9kaWRhZF9jbGltYV9hcmVhLCBwZXJjZXBjaW9uX2VzdHJlc19iYWpvLA0KICBuY29sID0gMywgbnJvdyA9IDQNCikNCmBgYA0KDQojIyMgTWVkaWRhcyBkZSBkaXNwZXJzacOzbg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmRmX251bWVyaWMgPC0gZGYgJT4lDQogIHNlbGVjdF9pZihpcy5udW1lcmljKQ0KDQpkaXNwZXJzaW9uX3NkIDwtIHNhcHBseShkZl9udW1lcmljLCBzZCkNCnByaW50KGRpc3BlcnNpb25fc2QpDQoNCiNSYW5nbyBkZSBjYWRhIGNvbHVtbmENCmRpc3BlcnNpb25fcmFuZ2UgPC0gc2FwcGx5KGRmX251bWVyaWMsIHJhbmdlKQ0KcHJpbnQoZGlzcGVyc2lvbl9yYW5nZSkNCg0KI1JhbmdvIGludGVyY3VhcnTDrWxpY28gZGUgY2FkYSBjb2x1bW5hDQpkaXNwZXJzaW9uX2lxciA8LSBzYXBwbHkoZGZfbnVtZXJpYywgSVFSKQ0KcHJpbnQoZGlzcGVyc2lvbl9pcXIpDQoNCm91dGxpZXJfcmF0aW8gPC0gZGlzcGVyc2lvbl9zZCAvIGRpc3BlcnNpb25faXFyDQoNCiMgQ29sdW1uYSBjb24gbGEgcHJvcG9yY2nDs24gbcOhcyBhbHRhDQptYXhfb3V0bGllcl9jb2x1bW4gPC0gbmFtZXMob3V0bGllcl9yYXRpbylbd2hpY2gubWF4KG91dGxpZXJfcmF0aW8pXQ0KDQpwcmludChvdXRsaWVyX3JhdGlvKQ0KcHJpbnQocGFzdGUoIkxhIHZhcmlhYmxlIGNvbiBtw6FzIG91dGxpZXJzIGVzOiIsIG1heF9vdXRsaWVyX2NvbHVtbikpDQoNCnBsb3RfYm94cGxvdChkZl9udW1lcmljLCBieT0icGVyY2VwY2lvbl9wcm9iYWJpbGlkYWRfc2VndWlyX2Zvcm0iKQ0KDQpgYGANCg0KDQojIyMgR3LDoWZpY29zIGRlIHBhdHJvbmVzDQoNCkhhbGxhemdvcyBhY29yZGUgYSBjb3JyZWxhY2lvbmVzOg0KDQoqIEVkYWQ6IExhIGVkYWQgcGFyZWNlIHNlciB1biBmYWN0b3IgaW1wb3J0YW50ZSBxdWUgYWZlY3RhIGxhIGNvbW9kaWRhZCB5IGVsIGVzdHLDqXMgZGUgbG9zIGVtcGxlYWRvcyBlbiBlbCB0cmFiYWpvOyBkb25kZSBhIG1heW9yIGVkYWQsIGxvcyBlbXBsZWFkb3MgZXhwZXJpbWVudGFuIG1lbm9yIGNvbW9kaWRhZCBlbiBlbCDDoXJlYSBkZSB0cmFiYWpvLCBtZW5vciBmYWNpbGlkYWQgZGUgdHJhc2xhZG8geSBtYXlvciBlc3Ryw6lzIGxhYm9yYWwuDQoNCiogQW50aWfDvGVkYWQ6IExhIGFudGlnw7xlZGFkIHNlIGFzb2NpYSBjb24gdW5hIG1heW9yIHNhdGlzZmFjY2nDs24gY29uIGVsIHNhbGFyaW8geSBsYXMgcHJlc3RhY2lvbmVzOyBwb3IgZW5kZSwgYSBtYXlvciBhbnRpZ8O8ZWRhZCBlbiBsYSBlbXByZXNhLCBsb3MgZW1wbGVhZG9zIHBlcmNpYmVuIHVuIHNhbGFyaW8gbcOhcyBqdXN0byB5IG1lam9yZXMgcHJlc3RhY2lvbmVzLiAgDQoNCiogQ2xpbWEgbGFib3JhbDogVW4gbWVqb3IgY2xpbWEgbGFib3JhbCBzZSByZWxhY2lvbmEgY29uIHVuYSBtYXlvciBjb21vZGlkYWQgZW4gZWwgw6FyZWEgZGUgdHJhYmFqbyB5IHVuYSBtYXlvciBmYWNpbGlkYWQgZGUgdHJhc2xhZG8uICANCiogRGVwZW5kaWVudGVzIGVjb27Ds21pY29zOiBUZW5lciBtw6FzIGRlcGVuZGllbnRlcyBlY29uw7NtaWNvcyBwdWVkZSBhZmVjdGFyIG5lZ2F0aXZhbWVudGUgbGEgcHJvYmFiaWxpZGFkIGRlIHF1ZSBsb3MgZW1wbGVhZG9zIGNvbnRpbsO6ZW4gZW4gbGEgZW1wcmVzYS4gIA0KDQoqIERlc2Fycm9sbG8gcGVyc29uYWw6IFVuYSBtYXlvciBwZXJjZXBjacOzbiBkZSBkZXNhcnJvbGxvIHBlcnNvbmFsIGVuIGxhIGVtcHJlc2EgcHVlZGUgYXVtZW50YXIgbGEgcHJvYmFiaWxpZGFkIGRlIHF1ZSBsb3MgZW1wbGVhZG9zIGNvbnRpbsO6ZW4gc2llbmRvIHBhcnRlIGRlIGxhIG9yZ2FuaXphY2nDs24uICANCg0KKiBQcmVzdGFjaW9uZXM6IFVuYSBtZWpvciBwZXJjZXBjacOzbiBkZSBsYXMgcHJlc3RhY2lvbmVzIHB1ZWRlIHJlZHVjaXIgbGEgcGVyY2VwY2nDs24gbmVnYXRpdmEgZGVsIGltcGFjdG8gZGUgbGEgam9ybmFkYSBsYWJvcmFsIGVuIGxhIHZpZGEgcGVyc29uYWwuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBHcsOhZmljbyBkZSBjb3JyZWxhY2nDs24NCnBsb3RfY29ycmVsYXRpb24oZGZfbnVtZXJpYykNCg0KIyBHcsOhZmljbyBkZSBkaXNwZXJzacOzbg0KcGxvdF9oaXN0b2dyYW0oZGYpDQoNCiNHcmFmaWNvIHNjYXR0ZXJwbG90DQpwbG90KGRmX251bWVyaWMpDQoNCiNHcmFmaWNvIG5vcm1hbGlkYWQNCnBsb3Rfbm9ybWFsaXR5KGRmKQ0KYGBgDQoNCg0KDQojIyMgVGV4dCBNaW5pbmcNCiMjIyMgQXNwZWN0b3MgTmVnYXRpdm9zIGRlIEZvcm0NCg0KQSB0cmF2w6lzIGRlIGxhIGV4cGxvcmFjacOzbiBkZSBsYSBjb2x1bW5hIGRlIHRleHRvIGxpYnJlIHNvYnJlIGFxdWVsbG9zIGFzcGVjdG9zIG1lbm9zIGF0cmFjdGl2b3MgZGUgRm9ybSwgc2UgcHVkbyBjb21wcm9iYXIgcXVlIGxvcyBhc3BlY3RvcyBxdWUgdGllbmVuIHVuIG1heW9yIGltcGFjdG8gbmVnYXRpdm8gc29icmUgbG9zIGVtcGxlYWRvcyBmdWVyb24gbGFzIGFsdGFzIHRlbXBlcmF0dXJhcywgbGFzIGNvbXBlbnNhY2lvbmVzIHJlY2liaWRhcyB0YW50byBlbiBzYWxhcmlvIGNvbW8gcHJlc3RhY2lvbmVzLCBhc8OtIGNvbW8gbGEgcGVyY2VwY2nDs24gZGUgbGFzIGFjdGl2aWRhZGVzIGxhYm9yYWxlcyAoaW5jbHV5ZW5kbyBlbCBzw6FiYWRvKSBxdWUgcmVzdWx0YSBlbiBlc3Ryw6lzLiBJZ3VhbG1lbnRlLCBlc3RvIMO6bHRpbW8gcHVlZGUgcmVmbGVqYXJzZSBlbiBlbCBhbsOhbGlzaXMgZGUgc2VudGltaWVudG9zLCByZWxhY2lvbmFuZG8gZXN0b3MgYXNwZWN0b3MgY29uIGxhIGFuc2llZGFkIChhbnRpY2lwYXRpb24pLCBjb21vIGxhIDNyYSBlbW9jacOzbiBwcmVkb21pbmFudGUuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0ZXh0b19uZWdhdGl2byA8LSBkZl9zZW50aW1lbnQkb3Bpbmlvbl9tYWxvc19hc3BlY3Rvcw0KDQojIENyZWFyIHVuIENvcnB1cyBjb24gbG9zIGNvbWVudGFyaW9zDQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0b19uZWdhdGl2bykpDQoNCiMgTGltcGlhciBlbCB0ZXh0bw0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpICAgICAgICMgQ29udmVydGlyIGEgbWluw7pzY3VsYXMNCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVQdW5jdHVhdGlvbikgICAgICAgICAgICAgICAgICAjIEVsaW1pbmFyIHB1bnR1YWNpw7NuDQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlTnVtYmVycykgICAgICAgICAgICAgICAgICAgICAgIyBFbGltaW5hciBuw7ptZXJvcw0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoInNwYW5pc2giKSkgICMgRWxpbWluYXIgc3RvcHdvcmRzIGVuIGVzcGHDsW9sDQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlV29yZHMsIGMoImJpZW4iLCAibmluZ3VubyIpKSAgICAgICAgICAgICAjIEVsaW1pbmFyIHBhbGFicmEgImJpZW4iDQoNCg0KIyBDcmVhciBsYSBtYXRyaXogdMOpcm1pbm8tZG9jdW1lbnRvDQp0ZG0gPC0gVGVybURvY3VtZW50TWF0cml4KGNvcnB1cykNCm0gPC0gYXMubWF0cml4KHRkbSkgICAgICAgI0N1ZW50YSBsYXMgdmVjZXMgcXVlIGFwYXJlY2UgY2FkYSBwYWxhYnJhIHBvciByZW5nbMOzbg0KDQoNCmZyZWN1ZW5jaWEgPC0gc29ydChyb3dTdW1zKG0pLCBkZWNyZWFzaW5nID0gVFJVRSkgI0N1ZW50YSBsYSBmcmVjdWVuY2lhIGRlIGNhZGEgcGFsYWJyYSBlbiBlbCB0ZXh0byBjb21wbGV0bw0KDQpmcmVjdWVuY2lhX2RmIDwtIGRhdGEuZnJhbWUod29yZD1uYW1lcyhmcmVjdWVuY2lhKSwgZnJlcT1mcmVjdWVuY2lhKSAjIENvbnZpZXJ0ZSBsYSBmcmVjdWVuY2lhIGVuIHVuIGRhdGEgZnJhbWUNCg0KIyBUb3AgMTAgUGFsYWJyYXMNCmdncGxvdChoZWFkKGZyZWN1ZW5jaWFfZGYsIDEwKSwgYWVzKHggPSByZW9yZGVyKHdvcmQsIC1mcmVxKSwgeSA9IGZyZXEpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gImxpZ2h0Ymx1ZSIpKw0KICBsYWJzKHg9ICJQYWxhYnJhIiwgeSA9ICJGcmVjdWVuY2lhIiwgdGl0bGUgPSAiVG9wIDEwIFBhbGFicmFzIE5lZ2F0aXZhcyBkZSBGb3JtIikrDQogIGdlb21fdGV4dChhZXMobGFiZWwgPSBmcmVxKSwgdmp1c3QgPSAtMC41KSArDQogIHlsaW0oMCwxMCkrDQogIHRoZW1lX21pbmltYWwoKSsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSwNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiLCBzaXplID0gMTgpLA0KICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSAyMCksDQogICAgICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTgpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpDQoNCiMgTnViZSBkZSBQYWxhYnJhcw0Kc2V0LnNlZWQoMTIzKQ0Kd29yZGNsb3VkKHdvcmRzPSBmcmVjdWVuY2lhX2RmJHdvcmQsIGZyZXE9ZnJlY3VlbmNpYV9kZiRmcmVxLCBtaW4uZnJlcSA9IDIsIHJhbmRvbS5vcmRlciA9IEZBTFNFLCBjb2xvcnMgPSBicmV3ZXIucGFsKDgsICJTcGVjdHJhbCIpKQ0KDQojIEFuw6FsaXNpcyBkZSBTZW50aW1pZW50b3MNCnRleHRvX3BhbGFicmFzIDwtIGdldF90b2tlbnMoY29ycHVzKQ0KZW1vY2lvbmVzX2RmIDwtIGdldF9ucmNfc2VudGltZW50KHRleHRvX3BhbGFicmFzLCBsYW5ndWFnZSA9ICJzcGFuaXNoIikNCmVtb2Npb25lc19wcm9wIDwtIGNvbFN1bXMocHJvcC50YWJsZShlbW9jaW9uZXNfZGZbMTo4XSkpDQplbW9jaW9uZXNfZGYgPC0gZGF0YS5mcmFtZShFbW9jaW9uID0gbmFtZXMoZW1vY2lvbmVzX3Byb3ApLCBQcm9wb3JjaW9uID0gZW1vY2lvbmVzX3Byb3ApDQpnZ3Bsb3QoZW1vY2lvbmVzX2RmLCBhZXMoeCA9IEVtb2Npb24sIHkgPSBQcm9wb3JjaW9uLCBmaWxsID0gRW1vY2lvbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsNCiAgbGFicyh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIGVtb2Npb25lcyBlbiBsb3MgY29tZW50YXJpb3MgbmVnYXRpdm9zIGRlIEZPUk0iLA0KICAgICAgIHggPSAiRW1vY2nDs24iLA0KICAgICAgIHkgPSAiUHJvcG9yY2nDs24iKSArDQogIHRoZW1lX21pbmltYWwoKSArICAjIEVzdGlsbyBtaW5pbWFsaXN0YQ0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIsIHNpemUgPSAxOCksDQogICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDIwKSwNCiAgICAgICAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxOCksDQogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikNCmBgYA0KDQoNCiMjIyMgT3BpbmnDs24gZGUgRm9ybQ0KDQpBbCBhbmFsaXphciBsYSBvcGluacOzbiBnZW5lcmFsIGRlIGxvcyBlbXBsZWFkb3MgZGUgRm9ybSwgc2Ugb2J0aWVuZW4gcmVzdWx0YWRvcyBwb3NpdGl2b3MsIGxvcyBjdWFsZXMgbWVuY2lvbmFuIHVuYSBwZXJjZXBjacOzbiBhZ3JhZGFibGUgeSBjw7Ntb2RhIHNvYnJlIGxhIGVtcHJlc2EsIGRlc3RhY2FuZG8gYXNwZWN0b3MgY29tbyBlbCBhbWJpZW50ZSBsYWJvcmFsIHkgbGEgb3BvcnR1bmlkYWQgZGUgY3JlY2ltaWVudG8uIEFzaW1pc21vLCBtZWRpYW50ZSBlbCBhbsOhbGlzaXMgZGUgc2VudGltaWVudG9zIHNlIG9ic2VydmEgcXVlIGVzdG9zIGNvbWVudGFyaW9zIGVzdMOhbiByZWxhY2lvbmFkb3MgZW4gc3UgbWF5b3LDrWEgY29uIGVtb2Npb25lcyBkZSBmZWxpY2lkYWQgeSBjb25maWFuemEuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0ZXh0b19wb3NpdGl2byA8LSBkZl9zZW50aW1lbnQkb3Bpbmlvbl90cmFiYWphcl9mb3Jtcw0KDQojIENyZWFyIHVuIENvcnB1cyBjb24gbG9zIGNvbWVudGFyaW9zDQpjb3JwdXMgPC0gQ29ycHVzKFZlY3RvclNvdXJjZSh0ZXh0b19wb3NpdGl2bykpDQoNCiMgTGltcGlhciBlbCB0ZXh0bw0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIGNvbnRlbnRfdHJhbnNmb3JtZXIodG9sb3dlcikpICAgICAgICAjIENvbnZlcnRpciBhIG1pbsO6c2N1bGFzDQpjb3JwdXMgPC0gdG1fbWFwKGNvcnB1cywgcmVtb3ZlUHVuY3R1YXRpb24pICAgICAgICAgICAgICAgICAgICMgRWxpbWluYXIgcHVudHVhY2nDs24NCmNvcnB1cyA8LSB0bV9tYXAoY29ycHVzLCByZW1vdmVOdW1iZXJzKSAgICAgICAgICAgICAgICAgICAgICAgIyBFbGltaW5hciBuw7ptZXJvcw0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBzdG9wd29yZHMoInNwYW5pc2giKSkgICAjIEVsaW1pbmFyIHN0b3B3b3JkcyBlbiBlc3Bhw7FvbA0KY29ycHVzIDwtIHRtX21hcChjb3JwdXMsIHJlbW92ZVdvcmRzLCBjKCJiaWVuIikpICAgICAgICAgICAgICAjIEVsaW1pbmFyIHBhbGFicmEgImJpZW4iDQoNCiMgQ3JlYXIgbGEgbWF0cml6IHTDqXJtaW5vLWRvY3VtZW50bw0KdGRtIDwtIFRlcm1Eb2N1bWVudE1hdHJpeChjb3JwdXMpIA0KbSA8LSBhcy5tYXRyaXgodGRtKSAjQ3VlbnRhIGxhcyB2ZWNlcyBxdWUgYXBhcmVjZSBjYWRhIHBhbGFicmEgcG9yIHJlbmdsw7NuDQoNCg0KZnJlY3VlbmNpYSA8LSBzb3J0KHJvd1N1bXMobSksIGRlY3JlYXNpbmcgPSBUUlVFKSANCmZyZWN1ZW5jaWFfZGYgPC0gZGF0YS5mcmFtZSh3b3JkPW5hbWVzKGZyZWN1ZW5jaWEpLCBmcmVxPWZyZWN1ZW5jaWEpDQoNCiMgR3LDoWZpY2EgVG9wIDEwIFBhbGFicmFzDQpnZ3Bsb3QoaGVhZChmcmVjdWVuY2lhX2RmLCAxMCksIGFlcyh4ID0gcmVvcmRlcih3b3JkLCAtZnJlcSksIHkgPSBmcmVxKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJsaWdodGJsdWUiKSsNCiAgbGFicyh4PSAiUGFsYWJyYSIsIHkgPSAiRnJlY3VlbmNpYSIsIHRpdGxlID0gIlRvcCAxMCBQYWxhYnJhcyBQb3NpdGl2YXMgZGUgRm9ybSIpKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsID0gZnJlcSksIHZqdXN0ID0gLTAuNSkgKw0KICB5bGltKDAsMTUpICsNCiAgdGhlbWVfbWluaW1hbCgpICsgICMgRXN0aWxvIG1pbmltYWxpc3RhDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE4KSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KDQojIE51YmUgZGUgUGFsYWJyYXMNCnNldC5zZWVkKDEyMykNCndvcmRjbG91ZCh3b3Jkcz0gZnJlY3VlbmNpYV9kZiR3b3JkLCBmcmVxPWZyZWN1ZW5jaWFfZGYkZnJlcSwgbWluLmZyZXEgPSAyLCByYW5kb20ub3JkZXIgPSBGQUxTRSwgY29sb3JzID0gYnJld2VyLnBhbCg4LCAiUFJHbiIpKQ0KDQojIEFuw6FsaXNpcyBkZSBTZW50aW1pZW50b3MNCnRleHRvX3BhbGFicmFzIDwtIGdldF90b2tlbnModGV4dG9fcG9zaXRpdm8pDQplbW9jaW9uZXNfZGYgPC0gZ2V0X25yY19zZW50aW1lbnQodGV4dG9fcGFsYWJyYXMsIGxhbmd1YWdlID0gInNwYW5pc2giKQ0KZW1vY2lvbmVzX3Byb3AgPC0gY29sU3Vtcyhwcm9wLnRhYmxlKGVtb2Npb25lc19kZlsxOjhdKSkNCmVtb2Npb25lc19kZiA8LSBkYXRhLmZyYW1lKEVtb2Npb24gPSBuYW1lcyhlbW9jaW9uZXNfcHJvcCksIFByb3BvcmNpb24gPSBlbW9jaW9uZXNfcHJvcCkNCmdncGxvdChlbW9jaW9uZXNfZGYsIGFlcyh4ID0gRW1vY2lvbiwgeSA9IFByb3BvcmNpb24sIGZpbGwgPSBFbW9jaW9uKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBsYWJzKHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgZW1vY2lvbmVzIGVuIGxvcyBjb21lbnRhcmlvcyBkZSBGT1JNIiwNCiAgICAgICB4ID0gIkVtb2Npw7NuIiwNCiAgICAgICB5ID0gIlByb3BvcmNpw7NuIikgICsNCiAgdGhlbWVfbWluaW1hbCgpICsgICMgRXN0aWxvIG1pbmltYWxpc3RhDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoZmFjZSA9ICJib2xkIiwgc2l6ZSA9IDE4KSwNCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gMjApLA0KICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE4KSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKQ0KYGBgDQoNCg0KDQojIyMgTW9kZWxvcyBkZSBQcmVkaWNjacOzbg0KU2UgZGV0ZXJtaW5hIHF1ZSBlcyBtw6FzIHByb2JhYmxlIHF1ZSBsb3MgZW1wbGVhZG9zIGRlIEZPUk0gcXVlIHNlYW4gbXVqZXJlcyB5IHRlbmdhbiB1bmEgcGVyY2VwY2nDs24gcG9zaXRpdmEgdGFudG8gZGUgc3Ugc2FsYXJpbyBjb21vIGRlIHN1cyBwcmVzdGFjaW9uZXMgdGllbmVuIGFsdGEgcHJvYmFiaWxpZGFkIGRlIHBlcm1hbmVjZXIgZW4gbGEgZW1wcmVzYS4gUG9yIGxvIHRhbnRvLCBlc3RhYmxlY2VyIGVzdHJhdGVnaWFzIGRlIHJldGVuY2nDs24gcGFyYSBlc3RlIHNlZ21lbnRvIGdlbmVyYXLDrWEgdW4gbWF5b3Igc2VudGlkbyBkZSBwZXJ0ZW5lbmNpYSBhIGxhIGNvbXBhw7HDrWEuIEFzaW1pc21vLCBzZSByZXF1aWVyZSBlc3RhYmxlY2VyIGFsdGVybmF0aXZhcyBkZSBhdHJhY2Npw7NuIHkgcmV0ZW5jacOzbiBlbmZvY2FkYXMgZW4gbWVqb3JhciBsYSBwZXJjZXBjacOzbiBkZWwgc2FsYXJpbyB5IHByZXN0YWNpb25lcyBxdWUgb2ZyZWNlIGxhIGVtcHJlc2EgY29tbyB1bmEgdmVudGFqYSBjb21wZXRpdGl2YSBlbiBjb21wYXJhY2nDs24gY29uIG90cmFzIGNvbXBhw7HDrWFzIGRlbCBzZWN0b3IsIGVzcGVjaWFsbWVudGUgZW4gbGEgdWJpY2FjacOzbiBkZSBBcG9kYWNhLiANCg0KDQojIyMjIFByZXBhcmFjacOzbiBkZSBkYXRvcyBwYXJhIG1vZGVsb3M6DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGZfbW9kZWxzIDwtIGRmICU+JSBtdXRhdGUocGVyY2VwY2lvbl9wcm9iYWJpbGlkYWRfc2VndWlyX2Zvcm0gPSBpZmVsc2UocGVyY2VwY2lvbl9wcm9iYWJpbGlkYWRfc2VndWlyX2Zvcm0gPCAzLCAibm8gc2VndWlyIiwgInNpIHNlZ3VpciIpKQ0KDQpmcmVjdWVuY2lhX3NlZ3VpcmZvcm0gPC0gdGFibGUoZGZfbW9kZWxzJHBlcmNlcGNpb25fcHJvYmFiaWxpZGFkX3NlZ3Vpcl9mb3JtKQ0KZnJlY3VlbmNpYV9zZWd1aXJmb3JtDQoNCnNldC5zZWVkKDEyMykNCmRmX21vZGVscyRwZXJjZXBjaW9uX3Byb2JhYmlsaWRhZF9zZWd1aXJfZm9ybSA8LSBhcy5mYWN0b3IoZGZfbW9kZWxzJHBlcmNlcGNpb25fcHJvYmFiaWxpZGFkX3NlZ3Vpcl9mb3JtKQ0Kc2FtcGxlIDwtIGNyZWF0ZURhdGFQYXJ0aXRpb24oeSA9IGRmX21vZGVscyRwZXJjZXBjaW9uX3Byb2JhYmlsaWRhZF9zZWd1aXJfZm9ybSwgcD0wLjcsIGxpc3Q9RikNCnRyYWluICA8LSBkZl9tb2RlbHNbc2FtcGxlLCBdDQp0ZXN0ICAgPC0gZGZfbW9kZWxzWy1zYW1wbGUsIF0NCmBgYA0KDQoNCg0KDQojIyMjIGEpIFJlZ3Jlc2lvbiBsb2dpc3RpY2ENCg0KRWwgcHJpbWVyIG1vZGVsbyBjb25zdHJ1aWRvIGNvcnJlc3BvbmRlIGEgbGEgcmVncmVzacOzbiBsb2fDrXN0aWNhLCBlbXBsZWFuZG8gdmFyaWFibGVzIGNvbW8gZWwgbsO6bWVybyBkZSBkZXBlbmRpZW50ZXMgZWNvbsOzbWljb3MsIGxhIGVkYWQsIGxhcyBkaXN0aW50YXMgcGVyY2VwY2lvbmVzIHNvYnJlIEZvcm0sIGxvcyBtZXNlcyBkZSBhbnRpZ8O8ZWRhZCB5IGVsIGfDqW5lcm8uDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0Kc2V0LnNlZWQoMTIzKQ0KZm9ybXVsYSA8LSBwZXJjZXBjaW9uX3Byb2JhYmlsaWRhZF9zZWd1aXJfZm9ybSB+IG51bV9kZXBlbmRpZW50ZXNfZWNvbsOzbWljb3MgKyBlZGFkICsgcGVyY2VwY2lvbl9jb21vZGlkYWRfYXJlYV90cmFiYWpvICsgcGVyY2VwY2lvbl9mYWNpbGlkYWRfdHJhc2xhZG8gKyBwZXJjZXBjaW9uX2VzdHJlc19iYWpvICsgcGVyY2VwY2lvbl9jb21vZGlkYWRfY2xpbWFfYXJlYSArIHBlcmNlcGNpb25fZGVzZXJyb2xsb19wZXJzb25hbF9mb3JtICsgcGVycGNlcGNpb25fcGVzb19uZWdhdGl2b19qb3JuYWRhICsgZXNjYWxhX3BlcmNlcGNpb25fcHJlc3RhY2lvbmVzICsgZXNjYWxhX3NhbGFyaW9fanVzdG8gKyBtZXNlc19hbnRpZ8O8ZWRhZCArIGfDqW5lcm8NCg0KbW9kZWxfZ2xtIDwtIGdsbShmb3JtdWxhLCBmYW1pbHkgPSAiYmlub21pYWwiLCBkYXRhID0gdHJhaW4pDQpzdW1tYXJ5KG1vZGVsX2dsbSkNCnZhckltcChtb2RlbF9nbG0pDQpgYGANCg0KDQpFbCBtb2RlbG8gZGVtdWVzdHJhIHRlbmVyIHVuIGRlc2VtcGXDsW8gaW5pY2lhbCBhZGVjdWFkbywgcHJlZGljaWVuZG8gYWNlcnRhZGFtZW50ZSBlbCA4My44NyUgZGUgbG9zIGNhc29zIGVuIHF1ZSB1biBlbXBsZWFkbyB0aWVuZSB1bmEgcGVyY2VwY2nDs24gZGUgY29udGludWFyIG8gbm8gZW4gbGEgZW1wcmVzYS4uIEVzdGUgcmVzdWx0YWRvIGVzIHJlbGV2YW50ZSBkZWJpZG8gYSBxdWUgdGllbmUgdW4ga2FwcGEgZGVsIC4zNTE1LCBlcyBkZWNpciwgbm8gZXMgdW5hIHByZWRpY2Npw7NuIGFsZWF0b3JpYS4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwcmVkaWNjaW9uX2dsbSA8LSBwcmVkaWN0KG1vZGVsX2dsbSwgdGVzdCwgdHlwZSA9ICJyZXNwb25zZSIpDQoNCmNvbmZ1c2lvbl9nbG0gPC0gY29uZnVzaW9uTWF0cml4KGFzLmZhY3RvcihpZmVsc2UocHJlZGljY2lvbl9nbG0+MC41LCAic2kgc2VndWlyIiwgIm5vIHNlZ3VpciIpKSwgdGVzdCRwZXJjZXBjaW9uX3Byb2JhYmlsaWRhZF9zZWd1aXJfZm9ybSwgcG9zaXRpdmUgPSAibm8gc2VndWlyIikNCnByaW50KGNvbmZ1c2lvbl9nbG0pDQpgYGANCg0KTWVkaWFudGUgbGEgY3VydmEgUk9DIHBhcmEgZWwgbW9kZWxvIGxvZ8Otc3RpY28sIHNlIHJlYWZpcm1hIGVsIHB1bnRvIGFudGVyaW9yLCBwdWVzIGFsIHJlc3VsdGFyIGVuIHVuIEFVQyBjb24gdmFsb3IgZGUgMC44Niwgc2UgZGV0ZXJtaW5hIHF1ZSBsYSBwcmVkaWNjacOzbiBkZWwgbW9kZWxvIGVzIG1lam9yIHF1ZSB1bmEgcHJlZGljY2nDs24gYWxlYXRvcmlhLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgIEN1cnZhIFJPQyB5IHZhbG9yIGRlIEFVQw0KIyMgT2J0ZW5lciBsYXMgcHVudHVhY2lvbmVzIGRlIHByb2JhYmlsaWRhZA0KcHJlZGljY2lvbl9wcm9iX2dsbSA8LSBwcmVkaWN0KG1vZGVsX2dsbSwgdGVzdCwgdHlwZSA9ICJyZXNwb25zZSIpDQoNCiMjIEdlbmVyYXIgbGEgY3VydmEgUk9DDQpyb2Nfb2JqX2dsbSA8LSByb2ModGVzdCRwZXJjZXBjaW9uX3Byb2JhYmlsaWRhZF9zZWd1aXJfZm9ybSwgYXMubnVtZXJpYyhwcmVkaWNjaW9uX3Byb2JfZ2xtKSkNCg0KIyMgRGlidWphciBsYSBjdXJ2YSBST0MNCnBsb3Qucm9jKHJvY19vYmpfZ2xtLCBtYWluID0gIkN1cnZhIFJPQyIsIGNvbCA9ICJibHVlIikNCg0KIyMgQ2FsY3VsYXIgZWwgQVVDDQphdWNfZ2xtIDwtIHBST0M6OmF1Yyhyb2Nfb2JqX2dsbSkNCmF1Y19nbG0NCg0KDQpgYGANCg0KDQoNCiMjIyMgYikgTmFpdmUgQmF5ZXMNCg0KRWwgbW9kZWxvIGRlIE5haXZlIEJheWVzIGRlbXVlc3RyYSBpZ3VhbG1lbnRlLCB0ZW5lciB1biBkZXNlbXBlw7FvIGluaWNpYWwgYWRlY3VhZG8sIHByZWRpY2llbmRvIGFjZXJ0YWRhbWVudGUgZWwgODAuNjUlIGRlIGxvcyBjYXNvcyBlbiBxdWUgdW4gZW1wbGVhZG8gdGllbmUgdW5hIHBlcmNlcGNpw7NuIGRlIGNvbnRpbnVhciBvIG5vIGVuIGxhIGVtcHJlc2EuIEVzdGUgcmVzdWx0YWRvIGVzIHJlbGV2YW50ZSBkZWJpZG8gYSBxdWUgdGllbmUgdW4ga2FwcGEgZGVsIDAuMjkwMSAobWF5b3IgYSAwKSwgZXMgZGVjaXIsIG5vIGVzIHVuYSBwcmVkaWNjacOzbiBhbGVhdG9yaWEuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQptb2RlbG9fbmIgPC0gbmFpdmVCYXllcyhmb3JtdWxhLCBkYXRhID0gdHJhaW4pDQoNCiMgTWF0cml6IGRlIENvbmZ1c2nDs24NCnByZWRpY2Npb25fbmIgPC0gcHJlZGljdChtb2RlbG9fbmIsIHRlc3QpDQpjb25mdXNpb25fbmIgPC0gY29uZnVzaW9uTWF0cml4KHByZWRpY2Npb25fbmIsIHRlc3QkcGVyY2VwY2lvbl9wcm9iYWJpbGlkYWRfc2VndWlyX2Zvcm0scG9zaXRpdmUgPSAibm8gc2VndWlyIikNCnByaW50KGNvbmZ1c2lvbl9uYikNCmBgYA0KDQpFbCBwdW50byBhbnRlcmlvciBzZSByZWFmaXJtYXIgbWVkaWFudGUgbGEgY3VydmEgUk9DIGRlbCBtb2RlbG8gYmF5ZXNpYW5vLCBvYnRlbmllbmRvIHVuIEFVQyBkZSAwLjc2IChtYXlvciBhIC41KSwgZGV0ZXJtaW5hbmRvIG51ZXZhbWVudGUgcXVlIGVsIG1vZGVsbyBlcyBtZWpvciBhIHVuYSBwcmVkaWNjacOzbiBhbGVhdG9yaWEuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KDQojICBDdXJ2YSBST0MgeSB2YWxvciBkZSBBVUMNCiMjIE9idGVuZXIgbGFzIHB1bnR1YWNpb25lcyBkZSBwcm9iYWJpbGlkYWQNCnByZWRpY2Npb25fcHJvYl9uYiA8LSBwcmVkaWN0KG1vZGVsb19uYiwgdGVzdCwgdHlwZSA9ICJyYXciKQ0KDQojIyBTaSBlbCByZXN1bHRhZG8gZXMgdW5hIG1hdHJpeiwgc2VsZWNjaW9uYSBsYSBjb2x1bW5hIHF1ZSBjb3JyZXNwb25kZSBhIGxhIGNsYXNlICdZZXMnIG8gJzEnDQpwcmVkaWNjaW9uX3Byb2JfdHJ1ZV9uYiA8LSBwcmVkaWNjaW9uX3Byb2JfbmJbLCAibm8gc2VndWlyIl0NCg0KIyMgR2VuZXJhciBsYSBjdXJ2YSBST0MNCnJvY19vYmpfbmIgPC0gcm9jKHRlc3QkcGVyY2VwY2lvbl9wcm9iYWJpbGlkYWRfc2VndWlyX2Zvcm0sIHByZWRpY2Npb25fcHJvYl90cnVlX25iKQ0KDQojIyBEaWJ1amFyIGxhIGN1cnZhIFJPQw0KcGxvdC5yb2Mocm9jX29ial9uYiwgbWFpbj0iQ3VydmEgUk9DIiwgY29sPSJibHVlIikNCg0KIyMgQ2FsY3VsYXIgZWwgQVVDDQphdWNfbmIgPC0gcFJPQzo6YXVjKHJvY19vYmpfbmIpDQphdWNfbmINCmBgYA0KDQpEZWJpZG8gYSBsYSBmYWx0YSBkZSBzaWduaWZpY2FuY2lhIGVuIGxhcyB2YXJpYWJsZXMgZGVsIG1vZGVsbyBsb2fDrXN0aWNvLCBjb25zaWRlcmFuZG8gZWwgYnVlbiBkZXNlbXBlw7FvIGRlbCBtb2RlbG8gZGUgTmFpdmUgQmF5ZXMsIGVuIGNvbmp1bnRvIGNvbiBzdSBwcmluY2lwaW8gZGUgaW5kZXBlbmRlbmNpYSwgc2UgYW5hbGl6YXLDoW4gc3VzIHJlc3VsdGFkb3MgYSB0cmF2w6lzIGRlIGxhcyB0YWJsYXMgZGUgcHJvYmFiaWxpZGFkIGNvbmRpY2lvbmFsIHkgZGlzdHJpYnVjacOzbiBwYXJhIGRldGVybWluYXIgZWwgaW1wYWN0byBkZSBsYXMgdmFyaWFibGVzIGluZGVwZW5kaWVudGVzIHNvYnJlIGxhIHBlcmNlcGNpw7NuIGRlIGNvbnRpbnVhciBvIG5vIHRyYWJhamFuZG8gZW4gRm9ybS4NCg0KKiBMb3MgZW1wbGVhZG9zIGRlIGfDqW5lcm8gZmVtZW5pbm8gdGllbmVuIG1heW9yIHByb2JhYmlsaWRhZCBkZSBjb25zaWRlcmFyIHNlZ3VpciB0cmFiYWphbmRvIGVuIEZvcm0uDQoNCiogTG9zIGVtcGxlYWRvcyBkZSBtYXlvciBlZGFkIHRpZW5lbiBtYXlvciBwcm9iYWJpbGlkYWQgZGUgY29uc2lkZXJhciBzZWd1aXIgdHJhYmFqYW5kbyBlbiBGb3JtLg0KDQoqIExvcyBlbXBsZWFkb3MgcXVlIGhhbiB0cmFiYWphZG8gcG9yIHVuIHBlcmlvZG8gbcOhcyBsYXJnbyB0aWVuZW4gbWF5b3IgcHJvYmFiaWxpZGFkIGRlIGNvbnNpZGVyYXIgc2VndWlyIHRyYWJhamFuZG8gZW4gRm9ybS4NCg0KKiBMb3MgZW1wbGVhZG9zIHF1ZSBwZXJjaWJlbiBzdSBzYWxhcmlvIHkgcHJlc3RhY2lvbmVzIGNvbW8gbcOhcyBqdXN0b3MsIHRpZW5lbiBtYXlvciBwcm9iYWJpbGlkYWQgZGUgY29uc2lkZXJhciBzZWd1aXIgdHJhYmFqYW5kbyBlbiBGb3JtLg0KDQoqIExvcyBlbXBsZWFkb3MgcXVlIHBlcmNpYmVuIHN1IG5pdmVsIGRlIGVzdHLDqXMgY29tbyBiYWpvLCB0aWVuZW4gbWF5b3IgcHJvYmFiaWxpZGFkIGRlIGNvbnNpZGVyYXIgc2VndWlyIHRyYWJhamFuZG8gZW4gRm9ybS4NCg0KKiBMb3MgZW1wbGVhZG9zIHF1ZSBwZXJjaWJlbiBidWVuYSBmYWNpbGlkYWQgZGUgdHJhc2xhZG8sIHRpZW5lbiBtYXlvciBwcm9iYWJpbGlkYWQgZGUgY29uc2lkZXJhciBzZWd1aXIgdHJhYmFqYW5kbyBlbiBGb3JtLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyMgVGFibGFzIGRlIFByb2JhYmlsaWRhZCBDb25kaWNpb25hbCAoRkFDVE9SRVMvQ0FURUdPUklBUykNCmJhcnBsb3QobW9kZWxvX25iJHRhYmxlcyRnw6luZXJvLCBsZWdlbmQudGV4dCA9IFRSVUUsIGJlc2lkZSA9IFRSVUUsIGNvbCA9IGMoImJsYWNrIiwgImxpZ2h0Z3JheSIpLCBtYWluID0gIkfDqW5lcm8iKQ0KDQojIyBUYWJsYXMgZGUgTWVkaWEgeSBEZXN2aWFjacOzbiBFc3TDoW5kYXIgcGFyYSBWYXJpYWJsZXMgQ29udGludWFzIChOVU1FUk9TKQ0KDQpiYXJwbG90KG1vZGVsb19uYiR0YWJsZXMkZWRhZCwgbGVnZW5kLnRleHQgPSBUUlVFLCBiZXNpZGUgPSBUUlVFLCBjb2wgPSBjKCJibGFjayIsICJsaWdodGdyYXkiKSwgbmFtZXMuYXJnID0gYygiTWVkaWEiLCAiRGVzdmlhY2nDs24gZXN0w6FuZGFyIiksIG1haW4gPSAiRWRhZCIpDQoNCmJhcnBsb3QobW9kZWxvX25iJHRhYmxlcyRtZXNlc19hbnRpZ8O8ZWRhZCwgbGVnZW5kLnRleHQgPSBUUlVFLCBiZXNpZGUgPSBUUlVFLCBjb2wgPSBjKCJibGFjayIsICJsaWdodGdyYXkiKSwgbmFtZXMuYXJnID0gYygiTWVkaWEiLCAiRGVzdmlhY2nDs24gZXN0w6FuZGFyIiksIG1haW4gPSAiTWVzZXMiKQ0KDQpiYXJwbG90KG1vZGVsb19uYiR0YWJsZXMkZXNjYWxhX3NhbGFyaW9fanVzdG8sIGxlZ2VuZC50ZXh0ID0gVFJVRSwgYmVzaWRlID0gVFJVRSwgY29sID0gYygiYmxhY2siLCAibGlnaHRncmF5IiksIG5hbWVzLmFyZyA9IGMoIk1lZGlhIiwgIkRlc3ZpYWNpw7NuIGVzdMOhbmRhciIpLCBtYWluID0gIlNhbGFyaW8ganVzdG8iKQ0KDQpiYXJwbG90KG1vZGVsb19uYiR0YWJsZXMkZXNjYWxhX3BlcmNlcGNpb25fcHJlc3RhY2lvbmVzLCBsZWdlbmQudGV4dCA9IFRSVUUsIGJlc2lkZSA9IFRSVUUsIGNvbCA9IGMoImJsYWNrIiwgImxpZ2h0Z3JheSIpLCBuYW1lcy5hcmcgPSBjKCJNZWRpYSIsICJEZXN2aWFjacOzbiBlc3TDoW5kYXIiKSwgbWFpbiA9ICJQcmVzdGFjaW9uZXMiKQ0KDQpiYXJwbG90KG1vZGVsb19uYiR0YWJsZXMkcGVyY2VwY2lvbl9lc3RyZXNfYmFqbywgbGVnZW5kLnRleHQgPSBUUlVFLCBiZXNpZGUgPSBUUlVFLCBjb2wgPSBjKCJibGFjayIsICJsaWdodGdyYXkiKSwgbmFtZXMuYXJnID0gYygiTWVkaWEiLCAiRGVzdmlhY2nDs24gZXN0w6FuZGFyIiksIG1haW4gPSAiUGVyY2VwY2nDs24gZXN0csOpcyBiYWpvIikNCg0KYmFycGxvdChtb2RlbG9fbmIkdGFibGVzJHBlcmNlcGNpb25fZmFjaWxpZGFkX3RyYXNsYWRvLCBsZWdlbmQudGV4dCA9IFRSVUUsIGJlc2lkZSA9IFRSVUUsIGNvbCA9IGMoImJsYWNrIiwgImxpZ2h0Z3JheSIpLCBuYW1lcy5hcmcgPSBjKCJNZWRpYSIsICJEZXN2aWFjacOzbiBlc3TDoW5kYXIiKSwgbWFpbiA9ICJQZXJjZXBjacOzbiBmYWNpbGlkYWQgZGUgdHJhc2xhZG8iKQ0KYGBgDQoNCiMgKipOZWFyc2hvcmluZyoqDQoNCiMjIElFRCAtIFZlY3RvciBBdXRvcmVncmVzc2l2ZSBNb2RlbA0KDQojIyMgTGltcGllemEgeSBUcmFuc2Zvcm1hY2nDs24gZGUgVmFyaWFibGVzDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBDYXJnYXIgQmFzZSBkZSBEYXRvcw0KbmVhcnNob3JpbmdfZGF0YSA8LSByZWFkLmNzdigiQzpcXFVzZXJzXFxBVlJJTFxcRG9jdW1lbnRzXFxuZWFyc2hvcmluZ19kYXRhLmNzdiIpDQoNCiMgVGlwb3MgZGUgVmFyaWFibGVzDQpzdW1tYXJ5KG5lYXJzaG9yaW5nX2RhdGEpDQpuZWFyc2hvcmluZ19kYXRhJEVtcGxlbyA8LSBhcy5udW1lcmljKG5lYXJzaG9yaW5nX2RhdGEkRW1wbGVvKQ0KbmVhcnNob3JpbmdfZGF0YSRFZHVjYWNpw7NuIDwtIGFzLm51bWVyaWMobmVhcnNob3JpbmdfZGF0YSRFZHVjYWNpw7NuKQ0KbmVhcnNob3JpbmdfZGF0YSRJbm5vdmFjacOzbiA8LSBhcy5udW1lcmljKG5lYXJzaG9yaW5nX2RhdGEkSW5ub3ZhY2nDs24pDQpuZWFyc2hvcmluZ19kYXRhJEluc2VndXJpZGFkX0hvbWljaWRpbyA8LSBhcy5udW1lcmljKG5lYXJzaG9yaW5nX2RhdGEkSW5zZWd1cmlkYWRfSG9taWNpZGlvKQ0KbmVhcnNob3JpbmdfZGF0YSRFbXBsZW8gPC0gYXMubnVtZXJpYyhuZWFyc2hvcmluZ19kYXRhJEVtcGxlbykNCm5lYXJzaG9yaW5nX2RhdGEkQ08yX0VtaXNpb25lcyA8LSBhcy5udW1lcmljKG5lYXJzaG9yaW5nX2RhdGEkQ08yX0VtaXNpb25lcykNCm5lYXJzaG9yaW5nX2RhdGEkQ08yX0VtaXNpb25lcyA8LSBhcy5udW1lcmljKG5lYXJzaG9yaW5nX2RhdGEkQ08yX0VtaXNpb25lcykNCg0KIyBJbXB1dGFyIGxhIE1lZGlhIGEgVmFsb3JlcyBOdWxvcw0KbmVhcnNob3JpbmdfZGF0YSA8LSBuYS5hZ2dyZWdhdGUobmVhcnNob3JpbmdfZGF0YSwgRlVOID0gbWVkaWFuKQ0KDQoNCiMgQ29udmVyc2nDs24gYSBOw7ptZXJvcyBSZWFsZXMNCm5lYXJzaG9yaW5nX2RhdGEkSUVEX0ZsdWpvc19SZWFsZXMgPC0gKChuZWFyc2hvcmluZ19kYXRhJElFRF9GbHVqb3MgICogbmVhcnNob3JpbmdfZGF0YSRUaXBvX2RlX0NhbWJpbykgLyBuZWFyc2hvcmluZ19kYXRhJElOUEMpKjEwMA0KDQojIEVsaW1pbmFyIGNvbHVtbmFzIGlubmVjZXNhcmlhcw0KbmVhcnNob3JpbmdfZGF0YSA8LSBzdWJzZXQobmVhcnNob3JpbmdfZGF0YSwgc2VsZWN0ID0gLWMoSUVEX0ZsdWpvcykpDQoNCiMgVmVyaWZpY2FyIGxvcyByZXN1bHRhZG9zDQpoZWFkKG5lYXJzaG9yaW5nX2RhdGEpDQpgYGANCg0KIyMjIFNlbGVjY2lvbmFyIHZhcmlhYmxlcyBtw6FzIGltcG9ydGFudGVzIHBhcmEgbGEgY29uc3RydWNjacOzbiBkZWwgbW9kZWxvIFZBUg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRXh0cmFlciB2YXJpYWJsZXMgbcOhcyBpbXBvcnRhbnRlcyBjb24gbW9kZWxvIE9MUw0Kb2xzX21vZGVsIDwtIGxtKElFRF9GbHVqb3NfUmVhbGVzIH4uLCBuZWFyc2hvcmluZ19kYXRhKQ0Kc3VtbWFyeShvbHNfbW9kZWwpDQp2YXJJbXAob2xzX21vZGVsKQ0KYGBgDQoNCiMjIyMgVmlzdWFsaXphY2nDs24gSW5kaXZpZHVhbCBkZSBjYWRhIFZhcmlhYmxlDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KSUVEX0ZMdWpvc190czwtdHMobmVhcnNob3JpbmdfZGF0YSRJRURfRmx1am9zX1JlYWxlcyxzdGFydD1jKDE5OTcsIDEpLGVuZD1jKDIwMjIsIDEpLGZyZXF1ZW5jeT0xKQ0KSW5zZWd1cmlkYWRSb2JvX3RzPC10cyhuZWFyc2hvcmluZ19kYXRhJEluc2VndXJpZGFkX1JvYm8sc3RhcnQ9YygxOTk3LCAxKSxlbmQ9YygyMDIyLCAxKSxmcmVxdWVuY3k9MSkNCkluc2VndXJpZGFkSG9taWNpZGlvX3RzPC10cyhuZWFyc2hvcmluZ19kYXRhJEluc2VndXJpZGFkX0hvbWljaWRpbyxzdGFydD1jKDE5OTcsIDEpLGVuZD1jKDIwMjIsIDEpLGZyZXF1ZW5jeT0xKQ0KRWR1Y2FjaW9uX3RzIDwtIHRzKG5lYXJzaG9yaW5nX2RhdGEkRWR1Y2FjacOzbixzdGFydD1jKDE5OTcsIDEpLGVuZD1jKDIwMjIsIDEpLGZyZXF1ZW5jeT0xKQ0KSW5ub3ZhY2lvbl90cyA8LSB0cyhuZWFyc2hvcmluZ19kYXRhJElubm92YWNpw7NuLHN0YXJ0PWMoMTk5NywgMSksZW5kPWMoMjAyMiwgMSksZnJlcXVlbmN5PTEpDQpEZW5zaWRhZFBvYmxhY2lvbl90cyA8LSB0cyhuZWFyc2hvcmluZ19kYXRhJERlbnNpZGFkX1BvYmxhY2nDs24sc3RhcnQ9YygxOTk3LCAxKSxlbmQ9YygyMDIyLCAxKSxmcmVxdWVuY3k9MSkNCkNPMl90cyA8LSB0cyhuZWFyc2hvcmluZ19kYXRhJENPMl9FbWlzaW9uZXMsc3RhcnQ9YygxOTk3LCAxKSxlbmQ9YygyMDIyLCAxKSxmcmVxdWVuY3k9MSkNCg0KDQphdXRvcGxvdChJRURfRkx1am9zX3RzKQ0KYXV0b3Bsb3QoSW5zZWd1cmlkYWRSb2JvX3RzKQ0KYXV0b3Bsb3QoSW5zZWd1cmlkYWRIb21pY2lkaW9fdHMpDQphdXRvcGxvdChFZHVjYWNpb25fdHMpDQphdXRvcGxvdChJbm5vdmFjaW9uX3RzKQ0KYXV0b3Bsb3QoRGVuc2lkYWRQb2JsYWNpb25fdHMpDQphdXRvcGxvdChDTzJfdHMpDQpgYGANCg0KIyMjIENvbnN0cnVpciBNb2RlbG8gVkFSDQoNCkxvcyByZXN1bHRhZG9zIGRlbCBtb2RlbG8gcGFyYSBsYSB2YXJpYWJsZSBJRURfRmx1am9zX1JlYWxlcyBtdWVzdHJhbiBjYXB0dXJhciBlbCAzNCUgZGUgc3UgdmFyaWFiaWxpZGFkIChSLWFqdXN0YWRhKSwgc2luIGVtYmFyZ28gZWwgZXN0YWTDrXN0aWNvIEYgbXVlc3RyYSBxdWUgZXN0YSByZWxhY2nDs24gbm8gZXMgc2lnbmlmaWNhdGl2YSAocC12YWx1ZSA+IDAuMDUpLiBBc2ltaXNtbywgbG9zIHJlc3VsdGFkb3MgbXVlc3RyYW4gZW4gc3UgbWF5b3LDrWEgcXVlIHZhbG9yZXMgbWF5b3JlcyBkZSBsYXMgdmFyaWFibGVzIGV4cGxpY2F0aXZhcyBlbiBwZXJpb2RvcyBhbnRlcmlvcmVzIGNvbmR1Y2VuIGEgZGlzbWludWlyIGVsIHZhbG9yIGFjdHVhbCBkZSBsb3MgZmx1am9zIGRlIElFRCwgZXhjZXB0dWFuZG8gbGFzIGlubm92YWNpb25lcyB5IGxhIGVkdWNhY2nDs24uIEVzIGRlY2lyLCB2YWxvcmVzIGVsZXZhZG9zIGVuIHBlcmlvZG9zIHByZXZpb3MgcGFyYSBlc3RvcyDDumx0aW1vcyBjYXNvcywgY29udHJpYnV5ZW4gYSBhdW1lbnRhciBsb3MgZmx1am9zIGRlIElFRC4gQXNpbWlzbW8sIGVzIGltcG9ydGFudGUgcmVjb25vY2VyIHF1ZSBuaW5ndW5vIGRlIGxvcyB2YWxvcmVzIHNlIG11ZXN0cmEgc2lnbmlmaWNhdGl2byB0YW1wb2NvIChwLXZhbHVlID4gMC4wNSkuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGF0YV90cyA8LSBjYmluZChuZWFyc2hvcmluZ19kYXRhJElFRF9GbHVqb3NfUmVhbGVzLCBuZWFyc2hvcmluZ19kYXRhJEluc2VndXJpZGFkX1JvYm8sIG5lYXJzaG9yaW5nX2RhdGEkSW5zZWd1cmlkYWRfSG9taWNpZGlvLCBuZWFyc2hvcmluZ19kYXRhJEVkdWNhY2nDs24sIG5lYXJzaG9yaW5nX2RhdGEkSW5ub3ZhY2nDs24sIG5lYXJzaG9yaW5nX2RhdGEkRGVuc2lkYWRfUG9ibGFjacOzbiwgbmVhcnNob3JpbmdfZGF0YSRDTzJfRW1pc2lvbmVzKQ0KY29sbmFtZXMoZGF0YV90cykgPC0gYygiSUVEX0ZsdWpvc19SZWFsZXMiLCAiSW5zZWd1cmlkYWRfUm9ibyIsIkluc2VndXJpZGFkX0hvbWljaWRpbyIsICJFZHVjYWNpw7NuIiwgIklubm92YWNpw7NuIiwgIkRlbnNpZGFkX1BvYmxhY2nDs24iLCAiQ08yX2VtaXNpb25lcyIpDQoNCiNkYXRhX3RzX2RpZmYgPC0gbG9nKGRhdGFfdHMrLjAwMDAwMDAwMDEpDQpWQVJfbW9kZWwgPC0gVkFSKGRhdGFfdHMsIHAgPSAyLCB0eXBlID0gImNvbnN0IikNCnN1bW1hcnkoVkFSX21vZGVsKQ0KVkFSX21vZGVsX3Jlc2lkdWFscyA8LSBkYXRhLmZyYW1lKHJlc2lkdWFscyhWQVJfbW9kZWwpKQ0KYGBgDQoNCiMjIyMgUHJ1ZWJhIEFERg0KQ29tZW50YXJpbzogQWwgb2J0ZW5lciB1biBwLXZhbHVlIG1heW9yIGEgMC4wNSwgbm8gc2UgcmVjaGF6YSBsYSBoaXBvdMOpc2lzIG51bGEsIHBvciBsbyBxdWUgbm8gZXMgZXN0YWNpb25hcmlvLiANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQphZGYudGVzdChWQVJfbW9kZWxfcmVzaWR1YWxzJElFRF9GbHVqb3NfUmVhbGVzKQ0KYGBgDQoNCiMjIyMgUHJ1ZWJhIEJveC1ManVuZw0KQ29tZW50YXJpbzogQWwgb2J0ZW5lciB1biBwLXZhbHVlIG1heW9yIGEgMC4wNSwgbm8gc2UgcmVjaGF6YSBsYSBoaXBvdMOpc2lzIG51bGEsIHBvciBsbyBxdWUgbm8gaGF5IGV2aWRlbmNpYSBzdWZpY2llbnRlIHBhcmEgcmVjaGF6YXIgbGEgaGlww7N0ZXNpcyBudWxhLCBsbyBxdWUgc3VnaWVyZSBxdWUgbG9zIHJlc2lkdW9zIHNvbiBpbmRlcGVuZGllbnRlcyBlbiBlbCB0aWVtcG8gKGVzIGRlY2lyLCBubyBoYXkgYXV0b2NvcnJlbGFjacOzbiBzaWduaWZpY2F0aXZhIGVuIGxvcyByZXNpZHVvcykuDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KQm94LnRlc3QoVkFSX21vZGVsX3Jlc2lkdWFscyRJRURfRmx1am9zX1JlYWxlcywgbGFnID0gMSwgdHlwZSA9ICJManVuZy1Cb3giKQ0KYGBgDQoNCiMjIyBGb3JlY2FzdCBBw7FvcyAoMjAyMyBhIDIwMjcpDQpEZSBhY3VlcmRvIGEgbGEgcHJlZGljY2nDs24gZGVsIG1vZGVsbyBWQVIgY29uc2lkZXJhbmRvIGxhcyB2YXJpYWJsZXMgZGUgSW5zZWd1cmlkYWRfUm9ibywgSW5zZWd1cmlkYWRfSG9tb2NpZGlvLCBFZHVjYWNpw7NuLCBJbm5vdmFjacOzbiwgRGVuc2lkYWQgZGUgUG9ibGFjacOzbiB5IEVtaXNpb25lcyBkZSBDTzIsIGxhIGludmVyc2nDs24gZXh0cmFuamVyYSBhdW1lbnRhcsOhIGVuIDIwMjMtMjAyNSwgaW1wbGljYW5kbyBsYSBwb3NpYmxlIGxsZWdhZGEgZGVsIE5lYXJzaG9yaW5nIGEgTcOpeGljby4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFByZWRpY2Npw7NuIHBhcmEgbG9zIHNpZ3VpZW50ZXMgNSBwZXJpb2Rvcw0KZm9yZWNhc3RfdmFyIDwtIHByZWRpY3QoVkFSX21vZGVsLCBuLmFoZWFkID0gNSwgY2kgPSAwLjk1KQ0KcHJpbnQoZm9yZWNhc3RfdmFyKQ0KDQpmYW5jaGFydChmb3JlY2FzdF92YXIsIG5hbWVzID0gIklFRF9GbHVqb3NfUmVhbGVzIiwgbWFpbiA9ICJQcm9uw7NzdGljbyBkZSBGbHVqb3MgZGUgSUVEIGVuIE3DqXhpY28gKFZBUikiLCANCiAgICAgICAgIHhsYWIgPSAiUGVyaW9kbyIsIHlsYWIgPSAiSUVEIEZsdWpvcyBSZWFsZXMiKQ0KYGBgDQoNCg0KDQojIyBJRUQgZW4gTcOpeGljbw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ2FyZ2FuZG8gbG9zIGRhdG9zIGRlIGZsdWpvcyBkZSBJRUQNCmllZF9mbHVqb3MgPC0gcmVhZC5jc3YoIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcSUVEX0ZsdWpvcy5jc3YiKQ0Kc3VtbWFyeShpZWRfZmx1am9zKQ0KYGBgDQoNCiMjIyBWaXN1YWxpemFyIGxhIHNlcmllIGRlIHRpZW1wbyAobsO6bWVyb3MgcmVhbGVzKQ0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ3JlYXIgdW5hIG51ZXZhIGNvbHVtbmEgcGFyYSBsb3MgZmx1am9zIGVuIG7Dum1lcm9zIHJlYWxlcw0KaWVkX2ZsdWpvcyRJRURfTnVtZXJvX1JlYWwgPC0gKChpZWRfZmx1am9zJElFRF9GbHVqb3MgKiBpZWRfZmx1am9zJFRpcG9fQ2FtYmlvKSAvIGllZF9mbHVqb3MkSU5QQykqMTAwDQoNCiMgT2J0ZW5lciBsb3Mgw7psdGltb3MgMjAgdmFsb3JlcyBkZWwgcHJvbsOzc3RpY28gKDUgYcOxb3MpDQp1bHRpbW9zX3ZhbG9yZXMgPC0gdGFpbChpZWRfZmx1am9zJElFRF9OdW1lcm9fUmVhbCwgMjApDQoNCiMgQ2FsY3VsYXIgZWwgcHJvbWVkaW8gZGUgbG9zIMO6bHRpbW9zIDIwIHZhbG9yZXMgKDUgYcOxb3MpDQpwcm9tZWRpb19mbHVqb3MgPC0gbWVhbih1bHRpbW9zX3ZhbG9yZXMpDQoNCiMgQ29udmVydGlyIGEgc2VyaWUgZGUgdGllbXBvDQppZWRfZmx1am9zIDwtIHRzKGllZF9mbHVqb3MkSUVEX051bWVyb19SZWFsLCBzdGFydCA9IGMobWluKGllZF9mbHVqb3MkQcOxbyksIDEpLCBmcmVxdWVuY3kgPSA0KQ0KDQpwbG90KGllZF9mbHVqb3MpDQpgYGANCg0KIyMjIyBBbsOhbGlzaXMgZGUgc2VyaWVzIGRlIHRpZW1wbyBkZSBmbHVqb3MgZGUgSUVEDQojIyMjIEFERiBUZXN0DQpDb21lbnRhcmlvOiBDb24gdW4gdmFsb3IgZGUgcCBkZSAwLjAyLCBzZSBwdWVkZSByZWNoYXphciBsYSBoaXDDs3Rlc2lzIG51bGEgZGUgcXVlIHNlIHRpZW5lIHVuYSByYcOteiB1bml0YXJpYSwgbG8gcXVlIHNpZ25pZmljYSBxdWUgZXMgZXN0YWNpb25hcmlhLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiNQcnVlYmEgZGUgZXN0YWNpb25hcmllZGFkIChBREYgVGVzdCkNCmFkZl90ZXN0IDwtIGFkZi50ZXN0KGllZF9mbHVqb3MsIGFsdGVybmF0aXZlID0gInN0YXRpb25hcnkiKQ0KYWRmX3Rlc3QNCmBgYA0KDQoNCiMjIyMgQm94LUxqdW5nIFRlc3QgeSBBQ0YgUGxvdA0KQ29tZW50YXJpbzogQ29uIHVuIHZhbG9yIGRlIHAgZGUgMC45NDQ5LCBubyBoYXkgZXZpZGVuY2lhIHN1ZmljaWVudGUgcGFyYSByZWNoYXphciBsYSBoaXDDs3Rlc2lzIG51bGEsIGxvIHF1ZSBzdWdpZXJlIHF1ZSBsb3MgcmVzaWR1b3Mgc29uIGluZGVwZW5kaWVudGVzIGVuIGVsIHRpZW1wbyAoZXMgZGVjaXIsIG5vIGhheSBhdXRvY29ycmVsYWNpw7NuIHNpZ25pZmljYXRpdmEgZW4gbG9zIHJlc2lkdW9zKS4NCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCkJveC50ZXN0KGllZF9mbHVqb3MsIHR5cGUgPSAiTGp1bmctQm94IikNCmFjZihpZWRfZmx1am9zKQ0KYGBgDQoNCiMjIyBFc3RpbWFjacOzbiBTQVJJTUENCkRlIGFjdWVyZG8gYSBsYSBmdW5jacOzbiBhdXRvLmFyaW1hLCBsb3MgcGFyw6FtZXRyb3MgZGVsIG1vZGVsbyBmdWVyb24gb3B0aW1pemFkb3MgY29uIGxvcyB2YWxvcmVzICgwLDAsMCkoMCwxLDIpLCBlc3RvIGluZGljYSBwYXLDoW1ldHJvcyBkaWZlcmVudGVzIGEgMCDDum5pY2FtZW50ZSBlbiBlbCBjb21wb25lbnRlIGVzdGFjaW9uYWwuIEVuIGVzdGUgY29tcG9uZW50ZSBwb3NlZSAwIGF1dG9yZWdyZXNpb25lcywgMSBkaWZlcmVuY2lhLCB5IDIgcHJvbWVkaW9zIG3Ds3ZpbCwgZ2VuZXJhbmRvIGFzw60gdW4gbW9kZWxvIFNBUklNQSBjb24gbWVqb3IgZGVzZW1wZcOxbyBxdWUgb3Ryb3MgbW9kZWxvcywgdGVuaWVuZG8gdW4gUk1TRSBkZSA1MywyNjYgeSB1biBBSUMgZGUgMjI3Ni4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQphdXRvX2FyaW1hX21vZGVsIDwtIGF1dG8uYXJpbWEoaWVkX2ZsdWpvcykNCnN1bW1hcnkoYXV0b19hcmltYV9tb2RlbCkNCg0KYXJpbWFtb2RlbCA8LSBhcmltYShpZWRfZmx1am9zLCBvcmRlciA9IGMoMCwxLDApKQ0Kc3VtbWFyeShhcmltYW1vZGVsKQ0KYGBgDQoNCiMjIyMgRGlhZ27Ds3N0aWNvcyBkZWwgTW9kZWxvDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KY2hlY2tyZXNpZHVhbHMoYXV0b19hcmltYV9tb2RlbCkNCmBgYA0KDQojIyMgUHJlZGljY2lvbmVzIGRlbCBtb2RlbG8NCkRlIGFjdWVyZG8gYSBsbyB2aXN0byBwb3IgZWwgcHJvbsOzc3RpY28gZGVsIG1vZGVsbyBzYXJpbWEgcGFyYSBsb3Mgc2lndWllbnRlIDggcGVyaW9kb3MgKDIwMjQgeSAyMDI1KSwgc2UgcHVlZGVuIG9ic2VydmFyIHBpY29zIHRhbnRvIHBvc2l0aXZvcyBjb21vIG5lZ2F0aXZvcyBlbiBsb3MgZmx1am9zIGRlIElFRCwgc3ViaWVuZG8geSBiYWphbmRvIGVsIHByb21lZGlvIGRlIGxvcyDDumx0aW1vcyA1IGHDsW9zLCBsbyBjdWFsIGhhY2UgaW5jaWVydGEgbGEgbGxlZ2FkYSBkZWwgTmVhcnNob3JpbmcgYSBNw6l4aWNvLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgUHJlZGljY2lvbmVzIHBhcmEgNCB0cmltZXN0cmVzIGRlbCAyMDIzLCAyMDI0IHkgMjAyNQ0KZm9yZWNhc3RfYXJpbWEgPC0gZm9yZWNhc3QoYXV0b19hcmltYV9tb2RlbCwgaD0xNCkgIyBoIGVzIGVsIG7Dum1lcm8gZGUgcGVyaW9kb3MgYSBwcm9ub3N0aWNhcg0KZm9yZWNhc3RfYXJpbWENCg0KDQojIENyZWFyIGVsIGdyw6FmaWNvDQpncmFmaWNvIDwtIGF1dG9wbG90KGZvcmVjYXN0X2FyaW1hKSArIA0KICBsYWJzKHRpdGxlID0gIlByb27Ds3N0aWNvIGRlIGZsdWpvcyBkZSBJRUQgZW4gTcOpeGljbyIsIHggPSAiUGVyaW9kbyIsIHkgPSAiRmx1am9zIGRlIElFRCIpDQoNCiMgQWdyZWdhciBsYSBsw61uZWEgZGVsIHByb21lZGlvIGFsIGdyw6FmaWNvDQpncmFmaWNvX2Nvbl9wcm9tZWRpbyA8LSBncmFmaWNvICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gcHJvbWVkaW9fZmx1am9zLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQ0KDQojIE1vc3RyYXIgZWwgZ3LDoWZpY28NCnByaW50KGdyYWZpY29fY29uX3Byb21lZGlvKQ0KYGBgDQoNCg0KDQojIyBJRUQgRmFicmljYWNpw7NuIGRlIFBhcGVsIHkgQ2FydMOzbg0KDQojIyMgVmlzdWFsaXphciBsYSBzZXJpZSBkZSB0aWVtcG8gKG7Dum1lcm9zIHJlYWxlcykNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ2FyZ2FuZG8gbG9zIGRhdG9zIGRlIGZsdWpvcyBkZSBJRUQNCmllZF9mbHVqb3MgPC0gcmVhZF9leGNlbCgiQzpcXFVzZXJzXFxBVlJJTFxcRG9jdW1lbnRzXFxpZWRfY2FydG9uX3BhcGVsXzIwMjMueGxzeCIpDQpzdW1tYXJ5KGllZF9mbHVqb3MpDQppZWRfZmx1am9zJFRpcG9fQ2FtYmlvIDwtIGFzLm51bWVyaWMoaWVkX2ZsdWpvcyRUaXBvX0NhbWJpbykNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIENyZWFyIHVuYSBudWV2YSBjb2x1bW5hIHBhcmEgbG9zIGZsdWpvcyBlbiBuw7ptZXJvcyByZWFsZXMNCmllZF9mbHVqb3MkSUVEX0ZhYl9DYXJ0b25fUGFwZWxfTnVtZXJvX1JlYWwgPC0gKChpZWRfZmx1am9zJElFRF9GYWJfQ2FydG9uX1BhcGVsICAqIGllZF9mbHVqb3MkVGlwb19DYW1iaW8pIC8gaWVkX2ZsdWpvcyRJTlBDKSoxMDANCg0KIyBPYnRlbmVyIGxvcyDDumx0aW1vcyAyMCB2YWxvcmVzIGRlbCBwcm9uw7NzdGljbyAoNSBhw7FvcykNCnVsdGltb3NfdmFsb3JlcyA8LSB0YWlsKGllZF9mbHVqb3MkSUVEX0ZhYl9DYXJ0b25fUGFwZWxfTnVtZXJvX1JlYWwsIDIwKQ0KDQojIENhbGN1bGFyIGVsIHByb21lZGlvIGRlIGxvcyDDumx0aW1vcyAyMCB2YWxvcmVzICg1IGHDsW9zKQ0KcHJvbWVkaW9fZmx1am9zIDwtIG1lYW4odWx0aW1vc192YWxvcmVzKQ0KDQoNCiMgQ29udmVydGlyIGEgc2VyaWUgZGUgdGllbXBvDQppZWRfZmx1am9zIDwtIHRzKGllZF9mbHVqb3MkSUVEX0ZhYl9DYXJ0b25fUGFwZWxfTnVtZXJvX1JlYWwsIHN0YXJ0ID0gYyhtaW4oaWVkX2ZsdWpvcyRZZWFyKSwgMSksIGZyZXF1ZW5jeSA9IDQpDQoNCnBsb3QoaWVkX2ZsdWpvcykNCmBgYA0KDQojIyMgQW7DoWxpc2lzIGRlIHNlcmllcyBkZSB0aWVtcG8gZGUgZmx1am9zIGRlIElFRA0KIyMjIyBBREYgVGVzdA0KQ29tZW50YXJpbzogQ29uIHVuIHZhbG9yIGRlIHAgZGUgMC4wMSwgc2UgcHVlZGUgcmVjaGF6YXIgbGEgaGlww7N0ZXNpcyBudWxhIGRlIHF1ZSBzZSB0aWVuZSB1bmEgcmHDrXogdW5pdGFyaWEsIGxvIHF1ZSBzaWduaWZpY2EgcXVlIGVzIGVzdGFjaW9uYXJpYS4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojUHJ1ZWJhIGRlIGVzdGFjaW9uYXJpZWRhZCAoQURGIFRlc3QpDQphZGZfdGVzdCA8LSBhZGYudGVzdChpZWRfZmx1am9zLCBhbHRlcm5hdGl2ZSA9ICJzdGF0aW9uYXJ5IikNCmFkZl90ZXN0DQpgYGANCg0KDQojIyMjIEJveC1ManVuZyBUZXN0IHkgQUNGIFBsb3QNCkNvbWVudGFyaW86IENvbiB1biB2YWxvciBkZSBwIGRlIDAuNTczOSwgbm8gaGF5IGV2aWRlbmNpYSBzdWZpY2llbnRlIHBhcmEgcmVjaGF6YXIgbGEgaGlww7N0ZXNpcyBudWxhLCBsbyBxdWUgc3VnaWVyZSBxdWUgbG9zIHJlc2lkdW9zIHNvbiBpbmRlcGVuZGllbnRlcyBlbiBlbCB0aWVtcG8gKGVzIGRlY2lyLCBubyBoYXkgYXV0b2NvcnJlbGFjacOzbiBzaWduaWZpY2F0aXZhIGVuIGxvcyByZXNpZHVvcykuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpCb3gudGVzdChpZWRfZmx1am9zLCB0eXBlID0gIkxqdW5nLUJveCIpDQphY2YoaWVkX2ZsdWpvcykNCmBgYA0KDQojIyMgRXN0aW1hY2nDs24gU0FSSU1BDQpEZSBhY3VlcmRvIGEgbGEgZnVuY2nDs24gYXV0by5hcmltYSwgbG9zIHBhcsOhbWV0cm9zIGRlbCBtb2RlbG8gZnVlcm9uIG9wdGltaXphZG9zIGNvbiBsb3MgdmFsb3JlcyAoMCwwLDApKDIsMCwwKSwgZXN0byBpbmRpY2EgcGFyw6FtZXRyb3MgZGlmZXJlbnRlcyBhIDAgw7puaWNhbWVudGUgZW4gZWwgY29tcG9uZW50ZSBlc3RhY2lvbmFsLiBFbiBlc3RlIGNvbXBvbmVudGUgcG9zZWUgMiBhdXRvcmVncmVzaW9uZXMsIDAgZGlmZXJlbmNpYXMsIHkgMCBwcm9tZWRpb3MgbcOzdmlsLCBnZW5lcmFuZG8gYXPDrSB1biBtb2RlbG8gU0FSSU1BIGNvbiBtZWpvciBkZXNlbXBlw7FvIHF1ZSBvdHJvcyBtb2RlbG9zLCB0ZW5pZW5kbyB1biBSTVNFIGRlIDcwOCB5IHVuIEFJQyBkZSAxNTg5DQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KYXV0b19hcmltYV9tb2RlbCA8LSBhdXRvLmFyaW1hKGllZF9mbHVqb3MpDQpzdW1tYXJ5KGF1dG9fYXJpbWFfbW9kZWwpDQoNCmFyaW1hbW9kZWwgPC0gYXJpbWEoaWVkX2ZsdWpvcywgb3JkZXIgPSBjKDAsMSwwKSkNCnN1bW1hcnkoYXJpbWFtb2RlbCkNCmBgYA0KDQojIyMjIERpYWduw7NzdGljb3MgZGVsIE1vZGVsbw0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmNoZWNrcmVzaWR1YWxzKGF1dG9fYXJpbWFfbW9kZWwpDQpgYGANCg0KIyMjIFByZWRpY2Npb25lcyBkZWwgbW9kZWxvDQpEZSBhY3VlcmRvIGEgbG8gdmlzdG8gcG9yIGVsIHByb27Ds3N0aWNvIGRlbCBtb2RlbG8gc2FyaW1hIHBhcmEgbG9zIHNpZ3VpZW50ZSA4IHBlcmlvZG9zICgyMDI0IHkgMjAyNSksIHNlIHB1ZWRlIG9ic2VydmFyIMO6bmljYW1lbnRlIHVuIHBpY28gdGFudG8gcG9zaXRpdm8gZW4gbG9zIGZsdWpvcyBkZSBJRUQgcGFyYSBsYSBpbmR1c3RyaWEgZGUgY2FydMOzbiB5IHBhcGVsIHF1ZSBzb2JyZXNhbGUgZGVsIHByb21lZGlvIGRlIGxvcyDDumx0aW1vcyA1IGHDsW9zLCBsbyBjdWFsIGRldGVybWluYSBxdWUgbm8gZXN0YXLDrWEgcHJlc2VudGUgZWwgZWZlY3RvIGRlbCBOZWFyc2hvcmluZyBlbiBlc3RhIGluZHVzdHJpYSBlbiBNw6l4aWNvIChkZSBhY3VlcmRvIGFsIG1vZGVsbykuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFByZWRpY2Npb25lcyBwYXJhIDQgdHJpbWVzdHJlcyBkZWwgMjAyNCB5IDIwMjUNCmZvcmVjYXN0X2FyaW1hIDwtIGZvcmVjYXN0KGF1dG9fYXJpbWFfbW9kZWwsIGg9OSkgIyBoIGVzIGVsIG7Dum1lcm8gZGUgcGVyaW9kb3MgYSBwcm9ub3N0aWNhcg0KZm9yZWNhc3RfYXJpbWENCg0KIyBDcmVhciBlbCBncsOhZmljbw0KZ3JhZmljbyA8LSBhdXRvcGxvdChmb3JlY2FzdF9hcmltYSkgKyANCiAgbGFicyh0aXRsZSA9ICJQcm9uw7NzdGljbyBkZSBmbHVqb3MgZGUgSUVEIGVuIGxhIEluZHVzdHJpYSBkZSBDYXJ0w7NuIHkgUGFwZWwgZW4gTcOpeGljbyIsIHggPSAiUGVyaW9kbyIsIHkgPSAiRmx1am9zIGRlIElFRCIpDQoNCiMgQWdyZWdhciBsYSBsw61uZWEgZGVsIHByb21lZGlvIGFsIGdyw6FmaWNvDQpncmFmaWNvX2Nvbl9wcm9tZWRpbyA8LSBncmFmaWNvICsNCiAgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gcHJvbWVkaW9fZmx1am9zLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQ0KDQojIE1vc3RyYXIgZWwgZ3LDoWZpY28NCnByaW50KGdyYWZpY29fY29uX3Byb21lZGlvKQ0KYGBgDQoNCiMjIFByb27Ds3N0aWNvIGRlIFZlbnRhcyBkZSBGT1JNIChDYW50aWRhZCBkZSAkKQ0KDQojIyMgQ2FyZ2FyIFRpbWVTZXJpZXMgRGF0YXNldA0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRGF0YXNldCBkZSBWZW50YXMgZGUgRm9ybXMNCmRmX3ZlbnRhcyA8LSByZWFkX2V4Y2VsKCJDOlxcVXNlcnNcXEFWUklMXFxEb2N1bWVudHNcXEZPUk0gLSBWZW50YXMueGxzeCIpICANCmRmX3ZlbnRhcyA8LSBoZWFkKGRmX3ZlbnRhcywgLTMpICMgRWxpbWluYXIgw7psdGltb3MgMyBwZXJpb2RvcyBpbmNvbXBsZXRvcw0KaGVhZChkZl92ZW50YXMpDQpzdW1tYXJ5KGRmX3ZlbnRhcykNCmRmX3ZlbnRhcyA8LSBkZl92ZW50YXMgJT4lIGRwbHlyOjpzZWxlY3QoQW5vLCBNZXMsIFRvdGFsKQ0KDQojIEluaWNpYXIgY29udmVyc2nDs24gYSBGb3JtYXRvIGRlIFRpbWUgU2VyaWVzDQptZXNlcyA8LSBjKCJFbmUiLCAiRmViIiwgIk1hciIsICJBYnIiLCAiTWF5IiwgIkp1biIsICJKdWwiLCAiQWdvIiwgIlNlcCIsICJPY3QiLCAiTm92IiwgIkRpYyIpDQpkZl92ZW50YXMkTWVzIDwtIGZhY3RvcihkZl92ZW50YXMkTWVzLCBsZXZlbHMgPSBtZXNlcykNCg0KIyBDb21iaW5hciBsYSBjb2x1bW5hIEFubyBjb24gbGEgY29sdW1uYSBNZXMNCmRmX3ZlbnRhcyRGZWNoYSA8LSBhcy5EYXRlKHBhc3RlKGRmX3ZlbnRhcyRBbm8sIGFzLm51bWVyaWMoZGZfdmVudGFzJE1lcyksICIwMSIsIHNlcCA9ICItIikpDQpkZl92ZW50YXMgPC0gZGZfdmVudGFzICU+JQ0KICBkcGx5cjo6c2VsZWN0KEZlY2hhLCBUb3RhbCkNCg0KIyBDcmVhciBsYSB0aW1lIHNlcmllcw0KZGZfdmVudGFzIDwtIHRzKGRmX3ZlbnRhcyRUb3RhbCwgc3RhcnQgPSBjKG1pbih5ZWFyKGRmX3ZlbnRhcyRGZWNoYSkpLCAxKSwgZnJlcXVlbmN5ID0gMTIpDQpgYGANCg0KDQojIyMgR3JhZmljYXIgc2VyaWUgZGUgdGllbXBvDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KcGxvdChkZl92ZW50YXMsIG1haW49IlNlcmllIGRlIHRpZW1wbyIsIHlsYWI9IlByZWNpbyIsIGNvbD0icmVkIikNCiANCiMgRGVzY29tcG9uZXIgbGEgc2VyaWUgZGUgdGllbXBvIGVuIHN1cyBjb21wb25lbnRlcw0KUG9yY29tcG9uZW50ZSA8LSBzdGF0czo6ZGVjb21wb3NlKGRmX3ZlbnRhcykNCg0KdGVuZCA8LSBQb3Jjb21wb25lbnRlJHRyZW5kIA0KZXN0YWMgPC0gUG9yY29tcG9uZW50ZSRzZWFzb25hbCANCmVycm9yIDwtIFBvcmNvbXBvbmVudGUkcmFuZG9tIA0KcGxvdChQb3Jjb21wb25lbnRlKQ0KYGBgDQoNCiMjIyBQcnVlYmEgZGUgRXN0YWNpb25hcmllZGFkIC0gQURGIHRlc3QNCkFsIG9idGVuZXIgdW4gdmFsb3IgZGUgcC12YWx1ZT0wLjY0NjI7IG5vIHNlIHJlY2hhemEgbGEgaGlwb3TDqXNpcyBudWxhLCBwb3IgbG8gcXVlIGVzIHBvc2libGUgZGVjaXIgcXVlICoqTk8gZXMgZXN0YWNpb25hcmlhKiouIA0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmFkZl90ZXN0IDwtIGFkZi50ZXN0KGRmX3ZlbnRhcykNCnByaW50KGFkZl90ZXN0KQ0KYGBgDQoNCiMjIyBQcnVlYmEgZGUgQXV0b2NvcnJlbGFjacOzbiAtIEJveC1ManVuZyBUZXN0IHkgQUNGIHBsb3QNCkVsIHAtdmFsdWUgcmVzdWx0YW50ZSBlczogMC4wMTQ3Ny4gUG9yIGxvIHF1ZSBhbCBhbmFsaXphcmxvLCBzZSBkZXRlcm1pbmEgcXVlIGVzIHBvc2libGUgcmVjaGF6YXIgbGEgaGlww7N0ZXNpcyBudWxhLCBwb3IgbG8gcXVlIHNlIGRpY2UgcXVlICoqSGF5IGF1dG9jb3JyZWxhY2nDs24gc2VyaWFsKiouDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBQcnVlYmEgZGUgQm94LUxqdW5nDQpib3hfbGp1bmdfdGVzdCA8LSBCb3gudGVzdCggZGZfdmVudGFzLCB0eXBlID0gIkxqdW5nLUJveCIpDQpwcmludChib3hfbGp1bmdfdGVzdCkNCg0KIyBQbG90IEFDRg0KYWNmX3Bsb3QgPC0gYWNmKGRmX3ZlbnRhcywgbWFpbiA9ICJGdW5jacOzbiBkZSBBdXRvY29ycmVsYWNpw7NuIChBQ0YpIGRlIFZlbnRhcyIpDQpgYGANCg0KIyMjIEVzdGltYWNpw7NuIGRlIG1vZGVsbw0KUGFyYSByZWFsaXphciBlbCBwcm9uw7NzaXRpY28gZGUgbGFzIHZlbnRhcyBtZW5zdWFsZXMgZGUgRm9ybSBzZSBlbXBsZcOzIGVsIG3DqXRvZG8gZGUgc3Vhdml6YWNpw7NuIGV4cG9uZW5jaWFsLCBjb25zaWRlcmFuZG8gdW4gYWxwaGEgZGUgMC45OSwgZXMgZGVjaXIsIG90b3JnYW5kbyB1biBtYXlvciBwZXNvIGEgbG9zIHZhbG9yZXMgbcOhcyByZWNpZW50ZXMgcXVlIGEgbG9zIGRhdG9zIGhpc3TDs3JpY29zLiBFc3RvIGltcGxpY2EgcXVlIHBhcmEgcHJldmVyIGxhcyB2ZW50YXMgbWVuc3VhbGVzIGRlIEZvcm0sIGxhcyBwcmVkaWNjaW9uZXMgcmVmbGVqYXLDoW4gZGUgbWFuZXJhIG3DoXMgcHJlY2lzYSBsYXMgdGVuZGVuY2lhcyByZWNpZW50ZXMgZW4gbGFzIHZlbnRhcy4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQptb2RlbG9fZXhwc21vb3RoIDwtIEhvbHRXaW50ZXJzKGRmX3ZlbnRhcywgYWxwaGEgPSAwLjk5KSANCm1vZGVsb19leHBzbW9vdGgNCmBgYA0KDQoNCiMjIyBEaWFnbsOzc3RpY29zIGRlbCBNb2RlbG8NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpjaGVja3Jlc2lkdWFscyhtb2RlbG9fZXhwc21vb3RoKQ0KYGBgDQoNCiMjIyBQcmVkaWNjaW9uZXMgZGVsIG1vZGVsbw0KQWwgcmVhbGl6YXIgZWwgcHJvbsOzc3RpY28gYmFzZSBtZWRpYW50ZSBlbCBtb2RlbG8gZGUgc3Vhdml6YWNpw7NuIGV4cG9uZW5jaWFsLCBlc3RlIHJlc3VsdMOzIGVuIHVuYSB0ZW5kZW5jaWEgY3JlY2llbnRlIGVuIGxhcyB2ZW50YXMgZnV0dXJhcyBkZSBGb3JtIGEgdHJhdsOpcyBkZSBsb3Mgc2lndWllbnRlcyBtZXNlcy4gU2luIGVtYmFyZ28gZXMgbmVjZXNhcmlvIGNvbnNpZGVyYXIgbGEgZGlmZXJlbmNpYSBlbnRyZSBsYSBsw61uZWEgdHJhemFkYSBkZWwgcHJvbsOzc3RpY28sIHkgZWwgc29tYnJlYWRvIGRlbCBlcnJvciwgZXhpc3RpZW5kbyB1bmEgaW5jZXJ0aWR1bWJyZSBjb25zaWRlcmFibGUgY29uc2lkZXJhbmRvIGxvcyBpbnRlcnZhbG9yZXMgZGUgY29uZmlhbnphIGRlbCA4MCB5IDk1LCBwdWRpZW5kbyBubyBzZXIgdW4gcHJvbsOzc3RpY28gY2VydGVybyBwYXJhIG1lZGlyIGVsIGRlc2VtcGXDsW8gZnV0dXJvIGNvbiBleGFjdGl0dWQsIHkgZGViZXLDrWEgY29tcGxlbWVudGFyc2UgY29uIG90cm9zIGZhY3RvcmVzLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCnByZWRpY2Npb25lcyA8LSBmb3JlY2FzdChtb2RlbG9fZXhwc21vb3RoLCBoID0gMTgpICAjIFByZWRpY2Npw7NuIGRlIDE4IHBlcmlvZG9zIChtZXNlcykgaGFjaWEgYWRlbGFudGUNCnByaW50KHByZWRpY2Npb25lcykNCg0KIyBHcmFmaWNhciBsYXMgcHJlZGljY2lvbmVzDQpwbG90KHByZWRpY2Npb25lcywgbWFpbiA9ICJQcmVkaWNjaW9uZXMgZGUgVmVudGFzIGRlIEZvcm0iKQ0KYGBgDQoNCg0KIyMgUHJvbsOzc3RpY28gZGUgVmVudGFzIGRlIEZPUk0gKENhbnRpZGFkIGRlIFByb2R1Y2Npw7NuKQ0KDQojIyMgQ2FyZ2FyIFRpbWVTZXJpZXMgRGF0YXNldA0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgRGF0YXNldCBkZSBWZW50YXMgZGUgRm9ybXMNCmRmIDwtIHJlYWRfZXhjZWwoIkM6XFxVc2Vyc1xcQVZSSUxcXERvY3VtZW50c1xcRGF0b3NfRk9STV9WZW50YXNfRkoyMDI0ICgxKS54bHN4IikNCg0KIyBSZW1vdmVyIGNvbHVtbmFzIGlubmVjZXNhcmlhcw0KZGZfdmVudGFzIDwtIGRmWywgIW5hbWVzKGRmKSAlaW4lIGMoIkZvbGlvX0ZhY3R1cmEiLCAiTm9fQ2xpZW50ZSIsICJSZWZfY2xpZW50ZSIsICJFc3RhZG8iKV0NCg0KIyBDb252ZXJ0aXIgdmFyaWFibGVzIGNhdGVnw7NyaWNhcyBhIGZhY3RvcmVzDQpkZl92ZW50YXMkUHJvZHVjdG8gPC0gYXMuZmFjdG9yKGRmX3ZlbnRhcyRQcm9kdWN0bykNCmRmX3ZlbnRhcyRDbGllbnRlIDwtIGFzLmZhY3RvcihkZl92ZW50YXMkQ2xpZW50ZSkNCmRmX3ZlbnRhcyRDYXRlZ29yaWFfUHJvZHVjdG8gPC0gYXMuZmFjdG9yKGRmX3ZlbnRhcyRDYXRlZ29yaWFfUHJvZHVjdG8pDQoNCiMgQ29udmVydGlyIGxhIGNvbHVtbmEgRmVjaGEgYSBmb3JtYXRvIGRlIGZlY2hhDQpkZl92ZW50YXMkRmVjaGEgPC0gYXMuRGF0ZShkZl92ZW50YXMkRmVjaGEpDQoNCiMgUmVzdW1lbiBkZWwgZGF0YWZyYW1lDQpzdW1tYXJ5KGRmX3ZlbnRhcykNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEV4dHJhZXIgTWVzIHkgQcOxbyBkZSBsYSBmZWNoYQ0KZGZfdmVudGFzIDwtIGRmX3ZlbnRhcyAlPiUNCiAgbXV0YXRlKE1lc19Bw7FvID0gZm9ybWF0KEZlY2hhLCAiJW0tJVkiKSkgICU+JSAjIENvbWJpbmFyIE1lcyB5IEHDsW8gZW4gdW5hIHNvbGEgY29sdW1uYQ0KICBhcnJhbmdlKEZlY2hhKQ0KICANCiMgQ29udmVydGlyIE1lc19Bw7FvIGEgZmFjdG9yIHBhcmEgb3JkZW5hciBhZGVjdWFkYW1lbnRlDQpkZl92ZW50YXMkTWVzX0HDsW8gPC0gZmFjdG9yKGRmX3ZlbnRhcyRNZXNfQcOxbywgbGV2ZWxzID0gdW5pcXVlKGRmX3ZlbnRhcyRNZXNfQcOxbykpDQoNCiMgQWdydXBhciBwb3IgQ2xpZW50ZSwgTWVzX0HDsW8geSBjYWxjdWxhciBsYSBzdW1hIGRlIHZlbnRhcyBtZW5zdWFsZXMNCmRmX3ZlbnRhc19hZ3J1cGFkbyA8LSBkZl92ZW50YXMgJT4lDQogIGdyb3VwX2J5KE1lc19Bw7FvLCBDbGllbnRlKSAlPiUNCiAgc3VtbWFyaXNlKFRvdGFsX1ZlbnRhcyA9IHN1bShDYW50aWRhZCkpDQoNCiMgVmVyIGVsIHJlc3VsdGFkbw0KaGVhZChkZl92ZW50YXNfYWdydXBhZG8pDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgQ2FsY3VsYXIgbGFzIHZlbnRhcyB0b3RhbGVzIHBvciBwcm9kdWN0bw0KdmVudGFzX3Bvcl9jbGllbnRlIDwtIGRmX3ZlbnRhcyAlPiUNCiAgZ3JvdXBfYnkoQ2xpZW50ZSkgJT4lDQogIHN1bW1hcmlzZShWZW50YXMgPSBzdW0oQ2FudGlkYWQpKSAlPiUNCiAgYXJyYW5nZShkZXNjKFZlbnRhcykpICU+JQ0KICB0b3BfbigxMCkNCg0KIyBHcsOhZmljbyBkZSBiYXJyYXMgZGUgbG9zIHByb2R1Y3RvcyBjb24gbWF5b3JlcyB2ZW50YXMNCmdncGxvdCh2ZW50YXNfcG9yX2NsaWVudGUsIGFlcyh4ID0gcmVvcmRlcihDbGllbnRlLCBWZW50YXMpLCB5ID0gVmVudGFzKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICJvcmFuZ2UiKSArDQogIGxhYnMoeCA9ICJDbGllbnRlIiwgeSA9ICJWZW50YXMiLCB0aXRsZSA9ICJUb3AgMTAgZGUgQ2xpZW50ZSBjb24gbWF5b3JlcyB2ZW50YXMiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQoNCg0KIyBDYWxjdWxhciBsYXMgdmVudGFzIHRvdGFsZXMgcG9yIHByb2R1Y3RvDQp2ZW50YXNfcG9yX3Byb2R1Y3RvIDwtIGRmX3ZlbnRhcyAlPiUNCiAgZ3JvdXBfYnkoUHJvZHVjdG8pICU+JQ0KICBzdW1tYXJpc2UoVmVudGFzID0gc3VtKENhbnRpZGFkKSkgJT4lDQogIGFycmFuZ2UoZGVzYyhWZW50YXMpKSAlPiUNCiAgdG9wX24oNSkNCg0KIyBHcsOhZmljbyBkZSBiYXJyYXMgZGUgbG9zIHByb2R1Y3RvcyBjb24gbWF5b3JlcyB2ZW50YXMNCmdncGxvdCh2ZW50YXNfcG9yX3Byb2R1Y3RvLCBhZXMoeCA9IHJlb3JkZXIoUHJvZHVjdG8sIFZlbnRhcyksIHkgPSBWZW50YXMpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gInNreWJsdWUiKSArDQogIGxhYnMoeCA9ICJQcm9kdWN0byIsIHkgPSAiVmVudGFzIiwgdGl0bGUgPSAiVG9wIDUgZGUgcHJvZHVjdG9zIGNvbiBtYXlvcmVzIHZlbnRhcyIpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkNCg0KIyBDYWxjdWxhciBsYXMgdmVudGFzIHRvdGFsZXMgcG9yIGNhdGVnb3LDrWEgZGUgcHJvZHVjdG8NCnZlbnRhc19wb3JfY2F0ZWdvcmlhIDwtIGRmX3ZlbnRhcyAlPiUNCiAgZ3JvdXBfYnkoQ2F0ZWdvcmlhX1Byb2R1Y3RvKSAlPiUNCiAgc3VtbWFyaXNlKFZlbnRhcyA9IHN1bShDYW50aWRhZCkpICU+JQ0KICBhcnJhbmdlKGRlc2MoVmVudGFzKSkgJT4lDQogIHRvcF9uKDUpDQogIA0KIyBHcsOhZmljbyBkZSBiYXJyYXMgZGUgbGFzIGNhdGVnb3LDrWFzIGRlIHByb2R1Y3RvcyBjb24gbWF5b3JlcyB2ZW50YXMNCmdncGxvdCh2ZW50YXNfcG9yX2NhdGVnb3JpYSwgYWVzKHggPSByZW9yZGVyKENhdGVnb3JpYV9Qcm9kdWN0bywgVmVudGFzKSwgeSA9IFZlbnRhcykpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIGZpbGwgPSAibGlnaHRncmVlbiIpICsNCiAgbGFicyh4ID0gIkNhdGVnb3LDrWEgZGUgUHJvZHVjdG8iLCB5ID0gIlZlbnRhcyIsIHRpdGxlID0gIkNhdGVnb3LDrWFzIGRlIHByb2R1Y3RvcyBjb24gbWF5b3JlcyB2ZW50YXMiKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGZfdmVudGFzX2FncnVwYWRvX3RvdGFsIDwtIGRmX3ZlbnRhcyAlPiUNCiAgZ3JvdXBfYnkoTWVzX0HDsW8pICU+JQ0KICBzdW1tYXJpc2UoVG90YWxfVmVudGFzID0gc3VtKENhbnRpZGFkKSkNCg0KZGZfdmVudGFzX3RzX3RvdGFsIDwtIHRzKGRmX3ZlbnRhc19hZ3J1cGFkb190b3RhbCRUb3RhbF9WZW50YXMsIHN0YXJ0ID0gYygyMDIxLCAxKSwgZW5kID0gYygyMDIzLDEyKSwgZnJlcXVlbmN5ID0gMTIpDQoNCiMgR3JhZmljYXIgbGEgc2VyaWUgZGUgdGllbXBvDQpwbG90KGRmX3ZlbnRhc190c190b3RhbCwgbWFpbiA9ICJTZXJpZSBkZSB0aWVtcG8iLCB5bGFiID0gIkNhbnRpZGFkIiwgY29sID0gImJsdWUiKQ0KDQojIFJlYWxpemFyIGxhIGRlc2NvbXBvc2ljacOzbiBkZSBsYSBzZXJpZSBkZSB0aWVtcG8NClBvcmNvbXBvbmVudGUxIDwtIHN0YXRzOjpkZWNvbXBvc2UoZGZfdmVudGFzX3RzX3RvdGFsKQ0KDQojIEdyYWZpY2FyIGxhcyBjb21wb25lbnRlcw0KcGxvdChQb3Jjb21wb25lbnRlMSkNCmBgYA0KDQojIyMjIFBydWViYSBhZGYNCkFsIHRlbmVyIHVuIHZhbG9yIGRlIHAgbWVub3IgYSAwLjA1LCBzZSByZWNoYXphIGxhIGhpcG90w6lzaXMgbnVsYSwgcG9yIGxvIHF1ZSBleGlzdGUgZXN0YWNpb25hcmllZGFkLg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmFkZl90ZXN0MSA8LSBhZGYudGVzdChkZl92ZW50YXNfdHNfdG90YWwpDQpwcmludChhZGZfdGVzdDEpDQpgYGANCg0KDQojIyMjIFBydWViYSBCb3gtTGp1bmcNCg0KQWwgdGVuZXIgdW4gdmFsb3IgZGUgcCBtZW5vciBhIDAuMDUsIHNlIHJlY2hhemEgbGEgaGlwb3TDqXNpcyBudWxhLCBwb3IgbG8gcXVlIGV4aXN0ZSBhdXRvY29ycmVsYWNpw7NuIHNlcmlhbA0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBQcnVlYmEgZGUgQm94LUxqdW5nDQpib3hfbGp1bmdfdGVzdDEgPC0gQm94LnRlc3QoZGZfdmVudGFzX3RzX3RvdGFsLCB0eXBlID0gIkxqdW5nLUJveCIpDQpwcmludChib3hfbGp1bmdfdGVzdDEpDQoNCiMgUGxvdCBBQ0YNCmFjZl9wbG90MSA8LSBhY2YoZGZfdmVudGFzX3RzX3RvdGFsLCBtYWluID0gIkZ1bmNpw7NuIGRlIEF1dG9jb3JyZWxhY2nDs24gKEFDRikgZGUgVmVudGFzIikNCmBgYA0KDQojIyMjIEVzdGltYWNpw7NuIGRlbCBtb2RlbG8NCkRlbnRybyBkZSBsYSBlc3RpbWFjacOzbiBkZWwgbW9kZWxvLCBhbCB1dGlsaXphciBsYSBmdW5jacOzbiBhdXRvLmFyaW1hLCBsb3MgcGFyw6FtZXRyb3Mgb3B0aW1pemFkb3MgY29ycmVzcG9uZGVuIGEgMSBhdXRvY29ycmVsYWNpb24sIDAgZGlmZXJlbmNpYXMgeSAwIHByb21lZGlvcyBtw7N2aWxlcywgZGV0ZXJtaW5hbmRvIHVuIG1vZGVsbyBjb24gdW4gQUlDIGRlIDg3MyB5IFJNU0UgZGUgNDA4MzguMzMuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQptb2RlbG9fYXJpbWExIDwtIGF1dG8uYXJpbWEoZGZfdmVudGFzX3RzX3RvdGFsKQ0Kc3VtbWFyeShtb2RlbG9fYXJpbWExKQ0KDQptb2RlbG9fc2FyaW1hMiA8LSBhcmltYShkZl92ZW50YXNfdHNfdG90YWwsIG9yZGVyID0gYygwLDEsMSksIHNlYXNvbmFsID0gYygwLDEsMSkpDQpzdW1tYXJ5KG1vZGVsb19zYXJpbWEyKQ0KYGBgDQoNCiMjIyMgRGlhZ27Ds3N0aWNvcyBkZWwgTW9kZWxvDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KY2hlY2tyZXNpZHVhbHMobW9kZWxvX2FyaW1hMSkNCmBgYA0KDQojIyMgUHJlZGljY2lvbmVzIGRlIFByb2R1Y2Npw7NuIE1lbnN1YWxlcyBUb3RhbGVzIDIwMjMgeSAyMDI0DQoNCkFsIHByZWRlY2lyIGxhIHByb2R1Y2Npw7NuIG1lbnN1YWwgZGUgRm9ybSBtZWRpYW50ZSBlbCBtb2RlbG8gb2J0ZW5pZG8sIGxvcyByZXN1bHRhZG9zIG5vIG11ZXN0cmFuIHNlZ3VpciB1biBwYXRyw7NuIG8gdGVuZGVuY2lhIGJpZW4gZGVmaW5pZG8sIHJlc3VsdGFuZG8gZW4gdW4gcHJvbsOzc3RpY28gbGlnZXJhbWVudGUgY3JlY2llbnRlLCBwdWRpZW5kbyBzZXIgY29uc2lkZXJhZG8gcGFyY2lhbG1lbnRlIGZsYXQuIEFudGUgZXN0bywgZXMgbmVjZXNhcmlvIGFuYWxpemFyIHN1IGNvbXBvcnRhbWllbnRvIG1lZGlhbnRlIGVuZm9xdWVzIGFsdGVybmF0aXZvcy4gRW4gZXN0ZSBjYXNvLCBhIGNvbnRpbnVhY2nDs24gc2UgYnVzY2Fyw6EgcHJvbm9zdGljYXIgZWwgY29tcG9ydGFtaWVudG8gZGUgbGEgcHJvZHVjY2nDs24gc29saWNpdGFkYSBwb3IgbG9zIDMgcHJpbmNpcGFsZXMgY2xpZW50ZXMgZW4gRm9ybS4NCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpwcmVkaWNjaW9uZXMxIDwtIGZvcmVjYXN0KG1vZGVsb19hcmltYTEsIGggPSAyNCkgICMgUHJlZGljY2nDs24gZGUgMjQgcGVyaW9kb3MgKG1lc2VzKSBoYWNpYSBhZGVsYW50ZQ0KcHJpbnQocHJlZGljY2lvbmVzMSkNCg0KIyBHcmFmaWNhciBsYXMgcHJlZGljY2lvbmVzDQpwbG90KHByZWRpY2Npb25lczEsIG1haW4gPSAiUHJlZGljY2lvbmVzIGRlIFZlbnRhcyIpDQpgYGANCg0KIyMjIyBEZWZpbmlyIENsaWVudGVzIE3DoXMgSW1wb3J0YW50ZXMgcGFyYSBGb3JtDQpBbCByZWFsaXphciBsYSBzdW1hIGRlIGxhcyB2ZW50YXMgcGFyYSBjYWRhIHVubyBkZSBsb3MgY2xpZW50ZXMgZGUgRm9ybSwgZnVlIHBvc2libGUgaWRlbnRpZmljYXIgYSBsb3MgY2xpZW50ZXMgbcOhcyBzb2JyZXNhbGllbnRlcy4gUGFyYSBlc3RhIHNlbGVjY2nDs24gc2UgYnVzY28gb2JzZXJ2YXIgbGEgc3VtYSBkZSBzdXMgY29tcHJhcyBhIHRyYXbDqXMgZGUgbG9zIHRyZXMgYcOxb3MsIGRldGVybWluYW5kbyBzaSBleGlzdGnDsyBvIG5vIGNvbXByYXMgZGVsIGNsaWVudGUgcGFyYSB0b2RvcyBsb3MgYcOxb3MuIERlIGVzdGEgZm9ybWEsIGxvcyBjbGllbnRlcyBzZWxlY2Npb25hZG9zIHNlcsOtYW4gYXF1ZWxsb3MgY29uIGxhcyBjb21wcmFzIG3DoXMgYWx0YXMsIHBlcm8gcXVlIHRhbWJpw6luIHR1dmllcm9uIHJlbGFjacOzbiBjb21lcmNpYWwgY29uIGxhIGVtcHJlc2EgZW4gY2FkYSB1bm8gZGUgbG9zIDMgYcOxb3MgcHJldmlvcy4gRXN0b3MgY2xpZW50ZXMgc29uOiAqU3RhYmlsdXMsICoqSEVMTEEgQXV0b21vdGl2ZSBNZXhpY28sIHkgKipUb2thaSBSaWthIE1leGljbyouDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQp0b3BfY2xpZW50ZXMgPC0gZGZfdmVudGFzX2FncnVwYWRvICU+JQ0KICBncm91cF9ieShDbGllbnRlKSAlPiUNCiAgc3VtbWFyaXNlKFRvdGFsX1ZlbnRhcyA9IHN1bShUb3RhbF9WZW50YXMpKSAlPiUNCiAgdG9wX24oNSwgVG90YWxfVmVudGFzKSAlPiUNCiAgcHVsbChDbGllbnRlKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZl92ZW50YXNfYWdydXBhZG8gPC0gZGZfdmVudGFzX2FncnVwYWRvICU+JQ0KICBtdXRhdGUoQcOxbyA9IHN1YnN0cihNZXNfQcOxbywgNCwgNykpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBBZ3J1cGFyIHBvciBDbGllbnRlIHkgQcOxbyB5IGNhbGN1bGFyIGxhIHN1bWEgZGUgbGFzIHZlbnRhcw0KZGZfdmVudGFzX2FncnVwYWRvX2FudWFsIDwtIGRmX3ZlbnRhc19hZ3J1cGFkbyAlPiUNCiAgZ3JvdXBfYnkoQcOxbywgQ2xpZW50ZSkgJT4lDQogIHN1bW1hcmlzZShUb3RhbF9WZW50YXMgPSBzdW0oVG90YWxfVmVudGFzKSkNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEVuY29udHJhciBsb3MgdHJlcyBwcmluY2lwYWxlcyBjbGllbnRlcw0KdG9wX2NsaWVudGVzIDwtIGRmX3ZlbnRhc19hZ3J1cGFkb19hbnVhbCAlPiUNCiAgZ3JvdXBfYnkoQ2xpZW50ZSkgJT4lDQogIHN1bW1hcmlzZShUb3RhbF9WZW50YXMgPSBzdW0oVG90YWxfVmVudGFzKSkgJT4lDQogIHRvcF9uKDUsIFRvdGFsX1ZlbnRhcykgJT4lDQogIHB1bGwoQ2xpZW50ZSkNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEZpbHRyYXIgbG9zIGRhdG9zIHNvbG8gcGFyYSBsb3MgdHJlcyBwcmluY2lwYWxlcyBjbGllbnRlcw0KZGZfdG9wX2NsaWVudGVzIDwtIGRmX3ZlbnRhc19hZ3J1cGFkb19hbnVhbCAlPiUNCiAgZmlsdGVyKENsaWVudGUgJWluJSB0b3BfY2xpZW50ZXMpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBDcmVhciBsYSBncsOhZmljYSBkZSBiYXJyYXMNCmdncGxvdChkZl90b3BfY2xpZW50ZXMsIGFlcyh4ID0gQcOxbywgeSA9IFRvdGFsX1ZlbnRhcywgZmlsbCA9IENsaWVudGUpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsNCiAgbGFicyh0aXRsZSA9ICJWZW50YXMgZGUgRm9ybSBwb3IgQ2xpZW50ZSB5IEHDsW8iLA0KICAgICAgIHggPSAiQcOxbyIsDQogICAgICAgeSA9ICJUb3RhbCBWZW50YXMiLA0KICAgICAgIGZpbGwgPSAiQ2xpZW50ZSIpICsNCiAgdGhlbWVfbWluaW1hbCgpICsNCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gMTUpLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGZhY2U9ICJib2xkIiwgc2l6ZSA9IDE4KSkNCmBgYA0KDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIEZpbHRyYXIgbG9zIGRhdG9zIHNvbG8gcGFyYSBsb3MgdHJlcyBwcmluY2lwYWxlcyBjbGllbnRlcw0KZGZfdG9wX2NsaWVudGVzIDwtIGRmX3ZlbnRhc19hZ3J1cGFkbyAlPiUNCiAgZmlsdGVyKENsaWVudGUgJWluJSB0b3BfY2xpZW50ZXMpDQpgYGANCg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KIyBDcmVhciBEYXRhZnJhbWUgcGFyYSBjYWRhIENsaWVudGUgUHJpbmNpcGFsDQpTdGFiaWx1cyA8LSBmaWx0ZXIoZGZfdmVudGFzX2FncnVwYWRvLCBDbGllbnRlID09ICJTdGFiaWx1cyIpDQpIRUxMQSA8LSBmaWx0ZXIoZGZfdmVudGFzX2FncnVwYWRvLCBDbGllbnRlID09ICJIRUxMQSBBVVRPTU9USVZFIE1FWElDTyIpDQpUT0tBSSA8LSBmaWx0ZXIoZGZfdmVudGFzX2FncnVwYWRvLCBDbGllbnRlID09ICJUT0tBSSBSSUtBIE1FWElDTyIpDQpgYGANCg0KDQojIyMjIERhdGFzZXJpZXMgcG9yIFByaW5jaXBhbGVzIENsaWVudGVzDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KZGZfdmVudGFzX3RzMSA8LSB0cyhTdGFiaWx1cyRUb3RhbF9WZW50YXMsIHN0YXJ0ID0gYygyMDIxLCAxKSwgZW5kID0gYygyMDIzLDEyKSwgZnJlcXVlbmN5ID0gMTIpDQpkZl92ZW50YXNfdHMyIDwtIHRzKEhFTExBJFRvdGFsX1ZlbnRhcywgc3RhcnQgPSBjKDIwMjEsIDEpLCBlbmQgPSBjKDIwMjMsMTIpLCBmcmVxdWVuY3kgPSAxMikNCmRmX3ZlbnRhc190czMgPC0gdHMoVE9LQUkkVG90YWxfVmVudGFzLCBzdGFydCA9IGMoMjAyMSwgMSksIGVuZCA9IGMoMjAyMywxMiksIGZyZXF1ZW5jeSA9IDEyKQ0KYGBgDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQpkZl92ZW50YXNfdHMgPC0gbGlzdChkZl92ZW50YXNfdHMxLCBkZl92ZW50YXNfdHMyLCBkZl92ZW50YXNfdHMzKQ0KZm9yIChpIGluIDE6Mykgew0KICBjbGllbnRlIDwtIGMoIlN0YWJpbHVzIiwgIkhFTExBIEFVVE9NT1RJVkUgTUVYSUNPIiwgIlRPS0FJIFJJS0EgTUVYSUNPIilbaV0gDQogIHBsb3QoZGZfdmVudGFzX3RzW1tpXV0sIG1haW4gPSBwYXN0ZSgiU2VyaWUgZGUgdGllbXBvIC0iLCBjbGllbnRlKSwgeWxhYiA9ICJDYW50aWRhZCIsIGNvbCA9ICJibHVlIikNCn0NCg0KDQpQb3Jjb21wb25lbnRlIDwtIGxpc3QoKQ0KYGBgDQoNCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCiMgUmVhbGl6YXIgbGEgZGVzY29tcG9zaWNpw7NuIGVzdGFjaW9uYWwgcGFyYSBjYWRhIHNlcmllIGRlIHRpZW1wbw0KDQpmb3IgKGkgaW4gMTozKSB7DQogIGNsaWVudGUgPC0gYygiU3RhYmlsdXMiLCAiSEVMTEEgQVVUT01PVElWRSBNRVhJQ08iLCAiVE9LQUkgUklLQSBNRVhJQ08iKVtpXSAgDQogIFBvcmNvbXBvbmVudGVbW2ldXSA8LSBzdGF0czo6ZGVjb21wb3NlKGRmX3ZlbnRhc190c1tbaV1dKQ0KfQ0KDQoNCiMgVHJhemFyIGxhcyBjb21wb25lbnRlcyBkZSBsYSBkZXNjb21wb3NpY2nDs24gZXN0YWNpb25hbCBwYXJhIGNhZGEgY2xpZW50ZQ0KDQpmb3IgKGkgaW4gMTozKSB7DQogIGNsaWVudGUgPC0gYygiU3RhYmlsdXMiLCAiSEVMTEEgQVVUT01PVElWRSBNRVhJQ08iLCAiVE9LQUkgUklLQSBNRVhJQ08iKVtpXSAgDQogIHBsb3QoUG9yY29tcG9uZW50ZVtbaV1dKQ0KICBtdGV4dChwYXN0ZSgiRGVzY29tcG9zaWNpw7NuIC0iLCBjbGllbnRlKSwgc2lkZSA9IDMsIGxpbmUgPSAxLCBjZXggPSAxKQ0KfQ0KYGBgDQoNCiMjIyMgRGlhZ27Ds3N0aWNvcyBkZSBTZXJpZXMgZGUgVGllbXBvIC0gUG9yIENsaWVudGUNCg0KKkRpY2tleSBGdWxsZXIqDQoNCiogU3RhYmlsdXM6IEFsIHRlbmVyIHVuIHZhbG9yIGRlIHAgbWF5b3IgYSAwLjA1LCBubyBzZSByZWNoYXphIGxhIGhpcG90w6lzaXMgbnVsYSwgcG9yIGxvIHF1ZSBubyBleGlzdGUgZXN0YWNpb25hcmllZGFkLg0KDQoqIEhlbGxhOiBBbCB0ZW5lciB1biB2YWxvciBkZSBwIG1heW9yIGEgMC4wNSwgbm8gc2UgcmVjaGF6YSBsYSBoaXBvdMOpc2lzIG51bGEsIHBvciBsbyBxdWUgbm8gZXhpc3RlIGVzdGFjaW9uYXJpZWRhZC4NCg0KKiBUb2thaSBSaWthOiBBbCB0ZW5lciB1biB2YWxvciBkZSBwIG1heW9yIGEgMC4wNSwgbm8gc2UgcmVjaGF6YSBsYSBoaXBvdMOpc2lzIG51bGEsIHBvciBsbyBxdWUgbm8gZXhpc3RlIGVzdGFjaW9uYXJpZWRhZC4NCg0KKkJveCAtIExqdW5nKg0KDQoqIFN0YWJpbHVzOiBBbCB0ZW5lciB1biB2YWxvciBkZSBwIG1heW9yIGEgMC4wNSwgbm8gc2UgcmVjaGF6YSBsYSBoaXBvdMOpc2lzIG51bGEsIHBvciBsbyBxdWUgbm8gZXhpc3RlIGF1dG9jb3JyZWxhY2nDs24uDQoNCiogSGVsbGE6IEFsIHRlbmVyIHVuIHZhbG9yIGRlIHAgbWVub3IgYSAwLjA1LCBzZSByZWNoYXphIGxhIGhpcG90w6lzaXMgbnVsYSwgcG9yIGxvIHF1ZSBleGlzdGUgYXV0b2NvcnJlbGFjacOzbi4NCg0KKiBUb2thaSBSaWthOiBBbCB0ZW5lciB1biB2YWxvciBkZSBwIG1lbm9yIGEgMC4wNSwgc2UgcmVjaGF6YSBsYSBoaXBvdMOpc2lzIG51bGEsIHBvciBsbyBxdWUgZXhpc3RlIGF1dG9jb3JyZWxhY2nDs24uDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojIFBydWViYSBkZSBEaWNrZXktRnVsbGVyIHBhcmEgY2FkYSBzZXJpZSBkZSB0aWVtcG8NCmZvciAoaSBpbiAxOjMpIHsNCiAgY2xpZW50ZSA8LSBjKCJTdGFiaWx1cyIsICJIRUxMQSBBVVRPTU9USVZFIE1FWElDTyIsICJUT0tBSSBSSUtBIE1FWElDTyIpW2ldIA0KICBjYXQoIkNsaWVudGU6IiwgY2xpZW50ZSwgIlxuIikNCiAgYWRmX3Jlc3VsdCA8LSBhZGYudGVzdChkZl92ZW50YXNfdHNbW2ldXSkNCiAgcHJpbnQoYWRmX3Jlc3VsdCkNCiAgY2F0KCJcbiIpDQp9DQoNCiMgUHJ1ZWJhIGRlIEJveC1ManVuZyBwYXJhIGNhZGEgc2VyaWUgZGUgdGllbXBvDQpmb3IgKGkgaW4gMTozKSB7DQogIGNsaWVudGUgPC0gYygiU3RhYmlsdXMiLCAiSEVMTEEgQVVUT01PVElWRSBNRVhJQ08iLCAiVE9LQUkgUklLQSBNRVhJQ08iKVtpXSANCiAgY2F0KCJDbGllbnRlOiIsIGNsaWVudGUsICJcbiIpDQogIGJveF9sanVuZ190ZXN0IDwtIEJveC50ZXN0KGRmX3ZlbnRhc190c1tbaV1dLCB0eXBlID0gIkxqdW5nLUJveCIpDQogIHByaW50KGJveF9sanVuZ190ZXN0KQ0KICBjYXQoIlxuIikNCn0NCg0KIyBHcmFmaWNhciBsYSBmdW5jacOzbiBkZSBhdXRvY29ycmVsYWNpw7NuIHBhcmEgY2FkYSBzZXJpZSBkZSB0aWVtcG8NCmZvciAoaSBpbiAxOjMpIHsNCiAgY2xpZW50ZSA8LSBjKCJTdGFiaWx1cyIsICJIRUxMQSBBVVRPTU9USVZFIE1FWElDTyIsICJUT0tBSSBSSUtBIE1FWElDTyIpW2ldICANCiAgY2F0KCJDbGllbnRlOiIsIGNsaWVudGUsICJcbiIpDQogIGFjZl9wbG90IDwtIGFjZihkZl92ZW50YXNfdHNbW2ldXSwgcGxvdCA9IEZBTFNFKSAgDQogIHBsb3QoYWNmX3Bsb3QpICANCiAgbXRleHQocGFzdGUoY2xpZW50ZSksIHNpZGUgPSAzLCBsaW5lID0gMSwgY2V4ID0gMSkNCiAgY2F0KCJcbiIpDQp9DQpgYGANCg0KIyMjIyBFc3RpbWFjacOzbiBkZWwgTW9kZWxvIFNBUklNQQ0KDQpMYSBlc3RpbWFjacOzbiBkZSBsb3MgbW9kZWxvcyBwYXJhIGNhZGEgdW5vIGRlIGxvcyBwcmluY2lwYWxlcyBjbGllbnRlcyBzZSByZWFsaXrDsyBjb24gYmFzZSBlbiBsbyByZXZpc2FkbyBwcmV2aWFtZW50ZSB5IGxvcyBwYXLDoW1ldHJvcyBlbXBsZWFkb3Mgc2UgZWxpZ2llcm9uIGRlYmlvIGEgcXVlIGxhIHNlcmllIHRlbXBvcmFsIHRpZW5lIGNpZXJ0YXMgY2FyYWN0ZXLDrXN0aWNhcyBwYXJ0aWN1bGFyZXMgcXVlIG5vIHNvbiBiaWVuIG1hbmVqYWRhcyBwb3IgbG9zIG3DqXRvZG9zIGF1dG9tw6F0aWNvcyBjb21vIGFsZ3Vub3MgY2FtYmlvcyBlc3RydWN0dXJhbGVzIG8gY29uIHBhdHJvbmVzIHJlbGF0aXZhbWVudGUgY29tcGxlam9zLiBMbyBhbnRlcmlvciBzZSByZWFsaXrDsyBjb24gZWwgZmluIGRlIG9ic2VydmFyIHVuIGNvbXBvcnRhbWllbnRvIG3DoXMgZGVmaW5pZG8geSBwcmVjaXNvIGEgdHJhdsOpcyBkZSBsb3MgbWVzZXMuIFBvciBsbyB0YW50bywgc2Ugb3B0w7MgcG9yIHJlYWxpemFyIHVuIG1vZGVsbyBlc3RhY2lvbmFsIChTQVJJTUEpIHBhcmEgYWRhcHRhcnNlIGFsIGNvbXBvcnRhbWllbnRvIGVudHJlIG1lc2VzLiBObyBvYnN0YW50ZSwgYSBmdXR1cm8gc2UgcGxhbmVhIHJlYWxpemFyIG90cm9zIG1vZGVsb3MgcHJlZGljdGl2b3MgY29uIGVsIGZpbiBkZSBvcHRpbWl6YXIgbG9zIHJlc3VsdGFkb3Mgb2J0ZW5pZG9zLg0KDQoqIEVsIGFqdXN0ZSBkZSBwYXLDoW1ldHJvcyBwYXJhIGxhIHByb2R1Y2Npw7NuIHNvbGljaXRhZGEgcG9yIFN0YWJpbHVzIGZ1ZSAoMCwwLDEpKDAsMCwxKSwgYWp1c3RhbmRvIHVuIG1vZGVsbyBTQVJJTUEsIGVzIGRlY2lyLCBxdWUgY29uc2lkZXJhIGVsIGNvbXBvbmVudGUgZXN0YWNpb25hbCwgY29uIDEgcHJvbWVkaW8gbcOzdmlsIHRhbnRvIGVuIGVsIGNvbXBvbmVudGUgb3JkZXIgY29tbyBlbiBlbCBzZWFzb25hbC4NCg0KKiBFbCBhanVzdGUgZGUgcGFyw6FtZXRyb3MgcGFyYSBsYSBwcm9kdWNjacOzbiBzb2xpY2l0YWRhIHBvciBIZWxsYSBBdXRvbW90aXZlIGZ1ZSAoMCwwLDEpKDAsMCwxKSwgYWp1c3RhbmRvIHVuIG1vZGVsbyBTQVJJTUEsIGVzIGRlY2lyLCBxdWUgY29uc2lkZXJhIGVsIGNvbXBvbmVudGUgZXN0YWNpb25hbCwgY29uIDEgcHJvbWVkaW8gbcOzdmlsIHRhbnRvIGVuIGVsIGNvbXBvbmVudGUgb3JkZXIgY29tbyBlbiBlbCBzZWFzb25hbC4NCg0KKiBFbCBhanVzdGUgZGUgcGFyw6FtZXRyb3MgcGFyYSBsYSBwcm9kdWNjacOzbiBzb2xpY2l0YWRhIHBvciBUb2thaSBSaWthIGZ1ZSAoMCwxLDApKDAsMCwxKSwgYWp1c3RhbmRvIHVuIG1vZGVsbyBTQVJJTUEsIGVzIGRlY2lyLCBxdWUgY29uc2lkZXJhIGVsIGNvbXBvbmVudGUgZXN0YWNpb25hbCwgY29uIDEgZGlmZXJlbmNpYSBlbiBlbCBjb21wb25lbnRlIG9yZGVyLCB5IDEgcHJvbWVkaW8gbcOzdmlsIGVuIGVsIGNvbXBvbmVudGUgc2Vhc29uYWwuDQoNCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQojU3RhYmlsdXMNCiMgQWp1c3RhciBlbCBtb2RlbG8gQVJJTUEgYSBsYSBzZXJpZSB0ZW1wb3JhbA0KbW9kZWxvX2FyaW1hX3RzMSA8LSBhcmltYShkZl92ZW50YXNfdHMxLCBvcmRlciA9IGMoMCwgMCwgMSksIHNlYXNvbmFsID0gYygwLCAwLCAxKSkNCnN1bW1hcnkobW9kZWxvX2FyaW1hX3RzMSkNCg0KDQojSEVMTEENCiMgQWp1c3RhciBlbCBtb2RlbG8gQVJJTUEgYSBsYSBzZXJpZSB0ZW1wb3JhbA0KbW9kZWxvX2FyaW1hX3RzMiA8LSBhcmltYShkZl92ZW50YXNfdHMyLCBvcmRlciA9IGMoMCwgMCwgMSksIHNlYXNvbmFsID0gYygwLCAwLCAxKSkNCnN1bW1hcnkobW9kZWxvX2FyaW1hX3RzMikNCg0KDQoNCiNUT0tBSSBSSUtBDQojIEFqdXN0YXIgZWwgbW9kZWxvIEFSSU1BIGEgbGEgc2VyaWUgdGVtcG9yYWwNCm1vZGVsb19hcmltYV90czMgPC0gYXJpbWEoZGZfdmVudGFzX3RzMywgb3JkZXIgPSBjKDAsIDEsIDApLCBzZWFzb25hbCA9IGMoMCwgMCwgMSkpDQpzdW1tYXJ5KG1vZGVsb19hcmltYV90czMpDQoNCmBgYA0KDQojIyMgUHJlZGljY2lvbmVzIE1lbnN1YWxlcyBwYXJhIGxvcyAzIENsaWVudGVzIHByaW5jaXBhbGVzIDIwMjMgeSAyMDI0DQoNCiogRGUgYWN1ZXJkbyBhbCBtb2RlbG8gU0FSSU1BLCBsYSBwcm9kdWNjacOzbiBzb2xpY2l0YWRhIHBvciBTdGFiaWx1cyB0aWVuZSB1biBwYXRyw7NuIGluY3JlbWVudG8geSBkZXNjZW5zbywgbG8gY3VhbCBwdWVkZSBzZXIgaW5jaWVydG8gcGFyYSBGb3JtIGFsIHNlciBzdSBjbGllbnRlIHByaW5jaXBhbC4gQW50ZSBlc3RvLCBwdWVkZSBzdXBvbmVyc2UgY2llcnRvIG5pdmVsIGRlIHJpZXNnbywgZXhpc3RpZW5kbyB1biBkZWNyZWNpbWllbnRvIGNvbnNpZGVyYWJsZSBjb24gcmVzcGVjdG8gYSBzdSBkZW1hbmRhIGFsIGZpbmFsIGRlIGNhZGEgYcOxby4NCg0KKiBEZSBhY3VlcmRvIGFsIG1vZGVsbyBTQVJJTUEsIGxhIHByb2R1Y2Npw7NuIHNvbGljaXRhZGEgcG9yIEhlbGxhIEF1dG9tb3RpdmUgc3Vwb25kcsOhIHVuIGNvbXBvcnRhbWllbnRvIGNvbiBsaWdlcm8gY3JlY2ltaWVudG8sICBjb24gdW4gdmFsbGUgZW4gSnVuaW8gZGVsIDIwMjUsIGNvbnRpbnVhbmRvIGNvbiBsYSB0ZW5kZW5jaWEgZGUgY3JlY2ltaWVudG8gZW4gbG9zIG5pdmVsZXMgZGUgcHJvZHVjY2nDs24gZHVyYW50ZSBlbCByZXN0byBkZWwgYcOxby4NCg0KKiBEZSBhY3VlcmRvIGFsIG1vZGVsbyBBUklNQSwgbGEgcHJvZHVjY2nDs24gc29saWNpdHVkYSBwb3IgVG9rYWkgUmlrYSBzdXBvbmRyw6EgdW4gY29tcG9ydGFtaWVudG8gY29uIGxpZ2VybyBkZWNyZWNpbWllbnRvIGNvbnN0YW50ZSwgY29uIHBpY29zIG3DrW5pbW9zIGVuIGNvbXBhcmFjacOzbiBjb24gZWwgY29tcG9ydGFtaWVudG8gZGVsIHJlc3RvIGRlbCBhw7FvLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KI1N0YWJpbHVzDQojIFJlYWxpemFyIHByZWRpY2Npb25lcyBjb24gZWwgbW9kZWxvIGFqdXN0YWRvDQpwcmVkaWNjaW9uZXMgPC0gZm9yZWNhc3QobW9kZWxvX2FyaW1hX3RzMSwgaCA9IDEyKQ0KcHJlZGljY2lvbmVzDQojIEdyYWZpY2FyIGxhcyBwcmVkaWNjaW9uZXMNCnBsb3QocHJlZGljY2lvbmVzLCBtYWluID0gIlByZWRpY2Npb25lcyBkZSBWZW50YXMgLSBTVEFCSUxVUyIsIHhsYWIgPSAiVGllbXBvIiwgeWxhYiA9ICJDYW50aWRhZCIpDQoNCg0KI0hFTExBDQojIFJlYWxpemFyIHByZWRpY2Npb25lcyBjb24gZWwgbW9kZWxvIGFqdXN0YWRvDQpwcmVkaWNjaW9uZXMgPC0gZm9yZWNhc3QobW9kZWxvX2FyaW1hX3RzMiwgaCA9IDEyKQ0KcHJlZGljY2lvbmVzDQojIEdyYWZpY2FyIGxhcyBwcmVkaWNjaW9uZXMNCnBsb3QocHJlZGljY2lvbmVzLCBtYWluID0gIlByZWRpY2Npb25lcyBkZSBWZW50YXMgLSBIRUxMQSBBVVRPTU9USVZFIiwgeGxhYiA9ICJUaWVtcG8iLCB5bGFiID0gIkNhbnRpZGFkIikNCg0KDQojVE9LQUkgUklLQQ0KIyBSZWFsaXphciBwcmVkaWNjaW9uZXMgY29uIGVsIG1vZGVsbyBhanVzdGFkbw0KcHJlZGljY2lvbmVzIDwtIGZvcmVjYXN0KG1vZGVsb19hcmltYV90czMsIGggPSAxMikNCnByZWRpY2Npb25lcw0KIyBHcmFmaWNhciBsYXMgcHJlZGljY2lvbmVzDQpwbG90KHByZWRpY2Npb25lcywgbWFpbiA9ICJQcmVkaWNjaW9uZXMgZGUgVmVudGFzIC0gVE9LQUkgUklLQSIsIHhsYWIgPSAiVGllbXBvIiwgeWxhYiA9ICJDYW50aWRhZCIpDQpgYGANCg0KDQojICoqUHJpbmNpcGFsZXMgSGFsbGF6Z29zKioNCiMjICpTaXR1YWNpw7NuIFByb2JsZW1hIDE6IEluY2VydGlkdW1icmUgZW4gZGVtYW5kYSBkZSBsYSBpbmR1c3RyaWEqDQoNCiogRWwgcHJvbsOzc3RpY28gZGUgdmVudGFzIGRlIEZPUk0sIGVuIHTDqXJtaW5vcyBtb25ldGFyaW9zLCBmdWUgbWVkaWFudGUgZWwgbW9kZWxvIGRlIHN1YXZpemFjacOzbiBleHBvbmVuY2lhbCwgZWwgY3VhbCByZXN1bHTDsyBlbiB1bmEgdGVuZGVuY2lhIGNyZWNpZW50ZSBlbiBsYXMgdmVudGFzIGZ1dHVyYXMgYSB0cmF2w6lzIGRlIGxvcyBzaWd1aWVudGVzIG1lc2VzLiBBIHBlc2FyIGRlIGVzdG8sIHNlIHByZXNlbnRhbiB2YXJpb3MgdmFsbGVzIGR1cmFudGUgZGljaG8gcGVyaW9kbyBsbyBxdWUgaW1wbGljYSBjaWVydG8gY29tcG9ydGFtaWVudG8gZW4gbG9zIGNsaWVudGVzIGRlIGxhIGluZHVzdHJpYSBhdXRvbW90cml6IHkgc3VzIGRlcml2YWRvcy4gDQoNCiogRWwgcHJvbsOzc3RpY28gZGUgdmVudGFzIGRlIEZPUk0sIGVuIHTDqXJtaW5vcyBkZSBjYW50aWRhZCBkZSBwcm9kdWN0b3MsIGRldGVybWluYSBxdWUgbGFzIHZlbnRhcyBnZW5lcmFsZXMgdGVuZHLDoW4gY2llcnRvIGRlY2FpbWllbnRvIHBlcm8gY29udGludWFyw6EgY29uIHVuIGF1bWVudG8gbWVuc3VhbC4gRXN0byBzZSBtdWVzdHJhIGNvbiBsYSBwcmVkaWNjacOzbiBkZSBsb3MgdHJlcyBwcmluY2lwYWxlcyBjbGllbnRlcyBjbGF2ZXMgZGUgRk9STSBxdWUgdGllbmVuIHByZXNlbmNpYSBjYWRhIGHDsW8gZW4gbGFzIHZlbnRhcywgeWEgcXVlIGxhcyB0cmVzIGVtcHJlc2FzIHRpZW5lbiAgdW4gY29tcG9ydGFtaWVudG8gcXVlIHN1YmUgeSBiYWphIHBlcm8gc2UgZGlmZXJlbmNpYSBlbiBsYSBtZWRpZGEgZGUgbHMgcGljb3MgeSB2YWxsZXMuIERlIGlndWFsIG1hbmVyYSwgc2UgbXVlc3RyYSBxdWUgU3RhYmlsdXMgdGVuZHLDoSB1bmEgcmVkdWNjacOzbiBlbiBzdSBuaXZlbCBkZSB2ZW50YXMgZW4gMjAyNTsgYWRlbcOhcyBjb2luY2lkZW4gZW4gcXVlIGhhYnLDoSBlbiBzdXMgdmVudGFzIGRlbCAyMDI1IGVuIGNvbXBhcmFjacOzbiBjb24gYcOxb3MgYW50ZXJpb3Jlcy4gUGVybyBlc3RvIG5vIGltcGxpY2EgcXVlIHNpZ2EgZXhpc3RpZW5kbyBjaWVydG8gYXVtZW50byBsaWdlcm8gY29uZm9ybWUgcGFzYSBjYWRhIHBlcmlvZG8uIEFjb3JkZSBhIGVzdG8sIHNlIHJlcXVpZXJlIGVzdGFibGVjZXIgZXN0cmF0ZWdpYXMgcGFyYSByZWR1Y2lyIGxvcyBlZmVjdG9zIGRlIGVzdGEgZGVwZW5kZW5jaWEgeSBhcHJvdmVjaGFyIGVsIGluY3JlbWVudG8gZGUgZGVtYW5kYSBnZW5lcmFsaXphZG8uDQoNCiMjICpTaXR1YWNpw7NuIFByb2JsZW1hIDI6IEFsdGEgcm90YWNpw7NuIGRlIHBlcnNvbmFsKg0KDQoqIEV4aXN0ZSB1biBkZXNhZsOtbyBkZSBSZXRlbmNpw7NuIGVuIEVtcGxlYWRvcyBKw7N2ZW5lcyB5IFNvbHRlcm9zLCB5YSBxdWUgZWwgYW7DoWxpc2lzIGRlIGNsdXN0ZXJpbmcgcmV2ZWxhIHF1ZSBsYSBtYXlvcsOtYSBkZSBsb3MgZW1wbGVhZG9zIHF1ZSBhYmFuZG9uYW4gRm9ybSByZXN1bHTDsyBlbiAzIHBlcmZpbGVzIGRlIGVkYWQuIEVzdG8gcGVybWl0acOzIG9ic2VydmFyIHF1ZSBsYSAqKm1heW9yIHBhcnRlIGRlIGVtcGxlYWRvcyBxdWUgdGVybWluYW4gc3UgcmVsYWNpw7NuIGxhYm9yYWwgZW4gbGEgZW1wcmVzYSBzb24gasOzdmVuZXMgc29sdGVyb3MgbyBlbiB1bmnDs24gbGlicmUqKiwgY29uc2lkZXJhbmRvIGxhIGxpYmVydGFkIGJyaW5kYWRhIHBvciBsYXMgcG9zaWJsZXMgb3BvcnR1bmlkYWRlcyBkaXNwb25pYmxlcyB5IGxhIGZhbHRhIGRlIHVuIGNvbXByb21pc28gZmFtaWxpYXIgKHJlc3BvbnNhYmlsaWRhZCBkZSBsYSBzaXR1YWNpw7NuIGZpbmFuY2llcmEgZGUgbGEgZmFtaWxpYSkuIEVuIGVzdG9zIHBlcmZpbGVzIGRlIGFiYWRvbm8sIHNlIGlkZW50aWZpY2EgdGFtYmnDqW4gZWwgbWF5b3IgYWJhbmRvbm8gYWwgcmVzaWRpciBlbiBBcG9kYWNhIChwcmluY2lwYWwgbXVuaWNpcGlvIGRlIHBhcnF1ZXMgaW5kdXN0cmlhbGVzKSB5IHNlciBtdWplcmVzIGpvdmVuZXMgKHBvc2libGVtZW50ZSBidXNjYW5kbyBvcG9ydHVuaWRhZGVzIGRlIGNyZWNpbWllbnRvKS4NCg0KKiBMYSAqKmZ1ZXJ6YSBsYWJvcmFsKiogZGUgRm9ybSBlc3TDoSBjb25mb3JtYWRhIHByaW5jaXBhbG1lbnRlIHBvciBlbXBsZWFkb3MgY29uIGxhcyBzaWd1aWVudGVzIGNhcmFjdGVyw61zdGljYXM6IE11amVyZXMsIHJlc2lkZW50ZXMgZGUgQXBvZGFjYSwgZWR1Y2FjacOzbiBzZWN1bmRhcmlhLCBjb24gbGEgcHJpbmNpcGFsIHJhesOzbiBwYXJhIHRyYWJhamFyIHNpZW5kbyBsYSB1YmljYWNpw7NuIGRlIGxhIGVtcHJlc2EuDQoNCiogRWwgYW7DoWxpc2lzIGRlIFRleHQgTWluaW5nIHNvYnJlIGxvcyBjb21lbnRhcmlvcyBkZSBsb3MgZW1wbGVhZG9zIHBvciBtZWRpbyBkZSBsYXMgKipmcmVjdWVuY2lhcyoqIGRldGVybWluw7MgcXVlIGxvcyBwcmluY2lwYWxlcyBmYWN0b3JlcyBuZWdhdGl2b3MgYWwgdHJhYmFqYXIgZW4gRm9ybSBzb246ICoqY2Fsb3IsIHNhbGFyaW8sIHByZXN0YWNpb25lcyB5IGVzdHLDqXMqKi4gQXNpbWlzbW8sIGVsICoqQW7DoWxpc2lzIGRlIFNlbnRpbWllbnRvcyoqIHRhbWJpw6luIHJlbGFjaW9uw7MgcXVlIGVzdG9zIGNvbWVudGFyaW9zIG5lZ2F0aXZvcyB0aWVuZW4gdW5hIHJlbGFjacOzbiBjb24gbGEgcHJpbmNpcGFsIGVtb2Npw7NuIG5lZ2F0aXZhIHNpZW5kbyBsYSAqKmFuc2llZGFkKiouIFBvciBsbyB0YW50bywgc2UgZGViZSBtZWpvcmFyIGVsIGJpZW5lc3RhciBsYWJvcmFsIGFib3JkYW5kbyBlc3RhcyBwcmVvY3VwYWNpb25lcyBwb3IgbWVkaW8gZGUgbGEgaW1wbGVtZW50YWNpw7NuIGRlIG1lZGlkYXMgcGFyYSByZWR1Y2lyIGVsIGVzdHLDqXMsIG1lam9yYXIgbGFzIGNvbmRpY2lvbmVzIGRlIHRyYWJham8geSBvZnJlY2VyIGNvbXBlbnNhY2lvbmVzIGNvbXBldGl0aXZhcy4NCg0KKiBFbCBtb2RlbG8gbcOhcyBhcHJvcGlhZG8gcGFyYSBhbmFsaXphciBlbCBhYmFuZG9ubyBkZSBsb3MgZW1wbGVhZG9zIGVuIEZvcm0gY29ycmVzcG9uZGUgYSAqKk5haXZlIEJheWVzKiosIGRlYmlkbyBhIHN1IGNhcGFjaWRhZCBkZSBhbmFsaXphciBjYWRhIGZhY3RvciBkZSAqKmZvcm1hIGluZGVwZW5kaWVudGUqKiwgYXPDrSBjb21vIHN1IGRlc2VtcGXDsW8gY29uc2lkZXJhYmxlIGVuIGxhcyBtw6l0cmljYXMuIEFjY3VyYWN5OjAuIDgwLCBLYXBwYTogLjI5IHkgQVVDOiAwLjc3Lg0KDQoqIERlIGFjdWVyZG8gYWwgbW9kZWxvIE5haXZlIEJheWVzLCBsYXMgdmFyaWFibGVzIGV4cGxpY2F0aXZhcyBlc3RpbWFuIGxhcyBzaWd1aWVudGVzICoqY3VhbGlkYWRlcyBwYXJhIGRldGVybWluYXIgbGEgcGVybWFuZW5jaWEvcmV0ZW5jacOzbioqIGRlIGxvcyBlbXBsZWFkb3MgZW4gRm9ybTogRWwgZW1wbGVhZG8gZXMgbXVqZXIsIGVzdMOhIGVuIHVuYSBlZGFkIGFkdWx0YSAobWVkaWEgMzUpLCB0cmFiYWrDsyB5YSBtw6FzIGRlIHVuIGHDsW8gZW4gbGEgZW1wcmVzYSAocHJvbWVkaW8gMTQgbWVzZXMpLCBjb25zaWRlcmEgcXVlIHJlY2liZSB1bmEgcmV0cmlidWNpw7NuIGp1c3RhIGRlIHNhbGFyaW8geSBwcmVzdGFjaW9uZXMgcGFyYSBzdXMgbGFib3JlcyByZWFsaXphZGFzLCBwZXJjaWJlbiBzdSBlc3Ryw6lzIGJham8geSB1bmEgYnVlbmEgZmFjaWxpZGFkIGRlIHRyYXNsYWRvLg0KDQoNCiMjIFJlbGFjacOzbiBkZSBsb3MgcmVzdWx0YWRvcyBlc3RpbWFkb3MgZGUgTmVhcnNob3JpbmcgY29uIGxhcyBzaXR1YWNpb25lcyBwcm9ibGVtYXMuDQpFbCBhY29udGVjaW1pZW50byBkZWwgTmVhcnNob3Jpbmcgc2Vyw6EgY2FzaSBudWxvIGVuIE3DqXhpY28sIHlhIHF1ZSBzZSBlc3RpbWEgcXVlIG9jdXJyZSBwZXJvIGVuIHVuIG5pdmVsIHBvY28gc2lnbmlmaWNhdGl2byBwYXJhIGxhIGluZHVzdHJpYSBlbiBtZW5vciBtZWRpZGEuIEF1bnVxZSBleGlzdGUgY2llcnRhIGluY2VydGlkdW1icmUgZWwgcmVzcGVjdG8gZGVwZW5kaWVuZG8gY2llcnRvcyBmYWN0b3JlcyBleHRlcm5vcyBwb2zDrXRpY29zIHkgZWNvbsOzbWljb3MuIEFjb3JkZSBhIGVzdG8sIHNlIGVzdGltYSBxdWUgdGVuZHLDoSB1biBpbXBhY3RvIG5lZ2F0aXZvIGVuIGxhIHByb2R1Y2Npw7NuIGRlIGVtcGFxdWVzIGRlIGNhcnTDs24gcGFyYSBhdXRvcGFydGVzIGVuIE3DqXhpY28geSwgcG9yIGVuZGUsIGVuIEZPUk0sIHB1ZXN0byBxdWUgZXN0ZSBlZmVjdG8gcG9kcsOtYSBhdW1lbnRhciBsYSByb3RhY2nDs24gZGUgZW1wbGVhZG9zIHkgZGlzbWludWlyIGxhIGRlbWFuZGEgZGUgZW1wYXF1ZXMgZGUgY2FydMOzbi4gTGEgcHJvYmFiaWxpZGFkIGRlbCBhdW1lbnRvIGRlIGxhIHJvdGFjacOzbiBkZSBlbXBsZWFkb3Mgc2Vyw61hIG3DoXMgYWx0YSBzaSBGT1JNIG5vIG9mcmVjZSBjb25kaWNpb25lcyBkZSB0cmFiYWpvIGF0cmFjdGl2YXMgZW4gcmVsYWNpw7NuIGEgc3VzIGNvbXBldGlkb3JlcyB5L28gc2kgbm8gdGllbmUgdW4gcGxhbiBpbnRlZ3JhbCBkZSBjcmVjaW1pZW50byBjbGFyby4gQXNpbWlzbW8sIGFjb3JkZSBhIGxhcyBlc3RpbWFjaW9uZXMgZGUgbGFzIHZlbnRhcyBkZWwgdG9wIDMgZGUgY2xpZW50ZXMgZGUgRk9STSBqdW50byBjb24gbGEgcHJlZGljY2nDs24gZGUgdmVudGFzIGdlbmVyYWwgZGUgbGEgZW1wcmVzYSwgc2UgZXN0aW1hIHF1ZSBoYWJyw6EgdW5hIGNpZXJ0byBjcmVjaW1pZW50byBlbiBzdXMgdmVudGFzIGRlIHByb2R1Y3RvIHkgbW9uZXRhcmlhcyBsbyBxdWUgaW1wbGljYSBxdWUgbGEgZW1wcmVzYSBzZWEgbcOhcyBzdXNjZXB0aWJsZSBhIGxhcyBmbHVjdHVhY2lvbmVzIGVuIGxhIGRlbWFuZGEgZGVsIG1lcmNhZG8gbG9jYWw7IGFkZW3DoXMgZGUgdGVuZXIgY2llcnRhcyBjb21wbGljYWNpb25lcyBjb24gZW1wcmVzYXMgaW50ZXJuYWNpb25hbGVzIGNvbiBmdWVydGUgcG9zaWNpb25hbWllbnRvIHkvbyBxdWUgdXRpbGl6YW4gdW5hIGVzdHJhdGVnaWEgZGUgcmVkdWNjacOzbiBkZSBjb3N0b3MuIFBvciBsbyB0YW50bywgc2UgcmVjb21pZW5kYSBkZXNhcnJvbGxhciBwbGFuZXMgZGUgY29udGluZ2VuY2lhIHBhcmEgYWRhcHRhcnNlIGEgZGlmZXJlbnRlcyBlc2NlbmFyaW9zIHkgZ2VuZXJhciBlc3RyYXRlZ2lhcyBwYXJhIG1pdGlnYXIgbGEgYWx0YSBkZXBlbmRlbmNpYSBhIGxvcyB0cmVzIHByaW5jaXBhbGVzIGNsaWVudGVzIHlhIHF1ZSwgcmVwcmVzZW50YW4gYXByb3hpbWFkYW1lbnRlIGVsIDcwJSBkZSBsYXMgdmVudGFzIHRvdGFsZXMgbG8gcXVlIGltcGxpY2EgZ3JhdmVzIGFmZWN0YWNpb25lcyBkZSByZW50YWJpbGlkYWQgYSBsYSBlbXByZXNhLg0KDQojICoqUmVmZXJlbmNpYXMqKg0KDQoqIEZvcm0uICgyMDIxKSAqVGhlIGZvcm0gd2F5Ki4gaHR0cHM6Ly9mb3JtLmNvbS5teC90aGUtZm9ybS13YXkvaHR0cHM6Ly9mb3JtLmNvbS5teC90aGUtZm9ybS13YXkvDQoNCiogKk1lcmNhZG8gZGUgY2FqYXMgZGUgY2FydMOzbiBjb3JydWdhZG8sIHRhbWHDsW8sIGN1b3RhIDIwMjQtMjAzMiouIChzLiBmLikuIEV4cGVydCBNYXJrZXQgUmVzZWFyY2guIGh0dHBzOi8vd3d3LmluZm9ybWVzZGVleHBlcnRvcy5jb20vaW5mb3JtZXMvbWVyY2Fkby1kZS1jYWphcy1kZS1jYXJ0b24tY29ycnVnYWRvDQoNCiogTnV2b0NhcmdvLiAoMjAyNCkuICpOZWFyc2hvcmluZyB0byBNZXhpY286IEEgZ29sZGVuIG9wcG9ydHVuaXR5IGZvciBhdXRvLCBwYWNrYWdpbmcsIGFuZCBlbGVjdHJvbmljcyouIE51dm9DYXJnby4gUmVjdXBlcmFkbyBlbCA1IGRlIG1hcnpvIGRlIDIwMjQgZGU6IGh0dHBzOi8vd3d3Lm51dm9jYXJnby5jb20vZW4vY29udGVudC9ibG9nLXBvc3RzL25lYXJzaG9yaW5nLXRvLW1leGljby1hLWdvbGRlbi1vcHBvcnR1bml0eS1mb3ItYXV0by1wYWNrYWdpbmctYW5kLWVsZWN0cm9uaWNzDQoNCiogUGF0aWwsIFAuICgyMDE4LCBNYXJjaCAyMykuICpXaGF0IGlzIEV4cGxvcmF0b3J5IERhdGEgQW5hbHlzaXM/IC0gVG93YXJkcyBEYXRhIFNjaWVuY2UqLiBNZWRpdW0uIGh0dHBzOi8vdG93YXJkc2RhdGFzY2llbmNlLmNvbS9leHBsb3JhdG9yeS1kYXRhLWFuYWx5c2lzLThmYzFjYjIwZmQxNQ0KDQoqIFBvcnRhbGVkb21leC4gKDIwMTkpLiAqT2N1cGEgTcOpeGljbyBzZXh0byBsdWdhciBhIG5pdmVsIG11bmRpYWwgZW4gY29uc3VtbyBkZSBwYXBlbCouIERpYXJpbyBQb3J0YWwuIGh0dHBzOi8vZGlhcmlvcG9ydGFsLmNvbS8yMDE5LzExLzA0L29jdXBhLW1leGljby1zZXh0by1sdWdhci1hLW5pdmVsLW11bmRpYWwtZW4tY29uc3Vtby1kZS1wYXBlbC8NCg0KKiBRdWludGFuYSwgRi4gKDIwMjIsIDI4IG9jdHVicmUpLiAqTWVyY2FkbyBkZSBjYXJ0w7NuIHkgcGFwZWwgbXVlc3RyYSBjcmVjaWVudGUgZGluYW1pc21vKi4gSW5vdmFjb3IuIGh0dHBzOi8vaW5vdmFjb3IubXgvbWVyY2Fkby1kZS1jYXJ0b24teS1wYXBlbC1tdWVzdHJhLWNyZWNpZW50ZS1kaW5hbWlzbW8vDQoNCiogU2F1Y2VkbywgRC4gKDIwMjIpICpGT1JNIC0gSHVtYW4gUmVzb3VyY2VzIERlcGFydG1lbnQgSy1NZWFucyBDbHVzdGVyaW5nKi4gVGVjIGRlIE1vbnRlcnJleS4gaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xUjJEZ1FCUmNvNVUyRWVmSUxpSVpRWW00X0NMS25aRVIvdmlldz91c3A9ZHJpdmVfbGluaw0KDQoqICpTRSBDT05TT0xJREEgQVBPREFDQSBDT01PIENBUElUQUwgSU5EVVNUUklBTCBERSBOVUVWTyBMRcOTTiouICgyMDE5LCBPY3RvYmVyIDYpLiBBcG9kYWNhLiBodHRwczovL2Fwb2RhY2EuZ29iLm14L3NlLWNvbnNvbGlkYS1hcG9kYWNhLWNvbW8tY2FwaXRhbC1pbmR1c3RyaWFsLWRlLW51ZXZvLWxlb24vDQoNCg==