Actividad Integradora

2024-02-27

EQUIPO 6

  • Alexa Mariana Marin Villar A00831342

  • Diego Martínez Ruibal A01740559

  • Oscar Emiliano Melendez Chavez A01276802

Librerias

#install.packages("maps")
library(maps)
library(readr)
library(dplyr)
library(forecast)
library(tidyverse)
library(janitor)
library(here)
library(plotly)

Ejemplo

El ejemplo con la librería maps no está funcionando, pero con fines prácticos de la actividad se agregó el código.

#library(maps)
#map(database = "state", fill = TRUE, col = "lightgray")  # Añade colores de fondo
#grupo1 <- c("New York", "California", "Texas")
#map(database = "state", regions = grupo1, col = "red", fill = TRUE, add = TRUE)
#grupo2 <- c("Arizona", "Florida", "Illinois")
#map(database = "state", regions = grupo2, col = "green", fill = TRUE, add = TRUE)

Generar base de datos del tipo panel

La base de datos cuenta con la información anual de los estados de Estados Unidos desde 1900 hasta 2019.

mapa <-  read_csv("C:/Users/alexa/OneDrive/Desktop/8VO/MODULO 1/historical_state_population_by_year.csv", 
    col_names = FALSE)

mapa<- mapa %>% 
  rename(estate = X1, year = X2, population = X3) 

Resumen de los datos

La base de datos consta de 3 variables y 6,020 observaciones. El mínimo de años recabados es desde 1900 hasta 2019, mientras que el mínimo de población consta de 43,000 con un máximo de 39,512,223.

glimpse(mapa)
## Rows: 6,020
## Columns: 3
## $ estate     <chr> "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK", "AK",…
## $ year       <dbl> 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959,…
## $ population <dbl> 135000, 158000, 189000, 205000, 215000, 222000, 224000, 231…
summary(mapa)
##     estate               year        population      
##  Length:6020        Min.   :1900   Min.   :   43000  
##  Class :character   1st Qu.:1930   1st Qu.:  901483  
##  Mode  :character   Median :1960   Median : 2359000  
##                     Mean   :1960   Mean   : 3726003  
##                     3rd Qu.:1990   3rd Qu.: 4541883  
##                     Max.   :2019   Max.   :39512223

Filtro de solo los estados a analizar

En este caso decidimos analizar los estados de:

  1. California

  2. Nueva York

  3. Florida

  4. Wyoming

  5. Texas

california <- filter(mapa, estate =="CA")
newyork <- filter(mapa, estate =="NY")
florida <- filter(mapa, estate =="FL")
wyoming <- filter(mapa, estate =="WY")
texas <- filter(mapa, estate =="TX")

Crear modelo de series de tiempo

california$population <- as.numeric(california$population)
tscalifornia <- ts(data = california$population, start=c(1900,1),end=c(2019,1),frequency=1)
newyork$population <- as.numeric(newyork$population)
tsnewyork <- ts(data = newyork$population, start=c(1900,1),end=c(2019,1),frequency=1)
florida$population <- as.numeric(florida$population)
tsflorida <- ts(data = florida$population, start=c(1900,1),end=c(2019,1),frequency=1)
wyoming$population <- as.numeric(wyoming$population)
tswyoming <- ts(data = wyoming$population, start=c(1900,1),end=c(2019,1),frequency=1)
texas$population <- as.numeric(texas$population)
tstexas <- ts(data = texas$population, start=c(1900,1),end=c(2019,1),frequency=1)

Modelo ARIMA

Con fines del formato del documento, se decidió ejecutar el código, pero no mostrar el resultado del modelo ARIMA por estado.

arimacali <- auto.arima(tscalifornia, D=1)
summary(arimacali)
arimany <- auto.arima(tsnewyork, D=1)
summary(arimany)
arimaflo <- auto.arima(tsflorida, D=1)
summary(arimaflo)
arimawy <- auto.arima(tswyoming, D=1)
summary(arimawy)
arimatx <- auto.arima(tstexas, D=1)
summary(arimatx)

Generar el pronóstico

pronosticocali <- forecast(arimacali,level=c(95), h=51)
pronosticony <- forecast(arimany,level=c(95), h=51)
pronosticoflorida <- forecast(arimaflo,level=c(95), h=51)
pronosticowyoming <- forecast(arimawy,level=c(95), h=51)
pronosticotx <- forecast(arimatx,level=c(95), h=51)

Observar el pronóstico por estado

plot(pronosticocali)

plot(pronosticony)

plot(pronosticoflorida)

plot(pronosticowyoming)

plot(pronosticotx)

Se puede observar un crecimiento positivo en cuanto a la poblacion de los estados de California,Nueva York, Florida, Wyoming y Texas.

Unir los pronósticos en una sola base de datos

library(dplyr)

# Crear un data frame con los pronósticos y estados correspondientes
pronosticos <- data.frame(
  estate = rep(c("CA", "NY", "FL", "WY", "TX"), each = 51),
  year = rep(seq(2020, 2070), times = 5),
  point_forecast = c(
    pronosticocali$mean,
    pronosticony$mean,
    pronosticoflorida$mean,
    pronosticowyoming$mean,
    pronosticotx$mean
  )
)

# Limpiar nombres de columnas
pronosticos <- pronosticos %>% clean_names()

Visualizaciones

California

Visualizar los años en el mapa

library(maps)
library(plotly)

# Filtra los datos para el estado de California
datos_cali <- subset(pronosticos, estate == "CA")

# Define la escala de colores personalizada
color_scale <- colorRampPalette(c("blue", "lightblue", "lightgreen", "darkgreen", "darkred", "red"))

# Crea un mapa interactivo para cada año deseado
for (ano in c(2020,2030, 2040, 2050, 2060, 2070)) {
  datos_ano <- subset(datos_cali, year == ano)
  
  mapa <- plot_ly(
    data = datos_ano,
    type = "choropleth",
    locationmode = "USA-states",
    locations = ~estate,
    z = ~point_forecast,
    colorscale = color_scale(100),
    marker = list(line = list(color = "rgb(255,255,255)", width = 2)),
    text = ~paste("Estado: ", estate, "<br>Año: ", year, "<br>Población Pronosticada: ", point_forecast),
    zmin = min(datos_cali$point_forecast),  # Establece el valor mínimo de la escala de colores
    zmax = max(datos_cali$point_forecast)   # Establece el valor máximo de la escala de colores
  ) %>%
    layout(
      title = paste("Población Pronosticada California en", ano),
      geo = list(scope = "usa", projection = list(type = "albers usa")),
      colorbar = list(title = "Población Pronosticada"),
      showlegend = FALSE
    )
  
  # Muestra el mapa
  print(mapa)
}

Al momento de hacer el ‘knit’ del documento, no se visualizan los mapas debido al bucle creado para mostrar cada década. Por esta razón y debido al formato del documento, se decidió adjuntar las imágenes de los pronósticos del estado de California, pero este resultado se obtiene para cada estado. Se eligió una escala de colores que muestra el pronóstico del crecimiento de la población década por década.

Imagen en grande sobre como se observa el pronóstico dentro del mapa creado

Imagenes juntas para observar de mejor manera la escala y el crecimiento del pronóstico.

New York

Visualizar los años en el mapa

# Instala y carga las librerías necesarias
# install.packages(c("maps", "plotly"))
library(maps)
library(plotly)

# Filtra los datos para el estado de California
datos_ny <- subset(pronosticos, estate == "NY")

# Define la escala de colores personalizada
color_scale <- colorRampPalette(c("blue", "lightblue", "lightgreen", "darkgreen", "darkred", "red"))

# Crea un mapa interactivo para cada año deseado
for (ano in c(2020,2030, 2040, 2050, 2060, 2070)) {
  datos_ano <- subset(datos_ny, year == ano)
  
  mapa <- plot_ly(
    data = datos_ano,
    type = "choropleth",
    locationmode = "USA-states",
    locations = ~estate,
    z = ~point_forecast,
    colorscale = color_scale(100),
    marker = list(line = list(color = "rgb(255,255,255)", width = 2)),
    text = ~paste("Estado: ", estate, "<br>Año: ", year, "<br>Población Pronosticada: ", point_forecast),
    zmin = min(datos_ny$point_forecast),  # Establece el valor mínimo de la escala de colores
    zmax = max(datos_ny$point_forecast)   # Establece el valor máximo de la escala de colores
  ) %>%
    layout(
      title = paste("Población Pronosticada Nueva York en", ano),
      geo = list(scope = "usa", projection = list(type = "albers usa")),
      colorbar = list(title = "Población Pronosticada"),
      showlegend = FALSE
    )
  
  # Muestra el mapa
  print(mapa)
}

Florida

Visualizar los años en el mapa

# Instala y carga las librerías necesarias
# install.packages(c("maps", "plotly"))
library(maps)
library(plotly)

# Filtra los datos para el estado de California
datos_flo <- subset(pronosticos, estate == "FL")

# Define la escala de colores personalizada
color_scale <- colorRampPalette(c("blue", "lightblue", "lightgreen", "darkgreen", "darkred", "red"))

# Crea un mapa interactivo para cada año deseado
for (ano in c(2020,2030, 2040, 2050, 2060, 2070)) {
  datos_ano <- subset(datos_flo, year == ano)
  
  mapa <- plot_ly(
    data = datos_ano,
    type = "choropleth",
    locationmode = "USA-states",
    locations = ~estate,
    z = ~point_forecast,
    colorscale = color_scale(100),
    marker = list(line = list(color = "rgb(255,255,255)", width = 2)),
    text = ~paste("Estado: ", estate, "<br>Año: ", year, "<br>Población Pronosticada: ", point_forecast),
    zmin = min(datos_flo$point_forecast),  # Establece el valor mínimo de la escala de colores
    zmax = max(datos_flo$point_forecast)   # Establece el valor máximo de la escala de colores
  ) %>%
    layout(
      title = paste("Población Pronosticada Florida en", ano),
      geo = list(scope = "usa", projection = list(type = "albers usa")),
      colorbar = list(title = "Población Pronosticada"),
      showlegend = FALSE
    )
  
  # Muestra el mapa
  print(mapa)
}

Texas

Visualizar los años en el mapa

library(maps)
library(plotly)

# Filtra los datos para el estado de California
datos_tx <- subset(pronosticos, estate == "TX")

# Define la escala de colores personalizada
color_scale <- colorRampPalette(c("blue", "lightblue", "lightgreen", "darkgreen", "darkred", "red"))

# Crea un mapa interactivo para cada año deseado
for (ano in c(2020,2030, 2040, 2050, 2060, 2070)) {
  datos_ano <- subset(datos_tx, year == ano)
  
  mapa <- plot_ly(
    data = datos_ano,
    type = "choropleth",
    locationmode = "USA-states",
    locations = ~estate,
    z = ~point_forecast,
    colorscale = color_scale(100),
    marker = list(line = list(color = "rgb(255,255,255)", width = 2)),
    text = ~paste("Estado: ", estate, "<br>Año: ", year, "<br>Población Pronosticada: ", point_forecast),
    zmin = min(datos_tx$point_forecast),  # Establece el valor mínimo de la escala de colores
    zmax = max(datos_tx$point_forecast)   # Establece el valor máximo de la escala de colores
  ) %>%
    layout(
      title = paste("Población Pronosticada Texas en", ano),
      geo = list(scope = "usa", projection = list(type = "albers usa")),
      colorbar = list(title = "Población Pronosticada"),
      showlegend = FALSE
    )
  
  # Muestra el mapa
  print(mapa)
}

Wyoming

Visualizar los años en el mapa

library(maps)
library(plotly)

# Filtra los datos para el estado de California
datos_wo <- subset(pronosticos, estate == "WY")

# Define la escala de colores personalizada
color_scale <- colorRampPalette(c("blue", "lightblue", "lightgreen", "darkgreen", "darkred", "red"))

# Crea un mapa interactivo para cada año deseado
for (ano in c(2020,2030, 2040, 2050, 2060, 2070)) {
  datos_ano <- subset(datos_wo, year == ano)
  
  mapa <- plot_ly(
    data = datos_ano,
    type = "choropleth",
    locationmode = "USA-states",
    locations = ~estate,
    z = ~point_forecast,
    colorscale = color_scale(100),
    marker = list(line = list(color = "rgb(255,255,255)", width = 2)),
    text = ~paste("Estado: ", estate, "<br>Año: ", year, "<br>Población Pronosticada: ", point_forecast),
    zmin = min(datos_wo$point_forecast),  # Establece el valor mínimo de la escala de colores
    zmax = max(datos_wo$point_forecast)   # Establece el valor máximo de la escala de colores
  ) %>%
    layout(
      title = paste("Población Pronosticada Wyoming en", ano),
      geo = list(scope = "usa", projection = list(type = "albers usa")),
      colorbar = list(title = "Población Pronosticada"),
      showlegend = FALSE
    )
  
  # Muestra el mapa
  print(mapa)
}
LS0tDQp0aXRsZTogIkFjdGl2aWRhZCBJbnRlZ3JhZG9yYSINCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCINCm91dHB1dDoNCiAgcm1kZm9ybWF0czo6ZG93bmN1dGU6DQogICAgZGVmYXVsdF9zdHlsZTogImxpZ2h0Ig0KICAgIGRvd25jdXRlX3RoZW1lOiAiZGVmYXVsdCINCiAgICBjb2RlX2Rvd25sb2FkIDogdHJ1ZQ0KICAgIGxpYl9kaXI6IGxpYnMNCiAgICBzZWxmX2NvbnRhaW5lZDogZmFsc2UNCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCi0tLQ0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0NCiMjIEdsb2JhbCBvcHRpb25zDQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBUUlVFLGVjaG8gPSBUUlVFLHdhcm5pbmcgPSBGQUxTRSxtZXNzYWdlID0gRkFMU0UpDQpgYGANCg0KIyMgKipFUVVJUE8gNioqDQoNCi0gICBBbGV4YSBNYXJpYW5hIE1hcmluIFZpbGxhciBBMDA4MzEzNDINCg0KLSAgIERpZWdvIE1hcnTDrW5leiBSdWliYWwgQTAxNzQwNTU5DQoNCi0gICBPc2NhciBFbWlsaWFubyBNZWxlbmRleiBDaGF2ZXogQTAxMjc2ODAyDQoNCiMjICoqTGlicmVyaWFzKioNCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygibWFwcyIpDQpsaWJyYXJ5KG1hcHMpDQpsaWJyYXJ5KHJlYWRyKQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkoZm9yZWNhc3QpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoamFuaXRvcikNCmxpYnJhcnkoaGVyZSkNCmxpYnJhcnkocGxvdGx5KQ0KYGBgDQoNCiMjICoqRWplbXBsbyoqDQoNCkVsIGVqZW1wbG8gY29uIGxhIGxpYnJlcsOtYSBtYXBzIG5vIGVzdMOhIGZ1bmNpb25hbmRvLCBwZXJvIGNvbiBmaW5lcyBwcsOhY3RpY29zIGRlIGxhIGFjdGl2aWRhZCBzZSBhZ3JlZ8OzIGVsIGPDs2RpZ28uDQoNCmBgYHtyfQ0KI2xpYnJhcnkobWFwcykNCiNtYXAoZGF0YWJhc2UgPSAic3RhdGUiLCBmaWxsID0gVFJVRSwgY29sID0gImxpZ2h0Z3JheSIpICAjIEHDsWFkZSBjb2xvcmVzIGRlIGZvbmRvDQojZ3J1cG8xIDwtIGMoIk5ldyBZb3JrIiwgIkNhbGlmb3JuaWEiLCAiVGV4YXMiKQ0KI21hcChkYXRhYmFzZSA9ICJzdGF0ZSIsIHJlZ2lvbnMgPSBncnVwbzEsIGNvbCA9ICJyZWQiLCBmaWxsID0gVFJVRSwgYWRkID0gVFJVRSkNCiNncnVwbzIgPC0gYygiQXJpem9uYSIsICJGbG9yaWRhIiwgIklsbGlub2lzIikNCiNtYXAoZGF0YWJhc2UgPSAic3RhdGUiLCByZWdpb25zID0gZ3J1cG8yLCBjb2wgPSAiZ3JlZW4iLCBmaWxsID0gVFJVRSwgYWRkID0gVFJVRSkNCmBgYA0KDQojICoqR2VuZXJhciBiYXNlIGRlIGRhdG9zIGRlbCB0aXBvIHBhbmVsKioNCg0KIVtdKGdpcGh5JTIwKDUpLmdpZil7d2lkdGg9IjE4MyJ9DQoNCkxhIGJhc2UgZGUgZGF0b3MgY3VlbnRhIGNvbiBsYSBpbmZvcm1hY2nDs24gYW51YWwgZGUgbG9zIGVzdGFkb3MgZGUgRXN0YWRvcyBVbmlkb3MgZGVzZGUgMTkwMCBoYXN0YSAyMDE5Lg0KDQpgYGB7cn0NCm1hcGEgPC0gIHJlYWRfY3N2KCJDOi9Vc2Vycy9hbGV4YS9PbmVEcml2ZS9EZXNrdG9wLzhWTy9NT0RVTE8gMS9oaXN0b3JpY2FsX3N0YXRlX3BvcHVsYXRpb25fYnlfeWVhci5jc3YiLCANCiAgICBjb2xfbmFtZXMgPSBGQUxTRSkNCg0KbWFwYTwtIG1hcGEgJT4lIA0KICByZW5hbWUoZXN0YXRlID0gWDEsIHllYXIgPSBYMiwgcG9wdWxhdGlvbiA9IFgzKSANCmBgYA0KDQojIyAqKlJlc3VtZW4gZGUgbG9zIGRhdG9zKioNCg0KTGEgYmFzZSBkZSBkYXRvcyBjb25zdGEgZGUgMyB2YXJpYWJsZXMgeSA2LDAyMCBvYnNlcnZhY2lvbmVzLiBFbCBtw61uaW1vIGRlIGHDsW9zIHJlY2FiYWRvcyBlcyBkZXNkZSAxOTAwIGhhc3RhIDIwMTksIG1pZW50cmFzIHF1ZSBlbCBtw61uaW1vIGRlIHBvYmxhY2nDs24gY29uc3RhIGRlIDQzLDAwMCBjb24gdW4gbcOheGltbyBkZSAzOSw1MTIsMjIzLg0KDQpgYGB7cn0NCmdsaW1wc2UobWFwYSkNCnN1bW1hcnkobWFwYSkNCmBgYA0KDQpgYGB7cixpbmNsdWRlPUZBTFNFfQ0KI0ZpbHRyYXIgaW5mb3JtYWNpw7NuIHBvciBlc3RhZG9maWx0cmFyIGVzdGFkbyBwb3IgcGVxdWXDsWEgcG9ibGFjaW9uIHkgZ3JhbmRlIHBvYmxhY2lvbg0KbWFwYTIgPC0gc2VsZWN0KG1hcGEgLGMoMSwzKSkNCg0KcHJvbWVkaW9fcG9yX2VzdGFkbyA8LSBtYXBhMiAlPiUNCiAgZ3JvdXBfYnkoZXN0YXRlKSAlPiUNCiAgc3VtbWFyaXNlKHByb21lZGlvX2NvbHVtbmEgPSBtZWFuKHBvcHVsYXRpb24pKQ0KDQpwcm9tZWRpb19wb3JfZXN0YWRvIDwtIHByb21lZGlvX3Bvcl9lc3RhZG9bb3JkZXIoLXByb21lZGlvX3Bvcl9lc3RhZG8kcHJvbWVkaW9fY29sdW1uYSksIF0NCg0KcHJvbWVkaW9fcG9yX2VzdGFkbw0KDQojbWFwYTIgJT4lIGdyb3VwX2J5KHN1bWFfcG9yX2VzdGFkbykgJT4lIGZpbHRlcihwb3B1bGF0aW9uID4gbWVhbihwb3B1bGF0aW9uLCBuYS5ybSA9IFRSVUUpKQ0KI21hcGEyICU+JSBncm91cF9ieShwcm9tZWRpb19wb3JfZXN0YWRvKSAlPiUgZmlsdGVyKHBvcHVsYXRpb24gPCBtZWFuKHBvcHVsYXRpb24sIG5hLnJtID0gVFJVRSkpDQpgYGANCg0KIyMgKipGaWx0cm8gZGUgc29sbyBsb3MgZXN0YWRvcyBhIGFuYWxpemFyKioNCg0KRW4gZXN0ZSBjYXNvIGRlY2lkaW1vcyBhbmFsaXphciBsb3MgZXN0YWRvcyBkZToNCg0KMS4gICoqQ2FsaWZvcm5pYSoqDQoNCjIuICAqKk51ZXZhIFlvcmsqKg0KDQozLiAgKipGbG9yaWRhKioNCg0KNC4gICoqV3lvbWluZyoqDQoNCjUuICAqKlRleGFzKioNCg0KYGBge3J9DQpjYWxpZm9ybmlhIDwtIGZpbHRlcihtYXBhLCBlc3RhdGUgPT0iQ0EiKQ0KbmV3eW9yayA8LSBmaWx0ZXIobWFwYSwgZXN0YXRlID09Ik5ZIikNCmZsb3JpZGEgPC0gZmlsdGVyKG1hcGEsIGVzdGF0ZSA9PSJGTCIpDQp3eW9taW5nIDwtIGZpbHRlcihtYXBhLCBlc3RhdGUgPT0iV1kiKQ0KdGV4YXMgPC0gZmlsdGVyKG1hcGEsIGVzdGF0ZSA9PSJUWCIpDQpgYGANCg0KIyAqKkNyZWFyIG1vZGVsbyBkZSBzZXJpZXMgZGUgdGllbXBvKioNCg0KYGBge3J9DQpjYWxpZm9ybmlhJHBvcHVsYXRpb24gPC0gYXMubnVtZXJpYyhjYWxpZm9ybmlhJHBvcHVsYXRpb24pDQp0c2NhbGlmb3JuaWEgPC0gdHMoZGF0YSA9IGNhbGlmb3JuaWEkcG9wdWxhdGlvbiwgc3RhcnQ9YygxOTAwLDEpLGVuZD1jKDIwMTksMSksZnJlcXVlbmN5PTEpDQpuZXd5b3JrJHBvcHVsYXRpb24gPC0gYXMubnVtZXJpYyhuZXd5b3JrJHBvcHVsYXRpb24pDQp0c25ld3lvcmsgPC0gdHMoZGF0YSA9IG5ld3lvcmskcG9wdWxhdGlvbiwgc3RhcnQ9YygxOTAwLDEpLGVuZD1jKDIwMTksMSksZnJlcXVlbmN5PTEpDQpmbG9yaWRhJHBvcHVsYXRpb24gPC0gYXMubnVtZXJpYyhmbG9yaWRhJHBvcHVsYXRpb24pDQp0c2Zsb3JpZGEgPC0gdHMoZGF0YSA9IGZsb3JpZGEkcG9wdWxhdGlvbiwgc3RhcnQ9YygxOTAwLDEpLGVuZD1jKDIwMTksMSksZnJlcXVlbmN5PTEpDQp3eW9taW5nJHBvcHVsYXRpb24gPC0gYXMubnVtZXJpYyh3eW9taW5nJHBvcHVsYXRpb24pDQp0c3d5b21pbmcgPC0gdHMoZGF0YSA9IHd5b21pbmckcG9wdWxhdGlvbiwgc3RhcnQ9YygxOTAwLDEpLGVuZD1jKDIwMTksMSksZnJlcXVlbmN5PTEpDQp0ZXhhcyRwb3B1bGF0aW9uIDwtIGFzLm51bWVyaWModGV4YXMkcG9wdWxhdGlvbikNCnRzdGV4YXMgPC0gdHMoZGF0YSA9IHRleGFzJHBvcHVsYXRpb24sIHN0YXJ0PWMoMTkwMCwxKSxlbmQ9YygyMDE5LDEpLGZyZXF1ZW5jeT0xKQ0KYGBgDQoNCiMjICoqTW9kZWxvIEFSSU1BKioNCg0KQ29uIGZpbmVzIGRlbCBmb3JtYXRvIGRlbCBkb2N1bWVudG8sIHNlIGRlY2lkacOzIGVqZWN1dGFyIGVsIGPDs2RpZ28sIHBlcm8gbm8gbW9zdHJhciBlbCByZXN1bHRhZG8gZGVsIG1vZGVsbyBBUklNQSBwb3IgZXN0YWRvLg0KDQpgYGB7cixldmFsPUZBTFNFfQ0KYXJpbWFjYWxpIDwtIGF1dG8uYXJpbWEodHNjYWxpZm9ybmlhLCBEPTEpDQpzdW1tYXJ5KGFyaW1hY2FsaSkNCmFyaW1hbnkgPC0gYXV0by5hcmltYSh0c25ld3lvcmssIEQ9MSkNCnN1bW1hcnkoYXJpbWFueSkNCmFyaW1hZmxvIDwtIGF1dG8uYXJpbWEodHNmbG9yaWRhLCBEPTEpDQpzdW1tYXJ5KGFyaW1hZmxvKQ0KYXJpbWF3eSA8LSBhdXRvLmFyaW1hKHRzd3lvbWluZywgRD0xKQ0Kc3VtbWFyeShhcmltYXd5KQ0KYXJpbWF0eCA8LSBhdXRvLmFyaW1hKHRzdGV4YXMsIEQ9MSkNCnN1bW1hcnkoYXJpbWF0eCkNCmBgYA0KDQojIyAqKkdlbmVyYXIgZWwgcHJvbsOzc3RpY28qKg0KDQpgYGB7cn0NCnByb25vc3RpY29jYWxpIDwtIGZvcmVjYXN0KGFyaW1hY2FsaSxsZXZlbD1jKDk1KSwgaD01MSkNCnByb25vc3RpY29ueSA8LSBmb3JlY2FzdChhcmltYW55LGxldmVsPWMoOTUpLCBoPTUxKQ0KcHJvbm9zdGljb2Zsb3JpZGEgPC0gZm9yZWNhc3QoYXJpbWFmbG8sbGV2ZWw9Yyg5NSksIGg9NTEpDQpwcm9ub3N0aWNvd3lvbWluZyA8LSBmb3JlY2FzdChhcmltYXd5LGxldmVsPWMoOTUpLCBoPTUxKQ0KcHJvbm9zdGljb3R4IDwtIGZvcmVjYXN0KGFyaW1hdHgsbGV2ZWw9Yyg5NSksIGg9NTEpDQpgYGANCg0KIyMgKipPYnNlcnZhciBlbCBwcm9uw7NzdGljbyBwb3IgZXN0YWRvKioNCg0KYGBge3J9DQpwbG90KHByb25vc3RpY29jYWxpKQ0KcGxvdChwcm9ub3N0aWNvbnkpDQpwbG90KHByb25vc3RpY29mbG9yaWRhKQ0KcGxvdChwcm9ub3N0aWNvd3lvbWluZykNCnBsb3QocHJvbm9zdGljb3R4KQ0KYGBgDQoNClNlIHB1ZWRlIG9ic2VydmFyIHVuIGNyZWNpbWllbnRvIHBvc2l0aXZvIGVuIGN1YW50byBhIGxhIHBvYmxhY2lvbiBkZSBsb3MgZXN0YWRvcyBkZSBDYWxpZm9ybmlhLE51ZXZhIFlvcmssIEZsb3JpZGEsIFd5b21pbmcgeSBUZXhhcy4NCg0KIyMgKipVbmlyIGxvcyBwcm9uw7NzdGljb3MgZW4gdW5hIHNvbGEgYmFzZSBkZSBkYXRvcyoqDQoNCmBgYHtyfQ0KbGlicmFyeShkcGx5cikNCg0KIyBDcmVhciB1biBkYXRhIGZyYW1lIGNvbiBsb3MgcHJvbsOzc3RpY29zIHkgZXN0YWRvcyBjb3JyZXNwb25kaWVudGVzDQpwcm9ub3N0aWNvcyA8LSBkYXRhLmZyYW1lKA0KICBlc3RhdGUgPSByZXAoYygiQ0EiLCAiTlkiLCAiRkwiLCAiV1kiLCAiVFgiKSwgZWFjaCA9IDUxKSwNCiAgeWVhciA9IHJlcChzZXEoMjAyMCwgMjA3MCksIHRpbWVzID0gNSksDQogIHBvaW50X2ZvcmVjYXN0ID0gYygNCiAgICBwcm9ub3N0aWNvY2FsaSRtZWFuLA0KICAgIHByb25vc3RpY29ueSRtZWFuLA0KICAgIHByb25vc3RpY29mbG9yaWRhJG1lYW4sDQogICAgcHJvbm9zdGljb3d5b21pbmckbWVhbiwNCiAgICBwcm9ub3N0aWNvdHgkbWVhbg0KICApDQopDQoNCiMgTGltcGlhciBub21icmVzIGRlIGNvbHVtbmFzDQpwcm9ub3N0aWNvcyA8LSBwcm9ub3N0aWNvcyAlPiUgY2xlYW5fbmFtZXMoKQ0KYGBgDQoNCiMgKipWaXN1YWxpemFjaW9uZXMqKg0KDQojIyAqKkNhbGlmb3JuaWEqKg0KDQojIyMgKipWaXN1YWxpemFyIGxvcyBhw7FvcyBlbiBlbCBtYXBhKioNCg0KYGBge3J9DQpsaWJyYXJ5KG1hcHMpDQpsaWJyYXJ5KHBsb3RseSkNCg0KIyBGaWx0cmEgbG9zIGRhdG9zIHBhcmEgZWwgZXN0YWRvIGRlIENhbGlmb3JuaWENCmRhdG9zX2NhbGkgPC0gc3Vic2V0KHByb25vc3RpY29zLCBlc3RhdGUgPT0gIkNBIikNCg0KIyBEZWZpbmUgbGEgZXNjYWxhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYQ0KY29sb3Jfc2NhbGUgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgImxpZ2h0Ymx1ZSIsICJsaWdodGdyZWVuIiwgImRhcmtncmVlbiIsICJkYXJrcmVkIiwgInJlZCIpKQ0KDQojIENyZWEgdW4gbWFwYSBpbnRlcmFjdGl2byBwYXJhIGNhZGEgYcOxbyBkZXNlYWRvDQpmb3IgKGFubyBpbiBjKDIwMjAsMjAzMCwgMjA0MCwgMjA1MCwgMjA2MCwgMjA3MCkpIHsNCiAgZGF0b3NfYW5vIDwtIHN1YnNldChkYXRvc19jYWxpLCB5ZWFyID09IGFubykNCiAgDQogIG1hcGEgPC0gcGxvdF9seSgNCiAgICBkYXRhID0gZGF0b3NfYW5vLA0KICAgIHR5cGUgPSAiY2hvcm9wbGV0aCIsDQogICAgbG9jYXRpb25tb2RlID0gIlVTQS1zdGF0ZXMiLA0KICAgIGxvY2F0aW9ucyA9IH5lc3RhdGUsDQogICAgeiA9IH5wb2ludF9mb3JlY2FzdCwNCiAgICBjb2xvcnNjYWxlID0gY29sb3Jfc2NhbGUoMTAwKSwNCiAgICBtYXJrZXIgPSBsaXN0KGxpbmUgPSBsaXN0KGNvbG9yID0gInJnYigyNTUsMjU1LDI1NSkiLCB3aWR0aCA9IDIpKSwNCiAgICB0ZXh0ID0gfnBhc3RlKCJFc3RhZG86ICIsIGVzdGF0ZSwgIjxicj5Bw7FvOiAiLCB5ZWFyLCAiPGJyPlBvYmxhY2nDs24gUHJvbm9zdGljYWRhOiAiLCBwb2ludF9mb3JlY2FzdCksDQogICAgem1pbiA9IG1pbihkYXRvc19jYWxpJHBvaW50X2ZvcmVjYXN0KSwgICMgRXN0YWJsZWNlIGVsIHZhbG9yIG3DrW5pbW8gZGUgbGEgZXNjYWxhIGRlIGNvbG9yZXMNCiAgICB6bWF4ID0gbWF4KGRhdG9zX2NhbGkkcG9pbnRfZm9yZWNhc3QpICAgIyBFc3RhYmxlY2UgZWwgdmFsb3IgbcOheGltbyBkZSBsYSBlc2NhbGEgZGUgY29sb3Jlcw0KICApICU+JQ0KICAgIGxheW91dCgNCiAgICAgIHRpdGxlID0gcGFzdGUoIlBvYmxhY2nDs24gUHJvbm9zdGljYWRhIENhbGlmb3JuaWEgZW4iLCBhbm8pLA0KICAgICAgZ2VvID0gbGlzdChzY29wZSA9ICJ1c2EiLCBwcm9qZWN0aW9uID0gbGlzdCh0eXBlID0gImFsYmVycyB1c2EiKSksDQogICAgICBjb2xvcmJhciA9IGxpc3QodGl0bGUgPSAiUG9ibGFjacOzbiBQcm9ub3N0aWNhZGEiKSwNCiAgICAgIHNob3dsZWdlbmQgPSBGQUxTRQ0KICAgICkNCiAgDQogICMgTXVlc3RyYSBlbCBtYXBhDQogIHByaW50KG1hcGEpDQp9DQoNCmBgYA0KDQpBbCBtb21lbnRvIGRlIGhhY2VyIGVsICdrbml0JyBkZWwgZG9jdW1lbnRvLCBubyBzZSB2aXN1YWxpemFuIGxvcyBtYXBhcyBkZWJpZG8gYWwgYnVjbGUgY3JlYWRvIHBhcmEgbW9zdHJhciBjYWRhIGTDqWNhZGEuIFBvciBlc3RhIHJhesOzbiB5IGRlYmlkbyBhbCBmb3JtYXRvIGRlbCBkb2N1bWVudG8sIHNlIGRlY2lkacOzIGFkanVudGFyIGxhcyBpbcOhZ2VuZXMgZGUgbG9zIHByb27Ds3N0aWNvcyBkZWwgZXN0YWRvIGRlIENhbGlmb3JuaWEsIHBlcm8gZXN0ZSByZXN1bHRhZG8gc2Ugb2J0aWVuZSBwYXJhIGNhZGEgZXN0YWRvLiBTZSBlbGlnacOzIHVuYSBlc2NhbGEgZGUgY29sb3JlcyBxdWUgbXVlc3RyYSBlbCBwcm9uw7NzdGljbyBkZWwgY3JlY2ltaWVudG8gZGUgbGEgcG9ibGFjacOzbiBkw6ljYWRhIHBvciBkw6ljYWRhLg0KDQojIyMgKipJbWFnZW4gZW4gZ3JhbmRlIHNvYnJlIGNvbW8gc2Ugb2JzZXJ2YSBlbCBwcm9uw7NzdGljbyBkZW50cm8gZGVsIG1hcGEgY3JlYWRvKioNCg0KIVtdKGltYWdlcy9TY3JlZW5zaG90JTIwMjAyNC0wMi0yMyUyMDA3MDE1Ni5wbmcpDQoNCiMjIyAqKkltYWdlbmVzIGp1bnRhcyBwYXJhIG9ic2VydmFyIGRlIG1lam9yIG1hbmVyYSBsYSBlc2NhbGEgeSBlbCBjcmVjaW1pZW50byBkZWwgcHJvbsOzc3RpY28uKioNCg0KIVtdKDEucG5nKQ0KDQohW10oMi5wbmcpDQoNCiMjICoqTmV3IFlvcmsqKg0KDQojIyMgKipWaXN1YWxpemFyIGxvcyBhw7FvcyBlbiBlbCBtYXBhKioNCg0KYGBge3J9DQojIEluc3RhbGEgeSBjYXJnYSBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzDQojIGluc3RhbGwucGFja2FnZXMoYygibWFwcyIsICJwbG90bHkiKSkNCmxpYnJhcnkobWFwcykNCmxpYnJhcnkocGxvdGx5KQ0KDQojIEZpbHRyYSBsb3MgZGF0b3MgcGFyYSBlbCBlc3RhZG8gZGUgQ2FsaWZvcm5pYQ0KZGF0b3NfbnkgPC0gc3Vic2V0KHByb25vc3RpY29zLCBlc3RhdGUgPT0gIk5ZIikNCg0KIyBEZWZpbmUgbGEgZXNjYWxhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYQ0KY29sb3Jfc2NhbGUgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgImxpZ2h0Ymx1ZSIsICJsaWdodGdyZWVuIiwgImRhcmtncmVlbiIsICJkYXJrcmVkIiwgInJlZCIpKQ0KDQojIENyZWEgdW4gbWFwYSBpbnRlcmFjdGl2byBwYXJhIGNhZGEgYcOxbyBkZXNlYWRvDQpmb3IgKGFubyBpbiBjKDIwMjAsMjAzMCwgMjA0MCwgMjA1MCwgMjA2MCwgMjA3MCkpIHsNCiAgZGF0b3NfYW5vIDwtIHN1YnNldChkYXRvc19ueSwgeWVhciA9PSBhbm8pDQogIA0KICBtYXBhIDwtIHBsb3RfbHkoDQogICAgZGF0YSA9IGRhdG9zX2FubywNCiAgICB0eXBlID0gImNob3JvcGxldGgiLA0KICAgIGxvY2F0aW9ubW9kZSA9ICJVU0Etc3RhdGVzIiwNCiAgICBsb2NhdGlvbnMgPSB+ZXN0YXRlLA0KICAgIHogPSB+cG9pbnRfZm9yZWNhc3QsDQogICAgY29sb3JzY2FsZSA9IGNvbG9yX3NjYWxlKDEwMCksDQogICAgbWFya2VyID0gbGlzdChsaW5lID0gbGlzdChjb2xvciA9ICJyZ2IoMjU1LDI1NSwyNTUpIiwgd2lkdGggPSAyKSksDQogICAgdGV4dCA9IH5wYXN0ZSgiRXN0YWRvOiAiLCBlc3RhdGUsICI8YnI+QcOxbzogIiwgeWVhciwgIjxicj5Qb2JsYWNpw7NuIFByb25vc3RpY2FkYTogIiwgcG9pbnRfZm9yZWNhc3QpLA0KICAgIHptaW4gPSBtaW4oZGF0b3NfbnkkcG9pbnRfZm9yZWNhc3QpLCAgIyBFc3RhYmxlY2UgZWwgdmFsb3IgbcOtbmltbyBkZSBsYSBlc2NhbGEgZGUgY29sb3Jlcw0KICAgIHptYXggPSBtYXgoZGF0b3NfbnkkcG9pbnRfZm9yZWNhc3QpICAgIyBFc3RhYmxlY2UgZWwgdmFsb3IgbcOheGltbyBkZSBsYSBlc2NhbGEgZGUgY29sb3Jlcw0KICApICU+JQ0KICAgIGxheW91dCgNCiAgICAgIHRpdGxlID0gcGFzdGUoIlBvYmxhY2nDs24gUHJvbm9zdGljYWRhIE51ZXZhIFlvcmsgZW4iLCBhbm8pLA0KICAgICAgZ2VvID0gbGlzdChzY29wZSA9ICJ1c2EiLCBwcm9qZWN0aW9uID0gbGlzdCh0eXBlID0gImFsYmVycyB1c2EiKSksDQogICAgICBjb2xvcmJhciA9IGxpc3QodGl0bGUgPSAiUG9ibGFjacOzbiBQcm9ub3N0aWNhZGEiKSwNCiAgICAgIHNob3dsZWdlbmQgPSBGQUxTRQ0KICAgICkNCiAgDQogICMgTXVlc3RyYSBlbCBtYXBhDQogIHByaW50KG1hcGEpDQp9DQoNCmBgYA0KDQojIyAqKkZsb3JpZGEqKg0KDQojIyMgKipWaXN1YWxpemFyIGxvcyBhw7FvcyBlbiBlbCBtYXBhKioNCg0KYGBge3J9DQojIEluc3RhbGEgeSBjYXJnYSBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzDQojIGluc3RhbGwucGFja2FnZXMoYygibWFwcyIsICJwbG90bHkiKSkNCmxpYnJhcnkobWFwcykNCmxpYnJhcnkocGxvdGx5KQ0KDQojIEZpbHRyYSBsb3MgZGF0b3MgcGFyYSBlbCBlc3RhZG8gZGUgQ2FsaWZvcm5pYQ0KZGF0b3NfZmxvIDwtIHN1YnNldChwcm9ub3N0aWNvcywgZXN0YXRlID09ICJGTCIpDQoNCiMgRGVmaW5lIGxhIGVzY2FsYSBkZSBjb2xvcmVzIHBlcnNvbmFsaXphZGENCmNvbG9yX3NjYWxlIDwtIGNvbG9yUmFtcFBhbGV0dGUoYygiYmx1ZSIsICJsaWdodGJsdWUiLCAibGlnaHRncmVlbiIsICJkYXJrZ3JlZW4iLCAiZGFya3JlZCIsICJyZWQiKSkNCg0KIyBDcmVhIHVuIG1hcGEgaW50ZXJhY3Rpdm8gcGFyYSBjYWRhIGHDsW8gZGVzZWFkbw0KZm9yIChhbm8gaW4gYygyMDIwLDIwMzAsIDIwNDAsIDIwNTAsIDIwNjAsIDIwNzApKSB7DQogIGRhdG9zX2FubyA8LSBzdWJzZXQoZGF0b3NfZmxvLCB5ZWFyID09IGFubykNCiAgDQogIG1hcGEgPC0gcGxvdF9seSgNCiAgICBkYXRhID0gZGF0b3NfYW5vLA0KICAgIHR5cGUgPSAiY2hvcm9wbGV0aCIsDQogICAgbG9jYXRpb25tb2RlID0gIlVTQS1zdGF0ZXMiLA0KICAgIGxvY2F0aW9ucyA9IH5lc3RhdGUsDQogICAgeiA9IH5wb2ludF9mb3JlY2FzdCwNCiAgICBjb2xvcnNjYWxlID0gY29sb3Jfc2NhbGUoMTAwKSwNCiAgICBtYXJrZXIgPSBsaXN0KGxpbmUgPSBsaXN0KGNvbG9yID0gInJnYigyNTUsMjU1LDI1NSkiLCB3aWR0aCA9IDIpKSwNCiAgICB0ZXh0ID0gfnBhc3RlKCJFc3RhZG86ICIsIGVzdGF0ZSwgIjxicj5Bw7FvOiAiLCB5ZWFyLCAiPGJyPlBvYmxhY2nDs24gUHJvbm9zdGljYWRhOiAiLCBwb2ludF9mb3JlY2FzdCksDQogICAgem1pbiA9IG1pbihkYXRvc19mbG8kcG9pbnRfZm9yZWNhc3QpLCAgIyBFc3RhYmxlY2UgZWwgdmFsb3IgbcOtbmltbyBkZSBsYSBlc2NhbGEgZGUgY29sb3Jlcw0KICAgIHptYXggPSBtYXgoZGF0b3NfZmxvJHBvaW50X2ZvcmVjYXN0KSAgICMgRXN0YWJsZWNlIGVsIHZhbG9yIG3DoXhpbW8gZGUgbGEgZXNjYWxhIGRlIGNvbG9yZXMNCiAgKSAlPiUNCiAgICBsYXlvdXQoDQogICAgICB0aXRsZSA9IHBhc3RlKCJQb2JsYWNpw7NuIFByb25vc3RpY2FkYSBGbG9yaWRhIGVuIiwgYW5vKSwNCiAgICAgIGdlbyA9IGxpc3Qoc2NvcGUgPSAidXNhIiwgcHJvamVjdGlvbiA9IGxpc3QodHlwZSA9ICJhbGJlcnMgdXNhIikpLA0KICAgICAgY29sb3JiYXIgPSBsaXN0KHRpdGxlID0gIlBvYmxhY2nDs24gUHJvbm9zdGljYWRhIiksDQogICAgICBzaG93bGVnZW5kID0gRkFMU0UNCiAgICApDQogIA0KICAjIE11ZXN0cmEgZWwgbWFwYQ0KICBwcmludChtYXBhKQ0KfQ0KDQpgYGANCg0KIyMgKipUZXhhcyoqDQoNCiMjIyAqKlZpc3VhbGl6YXIgbG9zIGHDsW9zIGVuIGVsIG1hcGEqKg0KDQpgYGB7cn0NCmxpYnJhcnkobWFwcykNCmxpYnJhcnkocGxvdGx5KQ0KDQojIEZpbHRyYSBsb3MgZGF0b3MgcGFyYSBlbCBlc3RhZG8gZGUgQ2FsaWZvcm5pYQ0KZGF0b3NfdHggPC0gc3Vic2V0KHByb25vc3RpY29zLCBlc3RhdGUgPT0gIlRYIikNCg0KIyBEZWZpbmUgbGEgZXNjYWxhIGRlIGNvbG9yZXMgcGVyc29uYWxpemFkYQ0KY29sb3Jfc2NhbGUgPC0gY29sb3JSYW1wUGFsZXR0ZShjKCJibHVlIiwgImxpZ2h0Ymx1ZSIsICJsaWdodGdyZWVuIiwgImRhcmtncmVlbiIsICJkYXJrcmVkIiwgInJlZCIpKQ0KDQojIENyZWEgdW4gbWFwYSBpbnRlcmFjdGl2byBwYXJhIGNhZGEgYcOxbyBkZXNlYWRvDQpmb3IgKGFubyBpbiBjKDIwMjAsMjAzMCwgMjA0MCwgMjA1MCwgMjA2MCwgMjA3MCkpIHsNCiAgZGF0b3NfYW5vIDwtIHN1YnNldChkYXRvc190eCwgeWVhciA9PSBhbm8pDQogIA0KICBtYXBhIDwtIHBsb3RfbHkoDQogICAgZGF0YSA9IGRhdG9zX2FubywNCiAgICB0eXBlID0gImNob3JvcGxldGgiLA0KICAgIGxvY2F0aW9ubW9kZSA9ICJVU0Etc3RhdGVzIiwNCiAgICBsb2NhdGlvbnMgPSB+ZXN0YXRlLA0KICAgIHogPSB+cG9pbnRfZm9yZWNhc3QsDQogICAgY29sb3JzY2FsZSA9IGNvbG9yX3NjYWxlKDEwMCksDQogICAgbWFya2VyID0gbGlzdChsaW5lID0gbGlzdChjb2xvciA9ICJyZ2IoMjU1LDI1NSwyNTUpIiwgd2lkdGggPSAyKSksDQogICAgdGV4dCA9IH5wYXN0ZSgiRXN0YWRvOiAiLCBlc3RhdGUsICI8YnI+QcOxbzogIiwgeWVhciwgIjxicj5Qb2JsYWNpw7NuIFByb25vc3RpY2FkYTogIiwgcG9pbnRfZm9yZWNhc3QpLA0KICAgIHptaW4gPSBtaW4oZGF0b3NfdHgkcG9pbnRfZm9yZWNhc3QpLCAgIyBFc3RhYmxlY2UgZWwgdmFsb3IgbcOtbmltbyBkZSBsYSBlc2NhbGEgZGUgY29sb3Jlcw0KICAgIHptYXggPSBtYXgoZGF0b3NfdHgkcG9pbnRfZm9yZWNhc3QpICAgIyBFc3RhYmxlY2UgZWwgdmFsb3IgbcOheGltbyBkZSBsYSBlc2NhbGEgZGUgY29sb3Jlcw0KICApICU+JQ0KICAgIGxheW91dCgNCiAgICAgIHRpdGxlID0gcGFzdGUoIlBvYmxhY2nDs24gUHJvbm9zdGljYWRhIFRleGFzIGVuIiwgYW5vKSwNCiAgICAgIGdlbyA9IGxpc3Qoc2NvcGUgPSAidXNhIiwgcHJvamVjdGlvbiA9IGxpc3QodHlwZSA9ICJhbGJlcnMgdXNhIikpLA0KICAgICAgY29sb3JiYXIgPSBsaXN0KHRpdGxlID0gIlBvYmxhY2nDs24gUHJvbm9zdGljYWRhIiksDQogICAgICBzaG93bGVnZW5kID0gRkFMU0UNCiAgICApDQogIA0KICAjIE11ZXN0cmEgZWwgbWFwYQ0KICBwcmludChtYXBhKQ0KfQ0KDQpgYGANCg0KIyMgKipXeW9taW5nKioNCg0KIyMjICoqVmlzdWFsaXphciBsb3MgYcOxb3MgZW4gZWwgbWFwYSoqDQoNCmBgYHtyfQ0KbGlicmFyeShtYXBzKQ0KbGlicmFyeShwbG90bHkpDQoNCiMgRmlsdHJhIGxvcyBkYXRvcyBwYXJhIGVsIGVzdGFkbyBkZSBDYWxpZm9ybmlhDQpkYXRvc193byA8LSBzdWJzZXQocHJvbm9zdGljb3MsIGVzdGF0ZSA9PSAiV1kiKQ0KDQojIERlZmluZSBsYSBlc2NhbGEgZGUgY29sb3JlcyBwZXJzb25hbGl6YWRhDQpjb2xvcl9zY2FsZSA8LSBjb2xvclJhbXBQYWxldHRlKGMoImJsdWUiLCAibGlnaHRibHVlIiwgImxpZ2h0Z3JlZW4iLCAiZGFya2dyZWVuIiwgImRhcmtyZWQiLCAicmVkIikpDQoNCiMgQ3JlYSB1biBtYXBhIGludGVyYWN0aXZvIHBhcmEgY2FkYSBhw7FvIGRlc2VhZG8NCmZvciAoYW5vIGluIGMoMjAyMCwyMDMwLCAyMDQwLCAyMDUwLCAyMDYwLCAyMDcwKSkgew0KICBkYXRvc19hbm8gPC0gc3Vic2V0KGRhdG9zX3dvLCB5ZWFyID09IGFubykNCiAgDQogIG1hcGEgPC0gcGxvdF9seSgNCiAgICBkYXRhID0gZGF0b3NfYW5vLA0KICAgIHR5cGUgPSAiY2hvcm9wbGV0aCIsDQogICAgbG9jYXRpb25tb2RlID0gIlVTQS1zdGF0ZXMiLA0KICAgIGxvY2F0aW9ucyA9IH5lc3RhdGUsDQogICAgeiA9IH5wb2ludF9mb3JlY2FzdCwNCiAgICBjb2xvcnNjYWxlID0gY29sb3Jfc2NhbGUoMTAwKSwNCiAgICBtYXJrZXIgPSBsaXN0KGxpbmUgPSBsaXN0KGNvbG9yID0gInJnYigyNTUsMjU1LDI1NSkiLCB3aWR0aCA9IDIpKSwNCiAgICB0ZXh0ID0gfnBhc3RlKCJFc3RhZG86ICIsIGVzdGF0ZSwgIjxicj5Bw7FvOiAiLCB5ZWFyLCAiPGJyPlBvYmxhY2nDs24gUHJvbm9zdGljYWRhOiAiLCBwb2ludF9mb3JlY2FzdCksDQogICAgem1pbiA9IG1pbihkYXRvc193byRwb2ludF9mb3JlY2FzdCksICAjIEVzdGFibGVjZSBlbCB2YWxvciBtw61uaW1vIGRlIGxhIGVzY2FsYSBkZSBjb2xvcmVzDQogICAgem1heCA9IG1heChkYXRvc193byRwb2ludF9mb3JlY2FzdCkgICAjIEVzdGFibGVjZSBlbCB2YWxvciBtw6F4aW1vIGRlIGxhIGVzY2FsYSBkZSBjb2xvcmVzDQogICkgJT4lDQogICAgbGF5b3V0KA0KICAgICAgdGl0bGUgPSBwYXN0ZSgiUG9ibGFjacOzbiBQcm9ub3N0aWNhZGEgV3lvbWluZyBlbiIsIGFubyksDQogICAgICBnZW8gPSBsaXN0KHNjb3BlID0gInVzYSIsIHByb2plY3Rpb24gPSBsaXN0KHR5cGUgPSAiYWxiZXJzIHVzYSIpKSwNCiAgICAgIGNvbG9yYmFyID0gbGlzdCh0aXRsZSA9ICJQb2JsYWNpw7NuIFByb25vc3RpY2FkYSIpLA0KICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFDQogICAgKQ0KICANCiAgIyBNdWVzdHJhIGVsIG1hcGENCiAgcHJpbnQobWFwYSkNCn0NCg0KYGBgDQo=