logo




1 Objetivo

Comprender mejor el comportamiento de los usuarios, el rendimiento del sitio y las diferencias de la edición 2022 de Hot Sale contra las ediciones pasadas.

# Cargar las librerías necesarias
if (!require("pacman")) install.packages("pacman")
pacman::p_load(arrow,
               correlationfunnel,
               formattable,
               ggplot2,
               lubridate,
               outliers,
               plotly,
               tidyverse)
# Leer la data de la edición
date_hour <- read_csv("data/2-processed/hotsale_2022_edition_2022-05-01_2022-05-31.csv", 
    col_types = cols(dateHour = col_datetime(format = "%Y%m%d%H"))) %>% 
    rename(fechaHora = dateHour,
           impresiones = productListViews,
           clics = productListClicks) %>% 
    mutate(diaSemana = factor(wday(fechaHora, week_start = 1))) %>% 
    mutate(diaSemana = recode_factor(diaSemana,
                  `1` = "lunes",
                  `2` = "martes",
                  `3` = "miércoles",
                  `4` = "jueves",
                  `5` = "viernes",
                  `6` = "sábado",
                  `7` = "domingo",
                  .ordered = TRUE),
           hora = format(fechaHora, "%H:00"))

# Leer la data de canales
channels <- read_csv("data/2-processed/hotsale_2022_channel_2022-05-01-2022-05-31.csv", 
                     col_types = cols(...1 = col_skip(), `ga:productSku` = col_character(), 
                                      date = col_date(format = "%Y-%m-%d"))) %>% 
    rename_with(~str_replace(., "ga:", ""), everything()) %>% 
    select(fecha = date,
           idPatrocinador = productSku,
           patrocinador = productBrand,
           canal = channelGrouping,
           fuenteMedio = sourceMedium,
           impresiones = productListViews,
           clics = productListClicks)

# Leer la data de creativos
creative <- read_csv("data/2-processed/hotsale_2022_creative_2022-05-10-2022-05-31.csv", 
                     col_types = cols(date = col_date(format = "%Y-%m-%d"))) %>% 
    rename_with(~str_replace(., "ga:", ""), everything()) %>% 
    select(fecha = date,
           tipoCreativo = dimension10,
           impresiones = productListViews,
           clics = productListClicks) %>% 
    mutate(tipoCreativo = case_when(
        tipoCreativo == "Sponsor" ~ "Logo",
        tipoCreativo == "Banner" ~ "Cintillo",
        TRUE ~ tipoCreativo
    ))

# Leer datos de las instastories
insta_stories <- read_csv("data/2-processed/hotsale_2022_creative_instaStories_2022-05-01_2022-05-31.csv", 
    col_types = cols(date = col_date(format = "%Y-%m-%d"))) %>% 
    rename(fecha = date,
           patrocinador = productBrand,
           tipoCreativo = dimension10,
           seccion = productListName,
           clics = productListClicks) %>% 
    mutate(impresiones = case_when(tipoCreativo == "InstaStories" ~ productDetailViews,
                                   TRUE ~ productListViews)) %>% 
    select(-productListViews,
           -productDetailViews) %>% 
    mutate(tipoCreativo = case_when(
        tipoCreativo == "Sponsor" ~ "Logo",
        tipoCreativo == "Banner" ~ "Cintillo",
        TRUE ~ tipoCreativo
    ))
# Leer la data de menu
menu <- read_csv("data/2-processed/hotsale_2022_menu_2022-05-16-2022-05-31.csv", 
                 col_types = cols(...1 = col_skip(), `ga:totalEvents` = col_integer(), 
                                  `ga:uniqueEvents` = col_integer(), 
                                  date = col_date(format = "%Y-%m-%d"))) %>%
    rename_with(~str_replace(., "ga:", ""), everything()) %>% 
    select(fecha = date,
           elemento = eventLabel,
           clicsTotales = totalEvents,
           clicsUnicos = uniqueEvents)

# Leer la data de ofertas hot
ofertas_hot <- read_csv("data/2-processed/hotsale_2022_ofertas-hot_2022-05-18-2022-05-31.csv", 
                        col_types = cols(...1 = col_skip(), date = col_date(format = "%Y-%m-%d"))) %>% 
    rename_with(~str_replace(., "ga:", ""), everything()) %>%
    mutate(pagePath = str_remove(pagePath, "/ofertas-hot")) %>% 
    select(fecha = date,
           pagina = pagePath,
           paginasVistas = pageviews,
           paginasVistasUnicas = uniquePageviews)

# Leer la data de productos
products <- read_csv("data/2-processed/hotsale-2022-products.csv", 
                     col_types = cols(productSku = col_character(), 
                                      date = col_date(format = "%Y-%m-%d"))) %>% 
    rename_with(~str_replace(., "ga:", ""), everything()) %>% 
    select(fecha = date,
           idPatrocinador = productSku,
           patrocinador = productBrand,
           seccion = productListName,
           nivelPatrocinio = dimension7,
           impresiones = views,
           clics)

# Leer la data de las búsquedas
searches <- read_csv("data/2-processed/hotsale_2022_searches_2022-05-16-2022-05-31.csv", 
                     col_types = cols(...1 = col_skip(), date = col_date(format = "%Y-%m-%d"))) %>%
    rename_with(~str_replace(., "ga:", ""), everything()) %>% 
    select(fecha = date,
           busqueda = eventLabel,
           totalBusquedas = totalEvents,
           busquedasUnicas = uniqueEvents)

# Leer la data de las secciones
sections <- read_csv("data/2-processed/hotsale_2022_sections_2022-05-01-2022-05-31.csv", 
                     col_types = cols(date = col_date(format = "%Y-%m-%d"), 
                                      `ga:pageviews` = col_integer(), `ga:uniquePageviews` = col_integer()))%>%
    rename_with(~str_replace(., "ga:", ""), everything()) %>% 
    select(fecha = date,
           seccion = cleanPage,
           paginasVistas = pageviews,
           paginasVistasUnicas = uniquePageviews)

# Leer la data de favoritos
wishlist <- read_csv("data/2-processed/hotsale_2022_wishlist_2022-05-04-2022-05-31.csv", 
                     col_types = cols(date = col_date(format = "%Y-%m-%d"))) %>% 
    rename_with(~str_replace(., "ga:", ""), everything()) %>% 
    select(fecha = date,
           totalFavoritos = totalEvents,
           favoritosUnicos = uniqueEvents)




2 Análisis Descriptivo

2.1 Edición

2.1.1 Tendencia de la edición por día

products %>% 
    group_by(fecha) %>% 
    summarise(impresiones = comma(sum(impresiones),
                                  digits = 0),
              clics = comma(sum(clics),
                            digits = 0)) %>% 
    plot_ly(x = ~fecha) %>% 
    add_trace(y = ~impresiones,
              type = 'scatter',
              mode = 'lines',
              name = 'impresiones',
              line = list(color = color_palette[2],
                          width = 2)) %>%
    add_trace(y = ~clics,
              type = 'scatter',
              mode = 'lines',
              name = 'clics',
              line = list(color = color_palette[1],
                          width = 4)) %>% 
    layout(title = "Tendencia de las impresiones y clics por día<br><sub>Del 1 al 31 mayo del 2022</sub>",
           xaxis = list(title = "",
                        showline = TRUE,
                        showgrid = FALSE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = FALSE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           yaxis = list(title = "",
                        type = "log",
                        showline = TRUE,
                        showgrid = TRUE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = FALSE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           margin = list(autoexpand = TRUE,
                         t = 100,
                         l = 50,
                         r = 200,
                         b = 100),
           autosize = TRUE,
           showlegend = TRUE,
           annotations = list(
               xref = 'paper',
               yref = 'paper',
               x = 0.73,
               y = 0.5,
               xanchor = 'right',
               yanchor = 'middle',
               text = 'Primer día del Hot Sale',
               font = list(family = 'PT Sans Narrow',
                           size = 16,
                           color = 'rgba(160,160,160,1)'),
               showarrow = TRUE)) %>%
    layout(annotations = list(
        xref = 'paper',
        yref = 'paper',
        x = 1,
        y = 0.44,
        xanchor = 'left',
        yanchor = 'middle',
        text = 'Último día del Hot Sale',
        font = list(family = 'PT Sans Narrow',
                    size = 16,
                    color = 'rgba(160,160,160,1)'),
        showarrow = TRUE))

Se observa que del 1 al 17 de mayo hay un crecimiento exponencial en las impresiones y clics, que aumenta aun más a partir de esa fecha y hasta el 23, del 24 al 31 los clics se mantienen entre los 200K y los 400K, lo que refiere a un comportamiento más estable que en ediciones pasadas.

products %>% 
    group_by(fecha) %>% 
    summarise(CTR = sum(clics) / sum(impresiones)) %>% 
    plot_ly(x = ~fecha) %>% 
    add_trace(y = ~CTR,
              type = 'scatter',
              mode = 'lines',
              name = 'CTR',
              line = list(color = color_palette[1],
                          width = 4)) %>% 
    layout(title = "Tendencia del CTR por día<br><sub>Del 1 al 31 Mayo de 2022<sub>",
           xaxis = list(title = "",
                        showline = TRUE,
                        showgrid = FALSE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = FALSE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           yaxis = list(title = "% CTR",
                        showline = TRUE,
                        showgrid = TRUE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = TRUE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickformat = ".2%",
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           margin = list(autoexpand = TRUE,
                         t = 100,
                         l = 10,
                         r = 110,
                         b = 100),
           autosize = TRUE,
           showlegend = FALSE,
           annotations = list(
               xref = 'paper',
               yref = 'paper',
               x = 0.73,
               y = 0.16,
               xanchor = 'right',
               yanchor = 'middle',
               text = 'Primer del Hot Sale',
               font = list(family = 'PT Sans Narrow',
                           size = 16,
                           color = 'rgba(160,160,160,1)'),
               showarrow = TRUE)) %>%
    layout(annotations = list(
        xref = 'paper',
        yref = 'paper',
        x = 1,
        y = 0.10,
        xanchor = 'left',
        yanchor = 'middle',
        text = 'Último del Hot Sale',
        font = list(family = 'PT Sans Narrow',
                    size = 16,
                    color = 'rgba(160,160,160,1)'),
        showarrow = TRUE))

Por su parte el CTR alcanza un pico importante el miércoles 4 de mayo ya que durante todo ese periodo se realizaron pruebas en el sitio productivo para verificar la capa de datos. lo que disparo el CTR, ya durante el evento se observan 2 picos importantes que superan el 0.10% del CTR: el primer día del evento (lunes 23 de mayo) y el jueves 26, el peor rendimiento observado fue el último día del evento (el martes 31 de mayo) con 0.06% del CTR.

products %>% 
    filter(between(fecha,as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>%
    mutate(diaSemana = factor(wday(fecha, week_start = 1))) %>% 
    mutate(diaSemana = recode_factor(diaSemana,
                  `1` = "lunes",
                  `2` = "martes",
                  `3` = "miércoles",
                  `4` = "jueves",
                  `5` = "viernes",
                  `6` = "sábado",
                  `7` = "domingo",
                  .ordered = TRUE)) %>% 
    group_by(diaSemana) %>% 
    summarise(CTR = sum(clics) / sum(impresiones)) %>% 
    plot_ly(x = ~diaSemana, y = ~CTR, type = "bar", marker = list(color = color_palette[1])) %>% 
    layout(title = "CTR por día de la semana",
           xaxis = list(title = "Día de la semana",
                        showline = TRUE,
                        showgrid = FALSE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = FALSE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           yaxis = list(title = "% CTR",
                        showline = TRUE,
                        showgrid = TRUE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = TRUE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickformat = ".2%",
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)'))) 

Al agrupar por día de la semana podemos ver que el jueves tiene el mejor CTR mientras que los martes son los que tienen el peor desempeño.

date_hour %>% 
    plot_ly(x = ~diaSemana,
            y = ~hora,
            z = ~clics,
            type = "heatmap",
            colors = colorRamp(c("#ffffff", color_palette[1]))
            ) %>% 
    layout(title = "Mapa de calor de los clics por hora y día de la semana",
           xaxis = list(title = "Día de la semana",
                        showline = TRUE,
                        showgrid = FALSE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = FALSE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           yaxis = list(title = "Hora",
                        showline = TRUE,
                        showgrid = TRUE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = TRUE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)'))) 
date_hour %>% 
    mutate(CTR =  percent(clics / impresiones)) %>% 
    plot_ly(x = ~diaSemana,
            y = ~hora,
            z = ~CTR,
            type = "heatmap",
            colors = colorRamp(c("#ffffff", color_palette[1]))
            ) %>% 
    layout(title = "Mapa de calor del CTR por hora y día de la semana",
           xaxis = list(title = "Día de la semana",
                        showline = TRUE,
                        showgrid = FALSE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = FALSE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           yaxis = list(title = "Hora",
                        showline = TRUE,
                        showgrid = TRUE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = TRUE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)'))) %>% 
    colorbar(tickformat = ".2%")




2.2 Adquisición

2.2.1 ¿Qué canales trajeron el tráfico de mejor calidad?

channels %>% 
    group_by(canal) %>% 
    summarise(impresiones =  sum(impresiones),
              clics = sum(clics),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    mutate(pct_impresiones = percent(impresiones / sum(impresiones))) %>%
    select(canal,
           pct_impresiones,
           CTR) %>% 
    arrange(desc(pct_impresiones)) %>% 
    formattable(list(
        pct_impresiones = color_bar(color = color_palette[2], fun = "proportion"),
        CTR = color_bar(color = color_palette[1])))
canal pct_impresiones CTR
Paid Media 87.31% 0.07%
(Other) 6.40% 0.06%
Organic Search 3.32% 0.25%
Direct 1.68% 0.24%
Social 0.49% 0.18%
Email 0.32% 0.32%
Paid Search 0.25% 0.13%
Referral 0.22% 0.22%
Other Advertising 0.00% 0.05%
Display 0.00% 0.00%

El trafico que llego por el canal Paid Media tuvo el 87% del total de las impresiones lo que lo hace el canal preponderante en cantidad de impresiones, sin embargo Email, Organic Search y Direct fueron los canales con el mejor rendimiento ya que su CTR se mantuvo por encima de la media.

2.2.2 ¿Qué fuentes / medios trajeron el tráfico de mejor calidad?

channels %>% 
    group_by(fuenteMedio) %>% 
    summarise(impresiones =  sum(impresiones),
              clics = sum(clics),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    mutate(pct_impresiones = percent(impresiones / sum(impresiones))) %>%
    select(fuenteMedio,
           pct_impresiones,
           CTR) %>% 
    arrange(desc(pct_impresiones)) %>%
    head(30) %>% 
    formattable(list(
        pct_impresiones = color_bar(color = color_palette[2], fun = "proportion"),
        CTR = color_bar(color = color_palette[1])))
fuenteMedio pct_impresiones CTR
tiktok / cpc 44.67% 0.03%
google / cpc 34.90% 0.12%
google / paid 5.16% 0.04%
google / organic 3.24% 0.25%
taboola / cpc 2.40% 0.06%
facebook / cpc 2.28% 0.13%
(direct) / (none) 1.68% 0.24%
twitter / cpc 1.08% 0.01%
erre / soc 0.96% 0.17%
huawei / cpc 0.68% 0.01%
facebook / paid 0.59% 0.13%
tiktok / paid 0.43% 0.05%
bing / cpc 0.37% 0.23%
l.instagram.com / referral 0.27% 0.17%
emBlue / email 0.23% 0.29%
grupoimagen / cpc 0.12% 0.05%
l.facebook.com / referral 0.09% 0.19%
rtbhouse / retargeting 0.09% 0.14%
lm.facebook.com / referral 0.06% 0.19%
bing / organic 0.06% 0.37%
promodescuentos.com / referral 0.04% 0.18%
newsletter / email 0.04% 0.63%
link / link 0.04% 0.15%
televisa / cpc 0.03% 0.01%
tvazteca / cpc 0.03% 0.03%
instagram.com / referral 0.03% 0.15%
industry_event / email 0.03% 0.12%
m.facebook.com / referral 0.02% 0.20%
ml / soc 0.02% 0.15%
tvazteca / soc 0.02% 0.10%

Al desagregar por Fuentes Medios descubrimos que tiktok / cpc es responsable del 45% de las impresiones totales, mientras que google / cpc le sigue con el 35% con lo que suman el 80% del trafico total. Por otro lado la relevancia del trafico traído por google / organic y directo es muy superior.




2.2.3 Top 10 patrocinadores - mejores VS peores canales

2.2.3.1 Top de patrocinadores con más clics en todo el periodo

El objetivo de los siguientes gráficos es poder comprobar que la distribución de los canales en los mejores patrocinadores (basado en los clics recibidos) dista mucho de la configuración de los canales de los patrocinadores que tuvieron un rendimiento inferior (a pesar de estar dentro del top 30 en impresiones).

Los siguientes patrocinadores tuvieron el mejor rendimiento en clics:

top_sponsors <- channels %>%
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>% 
    group_by(patrocinador) %>% 
    summarise(impresiones =  sum(impresiones),
              clics = sum(clics),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    arrange(desc(clics)) %>% 
    head(10)

worst_sponsors <- channels %>%
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>% 
    filter(!patrocinador %in% top_sponsors$patrocinador) %>% 
    group_by(patrocinador) %>% 
    summarise(impresiones =  sum(impresiones),
              clics = sum(clics),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    arrange(desc(impresiones)) %>% 
    head(30) %>% 
    arrange(CTR) %>% 
    head(10)

g <- channels %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>% 
    filter(patrocinador %in% top_sponsors$patrocinador) %>% 
    group_by(patrocinador,
             canal) %>% 
    summarise(impresiones =  sum(impresiones),
              clics = sum(clics),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    mutate(pct_impresiones = percent(impresiones / sum(impresiones)),
           pct_clics = percent(clics / sum(clics))) %>% 
    arrange(desc(pct_impresiones)) %>% 
    ggplot(aes(x = pct_impresiones, y = pct_clics, size = CTR, color = canal)) +
    geom_point(alpha = 0.6) +
    scale_size(range = c(1, 10), name="%CTR") +
    scale_x_log10(name = "% impresiones", labels = scales::percent) +
    scale_y_log10(name = "% clics", labels = scales::percent) +
    facet_wrap(vars(patrocinador), ncol = 2) +
    theme(axis.title=element_text(size=10,face="bold")) + 
    theme_light()
ggplotly(g)

Los siguientes patrocinadores tuvieron un rendimiento inferior a la media de su categoría con respecto a clics:

g <- channels %>%
    filter(between(fecha,
                   as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>% 
    filter(patrocinador %in% worst_sponsors$patrocinador) %>% 
    group_by(patrocinador,
             canal) %>% 
    summarise(impresiones =  sum(impresiones),
              clics = sum(clics),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    mutate(pct_impresiones = percent(impresiones / sum(impresiones)),
           pct_clics = percent(clics / sum(clics))) %>% 
    arrange(desc(pct_impresiones)) %>% 
    ggplot(aes(x = pct_impresiones, y = pct_clics, size = CTR, color = canal)) +
    geom_point(alpha = 0.6) +
    scale_size(range = c(1, 10), name="%CTR") +
    scale_x_log10(name = "% impresiones", labels = scales::percent) +
    scale_y_log10(name = "% clics", labels = scales::percent) +
    facet_wrap(vars(patrocinador), ncol = 2) +
    theme(axis.title=element_text(size=10,face="bold")) + 
    theme_light()
ggplotly(g)

El eje horizontal representa el porcentaje de impresiones recibidas, el eje vertical el porcentaje de clics y el tamaño de la burbuja es el CTR.

2.2.4 Porcentaje de participación de canales por día

channels %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    group_by(fecha,
             canal) %>% 
    summarise(impresiones = sum(impresiones)) %>% 
    mutate(canal = fct_rev(as_factor(tolower(fct_reorder(canal,
                                                         impresiones,
                                                         .fun = sum,
                                                         .desc = FALSE))))) %>% 
    mutate(pct_impresiones = percent(impresiones / sum(impresiones))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_impresiones,
            type = "bar",
            name = ~canal,
            color = ~canal,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del % de impresiones por canal por día",
           yaxis = list(title = "% de impresiones",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"),
           legend = list(font = list(size = 9)))

Durante los días del evento se observa que el % de participación de paid media en las impresiones se mantuvo entre el 74% y el 79%, siendo el jueves 26 el día con la menor y el martes 31 el de mayor participación.

channels %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    group_by(fecha,
             canal) %>% 
    summarise(clics = sum(clics)) %>% 
    mutate(canal = fct_rev(as_factor(tolower(fct_reorder(canal,
                                                         clics,
                                                         .fun = sum,
                                                         .desc = FALSE))))) %>% 
    mutate(pct_clics = percent(clics / sum(clics))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_clics,
            type = "bar",
            name = ~canal,
            color = ~canal,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del % de clics por canal por día",
           yaxis = list(title = "% de clics",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

Respecto al % de clics vemos que paid media mantiene entre el 68% y el 85% de participación, sin embargo cede un porcentaje importante para los canales organic search, directo y (other), principalmente durante el primer y antepenúltimo día del evento.

channels %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    group_by(fecha,
             canal) %>% 
    summarise(impresiones = sum(impresiones),
              clics = sum(clics),
              CTR = sum(clics) / sum(impresiones)) %>% 
    mutate(canal = fct_rev(as_factor(tolower(fct_reorder(canal,
                                                         clics,
                                                         .fun = sum,
                                                         .desc = FALSE))))) %>% 
    mutate(pct_CTR = percent(CTR / sum(CTR))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_CTR,
            type = "bar",
            name = ~canal,
            color = ~canal,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del % del CTR por canal por día",
           yaxis = list(title = "% del CTR",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

En cuanto al % del CTR vemos un panorama totalmente distinto con paid search con entre el 4% y el 9% de la participación, mientras que email, organic search y direct tienen la mayoría en prácticamente todos los días del evento.




2.2.5 Fuente / Medio con mejor calidad de tráfico por día

channels %>% 
    filter(between(fecha,as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>%
    group_by(fecha,
             fuenteMedio) %>% 
    summarise(impresiones = sum(impresiones)) %>% 
    mutate(fuenteMedio = fct_lump_n(
        fuenteMedio,
        9,
        w = impresiones,
        other_level = "Others")) %>% 
    mutate(fuenteMedio = fct_rev(as_factor(tolower(fct_reorder(fuenteMedio,
                                                         impresiones,
                                                         .fun = sum,
                                                         .desc = FALSE))))) %>% 
    mutate(pct_impresiones = percent(impresiones / sum(impresiones))) %>%
    plot_ly(x = ~fecha,
            y = ~pct_impresiones,
            type = "bar",
            name = ~fuenteMedio,
            color = ~fuenteMedio,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del % de impresiones por fuente / medio por día",
           yaxis = list(title = "% de impresiones",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"),
           legend = list(font = list(size = 9)))

Observamos que google cpc y ticktok tienen la mayor cantidad de impresiones durante todo el evento, con aproximadamente el 80% de la participación por día.

channels %>% 
    filter(between(fecha,as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>%
    group_by(fecha,
             fuenteMedio) %>% 
    summarise(clics = sum(clics)) %>% 
    mutate(fuenteMedio = fct_lump_n(
        fuenteMedio,
        9,
        w = clics,
        other_level = "Others")) %>% 
    mutate(fuenteMedio = fct_rev(as_factor(tolower(fct_reorder(fuenteMedio,
                                                         clics,
                                                         .fun = sum,
                                                         .desc = FALSE))))) %>% 
    mutate(pct_clics = percent(clics / sum(clics))) %>%
    plot_ly(x = ~fecha,
            y = ~pct_clics,
            type = "bar",
            name = ~fuenteMedio,
            color = ~fuenteMedio,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del % de clics por fuente / medio por día",
           yaxis = list(title = "% de clics",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"),
           legend = list(font = list(size = 9)))

Sin embargo en la cantidad de clics vemos claramente que google cpc domina la participación, es interesante observar que a partir del 26 de mayo el % de clics provenientes de ticktok aumenta de forma considerable.




2.3 Comportamiento

2.3.1 Tipo de creativo con mejor rendimiento

insta_stories %>%
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    group_by(tipoCreativo) %>% 
    summarise(impresiones = comma(sum(impresiones),0),
              clics = comma(sum(clics),0),
              CTR = percent(sum(clics) / sum(impresiones))) %>%
    mutate(pct_impresiones = percent(impresiones / sum(impresiones))) %>%
    arrange(desc(pct_impresiones)) %>% 
    formattable(list(
        pct_impresiones = color_bar(color = color_palette[2], fun = "proportion"),
        CTR = color_bar(color = color_palette[1])))
tipoCreativo impresiones clics CTR pct_impresiones
Logo 2,883,875,944 1,997,674 0.07% 90.00%
Producto 263,167,698 582,848 0.22% 8.21%
Cintillo 56,356,642 312,419 0.55% 1.76%
InstaStories 864,149 20,922 2.42% 0.03%

El tipo de creativo que recibió mayor porcentaje de impresiones fueron los logos de los patrocinadores, sin embargo el tipo de creativo con mejor CTR fueron las insta stories y los cintillos.

2.3.2 Tipo de creativo por impresiones al día

insta_stories %>% 
    filter(between(fecha,as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>%
    group_by(fecha,
             tipoCreativo) %>% 
    summarise(CTR = percent(sum(clics) / sum(impresiones)),
              clics = sum(clics)) %>% 
    mutate(pct_clics = percent(clics / sum(clics))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_clics,
            type = "bar",
            name = ~tipoCreativo,
            color = ~tipoCreativo,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del % clics por tipo de creativo por día",
           yaxis = list(title = "% de clics",
                        tickformat = ".0%"), barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

En la distribución por clic por tipo de creativo se aprecia claramente que los logos esta entre el 60% y 75% durante el evento, los productos y los cintillos incrementan su participación al final del evento.

2.3.3 Rendimeinto del tipo de creativo por día

insta_stories %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    group_by(fecha,
             tipoCreativo) %>% 
    summarise(CTR = percent(sum(clics) / sum(impresiones)),
              impresiones = sum(impresiones)) %>% 
    mutate(pct_CTR = percent(CTR / sum(CTR))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_CTR,
            type = "bar",
            name = ~tipoCreativo,
            color = ~tipoCreativo,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del CTR por tipo de creativo por día",
           yaxis = list(title = "CTR",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

Podemos observar que durante el evento las insta stories tienen un excelente CTR durante todo el evento pero sobre todo los primeros días.

2.3.4 Detalle insta-stories

2.3.4.1 Porcentaje de clics en cada tipo de creativo por sección del sitio.

insta_stories %>% 
    group_by(tipoCreativo,
             seccion) %>% 
    summarise(clics = comma(sum(clics),0)) %>%
    pivot_wider(names_from = tipoCreativo,
                values_from = clics) %>% 
    mutate(pct_logo = percent(Logo / sum(Logo, na.rm = TRUE)),
        pct_producto = percent(Producto / sum(Producto, na.rm = TRUE)),
           pct_cintillo = percent(Cintillo / sum(Cintillo, na.rm = TRUE)),
    pct_instaStories = percent(InstaStories / sum(InstaStories, na.rm = TRUE))) %>% 
    select(seccion,
           contains("pct_")) %>% 
    arrange(desc(pct_instaStories)) %>% 
    formattable(list(
        pct_logo = color_bar(color = color_palette[2]),
        pct_producto = color_bar(color = color_palette[2]),
        pct_cintillo = color_bar(color = color_palette[2]),
        pct_instaStories = color_bar(color = color_palette[1])
    ))
seccion pct_logo pct_producto pct_cintillo pct_instaStories
Home 75.89% 11.12% 62.01% 86.11%
Electro y tecno 9.23% 9.68% 27.64% 5.59%
Ropa y Calzado 4.37% 1.08% 2.55% 3.19%
Viajes 2.75% 1.63% 1.41% 1.71%
Deportes 1.33% 0.71% 1.80% 1.60%
Muebles y Hogar 1.91% 0.65% 1.34% 0.73%
Belleza 0.86% 0.85% 1.52% 0.53%
Alimentos y Bebidas 0.29% 0.08% 0.33% 0.28%
Otros / Servicios 0.11% 0.02% 0.06% 0.10%
Automotriz 0.58% 0.24% 0.31% 0.09%
Mascotas 0.15% 0.10% NA 0.04%
Luxury 0.10% 0.04% 0.06% 0.01%
content 0.00% NA 0.00% 0.01%
B2B 0.17% NA 0.00% NA
Layer 2 0.00% 0.00% 0.00% NA
Ofertas Flash 0.06% 1.00% 0.94% NA
Sponsor 0.47% 7.42% 0.01% NA
tipsempresas 0.00% NA 0.00% NA
TokenSigning 0.00% 0.00% 0.00% NA
favoritos 0.06% 0.05% NA NA
Índice 0.74% NA NA NA
kueskipay 0.00% NA NA NA
Mega Ofertas 0.43% 5.04% NA NA
Noticia 0.01% 0.03% NA NA
Noticias 0.00% NA NA NA
Ofertas Hot 0.41% 60.26% NA NA
preLanding 0.00% NA NA NA
Productos Hot 0.08% 0.00% NA NA
Registro 0.00% NA NA NA

2.3.4.2 Top Patrocinadores con mejor rendimiento de insta stories

insta_stories %>% 
    filter(tipoCreativo == "InstaStories") %>% 
    group_by(patrocinador) %>% 
    summarise(impresiones = comma(sum(impresiones),0),
              clics = comma(sum(clics),0),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    arrange(desc(impresiones)) %>% 
    head(50) %>% 
    arrange(desc(CTR)) %>% 
    head(10) %>% 
    formattable(list(
        CTR = color_bar(color = color_palette[1])
    ))
patrocinador impresiones clics CTR
Poco XIaomi MiStore 41,412 6,684 16.14%
Puma 11,421 1,343 11.76%
Autobuses ADO 3,025 249 8.23%
Sportico 34,638 2,575 7.43%
Eucerin 22,786 1,471 6.46%
Xiaomi 30,391 1,916 6.30%
La Europea 41,298 2,517 6.09%
Super Colchones 8,274 445 5.38%
American Eagle 7,874 412 5.23%
Prissa 44,192 2,303 5.21%

2.3.4.3 Top Patrocinadores con peor rendimiento de insta stories

insta_stories %>% 
    filter(tipoCreativo == "InstaStories") %>% 
    group_by(patrocinador) %>% 
    summarise(impresiones = comma(sum(impresiones),0),
              clics = comma(sum(clics),0),
              CTR = percent(sum(clics) / sum(impresiones))) %>% 
    arrange(desc(impresiones)) %>% 
    head(50) %>% 
    arrange(CTR) %>% 
    head(10) %>% 
    formattable(list(
        CTR = color_bar(color = color_palette[1])
    ))
patrocinador impresiones clics CTR
Sorteos Tec 4,488 17 0.38%
Zettle 13,431 81 0.60%
Pedidos.com 11,776 77 0.65%
Cosmic Shop 2,416 16 0.66%
Tienda Aeromexico 2,094 15 0.72%
Sillas ADS 2,647 20 0.76%
THE BAR 7,322 59 0.81%
Enterogermina 9,171 77 0.84%
Odetta.com 43,440 366 0.84%
CV Directo 44,513 403 0.91%

2.3.5 Elemento del menú con más clics

menu %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    mutate(elemento = fct_lump_n(
        elemento,
        20,
        w = clicsTotales,
        other_level = "Others")) %>% 
    group_by(elemento) %>% 
    summarise(clicsTotales = comma(sum(clicsTotales),0)) %>%
    mutate(pct_clics = percent(clicsTotales / sum(clicsTotales))) %>% 
    arrange(desc(pct_clics)) %>% 
    formattable(list(pct_clics = color_bar(color = color_palette[1], fun = "proportion"),
                     clicsTotales = color_bar(color = color_palette[2])))
elemento clicsTotales pct_clics
Electro y tecno 54,347 19.19%
Ropa y Calzado 46,695 16.49%
Muebles y Hogar 35,989 12.71%
Viajes 29,053 10.26%
Automotriz 17,745 6.27%
Mega Ofertas 14,795 5.23%
Belleza 14,452 5.10%
Ofertas Hot 14,047 4.96%
Deportes 11,877 4.19%
Ofertas Flash 11,422 4.03%
Alimentos y Bebidas 9,715 3.43%
Mascotas 6,880 2.43%
Otros / Servicios 5,487 1.94%
B2B / Servicios Financieros 5,023 1.77%
Luxury 4,282 1.51%
Preventa KueskiPay 1,335 0.47%

2.3.6 Elemento del menú con más clics por día

menu %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    mutate(elemento = fct_lump_n(
        elemento,
        10,
        w = clicsTotales,
        other_level = "Others")) %>% 
    group_by(fecha,
             elemento) %>%
    summarise_if(is.numeric, sum) %>%
    mutate(pct_clics = percent(clicsTotales / sum(clicsTotales))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_clics,
            type = "bar",
            name = ~elemento,
            color = ~elemento,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución de los clics totales por elemento del menú por día",
           yaxis = list(title = "% de los clics totales",
                        tickformat = ".0%"), barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

2.3.7 Ofertas hot más vistas

ofertas_hot %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>% 
    mutate(pagina = fct_lump_n(
        pagina,
        20,
        w = paginasVistas,
        other_level = "Others")) %>% 
    group_by(pagina) %>%
    summarise(paginasVistas = comma(sum(paginasVistas), 0),
              paginasVistasUnicas = comma(sum(paginasVistasUnicas),0)) %>%
    filter(!pagina == "Others") %>% 
    mutate(pct_paginasVistasUnicas = percent(paginasVistasUnicas / sum(paginasVistasUnicas))) %>% 
    arrange(desc(pct_paginasVistasUnicas)) %>% 
    formattable(list(pct_paginasVistasUnicas = color_bar(color = color_palette[1], fun = "proportion"),
                     paginasVistasUnicas = color_bar(color = color_palette[2])))
pagina paginasVistas paginasVistasUnicas pct_paginasVistasUnicas
/busqueda- 75,829 48,595 22.36%
/electro-y-tecno/computacion-computadoras-y-laptops 31,925 23,128 10.64%
/electro-y-tecno/electro-y-tecno-electrodomesticos-linea-blanca 22,493 19,993 9.20%
/electro-y-tecno 21,173 17,726 8.16%
/electro-y-tecno/electro-y-tecno-celulares-y-telefonia 19,279 16,585 7.63%
/viajes/vuelos-nacionales 21,859 14,264 6.56%
/ropa-y-calzado/calzado-zapatos 12,137 9,100 4.19%
/electro-y-tecno/electro-y-tecno-pantallas-y-televisores 9,090 7,583 3.49%
/viajes 8,511 7,227 3.33%
/ropa-y-calzado/calzado-tenis 8,858 6,430 2.96%
/electro-y-tecno/electro-y-tecno-celulares-y-telefonia?page=2 6,463 5,804 2.67%
/muebles-y-hogar/muebles-y-hogar-linea-blanca 6,477 5,383 2.48%
/viajes/viajes-hoteles 5,977 4,870 2.24%
/ropa-y-calzado 5,778 4,828 2.22%
/busqueda-Iphone/electro-y-tecno-celulares-y-telefonia 5,696 4,818 2.22%
/muebles-y-hogar 5,761 4,693 2.16%
/ropa-y-calzado/ropa-y-calzado-pantalones-y-denim 5,065 4,371 2.01%
/deportes/deportes-calzado-deportivo 5,304 4,343 2.00%
/electro-y-tecno/electro-y-tecno-electrodomesticos-linea-blanca?page=2 4,500 4,024 1.85%
/busqueda-Alexa 4,158 3,558 1.64%

2.3.8 Mejores busquedas de ofertas

ofertas_hot %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    filter(grepl("busqueda", pagina, ignore.case = TRUE)) %>% 
    mutate(pagina = fct_lump_n(
        pagina,
        10,
        w = paginasVistas,
        other_level = "Others")) %>% 
    group_by(pagina) %>%
    summarise(paginasVistasUnicas = comma(sum(paginasVistasUnicas),0)) %>%
    filter(!pagina == "Others") %>% 
    mutate(pct_paginasVistasUnicas = percent(paginasVistasUnicas / sum(paginasVistasUnicas))) %>% 
    arrange(desc(pct_paginasVistasUnicas)) %>% 
    formattable(list(pct_paginasVistasUnicas = color_bar(color = color_palette[1], fun = "proportion"),
                     paginasVistasUnicas = color_bar(color = color_palette[2])))
pagina paginasVistasUnicas pct_paginasVistasUnicas
/busqueda- 48,595 62.54%
/busqueda-Iphone/electro-y-tecno-celulares-y-telefonia 4,818 6.20%
/busqueda-Apple 3,634 4.68%
/busqueda-Alexa 3,558 4.58%
/busqueda-iPhone 3,218 4.14%
/busqueda-Iphone 3,060 3.94%
/busqueda-Xbox 2,961 3.81%
/busqueda-Nike 2,890 3.72%
/busqueda-Laptop/electro-y-tecno-computacion 2,553 3.29%
/busqueda-Refrigerador 2,412 3.10%

2.4 Conversiones

2.4.1 Patrocinadores con mejores impresiones, clics y CTR

products %>% 
    mutate(patrocinador = fct_lump_n(
        patrocinador,
        10,
        w = impresiones,
        other_level = "others")) %>% 
    group_by(patrocinador) %>%
    summarise_if(is.numeric, sum) %>% 
    filter(!patrocinador == "others") %>% 
    arrange(desc(impresiones)) %>% 
    mutate(patrocinador = fct_rev(as_factor(tolower(fct_reorder(patrocinador,
                                                        impresiones,
                                                        .fun = sum,
                                                        .desc = FALSE))))) %>% 
    plot_ly(x = ~clics,
            y = ~patrocinador,
            type = "bar",
            orientation = "h",
            name = "clics",
            marker = list(color = color_palette[2])) %>% 
    add_trace(x = ~impresiones,
              name = "impresiones",
              marker = list(color = color_palette[1])) %>% 
    layout(title = "Top 10 patrocinadores <br><sub>Ordenado por cantidad de impresiones</sub>",
           margin = list(autoexpand = TRUE,
                         t = 100,
                         l = 200,
                         r = 150,
                         b = 100),
           yaxis = list(title = 'Patrocinador',
                        automargin = TRUE),
           xaxis = list(title = "",
                        type = "log"),
           barmode = 'group')

2.4.2 Distribución de los patrocinadores por día

products %>% 
    filter(between(fecha,
                   as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>%
    mutate(patrocinador = fct_lump_n(
        patrocinador,
        10,
        w = impresiones,
        other_level = "others")) %>% 
    filter(!patrocinador == "others") %>% 
    group_by(fecha,
             patrocinador) %>%
    summarise_if(is.numeric, sum) %>%
    mutate(pct_impresiones = percent(impresiones / sum(impresiones))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_impresiones,
            type = "bar",
            name = ~patrocinador,
            color = ~patrocinador,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución de las impresiones por patrocinador por día",
           yaxis = list(title = "impresiones",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))
products %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    mutate(patrocinador = fct_lump_n(
        patrocinador,
        10,
        w = clics,
        other_level = "others")) %>% 
    filter(!patrocinador == "others") %>% 
    group_by(fecha,
             patrocinador) %>%
    summarise_if(is.numeric, sum) %>%
    mutate(pct_clics = percent(clics / sum(clics))) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_clics,
            type = "bar",
            name = ~patrocinador,
            color = ~patrocinador,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución de los clics por patrocinador por día",
           yaxis = list(title = "clics",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

2.4.3 Niveles de patrocinio con mayor cantidad de patrocinadores

sponsor_level_ex <- c("indice-de-marcas",
                      "oferta-hot",
                      "favoritos",
                      "oferta-hot-preventa")
products %>% 
    filter(between(fecha,
                   as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>%
    filter(!nivelPatrocinio %in% sponsor_level_ex & !grepl(pattern = "marcas.*|cat-.*",
                                                           x = nivelPatrocinio,
                                                           ignore.case = TRUE)) %>% 
    group_by(nivelPatrocinio) %>% 
    summarise(n_patrocinadores = n_distinct(patrocinador)) %>% 
    arrange(desc(n_patrocinadores)) %>% 
    head(10) %>% 
    formattable(list(n_patrocinadores = color_bar(color = color_palette[1],
                                                         fun = "proportion")))
nivelPatrocinio n_patrocinadores
insta-story-rotativo 95
plata-rotativo 95
bronce-rotativo 90
sponsor-y-apoyos 89
oro-rotativo 58
megaofertas 51
oferta-hot-destacado-categorias-top 51
mega-ofertas 46
oferta-hot-destacado-home 45
platino-rotativo 40

2.4.4 Clics por sección del sitio por día

products %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    mutate(seccion = fct_lump_n(
        seccion,
        10,
        w = clics,
        other_level = "others")) %>% 
    filter(!seccion == "others") %>% 
    group_by(fecha,
             seccion) %>%
    summarise_if(is.numeric, sum) %>% 
    mutate(pct_clics = percent(clics / sum(clics))) %>% mutate() %>% 
    plot_ly(x = ~fecha,
            y = ~pct_clics,
            type = "bar",
            name = ~seccion,
            color = ~seccion,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución de los clics por seccion por día",
           yaxis = list(title = "clics",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

2.4.5 Secciones con mayor cantidad de patrocinadores

products %>% 
    filter(between(fecha,
                   as.Date("2022-05-23"),
                   as.Date("2022-05-31"))) %>%
    group_by(seccion) %>% 
    summarise(n_patrocinadores = n_distinct(patrocinador)) %>% 
    arrange(desc(n_patrocinadores)) %>% 
    head(10) %>% 
    formattable(list(n_patrocinadores = color_bar(color = color_palette[1],
                                                         fun = "proportion")))
seccion n_patrocinadores
Índice 906
Ofertas Hot 615
Home 609
favoritos 510
Sponsor 309
Ropa y Calzado 160
Muebles y Hogar 139
Electro y tecno 134
Mega Ofertas 131
Otros / Servicios 113

2.4.6 Nivel de patrocinio con mejores impresiones, clics y CTR

products %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    mutate(nivelPatrocinio = fct_lump_n(
        nivelPatrocinio,
        10,
        w = impresiones,
        other_level = "others")) %>% 
    filter(!nivelPatrocinio == "others") %>% 
    group_by(fecha,
             nivelPatrocinio) %>%
    summarise_if(is.numeric, sum) %>%
    mutate(pct_impresiones = impresiones/ sum(impresiones)) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_impresiones,
            type = "bar",
            name = ~nivelPatrocinio,
            color = ~nivelPatrocinio,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución de las impresiones por nivel de patrocinio por día",
           yaxis = list(title = "impresiones",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))
products %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    mutate(nivelPatrocinio = fct_lump_n(
        nivelPatrocinio,
        10,
        w = clics,
        other_level = "others")) %>% 
    filter(!nivelPatrocinio == "others") %>% 
    group_by(fecha,
             nivelPatrocinio) %>%
    summarise_if(is.numeric, sum) %>%
    mutate(pct_clics = clics / sum(clics)) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_clics,
            type = "bar",
            name = ~nivelPatrocinio,
            color = ~nivelPatrocinio,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución de los clics por nivel de patrocinio por día",
           yaxis = list(title = "clics",
                        tickformat = ".0%"),
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))
products %>% 
    filter(between(fecha,as.Date("2022-05-23"), as.Date("2022-05-31"))) %>%
    mutate(nivelPatrocinio = fct_lump_n(
        nivelPatrocinio,
        10,
        w = impresiones,
        other_level = "others")) %>% 
    filter(!nivelPatrocinio == "others") %>% 
    group_by(fecha,
             nivelPatrocinio) %>%
    summarise(impresiones = sum(impresiones),
              clics = sum(clics),
              CTR = sum(clics) /  sum(impresiones)) %>% 
    mutate(pct_CRT = CTR / sum(CTR)) %>% 
    plot_ly(x = ~fecha,
            y = ~pct_CRT,
            type = "bar",
            name = ~nivelPatrocinio,
            color = ~nivelPatrocinio,
            colors = color_palette[3]) %>% 
    layout(title = "Distribución del CTR por nivel de patrocinio por día",
           yaxis = list(title = "CTR",
                        tickformat = ".0%"), 
           barmode = "stack",
           font = list(family = "PT Sans Narrow'"))

2.5 Landing tips empresas

2.5.1 tendencia de los clics y las impresiones

products %>%
    filter(grepl("tipsempresas",
                 seccion,
                 ignore.case = TRUE)) %>% 
    group_by(fecha) %>% 
    summarise(impresiones = sum(impresiones),
              clics = sum(clics)) %>% 
    plot_ly(x = ~fecha) %>%
    add_trace(y = ~clics,
              type = 'scatter',
              mode = 'lines',
              name = 'clics',
              line = list(color = color_palette[2],
                          width = 2)) %>%
    add_trace(y = ~impresiones,
              type = 'scatter',
              mode = 'lines',
              name = 'impresiones',
              line = list(color = color_palette[1],
                          width = 4)) %>%
    layout(title = "Landing tips - Tendencia por día",
           xaxis = list(title = "",
                        showline = TRUE,
                        showgrid = FALSE,
                        showticklabels = TRUE,
                        linecolor = 'rgb(204, 204, 204)',
                        linewidth = 2,
                        autotick = FALSE,
                        ticks = 'outside',
                        tickcolor = 'rgb(204, 204, 204)',
                        tickwidth = 2,
                        ticklen = 5,
                        tickfont = list(family = 'PT Sans Narrow',
                                        size = 12,
                                        color = 'rgb(82, 82, 82)')),
           yaxis = list(title = "",
                        type = "log"),
           margin = list(autoexpand = TRUE,
                         t = 100,
                         l = 50,
                         r = 200,
                         b = 100),
           autosize = TRUE,
           showlegend = TRUE,
           annotations = list(
               xref = 'paper',
               yref = 'paper',
               x = 0.73,
               y = 0.9,
               xanchor = 'right',
               yanchor = 'middle',
               text = 'Primer del Hot Sale',
               font = list(family = 'PT Sans Narrow',
                           size = 16,
                           color = 'rgba(160,160,160,1)'),
               showarrow = TRUE)) %>%
    layout(annotations = list(
        xref = 'paper',
        yref = 'paper',
        x = 1,
        y = 0.6,
        xanchor = 'left',
        yanchor = 'middle',
        text = 'Último del Hot Sale',
        font = list(family = 'PT Sans Narrow',
                    size = 16,
                    color = 'rgba(160,160,160,1)'),
        showarrow = TRUE))

2.5.2 Patrocinadores con más clics

products %>% 
    filter(grepl("tipsempresas",
                 seccion,
                 ignore.case = TRUE)) %>% 
    mutate(patrocinador = fct_lump_n(
        patrocinador,
        10,
        w = impresiones,
        other_level = "Others")) %>% 
    group_by(patrocinador) %>%
    summarise_if(is.numeric, sum) %>% 
    mutate(patrocinador = as_factor(tolower(fct_reorder(patrocinador,
                                              impresiones,
                                              .fun = sum,
                                              .desc = TRUE)))) %>% 
    filter(!patrocinador == "others") %>% 
    plot_ly(x = ~clics,
            y = ~patrocinador,
            type = "bar",
            orientation = "h",
            name = "clics",
            marker = list(color = color_palette[2])) %>%
    add_trace(x = ~impresiones,
              name = "impresiones",
              marker = list(color = color_palette[1])) %>% 
    layout(title = "Landings tips - Top 10 patrocinadores <br><sub>Ordenado por cantidad de impresiones</sub>",
           margin = list(autoexpand = TRUE,
                         t = 100,
                         l = 200,
                         r = 150,
                         b = 100),
           yaxis = list(title = 'Patrocinador',
                        automargin = TRUE),
           xaxis = list(title = "",
                        type = "log"),
           barmode = 'group')
LS0tCnRpdGxlOiAiSG90IFNhbGUgMjAyMiIKYXV0aG9yOiAiSm9zw6kgQ2FybG9zIENvcm9uYSIKZGF0ZTogIjcgZGUgSnVsaW8gZGUgMjAyMiIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogY29zbW8KICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgZmlnX3dpZHRoOiAxMAogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDoKICAgICAgY29sbGFwc2VkOiBubwogICAgICBzbW9vdGhfc2Nyb2xsOiBubwogICAgaGlnaGxpZ2h0OiBlc3ByZXNzbwogIHN1YnRpdGxlOiBBbsOhbGlzaXMgZXhwbG9yYXRvcmlvIGRlIGRhdG9zCi0tLQoKYGBge3Igb3B0aW9ucywgZWNobz1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHdhcm5pbmcgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBGQUxTRSkKaHRtbHRvb2xzOjppbWcoc3JjID0ga25pdHI6OmltYWdlX3VyaSgibG9nby1lcGEtMi5qcGciKSwgCiAgICAgICAgICAgICAgIGFsdCA9ICdsb2dvJywgCiAgICAgICAgICAgICAgIHN0eWxlID0gJ3Bvc2l0aW9uOmFic29sdXRlOyB0b3A6MDsgbGVmdDo5MHJlbTsgcmlnaHQ6MDsgcGFkZGluZzoxMHB4OyBoZWlnaHQ6MTAwcHg7IHdpZHRoOjEwMHB4JykKY29sb3JfcGFsZXR0ZSA8LSBjKCIjMjc4MGUzIiwKICAgICAgICAgICAgICAgICAgICIjYmRiZGJkIiwKICAgICAgICAgICAgICAgICAgICJTZXQzIikKYGBgCiAgCjxicj4KPGJyPgo8YnI+CiAgCiMgT2JqZXRpdm8KCkNvbXByZW5kZXIgbWVqb3IgZWwgY29tcG9ydGFtaWVudG8gZGUgbG9zIHVzdWFyaW9zLCBlbCByZW5kaW1pZW50byBkZWwgc2l0aW8geSBsYXMgZGlmZXJlbmNpYXMgZGUgbGEgZWRpY2nDs24gMjAyMiBkZSBIb3QgU2FsZSBjb250cmEgbGFzIGVkaWNpb25lcyBwYXNhZGFzLgoKYGBge3IgbGlicmFyaWVzfQojIENhcmdhciBsYXMgbGlicmVyw61hcyBuZWNlc2FyaWFzCmlmICghcmVxdWlyZSgicGFjbWFuIikpIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpCnBhY21hbjo6cF9sb2FkKGFycm93LAogICAgICAgICAgICAgICBjb3JyZWxhdGlvbmZ1bm5lbCwKICAgICAgICAgICAgICAgZm9ybWF0dGFibGUsCiAgICAgICAgICAgICAgIGdncGxvdDIsCiAgICAgICAgICAgICAgIGx1YnJpZGF0ZSwKICAgICAgICAgICAgICAgb3V0bGllcnMsCiAgICAgICAgICAgICAgIHBsb3RseSwKICAgICAgICAgICAgICAgdGlkeXZlcnNlKQoKYGBgCgpgYGB7ciByZWFkX2RhdGF9CiMgTGVlciBsYSBkYXRhIGRlIGxhIGVkaWNpw7NuCmRhdGVfaG91ciA8LSByZWFkX2NzdigiZGF0YS8yLXByb2Nlc3NlZC9ob3RzYWxlXzIwMjJfZWRpdGlvbl8yMDIyLTA1LTAxXzIwMjItMDUtMzEuY3N2IiwgCiAgICBjb2xfdHlwZXMgPSBjb2xzKGRhdGVIb3VyID0gY29sX2RhdGV0aW1lKGZvcm1hdCA9ICIlWSVtJWQlSCIpKSkgJT4lIAogICAgcmVuYW1lKGZlY2hhSG9yYSA9IGRhdGVIb3VyLAogICAgICAgICAgIGltcHJlc2lvbmVzID0gcHJvZHVjdExpc3RWaWV3cywKICAgICAgICAgICBjbGljcyA9IHByb2R1Y3RMaXN0Q2xpY2tzKSAlPiUgCiAgICBtdXRhdGUoZGlhU2VtYW5hID0gZmFjdG9yKHdkYXkoZmVjaGFIb3JhLCB3ZWVrX3N0YXJ0ID0gMSkpKSAlPiUgCiAgICBtdXRhdGUoZGlhU2VtYW5hID0gcmVjb2RlX2ZhY3RvcihkaWFTZW1hbmEsCiAgICAgICAgICAgICAgICAgIGAxYCA9ICJsdW5lcyIsCiAgICAgICAgICAgICAgICAgIGAyYCA9ICJtYXJ0ZXMiLAogICAgICAgICAgICAgICAgICBgM2AgPSAibWnDqXJjb2xlcyIsCiAgICAgICAgICAgICAgICAgIGA0YCA9ICJqdWV2ZXMiLAogICAgICAgICAgICAgICAgICBgNWAgPSAidmllcm5lcyIsCiAgICAgICAgICAgICAgICAgIGA2YCA9ICJzw6FiYWRvIiwKICAgICAgICAgICAgICAgICAgYDdgID0gImRvbWluZ28iLAogICAgICAgICAgICAgICAgICAub3JkZXJlZCA9IFRSVUUpLAogICAgICAgICAgIGhvcmEgPSBmb3JtYXQoZmVjaGFIb3JhLCAiJUg6MDAiKSkKCiMgTGVlciBsYSBkYXRhIGRlIGNhbmFsZXMKY2hhbm5lbHMgPC0gcmVhZF9jc3YoImRhdGEvMi1wcm9jZXNzZWQvaG90c2FsZV8yMDIyX2NoYW5uZWxfMjAyMi0wNS0wMS0yMDIyLTA1LTMxLmNzdiIsIAogICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKC4uLjEgPSBjb2xfc2tpcCgpLCBgZ2E6cHJvZHVjdFNrdWAgPSBjb2xfY2hhcmFjdGVyKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGUgPSBjb2xfZGF0ZShmb3JtYXQgPSAiJVktJW0tJWQiKSkpICU+JSAKICAgIHJlbmFtZV93aXRoKH5zdHJfcmVwbGFjZSguLCAiZ2E6IiwgIiIpLCBldmVyeXRoaW5nKCkpICU+JSAKICAgIHNlbGVjdChmZWNoYSA9IGRhdGUsCiAgICAgICAgICAgaWRQYXRyb2NpbmFkb3IgPSBwcm9kdWN0U2t1LAogICAgICAgICAgIHBhdHJvY2luYWRvciA9IHByb2R1Y3RCcmFuZCwKICAgICAgICAgICBjYW5hbCA9IGNoYW5uZWxHcm91cGluZywKICAgICAgICAgICBmdWVudGVNZWRpbyA9IHNvdXJjZU1lZGl1bSwKICAgICAgICAgICBpbXByZXNpb25lcyA9IHByb2R1Y3RMaXN0Vmlld3MsCiAgICAgICAgICAgY2xpY3MgPSBwcm9kdWN0TGlzdENsaWNrcykKCiMgTGVlciBsYSBkYXRhIGRlIGNyZWF0aXZvcwpjcmVhdGl2ZSA8LSByZWFkX2NzdigiZGF0YS8yLXByb2Nlc3NlZC9ob3RzYWxlXzIwMjJfY3JlYXRpdmVfMjAyMi0wNS0xMC0yMDIyLTA1LTMxLmNzdiIsIAogICAgICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKGRhdGUgPSBjb2xfZGF0ZShmb3JtYXQgPSAiJVktJW0tJWQiKSkpICU+JSAKICAgIHJlbmFtZV93aXRoKH5zdHJfcmVwbGFjZSguLCAiZ2E6IiwgIiIpLCBldmVyeXRoaW5nKCkpICU+JSAKICAgIHNlbGVjdChmZWNoYSA9IGRhdGUsCiAgICAgICAgICAgdGlwb0NyZWF0aXZvID0gZGltZW5zaW9uMTAsCiAgICAgICAgICAgaW1wcmVzaW9uZXMgPSBwcm9kdWN0TGlzdFZpZXdzLAogICAgICAgICAgIGNsaWNzID0gcHJvZHVjdExpc3RDbGlja3MpICU+JSAKICAgIG11dGF0ZSh0aXBvQ3JlYXRpdm8gPSBjYXNlX3doZW4oCiAgICAgICAgdGlwb0NyZWF0aXZvID09ICJTcG9uc29yIiB+ICJMb2dvIiwKICAgICAgICB0aXBvQ3JlYXRpdm8gPT0gIkJhbm5lciIgfiAiQ2ludGlsbG8iLAogICAgICAgIFRSVUUgfiB0aXBvQ3JlYXRpdm8KICAgICkpCgojIExlZXIgZGF0b3MgZGUgbGFzIGluc3Rhc3RvcmllcwppbnN0YV9zdG9yaWVzIDwtIHJlYWRfY3N2KCJkYXRhLzItcHJvY2Vzc2VkL2hvdHNhbGVfMjAyMl9jcmVhdGl2ZV9pbnN0YVN0b3JpZXNfMjAyMi0wNS0wMV8yMDIyLTA1LTMxLmNzdiIsIAogICAgY29sX3R5cGVzID0gY29scyhkYXRlID0gY29sX2RhdGUoZm9ybWF0ID0gIiVZLSVtLSVkIikpKSAlPiUgCiAgICByZW5hbWUoZmVjaGEgPSBkYXRlLAogICAgICAgICAgIHBhdHJvY2luYWRvciA9IHByb2R1Y3RCcmFuZCwKICAgICAgICAgICB0aXBvQ3JlYXRpdm8gPSBkaW1lbnNpb24xMCwKICAgICAgICAgICBzZWNjaW9uID0gcHJvZHVjdExpc3ROYW1lLAogICAgICAgICAgIGNsaWNzID0gcHJvZHVjdExpc3RDbGlja3MpICU+JSAKICAgIG11dGF0ZShpbXByZXNpb25lcyA9IGNhc2Vfd2hlbih0aXBvQ3JlYXRpdm8gPT0gIkluc3RhU3RvcmllcyIgfiBwcm9kdWN0RGV0YWlsVmlld3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgVFJVRSB+IHByb2R1Y3RMaXN0Vmlld3MpKSAlPiUgCiAgICBzZWxlY3QoLXByb2R1Y3RMaXN0Vmlld3MsCiAgICAgICAgICAgLXByb2R1Y3REZXRhaWxWaWV3cykgJT4lIAogICAgbXV0YXRlKHRpcG9DcmVhdGl2byA9IGNhc2Vfd2hlbigKICAgICAgICB0aXBvQ3JlYXRpdm8gPT0gIlNwb25zb3IiIH4gIkxvZ28iLAogICAgICAgIHRpcG9DcmVhdGl2byA9PSAiQmFubmVyIiB+ICJDaW50aWxsbyIsCiAgICAgICAgVFJVRSB+IHRpcG9DcmVhdGl2bwogICAgKSkKIyBMZWVyIGxhIGRhdGEgZGUgbWVudQptZW51IDwtIHJlYWRfY3N2KCJkYXRhLzItcHJvY2Vzc2VkL2hvdHNhbGVfMjAyMl9tZW51XzIwMjItMDUtMTYtMjAyMi0wNS0zMS5jc3YiLCAKICAgICAgICAgICAgICAgICBjb2xfdHlwZXMgPSBjb2xzKC4uLjEgPSBjb2xfc2tpcCgpLCBgZ2E6dG90YWxFdmVudHNgID0gY29sX2ludGVnZXIoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgZ2E6dW5pcXVlRXZlbnRzYCA9IGNvbF9pbnRlZ2VyKCksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlWS0lbS0lZCIpKSkgJT4lCiAgICByZW5hbWVfd2l0aCh+c3RyX3JlcGxhY2UoLiwgImdhOiIsICIiKSwgZXZlcnl0aGluZygpKSAlPiUgCiAgICBzZWxlY3QoZmVjaGEgPSBkYXRlLAogICAgICAgICAgIGVsZW1lbnRvID0gZXZlbnRMYWJlbCwKICAgICAgICAgICBjbGljc1RvdGFsZXMgPSB0b3RhbEV2ZW50cywKICAgICAgICAgICBjbGljc1VuaWNvcyA9IHVuaXF1ZUV2ZW50cykKCiMgTGVlciBsYSBkYXRhIGRlIG9mZXJ0YXMgaG90Cm9mZXJ0YXNfaG90IDwtIHJlYWRfY3N2KCJkYXRhLzItcHJvY2Vzc2VkL2hvdHNhbGVfMjAyMl9vZmVydGFzLWhvdF8yMDIyLTA1LTE4LTIwMjItMDUtMzEuY3N2IiwgCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGNvbHMoLi4uMSA9IGNvbF9za2lwKCksIGRhdGUgPSBjb2xfZGF0ZShmb3JtYXQgPSAiJVktJW0tJWQiKSkpICU+JSAKICAgIHJlbmFtZV93aXRoKH5zdHJfcmVwbGFjZSguLCAiZ2E6IiwgIiIpLCBldmVyeXRoaW5nKCkpICU+JQogICAgbXV0YXRlKHBhZ2VQYXRoID0gc3RyX3JlbW92ZShwYWdlUGF0aCwgIi9vZmVydGFzLWhvdCIpKSAlPiUgCiAgICBzZWxlY3QoZmVjaGEgPSBkYXRlLAogICAgICAgICAgIHBhZ2luYSA9IHBhZ2VQYXRoLAogICAgICAgICAgIHBhZ2luYXNWaXN0YXMgPSBwYWdldmlld3MsCiAgICAgICAgICAgcGFnaW5hc1Zpc3Rhc1VuaWNhcyA9IHVuaXF1ZVBhZ2V2aWV3cykKCiMgTGVlciBsYSBkYXRhIGRlIHByb2R1Y3Rvcwpwcm9kdWN0cyA8LSByZWFkX2NzdigiZGF0YS8yLXByb2Nlc3NlZC9ob3RzYWxlLTIwMjItcHJvZHVjdHMuY3N2IiwgCiAgICAgICAgICAgICAgICAgICAgIGNvbF90eXBlcyA9IGNvbHMocHJvZHVjdFNrdSA9IGNvbF9jaGFyYWN0ZXIoKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0ZSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlWS0lbS0lZCIpKSkgJT4lIAogICAgcmVuYW1lX3dpdGgofnN0cl9yZXBsYWNlKC4sICJnYToiLCAiIiksIGV2ZXJ5dGhpbmcoKSkgJT4lIAogICAgc2VsZWN0KGZlY2hhID0gZGF0ZSwKICAgICAgICAgICBpZFBhdHJvY2luYWRvciA9IHByb2R1Y3RTa3UsCiAgICAgICAgICAgcGF0cm9jaW5hZG9yID0gcHJvZHVjdEJyYW5kLAogICAgICAgICAgIHNlY2Npb24gPSBwcm9kdWN0TGlzdE5hbWUsCiAgICAgICAgICAgbml2ZWxQYXRyb2NpbmlvID0gZGltZW5zaW9uNywKICAgICAgICAgICBpbXByZXNpb25lcyA9IHZpZXdzLAogICAgICAgICAgIGNsaWNzKQoKIyBMZWVyIGxhIGRhdGEgZGUgbGFzIGLDunNxdWVkYXMKc2VhcmNoZXMgPC0gcmVhZF9jc3YoImRhdGEvMi1wcm9jZXNzZWQvaG90c2FsZV8yMDIyX3NlYXJjaGVzXzIwMjItMDUtMTYtMjAyMi0wNS0zMS5jc3YiLCAKICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyguLi4xID0gY29sX3NraXAoKSwgZGF0ZSA9IGNvbF9kYXRlKGZvcm1hdCA9ICIlWS0lbS0lZCIpKSkgJT4lCiAgICByZW5hbWVfd2l0aCh+c3RyX3JlcGxhY2UoLiwgImdhOiIsICIiKSwgZXZlcnl0aGluZygpKSAlPiUgCiAgICBzZWxlY3QoZmVjaGEgPSBkYXRlLAogICAgICAgICAgIGJ1c3F1ZWRhID0gZXZlbnRMYWJlbCwKICAgICAgICAgICB0b3RhbEJ1c3F1ZWRhcyA9IHRvdGFsRXZlbnRzLAogICAgICAgICAgIGJ1c3F1ZWRhc1VuaWNhcyA9IHVuaXF1ZUV2ZW50cykKCiMgTGVlciBsYSBkYXRhIGRlIGxhcyBzZWNjaW9uZXMKc2VjdGlvbnMgPC0gcmVhZF9jc3YoImRhdGEvMi1wcm9jZXNzZWQvaG90c2FsZV8yMDIyX3NlY3Rpb25zXzIwMjItMDUtMDEtMjAyMi0wNS0zMS5jc3YiLCAKICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhkYXRlID0gY29sX2RhdGUoZm9ybWF0ID0gIiVZLSVtLSVkIiksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBnYTpwYWdldmlld3NgID0gY29sX2ludGVnZXIoKSwgYGdhOnVuaXF1ZVBhZ2V2aWV3c2AgPSBjb2xfaW50ZWdlcigpKSklPiUKICAgIHJlbmFtZV93aXRoKH5zdHJfcmVwbGFjZSguLCAiZ2E6IiwgIiIpLCBldmVyeXRoaW5nKCkpICU+JSAKICAgIHNlbGVjdChmZWNoYSA9IGRhdGUsCiAgICAgICAgICAgc2VjY2lvbiA9IGNsZWFuUGFnZSwKICAgICAgICAgICBwYWdpbmFzVmlzdGFzID0gcGFnZXZpZXdzLAogICAgICAgICAgIHBhZ2luYXNWaXN0YXNVbmljYXMgPSB1bmlxdWVQYWdldmlld3MpCgojIExlZXIgbGEgZGF0YSBkZSBmYXZvcml0b3MKd2lzaGxpc3QgPC0gcmVhZF9jc3YoImRhdGEvMi1wcm9jZXNzZWQvaG90c2FsZV8yMDIyX3dpc2hsaXN0XzIwMjItMDUtMDQtMjAyMi0wNS0zMS5jc3YiLCAKICAgICAgICAgICAgICAgICAgICAgY29sX3R5cGVzID0gY29scyhkYXRlID0gY29sX2RhdGUoZm9ybWF0ID0gIiVZLSVtLSVkIikpKSAlPiUgCiAgICByZW5hbWVfd2l0aCh+c3RyX3JlcGxhY2UoLiwgImdhOiIsICIiKSwgZXZlcnl0aGluZygpKSAlPiUgCiAgICBzZWxlY3QoZmVjaGEgPSBkYXRlLAogICAgICAgICAgIHRvdGFsRmF2b3JpdG9zID0gdG90YWxFdmVudHMsCiAgICAgICAgICAgZmF2b3JpdG9zVW5pY29zID0gdW5pcXVlRXZlbnRzKQpgYGAKICAKPGJyPgo8YnI+Cjxicj4KICAKIyBBbsOhbGlzaXMgRGVzY3JpcHRpdm8KCiMjIEVkaWNpw7NuCgojIyMgVGVuZGVuY2lhIGRlIGxhIGVkaWNpw7NuIHBvciBkw61hCgpgYGB7ciBlZGljaW9uLXRyZW5kfQpwcm9kdWN0cyAlPiUgCiAgICBncm91cF9ieShmZWNoYSkgJT4lIAogICAgc3VtbWFyaXNlKGltcHJlc2lvbmVzID0gY29tbWEoc3VtKGltcHJlc2lvbmVzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDApLAogICAgICAgICAgICAgIGNsaWNzID0gY29tbWEoc3VtKGNsaWNzKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpZ2l0cyA9IDApKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEpICU+JSAKICAgIGFkZF90cmFjZSh5ID0gfmltcHJlc2lvbmVzLAogICAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsCiAgICAgICAgICAgICAgbW9kZSA9ICdsaW5lcycsCiAgICAgICAgICAgICAgbmFtZSA9ICdpbXByZXNpb25lcycsCiAgICAgICAgICAgICAgbGluZSA9IGxpc3QoY29sb3IgPSBjb2xvcl9wYWxldHRlWzJdLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoID0gMikpICU+JQogICAgYWRkX3RyYWNlKHkgPSB+Y2xpY3MsCiAgICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywKICAgICAgICAgICAgICBtb2RlID0gJ2xpbmVzJywKICAgICAgICAgICAgICBuYW1lID0gJ2NsaWNzJywKICAgICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9IGNvbG9yX3BhbGV0dGVbMV0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSA0KSkgJT4lIAogICAgbGF5b3V0KHRpdGxlID0gIlRlbmRlbmNpYSBkZSBsYXMgaW1wcmVzaW9uZXMgeSBjbGljcyBwb3IgZMOtYTxicj48c3ViPkRlbCAxIGFsIDMxIG1heW8gZGVsIDIwMjI8L3N1Yj4iLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93bGluZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dncmlkID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3d0aWNrbGFiZWxzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgbGluZWNvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG90aWNrID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tzID0gJ291dHNpZGUnLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgdGlja3dpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2xlbiA9IDUsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tmb250ID0gbGlzdChmYW1pbHkgPSAnUFQgU2FucyBOYXJyb3cnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiKDgyLCA4MiwgODIpJykpLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImxvZyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsaW5lID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2dyaWQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93dGlja2xhYmVscyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVjb2xvciA9ICdyZ2IoMjA0LCAyMDQsIDIwNCknLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSAyLAogICAgICAgICAgICAgICAgICAgICAgICBhdXRvdGljayA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrcyA9ICdvdXRzaWRlJywKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2NvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tsZW4gPSA1LAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9udCA9IGxpc3QoZmFtaWx5ID0gJ1BUIFNhbnMgTmFycm93JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ3JnYig4MiwgODIsIDgyKScpKSwKICAgICAgICAgICBtYXJnaW4gPSBsaXN0KGF1dG9leHBhbmQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgdCA9IDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIGwgPSA1MCwKICAgICAgICAgICAgICAgICAgICAgICAgIHIgPSAyMDAsCiAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMTAwKSwKICAgICAgICAgICBhdXRvc2l6ZSA9IFRSVUUsCiAgICAgICAgICAgc2hvd2xlZ2VuZCA9IFRSVUUsCiAgICAgICAgICAgYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICAgICAgICAgICB4cmVmID0gJ3BhcGVyJywKICAgICAgICAgICAgICAgeXJlZiA9ICdwYXBlcicsCiAgICAgICAgICAgICAgIHggPSAwLjczLAogICAgICAgICAgICAgICB5ID0gMC41LAogICAgICAgICAgICAgICB4YW5jaG9yID0gJ3JpZ2h0JywKICAgICAgICAgICAgICAgeWFuY2hvciA9ICdtaWRkbGUnLAogICAgICAgICAgICAgICB0ZXh0ID0gJ1ByaW1lciBkw61hIGRlbCBIb3QgU2FsZScsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICdQVCBTYW5zIE5hcnJvdycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiYSgxNjAsMTYwLDE2MCwxKScpLAogICAgICAgICAgICAgICBzaG93YXJyb3cgPSBUUlVFKSkgJT4lCiAgICBsYXlvdXQoYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICAgIHhyZWYgPSAncGFwZXInLAogICAgICAgIHlyZWYgPSAncGFwZXInLAogICAgICAgIHggPSAxLAogICAgICAgIHkgPSAwLjQ0LAogICAgICAgIHhhbmNob3IgPSAnbGVmdCcsCiAgICAgICAgeWFuY2hvciA9ICdtaWRkbGUnLAogICAgICAgIHRleHQgPSAnw5psdGltbyBkw61hIGRlbCBIb3QgU2FsZScsCiAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gJ1BUIFNhbnMgTmFycm93JywKICAgICAgICAgICAgICAgICAgICBzaXplID0gMTYsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiYSgxNjAsMTYwLDE2MCwxKScpLAogICAgICAgIHNob3dhcnJvdyA9IFRSVUUpKQpgYGAKClNlIG9ic2VydmEgcXVlICoqZGVsIDEgYWwgMTcgZGUgbWF5byoqIGhheSB1biAqKmNyZWNpbWllbnRvIGV4cG9uZW5jaWFsIGVuIGxhcyBpbXByZXNpb25lcyB5IGNsaWNzKiosIHF1ZSBhdW1lbnRhIGF1biBtw6FzIGEgcGFydGlyIGRlIGVzYSBmZWNoYSB5IGhhc3RhIGVsIDIzLCAqKmRlbCAyNCBhbCAzMSoqIGxvcyBjbGljcyBzZSBtYW50aWVuZW4gZW50cmUgbG9zIDIwMEsgeSBsb3MgNDAwSywgbG8gcXVlIHJlZmllcmUgYSB1biAqKmNvbXBvcnRhbWllbnRvIG3DoXMgZXN0YWJsZSBxdWUgZW4gZWRpY2lvbmVzIHBhc2FkYXMqKi4KXG5ld3BhZ2UKYGBge3IgZWRpY2lvbi10cmVuZC1jdHJ9CnByb2R1Y3RzICU+JSAKICAgIGdyb3VwX2J5KGZlY2hhKSAlPiUgCiAgICBzdW1tYXJpc2UoQ1RSID0gc3VtKGNsaWNzKSAvIHN1bShpbXByZXNpb25lcykpICU+JSAKICAgIHBsb3RfbHkoeCA9IH5mZWNoYSkgJT4lIAogICAgYWRkX3RyYWNlKHkgPSB+Q1RSLAogICAgICAgICAgICAgIHR5cGUgPSAnc2NhdHRlcicsCiAgICAgICAgICAgICAgbW9kZSA9ICdsaW5lcycsCiAgICAgICAgICAgICAgbmFtZSA9ICdDVFInLAogICAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gY29sb3JfcGFsZXR0ZVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDQpKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiVGVuZGVuY2lhIGRlbCBDVFIgcG9yIGTDrWE8YnI+PHN1Yj5EZWwgMSBhbCAzMSBNYXlvIGRlIDIwMjI8c3ViPiIsCiAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIiIsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsaW5lID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2dyaWQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5lY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b3RpY2sgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja3MgPSAnb3V0c2lkZScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tjb2xvciA9ICdyZ2IoMjA0LCAyMDQsIDIwNCknLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrd2lkdGggPSAyLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrbGVuID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2ZvbnQgPSBsaXN0KGZhbWlseSA9ICdQVCBTYW5zIE5hcnJvdycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICdyZ2IoODIsIDgyLCA4MiknKSksCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIiUgQ1RSIiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xpbmUgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93Z3JpZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3d0aWNrbGFiZWxzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgbGluZWNvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG90aWNrID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja3MgPSAnb3V0c2lkZScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tjb2xvciA9ICdyZ2IoMjA0LCAyMDQsIDIwNCknLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrd2lkdGggPSAyLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrbGVuID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2Zvcm1hdCA9ICIuMiUiLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9udCA9IGxpc3QoZmFtaWx5ID0gJ1BUIFNhbnMgTmFycm93JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ3JnYig4MiwgODIsIDgyKScpKSwKICAgICAgICAgICBtYXJnaW4gPSBsaXN0KGF1dG9leHBhbmQgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICAgdCA9IDEwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIGwgPSAxMCwKICAgICAgICAgICAgICAgICAgICAgICAgIHIgPSAxMTAsCiAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMTAwKSwKICAgICAgICAgICBhdXRvc2l6ZSA9IFRSVUUsCiAgICAgICAgICAgc2hvd2xlZ2VuZCA9IEZBTFNFLAogICAgICAgICAgIGFubm90YXRpb25zID0gbGlzdCgKICAgICAgICAgICAgICAgeHJlZiA9ICdwYXBlcicsCiAgICAgICAgICAgICAgIHlyZWYgPSAncGFwZXInLAogICAgICAgICAgICAgICB4ID0gMC43MywKICAgICAgICAgICAgICAgeSA9IDAuMTYsCiAgICAgICAgICAgICAgIHhhbmNob3IgPSAncmlnaHQnLAogICAgICAgICAgICAgICB5YW5jaG9yID0gJ21pZGRsZScsCiAgICAgICAgICAgICAgIHRleHQgPSAnUHJpbWVyIGRlbCBIb3QgU2FsZScsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICdQVCBTYW5zIE5hcnJvdycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiYSgxNjAsMTYwLDE2MCwxKScpLAogICAgICAgICAgICAgICBzaG93YXJyb3cgPSBUUlVFKSkgJT4lCiAgICBsYXlvdXQoYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICAgIHhyZWYgPSAncGFwZXInLAogICAgICAgIHlyZWYgPSAncGFwZXInLAogICAgICAgIHggPSAxLAogICAgICAgIHkgPSAwLjEwLAogICAgICAgIHhhbmNob3IgPSAnbGVmdCcsCiAgICAgICAgeWFuY2hvciA9ICdtaWRkbGUnLAogICAgICAgIHRleHQgPSAnw5psdGltbyBkZWwgSG90IFNhbGUnLAogICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICdQVCBTYW5zIE5hcnJvdycsCiAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDE2LAogICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ3JnYmEoMTYwLDE2MCwxNjAsMSknKSwKICAgICAgICBzaG93YXJyb3cgPSBUUlVFKSkKYGBgCgpQb3Igc3UgcGFydGUgZWwgQ1RSIGFsY2FuemEgdW4gcGljbyBpbXBvcnRhbnRlIGVsIG1pw6lyY29sZXMgKio0IGRlIG1heW8qKiB5YSBxdWUgZHVyYW50ZSB0b2RvIGVzZSBwZXJpb2RvICoqc2UgcmVhbGl6YXJvbiBwcnVlYmFzKiogZW4gZWwgc2l0aW8gcHJvZHVjdGl2byBwYXJhIHZlcmlmaWNhciBsYSBjYXBhIGRlIGRhdG9zLiBsbyBxdWUgZGlzcGFybyBlbCBDVFIsIHlhIGR1cmFudGUgZWwgZXZlbnRvIHNlIG9ic2VydmFuIDIgcGljb3MgaW1wb3J0YW50ZXMgcXVlICoqc3VwZXJhbiBlbCAwLjEwJSBkZWwgQ1RSKio6IGVsICoqcHJpbWVyIGTDrWEgZGVsIGV2ZW50byoqIChsdW5lcyAyMyBkZSBtYXlvKSAqKnkgZWwganVldmVzIDI2KiosIGVsIHBlb3IgcmVuZGltaWVudG8gb2JzZXJ2YWRvIGZ1ZSBlbCDDumx0aW1vIGTDrWEgZGVsIGV2ZW50byAoZWwgbWFydGVzIDMxIGRlIG1heW8pIGNvbiAwLjA2JSBkZWwgQ1RSLgoKYGBge3J9CnByb2R1Y3RzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwKICAgICAgICAgICAgICAgICAgIGFzLkRhdGUoIjIwMjItMDUtMzEiKSkpICU+JQogICAgbXV0YXRlKGRpYVNlbWFuYSA9IGZhY3Rvcih3ZGF5KGZlY2hhLCB3ZWVrX3N0YXJ0ID0gMSkpKSAlPiUgCiAgICBtdXRhdGUoZGlhU2VtYW5hID0gcmVjb2RlX2ZhY3RvcihkaWFTZW1hbmEsCiAgICAgICAgICAgICAgICAgIGAxYCA9ICJsdW5lcyIsCiAgICAgICAgICAgICAgICAgIGAyYCA9ICJtYXJ0ZXMiLAogICAgICAgICAgICAgICAgICBgM2AgPSAibWnDqXJjb2xlcyIsCiAgICAgICAgICAgICAgICAgIGA0YCA9ICJqdWV2ZXMiLAogICAgICAgICAgICAgICAgICBgNWAgPSAidmllcm5lcyIsCiAgICAgICAgICAgICAgICAgIGA2YCA9ICJzw6FiYWRvIiwKICAgICAgICAgICAgICAgICAgYDdgID0gImRvbWluZ28iLAogICAgICAgICAgICAgICAgICAub3JkZXJlZCA9IFRSVUUpKSAlPiUgCiAgICBncm91cF9ieShkaWFTZW1hbmEpICU+JSAKICAgIHN1bW1hcmlzZShDVFIgPSBzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSkgJT4lIAogICAgcGxvdF9seSh4ID0gfmRpYVNlbWFuYSwgeSA9IH5DVFIsIHR5cGUgPSAiYmFyIiwgbWFya2VyID0gbGlzdChjb2xvciA9IGNvbG9yX3BhbGV0dGVbMV0pKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiQ1RSIHBvciBkw61hIGRlIGxhIHNlbWFuYSIsCiAgICAgICAgICAgeGF4aXMgPSBsaXN0KHRpdGxlID0gIkTDrWEgZGUgbGEgc2VtYW5hIiwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2xpbmUgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93Z3JpZCA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93dGlja2xhYmVscyA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmVjb2xvciA9ICdyZ2IoMjA0LCAyMDQsIDIwNCknLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5ld2lkdGggPSAyLAogICAgICAgICAgICAgICAgICAgICAgICBhdXRvdGljayA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrcyA9ICdvdXRzaWRlJywKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2NvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tsZW4gPSA1LAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9udCA9IGxpc3QoZmFtaWx5ID0gJ1BUIFNhbnMgTmFycm93JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ3JnYig4MiwgODIsIDgyKScpKSwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiJSBDVFIiLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93bGluZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dncmlkID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5lY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b3RpY2sgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrcyA9ICdvdXRzaWRlJywKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2NvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tsZW4gPSA1LAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9ybWF0ID0gIi4yJSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tmb250ID0gbGlzdChmYW1pbHkgPSAnUFQgU2FucyBOYXJyb3cnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiKDgyLCA4MiwgODIpJykpKSAKYGBgCkFsIGFncnVwYXIgcG9yIGTDrWEgZGUgbGEgc2VtYW5hIHBvZGVtb3MgdmVyIHF1ZSBlbCAqKmp1ZXZlcyB0aWVuZSBlbCBtZWpvciBDVFIqKiBtaWVudHJhcyBxdWUgbG9zICoqbWFydGVzIHNvbiBsb3MgcXVlIHRpZW5lbiBlbCBwZW9yIGRlc2VtcGXDsW8qKi4gCgpcbmV3cGFnZQoKYGBge3J9CmRhdGVfaG91ciAlPiUgCiAgICBwbG90X2x5KHggPSB+ZGlhU2VtYW5hLAogICAgICAgICAgICB5ID0gfmhvcmEsCiAgICAgICAgICAgIHogPSB+Y2xpY3MsCiAgICAgICAgICAgIHR5cGUgPSAiaGVhdG1hcCIsCiAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yUmFtcChjKCIjZmZmZmZmIiwgY29sb3JfcGFsZXR0ZVsxXSkpCiAgICAgICAgICAgICkgJT4lIAogICAgbGF5b3V0KHRpdGxlID0gIk1hcGEgZGUgY2Fsb3IgZGUgbG9zIGNsaWNzIHBvciBob3JhIHkgZMOtYSBkZSBsYSBzZW1hbmEiLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJEw61hIGRlIGxhIHNlbWFuYSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsaW5lID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2dyaWQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5lY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b3RpY2sgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja3MgPSAnb3V0c2lkZScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tjb2xvciA9ICdyZ2IoMjA0LCAyMDQsIDIwNCknLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrd2lkdGggPSAyLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrbGVuID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2ZvbnQgPSBsaXN0KGZhbWlseSA9ICdQVCBTYW5zIE5hcnJvdycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICdyZ2IoODIsIDgyLCA4MiknKSksCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkhvcmEiLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93bGluZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dncmlkID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5lY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b3RpY2sgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrcyA9ICdvdXRzaWRlJywKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2NvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tsZW4gPSA1LAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9udCA9IGxpc3QoZmFtaWx5ID0gJ1BUIFNhbnMgTmFycm93JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ3JnYig4MiwgODIsIDgyKScpKSkgCmBgYApgYGB7cn0KZGF0ZV9ob3VyICU+JSAKICAgIG11dGF0ZShDVFIgPSAgcGVyY2VudChjbGljcyAvIGltcHJlc2lvbmVzKSkgJT4lIAogICAgcGxvdF9seSh4ID0gfmRpYVNlbWFuYSwKICAgICAgICAgICAgeSA9IH5ob3JhLAogICAgICAgICAgICB6ID0gfkNUUiwKICAgICAgICAgICAgdHlwZSA9ICJoZWF0bWFwIiwKICAgICAgICAgICAgY29sb3JzID0gY29sb3JSYW1wKGMoIiNmZmZmZmYiLCBjb2xvcl9wYWxldHRlWzFdKSkKICAgICAgICAgICAgKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiTWFwYSBkZSBjYWxvciBkZWwgQ1RSIHBvciBob3JhIHkgZMOtYSBkZSBsYSBzZW1hbmEiLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICJEw61hIGRlIGxhIHNlbWFuYSIsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dsaW5lID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd2dyaWQgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5lY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b3RpY2sgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja3MgPSAnb3V0c2lkZScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tjb2xvciA9ICdyZ2IoMjA0LCAyMDQsIDIwNCknLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrd2lkdGggPSAyLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrbGVuID0gNSwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2ZvbnQgPSBsaXN0KGZhbWlseSA9ICdQVCBTYW5zIE5hcnJvdycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xvciA9ICdyZ2IoODIsIDgyLCA4MiknKSksCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIkhvcmEiLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93bGluZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dncmlkID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgc2hvd3RpY2tsYWJlbHMgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICBsaW5lY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgbGluZXdpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b3RpY2sgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrcyA9ICdvdXRzaWRlJywKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2NvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2t3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tsZW4gPSA1LAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9udCA9IGxpc3QoZmFtaWx5ID0gJ1BUIFNhbnMgTmFycm93JywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gJ3JnYig4MiwgODIsIDgyKScpKSkgJT4lIAogICAgY29sb3JiYXIodGlja2Zvcm1hdCA9ICIuMiUiKQpgYGAKCjxicj4KPGJyPgo8YnI+CgpcbmV3cGFnZSAgCgojIyBBZHF1aXNpY2nDs24KCiMjIyDCv1F1w6kgY2FuYWxlcyB0cmFqZXJvbiBlbCB0csOhZmljbyBkZSBtZWpvciBjYWxpZGFkPwoKYGBge3IgY2hhbm5lbHMtdG9wfQpjaGFubmVscyAlPiUgCiAgICBncm91cF9ieShjYW5hbCkgJT4lIAogICAgc3VtbWFyaXNlKGltcHJlc2lvbmVzID0gIHN1bShpbXByZXNpb25lcyksCiAgICAgICAgICAgICAgY2xpY3MgPSBzdW0oY2xpY3MpLAogICAgICAgICAgICAgIENUUiA9IHBlcmNlbnQoc3VtKGNsaWNzKSAvIHN1bShpbXByZXNpb25lcykpKSAlPiUgCiAgICBtdXRhdGUocGN0X2ltcHJlc2lvbmVzID0gcGVyY2VudChpbXByZXNpb25lcyAvIHN1bShpbXByZXNpb25lcykpKSAlPiUKICAgIHNlbGVjdChjYW5hbCwKICAgICAgICAgICBwY3RfaW1wcmVzaW9uZXMsCiAgICAgICAgICAgQ1RSKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MocGN0X2ltcHJlc2lvbmVzKSkgJT4lIAogICAgZm9ybWF0dGFibGUobGlzdCgKICAgICAgICBwY3RfaW1wcmVzaW9uZXMgPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzJdLCBmdW4gPSAicHJvcG9ydGlvbiIpLAogICAgICAgIENUUiA9IGNvbG9yX2Jhcihjb2xvciA9IGNvbG9yX3BhbGV0dGVbMV0pKSkKYGBgCgpFbCB0cmFmaWNvIHF1ZSBsbGVnbyBwb3IgZWwgY2FuYWwgYFBhaWQgTWVkaWFgIHR1dm8gZWwgKio4NyUgZGVsIHRvdGFsIGRlIGxhcyBpbXByZXNpb25lcyoqIGxvIHF1ZSBsbyBoYWNlIGVsIGNhbmFsIHByZXBvbmRlcmFudGUgZW4gY2FudGlkYWQgZGUgaW1wcmVzaW9uZXMsIHNpbiBlbWJhcmdvICoqYEVtYWlsYCwgYE9yZ2FuaWMgU2VhcmNoYCB5IGBEaXJlY3RgIGZ1ZXJvbiBsb3MgY2FuYWxlcyBjb24gZWwgbWVqb3IgcmVuZGltaWVudG8geWEgcXVlIHN1IENUUiBzZSBtYW50dXZvIHBvciBlbmNpbWEgZGUgbGEgbWVkaWEqKi4KClxuZXdwYWdlCiMjIyDCv1F1w6kgZnVlbnRlcyAvIG1lZGlvcyB0cmFqZXJvbiBlbCB0csOhZmljbyBkZSBtZWpvciBjYWxpZGFkPwpgYGB7ciBjaGFubmVscy1zb3VyY2VNZWRpdW19CmNoYW5uZWxzICU+JSAKICAgIGdyb3VwX2J5KGZ1ZW50ZU1lZGlvKSAlPiUgCiAgICBzdW1tYXJpc2UoaW1wcmVzaW9uZXMgPSAgc3VtKGltcHJlc2lvbmVzKSwKICAgICAgICAgICAgICBjbGljcyA9IHN1bShjbGljcyksCiAgICAgICAgICAgICAgQ1RSID0gcGVyY2VudChzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSkpICU+JSAKICAgIG11dGF0ZShwY3RfaW1wcmVzaW9uZXMgPSBwZXJjZW50KGltcHJlc2lvbmVzIC8gc3VtKGltcHJlc2lvbmVzKSkpICU+JQogICAgc2VsZWN0KGZ1ZW50ZU1lZGlvLAogICAgICAgICAgIHBjdF9pbXByZXNpb25lcywKICAgICAgICAgICBDVFIpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhwY3RfaW1wcmVzaW9uZXMpKSAlPiUKICAgIGhlYWQoMzApICU+JSAKICAgIGZvcm1hdHRhYmxlKGxpc3QoCiAgICAgICAgcGN0X2ltcHJlc2lvbmVzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsyXSwgZnVuID0gInByb3BvcnRpb24iKSwKICAgICAgICBDVFIgPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzFdKSkpCmBgYApBbCBkZXNhZ3JlZ2FyIHBvciBGdWVudGVzIE1lZGlvcyBkZXNjdWJyaW1vcyBxdWUgYHRpa3RvayAvIGNwY2AgZXMgcmVzcG9uc2FibGUgZGVsIDQ1JSBkZSBsYXMgaW1wcmVzaW9uZXMgdG90YWxlcywgbWllbnRyYXMgcXVlIGBnb29nbGUgLyBjcGNgIGxlIHNpZ3VlIGNvbiBlbCAzNSUgY29uIGxvIHF1ZSAqKnN1bWFuIGVsIDgwJSBkZWwgdHJhZmljbyB0b3RhbCoqLiBQb3Igb3RybyBsYWRvIGxhICoqcmVsZXZhbmNpYSBkZWwgdHJhZmljbyB0cmHDrWRvIHBvciBgZ29vZ2xlIC8gb3JnYW5pY2AgeSBgZGlyZWN0b2AgZXMgbXV5IHN1cGVyaW9yKiouCiAgCjxicj4KPGJyPgo8YnI+CiAKXG5ld3BhZ2UKCiMjIyBUb3AgMTAgcGF0cm9jaW5hZG9yZXMgLSBtZWpvcmVzIFZTIHBlb3JlcyBjYW5hbGVzCgojIyMjIFRvcCBkZSBwYXRyb2NpbmFkb3JlcyBjb24gbcOhcyBjbGljcyBlbiB0b2RvIGVsIHBlcmlvZG8KCkVsIG9iamV0aXZvIGRlIGxvcyBzaWd1aWVudGVzIGdyw6FmaWNvcyBlcyBwb2RlciBjb21wcm9iYXIgcXVlIGxhICoqZGlzdHJpYnVjacOzbiBkZSBsb3MgY2FuYWxlcyBlbiBsb3MgKm1lam9yZXMqIHBhdHJvY2luYWRvcmVzKiogKGJhc2FkbyBlbiBsb3MgY2xpY3MgcmVjaWJpZG9zKSAqKmRpc3RhIG11Y2hvIGRlIGxhIGNvbmZpZ3VyYWNpw7NuIGRlIGxvcyBjYW5hbGVzIGRlIGxvcyBwYXRyb2NpbmFkb3JlcyBxdWUgdHV2aWVyb24gdW4gcmVuZGltaWVudG8gKmluZmVyaW9yKioqIChhIHBlc2FyIGRlIGVzdGFyIGRlbnRybyBkZWwgdG9wIDMwIGVuIGltcHJlc2lvbmVzKS4KCkxvcyBzaWd1aWVudGVzIHBhdHJvY2luYWRvcmVzIHR1dmllcm9uIGVsIG1lam9yIHJlbmRpbWllbnRvIGVuIGNsaWNzOgpgYGB7ciB0b3Atc3BvbnNvcnMtY2hhbm5lbHMsIGZpZy5oZWlnaHQ9MTB9CnRvcF9zcG9uc29ycyA8LSBjaGFubmVscyAlPiUKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lIAogICAgZ3JvdXBfYnkocGF0cm9jaW5hZG9yKSAlPiUgCiAgICBzdW1tYXJpc2UoaW1wcmVzaW9uZXMgPSAgc3VtKGltcHJlc2lvbmVzKSwKICAgICAgICAgICAgICBjbGljcyA9IHN1bShjbGljcyksCiAgICAgICAgICAgICAgQ1RSID0gcGVyY2VudChzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSkpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhjbGljcykpICU+JSAKICAgIGhlYWQoMTApCgp3b3JzdF9zcG9uc29ycyA8LSBjaGFubmVscyAlPiUKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lIAogICAgZmlsdGVyKCFwYXRyb2NpbmFkb3IgJWluJSB0b3Bfc3BvbnNvcnMkcGF0cm9jaW5hZG9yKSAlPiUgCiAgICBncm91cF9ieShwYXRyb2NpbmFkb3IpICU+JSAKICAgIHN1bW1hcmlzZShpbXByZXNpb25lcyA9ICBzdW0oaW1wcmVzaW9uZXMpLAogICAgICAgICAgICAgIGNsaWNzID0gc3VtKGNsaWNzKSwKICAgICAgICAgICAgICBDVFIgPSBwZXJjZW50KHN1bShjbGljcykgLyBzdW0oaW1wcmVzaW9uZXMpKSkgJT4lIAogICAgYXJyYW5nZShkZXNjKGltcHJlc2lvbmVzKSkgJT4lIAogICAgaGVhZCgzMCkgJT4lIAogICAgYXJyYW5nZShDVFIpICU+JSAKICAgIGhlYWQoMTApCgpnIDwtIGNoYW5uZWxzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lIAogICAgZmlsdGVyKHBhdHJvY2luYWRvciAlaW4lIHRvcF9zcG9uc29ycyRwYXRyb2NpbmFkb3IpICU+JSAKICAgIGdyb3VwX2J5KHBhdHJvY2luYWRvciwKICAgICAgICAgICAgIGNhbmFsKSAlPiUgCiAgICBzdW1tYXJpc2UoaW1wcmVzaW9uZXMgPSAgc3VtKGltcHJlc2lvbmVzKSwKICAgICAgICAgICAgICBjbGljcyA9IHN1bShjbGljcyksCiAgICAgICAgICAgICAgQ1RSID0gcGVyY2VudChzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSkpICU+JSAKICAgIG11dGF0ZShwY3RfaW1wcmVzaW9uZXMgPSBwZXJjZW50KGltcHJlc2lvbmVzIC8gc3VtKGltcHJlc2lvbmVzKSksCiAgICAgICAgICAgcGN0X2NsaWNzID0gcGVyY2VudChjbGljcyAvIHN1bShjbGljcykpKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MocGN0X2ltcHJlc2lvbmVzKSkgJT4lIAogICAgZ2dwbG90KGFlcyh4ID0gcGN0X2ltcHJlc2lvbmVzLCB5ID0gcGN0X2NsaWNzLCBzaXplID0gQ1RSLCBjb2xvciA9IGNhbmFsKSkgKwogICAgZ2VvbV9wb2ludChhbHBoYSA9IDAuNikgKwogICAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMSwgMTApLCBuYW1lPSIlQ1RSIikgKwogICAgc2NhbGVfeF9sb2cxMChuYW1lID0gIiUgaW1wcmVzaW9uZXMiLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICAgIHNjYWxlX3lfbG9nMTAobmFtZSA9ICIlIGNsaWNzIiwgbGFiZWxzID0gc2NhbGVzOjpwZXJjZW50KSArCiAgICBmYWNldF93cmFwKHZhcnMocGF0cm9jaW5hZG9yKSwgbmNvbCA9IDIpICsKICAgIHRoZW1lKGF4aXMudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MTAsZmFjZT0iYm9sZCIpKSArIAogICAgdGhlbWVfbGlnaHQoKQpnZ3Bsb3RseShnKQoKYGBgClxuZXdwYWdlCgpMb3Mgc2lndWllbnRlcyBwYXRyb2NpbmFkb3JlcyB0dXZpZXJvbiB1biByZW5kaW1pZW50byBpbmZlcmlvciBhIGxhIG1lZGlhIGRlIHN1IGNhdGVnb3LDrWEgY29uIHJlc3BlY3RvIGEgY2xpY3M6CgpgYGB7ciB3b3JzdC1zcG9uc29ycy1jaGFubmVscywgZmlnLmhlaWdodD0xMH0KZyA8LSBjaGFubmVscyAlPiUKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLAogICAgICAgICAgICAgICAgICAgYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLAogICAgICAgICAgICAgICAgICAgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lIAogICAgZmlsdGVyKHBhdHJvY2luYWRvciAlaW4lIHdvcnN0X3Nwb25zb3JzJHBhdHJvY2luYWRvcikgJT4lIAogICAgZ3JvdXBfYnkocGF0cm9jaW5hZG9yLAogICAgICAgICAgICAgY2FuYWwpICU+JSAKICAgIHN1bW1hcmlzZShpbXByZXNpb25lcyA9ICBzdW0oaW1wcmVzaW9uZXMpLAogICAgICAgICAgICAgIGNsaWNzID0gc3VtKGNsaWNzKSwKICAgICAgICAgICAgICBDVFIgPSBwZXJjZW50KHN1bShjbGljcykgLyBzdW0oaW1wcmVzaW9uZXMpKSkgJT4lIAogICAgbXV0YXRlKHBjdF9pbXByZXNpb25lcyA9IHBlcmNlbnQoaW1wcmVzaW9uZXMgLyBzdW0oaW1wcmVzaW9uZXMpKSwKICAgICAgICAgICBwY3RfY2xpY3MgPSBwZXJjZW50KGNsaWNzIC8gc3VtKGNsaWNzKSkpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhwY3RfaW1wcmVzaW9uZXMpKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKHggPSBwY3RfaW1wcmVzaW9uZXMsIHkgPSBwY3RfY2xpY3MsIHNpemUgPSBDVFIsIGNvbG9yID0gY2FuYWwpKSArCiAgICBnZW9tX3BvaW50KGFscGhhID0gMC42KSArCiAgICBzY2FsZV9zaXplKHJhbmdlID0gYygxLCAxMCksIG5hbWU9IiVDVFIiKSArCiAgICBzY2FsZV94X2xvZzEwKG5hbWUgPSAiJSBpbXByZXNpb25lcyIsIGxhYmVscyA9IHNjYWxlczo6cGVyY2VudCkgKwogICAgc2NhbGVfeV9sb2cxMChuYW1lID0gIiUgY2xpY3MiLCBsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnQpICsKICAgIGZhY2V0X3dyYXAodmFycyhwYXRyb2NpbmFkb3IpLCBuY29sID0gMikgKwogICAgdGhlbWUoYXhpcy50aXRsZT1lbGVtZW50X3RleHQoc2l6ZT0xMCxmYWNlPSJib2xkIikpICsgCiAgICB0aGVtZV9saWdodCgpCmdncGxvdGx5KGcpCmBgYApFbCBlamUgaG9yaXpvbnRhbCByZXByZXNlbnRhIGVsIHBvcmNlbnRhamUgZGUgaW1wcmVzaW9uZXMgcmVjaWJpZGFzLCBlbCBlamUgdmVydGljYWwgZWwgcG9yY2VudGFqZSBkZSBjbGljcyB5IGVsIHRhbWHDsW8gZGUgbGEgYnVyYnVqYSBlcyBlbCBDVFIuCgpcbmV3cGFnZQoKIyMjIFBvcmNlbnRhamUgZGUgcGFydGljaXBhY2nDs24gZGUgY2FuYWxlcyBwb3IgZMOtYQoKYGBge3IgY2hhbm5lbHMtaW1wcmVzaW9uc30KY2hhbm5lbHMgJT4lIAogICAgZmlsdGVyKGJldHdlZW4oZmVjaGEsYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLCBhcy5EYXRlKCIyMDIyLTA1LTMxIikpKSAlPiUKICAgIGdyb3VwX2J5KGZlY2hhLAogICAgICAgICAgICAgY2FuYWwpICU+JSAKICAgIHN1bW1hcmlzZShpbXByZXNpb25lcyA9IHN1bShpbXByZXNpb25lcykpICU+JSAKICAgIG11dGF0ZShjYW5hbCA9IGZjdF9yZXYoYXNfZmFjdG9yKHRvbG93ZXIoZmN0X3Jlb3JkZXIoY2FuYWwsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltcHJlc2lvbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZnVuID0gc3VtLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVzYyA9IEZBTFNFKSkpKSkgJT4lIAogICAgbXV0YXRlKHBjdF9pbXByZXNpb25lcyA9IHBlcmNlbnQoaW1wcmVzaW9uZXMgLyBzdW0oaW1wcmVzaW9uZXMpKSkgJT4lIAogICAgcGxvdF9seSh4ID0gfmZlY2hhLAogICAgICAgICAgICB5ID0gfnBjdF9pbXByZXNpb25lcywKICAgICAgICAgICAgdHlwZSA9ICJiYXIiLAogICAgICAgICAgICBuYW1lID0gfmNhbmFsLAogICAgICAgICAgICBjb2xvciA9IH5jYW5hbCwKICAgICAgICAgICAgY29sb3JzID0gY29sb3JfcGFsZXR0ZVszXSkgJT4lIAogICAgbGF5b3V0KHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGVsICUgZGUgaW1wcmVzaW9uZXMgcG9yIGNhbmFsIHBvciBkw61hIiwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiJSBkZSBpbXByZXNpb25lcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tmb3JtYXQgPSAiLjAlIiksCiAgICAgICAgICAgYmFybW9kZSA9ICJzdGFjayIsCiAgICAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gIlBUIFNhbnMgTmFycm93JyIpLAogICAgICAgICAgIGxlZ2VuZCA9IGxpc3QoZm9udCA9IGxpc3Qoc2l6ZSA9IDkpKSkKYGBgCkR1cmFudGUgbG9zIGTDrWFzIGRlbCBldmVudG8gc2Ugb2JzZXJ2YSBxdWUgZWwgJSBkZSBwYXJ0aWNpcGFjacOzbiBkZSBgcGFpZCBtZWRpYWAgZW4gbGFzIGltcHJlc2lvbmVzIHNlIG1hbnR1dm8gKiplbnRyZSBlbCA3NCUgeSBlbCA3OSUsIHNpZW5kbyBlbCBqdWV2ZXMgMjYgZWwgZMOtYSBjb24gbGEgbWVub3IgeSBlbCBtYXJ0ZXMgMzEgZWwgZGUgbWF5b3IqKiBwYXJ0aWNpcGFjacOzbi4KCmBgYHtyIGNoYW5uZWxzLWNsaWNzfQpjaGFubmVscyAlPiUgCiAgICBmaWx0ZXIoYmV0d2VlbihmZWNoYSxhcy5EYXRlKCIyMDIyLTA1LTIzIiksIGFzLkRhdGUoIjIwMjItMDUtMzEiKSkpICU+JQogICAgZ3JvdXBfYnkoZmVjaGEsCiAgICAgICAgICAgICBjYW5hbCkgJT4lIAogICAgc3VtbWFyaXNlKGNsaWNzID0gc3VtKGNsaWNzKSkgJT4lIAogICAgbXV0YXRlKGNhbmFsID0gZmN0X3Jldihhc19mYWN0b3IodG9sb3dlcihmY3RfcmVvcmRlcihjYW5hbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpY3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5mdW4gPSBzdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZXNjID0gRkFMU0UpKSkpKSAlPiUgCiAgICBtdXRhdGUocGN0X2NsaWNzID0gcGVyY2VudChjbGljcyAvIHN1bShjbGljcykpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEsCiAgICAgICAgICAgIHkgPSB+cGN0X2NsaWNzLAogICAgICAgICAgICB0eXBlID0gImJhciIsCiAgICAgICAgICAgIG5hbWUgPSB+Y2FuYWwsCiAgICAgICAgICAgIGNvbG9yID0gfmNhbmFsLAogICAgICAgICAgICBjb2xvcnMgPSBjb2xvcl9wYWxldHRlWzNdKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZWwgJSBkZSBjbGljcyBwb3IgY2FuYWwgcG9yIGTDrWEiLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIlIGRlIGNsaWNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2Zvcm1hdCA9ICIuMCUiKSwKICAgICAgICAgICBiYXJtb2RlID0gInN0YWNrIiwKICAgICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiUFQgU2FucyBOYXJyb3cnIikpCgpgYGAKUmVzcGVjdG8gYWwgJSBkZSBjbGljcyB2ZW1vcyBxdWUgKipgcGFpZCBtZWRpYWAgbWFudGllbmUgZW50cmUgZWwgNjglIHkgZWwgODUlIGRlIHBhcnRpY2lwYWNpw7NuKiosIHNpbiBlbWJhcmdvIGNlZGUgdW4gcG9yY2VudGFqZSBpbXBvcnRhbnRlIHBhcmEgbG9zIGNhbmFsZXMgYG9yZ2FuaWMgc2VhcmNoYCwgYGRpcmVjdG9gIHkgYChvdGhlcilgLCBwcmluY2lwYWxtZW50ZSBkdXJhbnRlIGVsIHByaW1lciB5IGFudGVwZW7Dumx0aW1vIGTDrWEgZGVsIGV2ZW50by4KClxuZXdwYWdlCgpgYGB7ciBjaGFubmVscy1jdHJ9CmNoYW5uZWxzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lCiAgICBncm91cF9ieShmZWNoYSwKICAgICAgICAgICAgIGNhbmFsKSAlPiUgCiAgICBzdW1tYXJpc2UoaW1wcmVzaW9uZXMgPSBzdW0oaW1wcmVzaW9uZXMpLAogICAgICAgICAgICAgIGNsaWNzID0gc3VtKGNsaWNzKSwKICAgICAgICAgICAgICBDVFIgPSBzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSkgJT4lIAogICAgbXV0YXRlKGNhbmFsID0gZmN0X3Jldihhc19mYWN0b3IodG9sb3dlcihmY3RfcmVvcmRlcihjYW5hbCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpY3MsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5mdW4gPSBzdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZXNjID0gRkFMU0UpKSkpKSAlPiUgCiAgICBtdXRhdGUocGN0X0NUUiA9IHBlcmNlbnQoQ1RSIC8gc3VtKENUUikpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEsCiAgICAgICAgICAgIHkgPSB+cGN0X0NUUiwKICAgICAgICAgICAgdHlwZSA9ICJiYXIiLAogICAgICAgICAgICBuYW1lID0gfmNhbmFsLAogICAgICAgICAgICBjb2xvciA9IH5jYW5hbCwKICAgICAgICAgICAgY29sb3JzID0gY29sb3JfcGFsZXR0ZVszXSkgJT4lIAogICAgbGF5b3V0KHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGVsICUgZGVsIENUUiBwb3IgY2FuYWwgcG9yIGTDrWEiLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIlIGRlbCBDVFIiLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9ybWF0ID0gIi4wJSIpLAogICAgICAgICAgIGJhcm1vZGUgPSAic3RhY2siLAogICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJQVCBTYW5zIE5hcnJvdyciKSkKYGBgCkVuIGN1YW50byBhbCAlIGRlbCBDVFIgdmVtb3MgdW4gcGFub3JhbWEgdG90YWxtZW50ZSBkaXN0aW50byBjb24gYHBhaWQgc2VhcmNoYCBjb24gZW50cmUgZWwgNCUgeSBlbCA5JSBkZSBsYSBwYXJ0aWNpcGFjacOzbiwgbWllbnRyYXMgcXVlICoqYGVtYWlsYCwgYG9yZ2FuaWMgc2VhcmNoYCB5IGBkaXJlY3RgIHRpZW5lbiBsYSBtYXlvcsOtYSBlbiBwcsOhY3RpY2FtZW50ZSB0b2RvcyBsb3MgZMOtYXMgZGVsIGV2ZW50byoqLgogIAo8YnI+Cjxicj4KPGJyPgogIAojIyMgRnVlbnRlIC8gTWVkaW8gY29uIG1lam9yIGNhbGlkYWQgZGUgdHLDoWZpY28gcG9yIGTDrWEKCmBgYHtyIHNvdXJjZU1lZGl1bS1jdHJ9CmNoYW5uZWxzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwKICAgICAgICAgICAgICAgICAgIGFzLkRhdGUoIjIwMjItMDUtMzEiKSkpICU+JQogICAgZ3JvdXBfYnkoZmVjaGEsCiAgICAgICAgICAgICBmdWVudGVNZWRpbykgJT4lIAogICAgc3VtbWFyaXNlKGltcHJlc2lvbmVzID0gc3VtKGltcHJlc2lvbmVzKSkgJT4lIAogICAgbXV0YXRlKGZ1ZW50ZU1lZGlvID0gZmN0X2x1bXBfbigKICAgICAgICBmdWVudGVNZWRpbywKICAgICAgICA5LAogICAgICAgIHcgPSBpbXByZXNpb25lcywKICAgICAgICBvdGhlcl9sZXZlbCA9ICJPdGhlcnMiKSkgJT4lIAogICAgbXV0YXRlKGZ1ZW50ZU1lZGlvID0gZmN0X3Jldihhc19mYWN0b3IodG9sb3dlcihmY3RfcmVvcmRlcihmdWVudGVNZWRpbywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1wcmVzaW9uZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5mdW4gPSBzdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZXNjID0gRkFMU0UpKSkpKSAlPiUgCiAgICBtdXRhdGUocGN0X2ltcHJlc2lvbmVzID0gcGVyY2VudChpbXByZXNpb25lcyAvIHN1bShpbXByZXNpb25lcykpKSAlPiUKICAgIHBsb3RfbHkoeCA9IH5mZWNoYSwKICAgICAgICAgICAgeSA9IH5wY3RfaW1wcmVzaW9uZXMsCiAgICAgICAgICAgIHR5cGUgPSAiYmFyIiwKICAgICAgICAgICAgbmFtZSA9IH5mdWVudGVNZWRpbywKICAgICAgICAgICAgY29sb3IgPSB+ZnVlbnRlTWVkaW8sCiAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yX3BhbGV0dGVbM10pICU+JSAKICAgIGxheW91dCh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlbCAlIGRlIGltcHJlc2lvbmVzIHBvciBmdWVudGUgLyBtZWRpbyBwb3IgZMOtYSIsCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gIiUgZGUgaW1wcmVzaW9uZXMiLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9ybWF0ID0gIi4wJSIpLAogICAgICAgICAgIGJhcm1vZGUgPSAic3RhY2siLAogICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJQVCBTYW5zIE5hcnJvdyciKSwKICAgICAgICAgICBsZWdlbmQgPSBsaXN0KGZvbnQgPSBsaXN0KHNpemUgPSA5KSkpCmBgYApPYnNlcnZhbW9zIHF1ZSBgZ29vZ2xlIGNwY2AgeSBgdGlja3Rva2AgdGllbmVuIGxhIG1heW9yIGNhbnRpZGFkIGRlIGltcHJlc2lvbmVzIGR1cmFudGUgdG9kbyBlbCBldmVudG8sIGNvbiBhcHJveGltYWRhbWVudGUgZWwgODAlIGRlIGxhIHBhcnRpY2lwYWNpw7NuIHBvciBkw61hLgoKXG5ld3BhZ2UKCgpgYGB7cn0KY2hhbm5lbHMgJT4lIAogICAgZmlsdGVyKGJldHdlZW4oZmVjaGEsYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLAogICAgICAgICAgICAgICAgICAgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lCiAgICBncm91cF9ieShmZWNoYSwKICAgICAgICAgICAgIGZ1ZW50ZU1lZGlvKSAlPiUgCiAgICBzdW1tYXJpc2UoY2xpY3MgPSBzdW0oY2xpY3MpKSAlPiUgCiAgICBtdXRhdGUoZnVlbnRlTWVkaW8gPSBmY3RfbHVtcF9uKAogICAgICAgIGZ1ZW50ZU1lZGlvLAogICAgICAgIDksCiAgICAgICAgdyA9IGNsaWNzLAogICAgICAgIG90aGVyX2xldmVsID0gIk90aGVycyIpKSAlPiUgCiAgICBtdXRhdGUoZnVlbnRlTWVkaW8gPSBmY3RfcmV2KGFzX2ZhY3Rvcih0b2xvd2VyKGZjdF9yZW9yZGVyKGZ1ZW50ZU1lZGlvLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGljcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZ1biA9IHN1bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlc2MgPSBGQUxTRSkpKSkpICU+JSAKICAgIG11dGF0ZShwY3RfY2xpY3MgPSBwZXJjZW50KGNsaWNzIC8gc3VtKGNsaWNzKSkpICU+JQogICAgcGxvdF9seSh4ID0gfmZlY2hhLAogICAgICAgICAgICB5ID0gfnBjdF9jbGljcywKICAgICAgICAgICAgdHlwZSA9ICJiYXIiLAogICAgICAgICAgICBuYW1lID0gfmZ1ZW50ZU1lZGlvLAogICAgICAgICAgICBjb2xvciA9IH5mdWVudGVNZWRpbywKICAgICAgICAgICAgY29sb3JzID0gY29sb3JfcGFsZXR0ZVszXSkgJT4lIAogICAgbGF5b3V0KHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGVsICUgZGUgY2xpY3MgcG9yIGZ1ZW50ZSAvIG1lZGlvIHBvciBkw61hIiwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiJSBkZSBjbGljcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tmb3JtYXQgPSAiLjAlIiksCiAgICAgICAgICAgYmFybW9kZSA9ICJzdGFjayIsCiAgICAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gIlBUIFNhbnMgTmFycm93JyIpLAogICAgICAgICAgIGxlZ2VuZCA9IGxpc3QoZm9udCA9IGxpc3Qoc2l6ZSA9IDkpKSkKYGBgClNpbiBlbWJhcmdvIGVuIGxhIGNhbnRpZGFkIGRlIGNsaWNzIHZlbW9zIGNsYXJhbWVudGUgcXVlIGBnb29nbGUgY3BjYCBkb21pbmEgbGEgcGFydGljaXBhY2nDs24sIGVzIGludGVyZXNhbnRlIG9ic2VydmFyIHF1ZSBhIHBhcnRpciBkZWwgMjYgZGUgbWF5byBlbCAlIGRlIGNsaWNzIHByb3ZlbmllbnRlcyBkZSBgdGlja3Rva2AgYXVtZW50YSBkZSBmb3JtYSBjb25zaWRlcmFibGUuCiAgCjxicj4KPGJyPgo8YnI+CgpcbmV3cGFnZQogIAojIyBDb21wb3J0YW1pZW50bwoKIyMjIFRpcG8gZGUgY3JlYXRpdm8gY29uIG1lam9yIHJlbmRpbWllbnRvCgpgYGB7ciBjcmVhdGl2ZVR5cGUtY3RyfQppbnN0YV9zdG9yaWVzICU+JQogICAgZmlsdGVyKGJldHdlZW4oZmVjaGEsYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLCBhcy5EYXRlKCIyMDIyLTA1LTMxIikpKSAlPiUKICAgIGdyb3VwX2J5KHRpcG9DcmVhdGl2bykgJT4lIAogICAgc3VtbWFyaXNlKGltcHJlc2lvbmVzID0gY29tbWEoc3VtKGltcHJlc2lvbmVzKSwwKSwKICAgICAgICAgICAgICBjbGljcyA9IGNvbW1hKHN1bShjbGljcyksMCksCiAgICAgICAgICAgICAgQ1RSID0gcGVyY2VudChzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSkpICU+JQogICAgbXV0YXRlKHBjdF9pbXByZXNpb25lcyA9IHBlcmNlbnQoaW1wcmVzaW9uZXMgLyBzdW0oaW1wcmVzaW9uZXMpKSkgJT4lCiAgICBhcnJhbmdlKGRlc2MocGN0X2ltcHJlc2lvbmVzKSkgJT4lIAogICAgZm9ybWF0dGFibGUobGlzdCgKICAgICAgICBwY3RfaW1wcmVzaW9uZXMgPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzJdLCBmdW4gPSAicHJvcG9ydGlvbiIpLAogICAgICAgIENUUiA9IGNvbG9yX2Jhcihjb2xvciA9IGNvbG9yX3BhbGV0dGVbMV0pKSkKICAgIApgYGAKRWwgdGlwbyBkZSBjcmVhdGl2byBxdWUgcmVjaWJpw7MgbWF5b3IgcG9yY2VudGFqZSBkZSBpbXByZXNpb25lcyBmdWVyb24gbG9zIGxvZ29zIGRlIGxvcyBwYXRyb2NpbmFkb3Jlcywgc2luIGVtYmFyZ28gZWwgdGlwbyBkZSBjcmVhdGl2byBjb24gbWVqb3IgQ1RSIGZ1ZXJvbiBsYXMgaW5zdGEgc3RvcmllcyB5IGxvcyBjaW50aWxsb3MuCgojIyMgVGlwbyBkZSBjcmVhdGl2byBwb3IgaW1wcmVzaW9uZXMgYWwgZMOtYQoKYGBge3IgY3JlYXRpdmVUeXBlLWltcHJlc2lvbnMtZGF0ZX0KaW5zdGFfc3RvcmllcyAlPiUgCiAgICBmaWx0ZXIoYmV0d2VlbihmZWNoYSxhcy5EYXRlKCIyMDIyLTA1LTIzIiksCiAgICAgICAgICAgICAgICAgICBhcy5EYXRlKCIyMDIyLTA1LTMxIikpKSAlPiUKICAgIGdyb3VwX2J5KGZlY2hhLAogICAgICAgICAgICAgdGlwb0NyZWF0aXZvKSAlPiUgCiAgICBzdW1tYXJpc2UoQ1RSID0gcGVyY2VudChzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSksCiAgICAgICAgICAgICAgY2xpY3MgPSBzdW0oY2xpY3MpKSAlPiUgCiAgICBtdXRhdGUocGN0X2NsaWNzID0gcGVyY2VudChjbGljcyAvIHN1bShjbGljcykpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEsCiAgICAgICAgICAgIHkgPSB+cGN0X2NsaWNzLAogICAgICAgICAgICB0eXBlID0gImJhciIsCiAgICAgICAgICAgIG5hbWUgPSB+dGlwb0NyZWF0aXZvLAogICAgICAgICAgICBjb2xvciA9IH50aXBvQ3JlYXRpdm8sCiAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yX3BhbGV0dGVbM10pICU+JSAKICAgIGxheW91dCh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlbCAlIGNsaWNzIHBvciB0aXBvIGRlIGNyZWF0aXZvIHBvciBkw61hIiwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiJSBkZSBjbGljcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tmb3JtYXQgPSAiLjAlIiksIGJhcm1vZGUgPSAic3RhY2siLAogICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJQVCBTYW5zIE5hcnJvdyciKSkKYGBgCkVuIGxhIGRpc3RyaWJ1Y2nDs24gcG9yIGNsaWMgcG9yIHRpcG8gZGUgY3JlYXRpdm8gc2UgYXByZWNpYSBjbGFyYW1lbnRlIHF1ZSBsb3MgbG9nb3MgZXN0YSBlbnRyZSBlbCA2MCUgeSA3NSUgZHVyYW50ZSBlbCBldmVudG8sIGxvcyBwcm9kdWN0b3MgeSBsb3MgY2ludGlsbG9zIGluY3JlbWVudGFuIHN1IHBhcnRpY2lwYWNpw7NuIGFsIGZpbmFsIGRlbCBldmVudG8uCgpcbmV3cGFnZQoKIyMjIFJlbmRpbWVpbnRvIGRlbCB0aXBvIGRlIGNyZWF0aXZvIHBvciBkw61hCgpgYGB7ciBjcmVhdGl2ZVR5cGUtY3RyLWRhdGV9Cmluc3RhX3N0b3JpZXMgJT4lIAogICAgZmlsdGVyKGJldHdlZW4oZmVjaGEsYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLCBhcy5EYXRlKCIyMDIyLTA1LTMxIikpKSAlPiUKICAgIGdyb3VwX2J5KGZlY2hhLAogICAgICAgICAgICAgdGlwb0NyZWF0aXZvKSAlPiUgCiAgICBzdW1tYXJpc2UoQ1RSID0gcGVyY2VudChzdW0oY2xpY3MpIC8gc3VtKGltcHJlc2lvbmVzKSksCiAgICAgICAgICAgICAgaW1wcmVzaW9uZXMgPSBzdW0oaW1wcmVzaW9uZXMpKSAlPiUgCiAgICBtdXRhdGUocGN0X0NUUiA9IHBlcmNlbnQoQ1RSIC8gc3VtKENUUikpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEsCiAgICAgICAgICAgIHkgPSB+cGN0X0NUUiwKICAgICAgICAgICAgdHlwZSA9ICJiYXIiLAogICAgICAgICAgICBuYW1lID0gfnRpcG9DcmVhdGl2bywKICAgICAgICAgICAgY29sb3IgPSB+dGlwb0NyZWF0aXZvLAogICAgICAgICAgICBjb2xvcnMgPSBjb2xvcl9wYWxldHRlWzNdKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZWwgQ1RSIHBvciB0aXBvIGRlIGNyZWF0aXZvIHBvciBkw61hIiwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQ1RSIiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2Zvcm1hdCA9ICIuMCUiKSwKICAgICAgICAgICBiYXJtb2RlID0gInN0YWNrIiwKICAgICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiUFQgU2FucyBOYXJyb3cnIikpCmBgYApQb2RlbW9zIG9ic2VydmFyIHF1ZSBkdXJhbnRlIGVsIGV2ZW50byBsYXMgaW5zdGEgc3RvcmllcyB0aWVuZW4gdW4gZXhjZWxlbnRlIENUUiBkdXJhbnRlIHRvZG8gZWwgZXZlbnRvIHBlcm8gc29icmUgdG9kbyBsb3MgcHJpbWVyb3MgZMOtYXMuCgpcbmV3cGFnZQoKIyMjIERldGFsbGUgaW5zdGEtc3RvcmllcwojIyMjIFBvcmNlbnRhamUgZGUgY2xpY3MgZW4gY2FkYSB0aXBvIGRlIGNyZWF0aXZvIHBvciBzZWNjacOzbiBkZWwgc2l0aW8uCmBgYHtyfQppbnN0YV9zdG9yaWVzICU+JSAKICAgIGdyb3VwX2J5KHRpcG9DcmVhdGl2bywKICAgICAgICAgICAgIHNlY2Npb24pICU+JSAKICAgIHN1bW1hcmlzZShjbGljcyA9IGNvbW1hKHN1bShjbGljcyksMCkpICU+JQogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRpcG9DcmVhdGl2bywKICAgICAgICAgICAgICAgIHZhbHVlc19mcm9tID0gY2xpY3MpICU+JSAKICAgIG11dGF0ZShwY3RfbG9nbyA9IHBlcmNlbnQoTG9nbyAvIHN1bShMb2dvLCBuYS5ybSA9IFRSVUUpKSwKICAgICAgICBwY3RfcHJvZHVjdG8gPSBwZXJjZW50KFByb2R1Y3RvIC8gc3VtKFByb2R1Y3RvLCBuYS5ybSA9IFRSVUUpKSwKICAgICAgICAgICBwY3RfY2ludGlsbG8gPSBwZXJjZW50KENpbnRpbGxvIC8gc3VtKENpbnRpbGxvLCBuYS5ybSA9IFRSVUUpKSwKICAgIHBjdF9pbnN0YVN0b3JpZXMgPSBwZXJjZW50KEluc3RhU3RvcmllcyAvIHN1bShJbnN0YVN0b3JpZXMsIG5hLnJtID0gVFJVRSkpKSAlPiUgCiAgICBzZWxlY3Qoc2VjY2lvbiwKICAgICAgICAgICBjb250YWlucygicGN0XyIpKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MocGN0X2luc3RhU3RvcmllcykpICU+JSAKICAgIGZvcm1hdHRhYmxlKGxpc3QoCiAgICAgICAgcGN0X2xvZ28gPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzJdKSwKICAgICAgICBwY3RfcHJvZHVjdG8gPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzJdKSwKICAgICAgICBwY3RfY2ludGlsbG8gPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzJdKSwKICAgICAgICBwY3RfaW5zdGFTdG9yaWVzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsxXSkKICAgICkpCgogICAgCmBgYApcbmV3cGFnZQoKIyMjIyBUb3AgUGF0cm9jaW5hZG9yZXMgY29uICoqbWVqb3IqKiByZW5kaW1pZW50byBkZSBpbnN0YSBzdG9yaWVzCgpgYGB7cn0KaW5zdGFfc3RvcmllcyAlPiUgCiAgICBmaWx0ZXIodGlwb0NyZWF0aXZvID09ICJJbnN0YVN0b3JpZXMiKSAlPiUgCiAgICBncm91cF9ieShwYXRyb2NpbmFkb3IpICU+JSAKICAgIHN1bW1hcmlzZShpbXByZXNpb25lcyA9IGNvbW1hKHN1bShpbXByZXNpb25lcyksMCksCiAgICAgICAgICAgICAgY2xpY3MgPSBjb21tYShzdW0oY2xpY3MpLDApLAogICAgICAgICAgICAgIENUUiA9IHBlcmNlbnQoc3VtKGNsaWNzKSAvIHN1bShpbXByZXNpb25lcykpKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoaW1wcmVzaW9uZXMpKSAlPiUgCiAgICBoZWFkKDUwKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoQ1RSKSkgJT4lIAogICAgaGVhZCgxMCkgJT4lIAogICAgZm9ybWF0dGFibGUobGlzdCgKICAgICAgICBDVFIgPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzFdKQogICAgKSkKYGBgCgojIyMjIFRvcCBQYXRyb2NpbmFkb3JlcyBjb24gKipwZW9yKiogcmVuZGltaWVudG8gZGUgaW5zdGEgc3RvcmllcwpgYGB7cn0KaW5zdGFfc3RvcmllcyAlPiUgCiAgICBmaWx0ZXIodGlwb0NyZWF0aXZvID09ICJJbnN0YVN0b3JpZXMiKSAlPiUgCiAgICBncm91cF9ieShwYXRyb2NpbmFkb3IpICU+JSAKICAgIHN1bW1hcmlzZShpbXByZXNpb25lcyA9IGNvbW1hKHN1bShpbXByZXNpb25lcyksMCksCiAgICAgICAgICAgICAgY2xpY3MgPSBjb21tYShzdW0oY2xpY3MpLDApLAogICAgICAgICAgICAgIENUUiA9IHBlcmNlbnQoc3VtKGNsaWNzKSAvIHN1bShpbXByZXNpb25lcykpKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoaW1wcmVzaW9uZXMpKSAlPiUgCiAgICBoZWFkKDUwKSAlPiUgCiAgICBhcnJhbmdlKENUUikgJT4lIAogICAgaGVhZCgxMCkgJT4lIAogICAgZm9ybWF0dGFibGUobGlzdCgKICAgICAgICBDVFIgPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzFdKQogICAgKSkKYGBgCgpcbmV3cGFnZQoKIyMjIEVsZW1lbnRvIGRlbCBtZW7DuiBjb24gbcOhcyBjbGljcwoKYGBge3IgbWVudS1jbGljc30KbWVudSAlPiUgCiAgICBmaWx0ZXIoYmV0d2VlbihmZWNoYSxhcy5EYXRlKCIyMDIyLTA1LTIzIiksIGFzLkRhdGUoIjIwMjItMDUtMzEiKSkpICU+JQogICAgbXV0YXRlKGVsZW1lbnRvID0gZmN0X2x1bXBfbigKICAgICAgICBlbGVtZW50bywKICAgICAgICAyMCwKICAgICAgICB3ID0gY2xpY3NUb3RhbGVzLAogICAgICAgIG90aGVyX2xldmVsID0gIk90aGVycyIpKSAlPiUgCiAgICBncm91cF9ieShlbGVtZW50bykgJT4lIAogICAgc3VtbWFyaXNlKGNsaWNzVG90YWxlcyA9IGNvbW1hKHN1bShjbGljc1RvdGFsZXMpLDApKSAlPiUKICAgIG11dGF0ZShwY3RfY2xpY3MgPSBwZXJjZW50KGNsaWNzVG90YWxlcyAvIHN1bShjbGljc1RvdGFsZXMpKSkgJT4lIAogICAgYXJyYW5nZShkZXNjKHBjdF9jbGljcykpICU+JSAKICAgIGZvcm1hdHRhYmxlKGxpc3QocGN0X2NsaWNzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsxXSwgZnVuID0gInByb3BvcnRpb24iKSwKICAgICAgICAgICAgICAgICAgICAgY2xpY3NUb3RhbGVzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsyXSkpKQogICAgCmBgYAoKIyMjIEVsZW1lbnRvIGRlbCBtZW7DuiBjb24gbcOhcyBjbGljcyBwb3IgZMOtYQoKYGBge3IgbWVudS1jbGljcy1ieS1kYXRlfQptZW51ICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lCiAgICBtdXRhdGUoZWxlbWVudG8gPSBmY3RfbHVtcF9uKAogICAgICAgIGVsZW1lbnRvLAogICAgICAgIDEwLAogICAgICAgIHcgPSBjbGljc1RvdGFsZXMsCiAgICAgICAgb3RoZXJfbGV2ZWwgPSAiT3RoZXJzIikpICU+JSAKICAgIGdyb3VwX2J5KGZlY2hhLAogICAgICAgICAgICAgZWxlbWVudG8pICU+JQogICAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIHN1bSkgJT4lCiAgICBtdXRhdGUocGN0X2NsaWNzID0gcGVyY2VudChjbGljc1RvdGFsZXMgLyBzdW0oY2xpY3NUb3RhbGVzKSkpICU+JSAKICAgIHBsb3RfbHkoeCA9IH5mZWNoYSwKICAgICAgICAgICAgeSA9IH5wY3RfY2xpY3MsCiAgICAgICAgICAgIHR5cGUgPSAiYmFyIiwKICAgICAgICAgICAgbmFtZSA9IH5lbGVtZW50bywKICAgICAgICAgICAgY29sb3IgPSB+ZWxlbWVudG8sCiAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yX3BhbGV0dGVbM10pICU+JSAKICAgIGxheW91dCh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIGxvcyBjbGljcyB0b3RhbGVzIHBvciBlbGVtZW50byBkZWwgbWVuw7ogcG9yIGTDrWEiLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIlIGRlIGxvcyBjbGljcyB0b3RhbGVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2Zvcm1hdCA9ICIuMCUiKSwgYmFybW9kZSA9ICJzdGFjayIsCiAgICAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gIlBUIFNhbnMgTmFycm93JyIpKQpgYGAKClxuZXdwYWdlCgojIyMgT2ZlcnRhcyBob3QgbcOhcyB2aXN0YXMKCmBgYHtyIGhvdC1vZmVycy1wYWdldmlld3N9Cm9mZXJ0YXNfaG90ICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lIAogICAgbXV0YXRlKHBhZ2luYSA9IGZjdF9sdW1wX24oCiAgICAgICAgcGFnaW5hLAogICAgICAgIDIwLAogICAgICAgIHcgPSBwYWdpbmFzVmlzdGFzLAogICAgICAgIG90aGVyX2xldmVsID0gIk90aGVycyIpKSAlPiUgCiAgICBncm91cF9ieShwYWdpbmEpICU+JQogICAgc3VtbWFyaXNlKHBhZ2luYXNWaXN0YXMgPSBjb21tYShzdW0ocGFnaW5hc1Zpc3RhcyksIDApLAogICAgICAgICAgICAgIHBhZ2luYXNWaXN0YXNVbmljYXMgPSBjb21tYShzdW0ocGFnaW5hc1Zpc3Rhc1VuaWNhcyksMCkpICU+JQogICAgZmlsdGVyKCFwYWdpbmEgPT0gIk90aGVycyIpICU+JSAKICAgIG11dGF0ZShwY3RfcGFnaW5hc1Zpc3Rhc1VuaWNhcyA9IHBlcmNlbnQocGFnaW5hc1Zpc3Rhc1VuaWNhcyAvIHN1bShwYWdpbmFzVmlzdGFzVW5pY2FzKSkpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhwY3RfcGFnaW5hc1Zpc3Rhc1VuaWNhcykpICU+JSAKICAgIGZvcm1hdHRhYmxlKGxpc3QocGN0X3BhZ2luYXNWaXN0YXNVbmljYXMgPSBjb2xvcl9iYXIoY29sb3IgPSBjb2xvcl9wYWxldHRlWzFdLCBmdW4gPSAicHJvcG9ydGlvbiIpLAogICAgICAgICAgICAgICAgICAgICBwYWdpbmFzVmlzdGFzVW5pY2FzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsyXSkpKQogICAgCmBgYAoKIyMjIE1lam9yZXMgYnVzcXVlZGFzIGRlIG9mZXJ0YXMKCmBgYHtyIGhvdC1vZmVycy1zZWFyY2hlc30Kb2ZlcnRhc19ob3QgJT4lIAogICAgZmlsdGVyKGJldHdlZW4oZmVjaGEsYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLCBhcy5EYXRlKCIyMDIyLTA1LTMxIikpKSAlPiUKICAgIGZpbHRlcihncmVwbCgiYnVzcXVlZGEiLCBwYWdpbmEsIGlnbm9yZS5jYXNlID0gVFJVRSkpICU+JSAKICAgIG11dGF0ZShwYWdpbmEgPSBmY3RfbHVtcF9uKAogICAgICAgIHBhZ2luYSwKICAgICAgICAxMCwKICAgICAgICB3ID0gcGFnaW5hc1Zpc3RhcywKICAgICAgICBvdGhlcl9sZXZlbCA9ICJPdGhlcnMiKSkgJT4lIAogICAgZ3JvdXBfYnkocGFnaW5hKSAlPiUKICAgIHN1bW1hcmlzZShwYWdpbmFzVmlzdGFzVW5pY2FzID0gY29tbWEoc3VtKHBhZ2luYXNWaXN0YXNVbmljYXMpLDApKSAlPiUKICAgIGZpbHRlcighcGFnaW5hID09ICJPdGhlcnMiKSAlPiUgCiAgICBtdXRhdGUocGN0X3BhZ2luYXNWaXN0YXNVbmljYXMgPSBwZXJjZW50KHBhZ2luYXNWaXN0YXNVbmljYXMgLyBzdW0ocGFnaW5hc1Zpc3Rhc1VuaWNhcykpKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MocGN0X3BhZ2luYXNWaXN0YXNVbmljYXMpKSAlPiUgCiAgICBmb3JtYXR0YWJsZShsaXN0KHBjdF9wYWdpbmFzVmlzdGFzVW5pY2FzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsxXSwgZnVuID0gInByb3BvcnRpb24iKSwKICAgICAgICAgICAgICAgICAgICAgcGFnaW5hc1Zpc3Rhc1VuaWNhcyA9IGNvbG9yX2Jhcihjb2xvciA9IGNvbG9yX3BhbGV0dGVbMl0pKSkKYGBgCgpcbmV3cGFnZQoKIyMgQ29udmVyc2lvbmVzCgojIyMgUGF0cm9jaW5hZG9yZXMgY29uIG1lam9yZXMgaW1wcmVzaW9uZXMsIGNsaWNzIHkgQ1RSCmBgYHtyIHNwb25zb3JzLXBlcmZvcm1hY2V9CnByb2R1Y3RzICU+JSAKICAgIG11dGF0ZShwYXRyb2NpbmFkb3IgPSBmY3RfbHVtcF9uKAogICAgICAgIHBhdHJvY2luYWRvciwKICAgICAgICAxMCwKICAgICAgICB3ID0gaW1wcmVzaW9uZXMsCiAgICAgICAgb3RoZXJfbGV2ZWwgPSAib3RoZXJzIikpICU+JSAKICAgIGdyb3VwX2J5KHBhdHJvY2luYWRvcikgJT4lCiAgICBzdW1tYXJpc2VfaWYoaXMubnVtZXJpYywgc3VtKSAlPiUgCiAgICBmaWx0ZXIoIXBhdHJvY2luYWRvciA9PSAib3RoZXJzIikgJT4lIAogICAgYXJyYW5nZShkZXNjKGltcHJlc2lvbmVzKSkgJT4lIAogICAgbXV0YXRlKHBhdHJvY2luYWRvciA9IGZjdF9yZXYoYXNfZmFjdG9yKHRvbG93ZXIoZmN0X3Jlb3JkZXIocGF0cm9jaW5hZG9yLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltcHJlc2lvbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5mdW4gPSBzdW0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmRlc2MgPSBGQUxTRSkpKSkpICU+JSAKICAgIHBsb3RfbHkoeCA9IH5jbGljcywKICAgICAgICAgICAgeSA9IH5wYXRyb2NpbmFkb3IsCiAgICAgICAgICAgIHR5cGUgPSAiYmFyIiwKICAgICAgICAgICAgb3JpZW50YXRpb24gPSAiaCIsCiAgICAgICAgICAgIG5hbWUgPSAiY2xpY3MiLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gY29sb3JfcGFsZXR0ZVsyXSkpICU+JSAKICAgIGFkZF90cmFjZSh4ID0gfmltcHJlc2lvbmVzLAogICAgICAgICAgICAgIG5hbWUgPSAiaW1wcmVzaW9uZXMiLAogICAgICAgICAgICAgIG1hcmtlciA9IGxpc3QoY29sb3IgPSBjb2xvcl9wYWxldHRlWzFdKSkgJT4lIAogICAgbGF5b3V0KHRpdGxlID0gIlRvcCAxMCBwYXRyb2NpbmFkb3JlcyA8YnI+PHN1Yj5PcmRlbmFkbyBwb3IgY2FudGlkYWQgZGUgaW1wcmVzaW9uZXM8L3N1Yj4iLAogICAgICAgICAgIG1hcmdpbiA9IGxpc3QoYXV0b2V4cGFuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICB0ID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgbCA9IDIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIHIgPSAxNTAsCiAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMTAwKSwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnUGF0cm9jaW5hZG9yJywKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b21hcmdpbiA9IFRSVUUpLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImxvZyIpLAogICAgICAgICAgIGJhcm1vZGUgPSAnZ3JvdXAnKQpgYGAKCiMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBwYXRyb2NpbmFkb3JlcyBwb3IgZMOtYQoKYGBge3Igc3BvbnNvcnMtcGVyZm9ybWFjZS1kYXRlLWltcHJlc2lvbnN9CnByb2R1Y3RzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLAogICAgICAgICAgICAgICAgICAgYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLAogICAgICAgICAgICAgICAgICAgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lCiAgICBtdXRhdGUocGF0cm9jaW5hZG9yID0gZmN0X2x1bXBfbigKICAgICAgICBwYXRyb2NpbmFkb3IsCiAgICAgICAgMTAsCiAgICAgICAgdyA9IGltcHJlc2lvbmVzLAogICAgICAgIG90aGVyX2xldmVsID0gIm90aGVycyIpKSAlPiUgCiAgICBmaWx0ZXIoIXBhdHJvY2luYWRvciA9PSAib3RoZXJzIikgJT4lIAogICAgZ3JvdXBfYnkoZmVjaGEsCiAgICAgICAgICAgICBwYXRyb2NpbmFkb3IpICU+JQogICAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIHN1bSkgJT4lCiAgICBtdXRhdGUocGN0X2ltcHJlc2lvbmVzID0gcGVyY2VudChpbXByZXNpb25lcyAvIHN1bShpbXByZXNpb25lcykpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEsCiAgICAgICAgICAgIHkgPSB+cGN0X2ltcHJlc2lvbmVzLAogICAgICAgICAgICB0eXBlID0gImJhciIsCiAgICAgICAgICAgIG5hbWUgPSB+cGF0cm9jaW5hZG9yLAogICAgICAgICAgICBjb2xvciA9IH5wYXRyb2NpbmFkb3IsCiAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yX3BhbGV0dGVbM10pICU+JSAKICAgIGxheW91dCh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIGxhcyBpbXByZXNpb25lcyBwb3IgcGF0cm9jaW5hZG9yIHBvciBkw61hIiwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiaW1wcmVzaW9uZXMiLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9ybWF0ID0gIi4wJSIpLAogICAgICAgICAgIGJhcm1vZGUgPSAic3RhY2siLAogICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJQVCBTYW5zIE5hcnJvdyciKSkKYGBgCgpcbmV3cGFnZQoKYGBge3Igc3BvbnNvcnMtcGVyZm9ybWFjZS1kYXRlLWNsaWNzfQpwcm9kdWN0cyAlPiUgCiAgICBmaWx0ZXIoYmV0d2VlbihmZWNoYSxhcy5EYXRlKCIyMDIyLTA1LTIzIiksIGFzLkRhdGUoIjIwMjItMDUtMzEiKSkpICU+JQogICAgbXV0YXRlKHBhdHJvY2luYWRvciA9IGZjdF9sdW1wX24oCiAgICAgICAgcGF0cm9jaW5hZG9yLAogICAgICAgIDEwLAogICAgICAgIHcgPSBjbGljcywKICAgICAgICBvdGhlcl9sZXZlbCA9ICJvdGhlcnMiKSkgJT4lIAogICAgZmlsdGVyKCFwYXRyb2NpbmFkb3IgPT0gIm90aGVycyIpICU+JSAKICAgIGdyb3VwX2J5KGZlY2hhLAogICAgICAgICAgICAgcGF0cm9jaW5hZG9yKSAlPiUKICAgIHN1bW1hcmlzZV9pZihpcy5udW1lcmljLCBzdW0pICU+JQogICAgbXV0YXRlKHBjdF9jbGljcyA9IHBlcmNlbnQoY2xpY3MgLyBzdW0oY2xpY3MpKSkgJT4lIAogICAgcGxvdF9seSh4ID0gfmZlY2hhLAogICAgICAgICAgICB5ID0gfnBjdF9jbGljcywKICAgICAgICAgICAgdHlwZSA9ICJiYXIiLAogICAgICAgICAgICBuYW1lID0gfnBhdHJvY2luYWRvciwKICAgICAgICAgICAgY29sb3IgPSB+cGF0cm9jaW5hZG9yLAogICAgICAgICAgICBjb2xvcnMgPSBjb2xvcl9wYWxldHRlWzNdKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSBsb3MgY2xpY3MgcG9yIHBhdHJvY2luYWRvciBwb3IgZMOtYSIsCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gImNsaWNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2Zvcm1hdCA9ICIuMCUiKSwKICAgICAgICAgICBiYXJtb2RlID0gInN0YWNrIiwKICAgICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiUFQgU2FucyBOYXJyb3cnIikpCmBgYAojIyMgTml2ZWxlcyBkZSBwYXRyb2NpbmlvIGNvbiBtYXlvciBjYW50aWRhZCBkZSBwYXRyb2NpbmFkb3JlcwpgYGB7cn0Kc3BvbnNvcl9sZXZlbF9leCA8LSBjKCJpbmRpY2UtZGUtbWFyY2FzIiwKICAgICAgICAgICAgICAgICAgICAgICJvZmVydGEtaG90IiwKICAgICAgICAgICAgICAgICAgICAgICJmYXZvcml0b3MiLAogICAgICAgICAgICAgICAgICAgICAgIm9mZXJ0YS1ob3QtcHJldmVudGEiKQpwcm9kdWN0cyAlPiUgCiAgICBmaWx0ZXIoYmV0d2VlbihmZWNoYSwKICAgICAgICAgICAgICAgICAgIGFzLkRhdGUoIjIwMjItMDUtMjMiKSwKICAgICAgICAgICAgICAgICAgIGFzLkRhdGUoIjIwMjItMDUtMzEiKSkpICU+JQogICAgZmlsdGVyKCFuaXZlbFBhdHJvY2luaW8gJWluJSBzcG9uc29yX2xldmVsX2V4ICYgIWdyZXBsKHBhdHRlcm4gPSAibWFyY2FzLip8Y2F0LS4qIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ID0gbml2ZWxQYXRyb2NpbmlvLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZS5jYXNlID0gVFJVRSkpICU+JSAKICAgIGdyb3VwX2J5KG5pdmVsUGF0cm9jaW5pbykgJT4lIAogICAgc3VtbWFyaXNlKG5fcGF0cm9jaW5hZG9yZXMgPSBuX2Rpc3RpbmN0KHBhdHJvY2luYWRvcikpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhuX3BhdHJvY2luYWRvcmVzKSkgJT4lIAogICAgaGVhZCgxMCkgJT4lIAogICAgZm9ybWF0dGFibGUobGlzdChuX3BhdHJvY2luYWRvcmVzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuID0gInByb3BvcnRpb24iKSkpCmBgYAoKXG5ld3BhZ2UKCiMjIyBDbGljcyBwb3Igc2VjY2nDs24gZGVsIHNpdGlvIHBvciBkw61hCgpgYGB7ciBzZWN0aW9ucy1jbGljc30KcHJvZHVjdHMgJT4lIAogICAgZmlsdGVyKGJldHdlZW4oZmVjaGEsYXMuRGF0ZSgiMjAyMi0wNS0yMyIpLCBhcy5EYXRlKCIyMDIyLTA1LTMxIikpKSAlPiUKICAgIG11dGF0ZShzZWNjaW9uID0gZmN0X2x1bXBfbigKICAgICAgICBzZWNjaW9uLAogICAgICAgIDEwLAogICAgICAgIHcgPSBjbGljcywKICAgICAgICBvdGhlcl9sZXZlbCA9ICJvdGhlcnMiKSkgJT4lIAogICAgZmlsdGVyKCFzZWNjaW9uID09ICJvdGhlcnMiKSAlPiUgCiAgICBncm91cF9ieShmZWNoYSwKICAgICAgICAgICAgIHNlY2Npb24pICU+JQogICAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIHN1bSkgJT4lIAogICAgbXV0YXRlKHBjdF9jbGljcyA9IHBlcmNlbnQoY2xpY3MgLyBzdW0oY2xpY3MpKSkgJT4lIG11dGF0ZSgpICU+JSAKICAgIHBsb3RfbHkoeCA9IH5mZWNoYSwKICAgICAgICAgICAgeSA9IH5wY3RfY2xpY3MsCiAgICAgICAgICAgIHR5cGUgPSAiYmFyIiwKICAgICAgICAgICAgbmFtZSA9IH5zZWNjaW9uLAogICAgICAgICAgICBjb2xvciA9IH5zZWNjaW9uLAogICAgICAgICAgICBjb2xvcnMgPSBjb2xvcl9wYWxldHRlWzNdKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZSBsb3MgY2xpY3MgcG9yIHNlY2Npb24gcG9yIGTDrWEiLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICJjbGljcyIsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tmb3JtYXQgPSAiLjAlIiksCiAgICAgICAgICAgYmFybW9kZSA9ICJzdGFjayIsCiAgICAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gIlBUIFNhbnMgTmFycm93JyIpKQpgYGAKIyMjIFNlY2Npb25lcyBjb24gbWF5b3IgY2FudGlkYWQgZGUgcGF0cm9jaW5hZG9yZXMKYGBge3J9Cgpwcm9kdWN0cyAlPiUgCiAgICBmaWx0ZXIoYmV0d2VlbihmZWNoYSwKICAgICAgICAgICAgICAgICAgIGFzLkRhdGUoIjIwMjItMDUtMjMiKSwKICAgICAgICAgICAgICAgICAgIGFzLkRhdGUoIjIwMjItMDUtMzEiKSkpICU+JQogICAgZ3JvdXBfYnkoc2VjY2lvbikgJT4lIAogICAgc3VtbWFyaXNlKG5fcGF0cm9jaW5hZG9yZXMgPSBuX2Rpc3RpbmN0KHBhdHJvY2luYWRvcikpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhuX3BhdHJvY2luYWRvcmVzKSkgJT4lIAogICAgaGVhZCgxMCkgJT4lIAogICAgZm9ybWF0dGFibGUobGlzdChuX3BhdHJvY2luYWRvcmVzID0gY29sb3JfYmFyKGNvbG9yID0gY29sb3JfcGFsZXR0ZVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuID0gInByb3BvcnRpb24iKSkpCmBgYAoKXG5ld3BhZ2UKCiMjIyBOaXZlbCBkZSBwYXRyb2NpbmlvIGNvbiBtZWpvcmVzIGltcHJlc2lvbmVzLCBjbGljcyB5IENUUgoKYGBge3Igc3BvbnNvckxldmVsLWltcHJlc2lvbnN9CnByb2R1Y3RzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lCiAgICBtdXRhdGUobml2ZWxQYXRyb2NpbmlvID0gZmN0X2x1bXBfbigKICAgICAgICBuaXZlbFBhdHJvY2luaW8sCiAgICAgICAgMTAsCiAgICAgICAgdyA9IGltcHJlc2lvbmVzLAogICAgICAgIG90aGVyX2xldmVsID0gIm90aGVycyIpKSAlPiUgCiAgICBmaWx0ZXIoIW5pdmVsUGF0cm9jaW5pbyA9PSAib3RoZXJzIikgJT4lIAogICAgZ3JvdXBfYnkoZmVjaGEsCiAgICAgICAgICAgICBuaXZlbFBhdHJvY2luaW8pICU+JQogICAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIHN1bSkgJT4lCiAgICBtdXRhdGUocGN0X2ltcHJlc2lvbmVzID0gaW1wcmVzaW9uZXMvIHN1bShpbXByZXNpb25lcykpICU+JSAKICAgIHBsb3RfbHkoeCA9IH5mZWNoYSwKICAgICAgICAgICAgeSA9IH5wY3RfaW1wcmVzaW9uZXMsCiAgICAgICAgICAgIHR5cGUgPSAiYmFyIiwKICAgICAgICAgICAgbmFtZSA9IH5uaXZlbFBhdHJvY2luaW8sCiAgICAgICAgICAgIGNvbG9yID0gfm5pdmVsUGF0cm9jaW5pbywKICAgICAgICAgICAgY29sb3JzID0gY29sb3JfcGFsZXR0ZVszXSkgJT4lIAogICAgbGF5b3V0KHRpdGxlID0gIkRpc3RyaWJ1Y2nDs24gZGUgbGFzIGltcHJlc2lvbmVzIHBvciBuaXZlbCBkZSBwYXRyb2NpbmlvIHBvciBkw61hIiwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiaW1wcmVzaW9uZXMiLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrZm9ybWF0ID0gIi4wJSIpLAogICAgICAgICAgIGJhcm1vZGUgPSAic3RhY2siLAogICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJQVCBTYW5zIE5hcnJvdyciKSkKYGBgCgpgYGB7ciBzcG9uc29yTGV2ZWwtY2xpY3N9CnByb2R1Y3RzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lCiAgICBtdXRhdGUobml2ZWxQYXRyb2NpbmlvID0gZmN0X2x1bXBfbigKICAgICAgICBuaXZlbFBhdHJvY2luaW8sCiAgICAgICAgMTAsCiAgICAgICAgdyA9IGNsaWNzLAogICAgICAgIG90aGVyX2xldmVsID0gIm90aGVycyIpKSAlPiUgCiAgICBmaWx0ZXIoIW5pdmVsUGF0cm9jaW5pbyA9PSAib3RoZXJzIikgJT4lIAogICAgZ3JvdXBfYnkoZmVjaGEsCiAgICAgICAgICAgICBuaXZlbFBhdHJvY2luaW8pICU+JQogICAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIHN1bSkgJT4lCiAgICBtdXRhdGUocGN0X2NsaWNzID0gY2xpY3MgLyBzdW0oY2xpY3MpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEsCiAgICAgICAgICAgIHkgPSB+cGN0X2NsaWNzLAogICAgICAgICAgICB0eXBlID0gImJhciIsCiAgICAgICAgICAgIG5hbWUgPSB+bml2ZWxQYXRyb2NpbmlvLAogICAgICAgICAgICBjb2xvciA9IH5uaXZlbFBhdHJvY2luaW8sCiAgICAgICAgICAgIGNvbG9ycyA9IGNvbG9yX3BhbGV0dGVbM10pICU+JSAKICAgIGxheW91dCh0aXRsZSA9ICJEaXN0cmlidWNpw7NuIGRlIGxvcyBjbGljcyBwb3Igbml2ZWwgZGUgcGF0cm9jaW5pbyBwb3IgZMOtYSIsCiAgICAgICAgICAgeWF4aXMgPSBsaXN0KHRpdGxlID0gImNsaWNzIiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2Zvcm1hdCA9ICIuMCUiKSwKICAgICAgICAgICBiYXJtb2RlID0gInN0YWNrIiwKICAgICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiUFQgU2FucyBOYXJyb3cnIikpCmBgYAoKXG5ld3BhZ2UKCmBgYHtyIHNwb25zb3JMZXZlbC1jdHJ9CnByb2R1Y3RzICU+JSAKICAgIGZpbHRlcihiZXR3ZWVuKGZlY2hhLGFzLkRhdGUoIjIwMjItMDUtMjMiKSwgYXMuRGF0ZSgiMjAyMi0wNS0zMSIpKSkgJT4lCiAgICBtdXRhdGUobml2ZWxQYXRyb2NpbmlvID0gZmN0X2x1bXBfbigKICAgICAgICBuaXZlbFBhdHJvY2luaW8sCiAgICAgICAgMTAsCiAgICAgICAgdyA9IGltcHJlc2lvbmVzLAogICAgICAgIG90aGVyX2xldmVsID0gIm90aGVycyIpKSAlPiUgCiAgICBmaWx0ZXIoIW5pdmVsUGF0cm9jaW5pbyA9PSAib3RoZXJzIikgJT4lIAogICAgZ3JvdXBfYnkoZmVjaGEsCiAgICAgICAgICAgICBuaXZlbFBhdHJvY2luaW8pICU+JQogICAgc3VtbWFyaXNlKGltcHJlc2lvbmVzID0gc3VtKGltcHJlc2lvbmVzKSwKICAgICAgICAgICAgICBjbGljcyA9IHN1bShjbGljcyksCiAgICAgICAgICAgICAgQ1RSID0gc3VtKGNsaWNzKSAvICBzdW0oaW1wcmVzaW9uZXMpKSAlPiUgCiAgICBtdXRhdGUocGN0X0NSVCA9IENUUiAvIHN1bShDVFIpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEsCiAgICAgICAgICAgIHkgPSB+cGN0X0NSVCwKICAgICAgICAgICAgdHlwZSA9ICJiYXIiLAogICAgICAgICAgICBuYW1lID0gfm5pdmVsUGF0cm9jaW5pbywKICAgICAgICAgICAgY29sb3IgPSB+bml2ZWxQYXRyb2NpbmlvLAogICAgICAgICAgICBjb2xvcnMgPSBjb2xvcl9wYWxldHRlWzNdKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiRGlzdHJpYnVjacOzbiBkZWwgQ1RSIHBvciBuaXZlbCBkZSBwYXRyb2NpbmlvIHBvciBkw61hIiwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAiQ1RSIiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2Zvcm1hdCA9ICIuMCUiKSwgCiAgICAgICAgICAgYmFybW9kZSA9ICJzdGFjayIsCiAgICAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gIlBUIFNhbnMgTmFycm93JyIpKQpgYGAKCiMjIExhbmRpbmcgdGlwcyBlbXByZXNhcwoKIyMjIHRlbmRlbmNpYSBkZSBsb3MgY2xpY3MgeSBsYXMgaW1wcmVzaW9uZXMKCmBgYHtyIHRpcHMtZW1wcmVzYXMtdHJlbmR9CnByb2R1Y3RzICU+JQogICAgZmlsdGVyKGdyZXBsKCJ0aXBzZW1wcmVzYXMiLAogICAgICAgICAgICAgICAgIHNlY2Npb24sCiAgICAgICAgICAgICAgICAgaWdub3JlLmNhc2UgPSBUUlVFKSkgJT4lIAogICAgZ3JvdXBfYnkoZmVjaGEpICU+JSAKICAgIHN1bW1hcmlzZShpbXByZXNpb25lcyA9IHN1bShpbXByZXNpb25lcyksCiAgICAgICAgICAgICAgY2xpY3MgPSBzdW0oY2xpY3MpKSAlPiUgCiAgICBwbG90X2x5KHggPSB+ZmVjaGEpICU+JQogICAgYWRkX3RyYWNlKHkgPSB+Y2xpY3MsCiAgICAgICAgICAgICAgdHlwZSA9ICdzY2F0dGVyJywKICAgICAgICAgICAgICBtb2RlID0gJ2xpbmVzJywKICAgICAgICAgICAgICBuYW1lID0gJ2NsaWNzJywKICAgICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9IGNvbG9yX3BhbGV0dGVbMl0sCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAyKSkgJT4lCiAgICBhZGRfdHJhY2UoeSA9IH5pbXByZXNpb25lcywKICAgICAgICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLAogICAgICAgICAgICAgIG1vZGUgPSAnbGluZXMnLAogICAgICAgICAgICAgIG5hbWUgPSAnaW1wcmVzaW9uZXMnLAogICAgICAgICAgICAgIGxpbmUgPSBsaXN0KGNvbG9yID0gY29sb3JfcGFsZXR0ZVsxXSwKICAgICAgICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDQpKSAlPiUKICAgIGxheW91dCh0aXRsZSA9ICJMYW5kaW5nIHRpcHMgLSBUZW5kZW5jaWEgcG9yIGTDrWEiLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICBzaG93bGluZSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3dncmlkID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgIHNob3d0aWNrbGFiZWxzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICAgbGluZWNvbG9yID0gJ3JnYigyMDQsIDIwNCwgMjA0KScsCiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmV3aWR0aCA9IDIsCiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG90aWNrID0gRkFMU0UsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tzID0gJ291dHNpZGUnLAogICAgICAgICAgICAgICAgICAgICAgICB0aWNrY29sb3IgPSAncmdiKDIwNCwgMjA0LCAyMDQpJywKICAgICAgICAgICAgICAgICAgICAgICAgdGlja3dpZHRoID0gMiwKICAgICAgICAgICAgICAgICAgICAgICAgdGlja2xlbiA9IDUsCiAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tmb250ID0gbGlzdChmYW1pbHkgPSAnUFQgU2FucyBOYXJyb3cnLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiKDgyLCA4MiwgODIpJykpLAogICAgICAgICAgIHlheGlzID0gbGlzdCh0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImxvZyIpLAogICAgICAgICAgIG1hcmdpbiA9IGxpc3QoYXV0b2V4cGFuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICB0ID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgbCA9IDUwLAogICAgICAgICAgICAgICAgICAgICAgICAgciA9IDIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIGIgPSAxMDApLAogICAgICAgICAgIGF1dG9zaXplID0gVFJVRSwKICAgICAgICAgICBzaG93bGVnZW5kID0gVFJVRSwKICAgICAgICAgICBhbm5vdGF0aW9ucyA9IGxpc3QoCiAgICAgICAgICAgICAgIHhyZWYgPSAncGFwZXInLAogICAgICAgICAgICAgICB5cmVmID0gJ3BhcGVyJywKICAgICAgICAgICAgICAgeCA9IDAuNzMsCiAgICAgICAgICAgICAgIHkgPSAwLjksCiAgICAgICAgICAgICAgIHhhbmNob3IgPSAncmlnaHQnLAogICAgICAgICAgICAgICB5YW5jaG9yID0gJ21pZGRsZScsCiAgICAgICAgICAgICAgIHRleHQgPSAnUHJpbWVyIGRlbCBIb3QgU2FsZScsCiAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICdQVCBTYW5zIE5hcnJvdycsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxNiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiYSgxNjAsMTYwLDE2MCwxKScpLAogICAgICAgICAgICAgICBzaG93YXJyb3cgPSBUUlVFKSkgJT4lCiAgICBsYXlvdXQoYW5ub3RhdGlvbnMgPSBsaXN0KAogICAgICAgIHhyZWYgPSAncGFwZXInLAogICAgICAgIHlyZWYgPSAncGFwZXInLAogICAgICAgIHggPSAxLAogICAgICAgIHkgPSAwLjYsCiAgICAgICAgeGFuY2hvciA9ICdsZWZ0JywKICAgICAgICB5YW5jaG9yID0gJ21pZGRsZScsCiAgICAgICAgdGV4dCA9ICfDmmx0aW1vIGRlbCBIb3QgU2FsZScsCiAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gJ1BUIFNhbnMgTmFycm93JywKICAgICAgICAgICAgICAgICAgICBzaXplID0gMTYsCiAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAncmdiYSgxNjAsMTYwLDE2MCwxKScpLAogICAgICAgIHNob3dhcnJvdyA9IFRSVUUpKQpgYGAKClxuZXdwYWdlCgojIyMgUGF0cm9jaW5hZG9yZXMgY29uIG3DoXMgY2xpY3MKCmBgYHtyIHRpcHMtZW1wcmVzYXMtdG9wfQpwcm9kdWN0cyAlPiUgCiAgICBmaWx0ZXIoZ3JlcGwoInRpcHNlbXByZXNhcyIsCiAgICAgICAgICAgICAgICAgc2VjY2lvbiwKICAgICAgICAgICAgICAgICBpZ25vcmUuY2FzZSA9IFRSVUUpKSAlPiUgCiAgICBtdXRhdGUocGF0cm9jaW5hZG9yID0gZmN0X2x1bXBfbigKICAgICAgICBwYXRyb2NpbmFkb3IsCiAgICAgICAgMTAsCiAgICAgICAgdyA9IGltcHJlc2lvbmVzLAogICAgICAgIG90aGVyX2xldmVsID0gIk90aGVycyIpKSAlPiUgCiAgICBncm91cF9ieShwYXRyb2NpbmFkb3IpICU+JQogICAgc3VtbWFyaXNlX2lmKGlzLm51bWVyaWMsIHN1bSkgJT4lIAogICAgbXV0YXRlKHBhdHJvY2luYWRvciA9IGFzX2ZhY3Rvcih0b2xvd2VyKGZjdF9yZW9yZGVyKHBhdHJvY2luYWRvciwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltcHJlc2lvbmVzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZ1biA9IHN1bSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5kZXNjID0gVFJVRSkpKSkgJT4lIAogICAgZmlsdGVyKCFwYXRyb2NpbmFkb3IgPT0gIm90aGVycyIpICU+JSAKICAgIHBsb3RfbHkoeCA9IH5jbGljcywKICAgICAgICAgICAgeSA9IH5wYXRyb2NpbmFkb3IsCiAgICAgICAgICAgIHR5cGUgPSAiYmFyIiwKICAgICAgICAgICAgb3JpZW50YXRpb24gPSAiaCIsCiAgICAgICAgICAgIG5hbWUgPSAiY2xpY3MiLAogICAgICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9yID0gY29sb3JfcGFsZXR0ZVsyXSkpICU+JQogICAgYWRkX3RyYWNlKHggPSB+aW1wcmVzaW9uZXMsCiAgICAgICAgICAgICAgbmFtZSA9ICJpbXByZXNpb25lcyIsCiAgICAgICAgICAgICAgbWFya2VyID0gbGlzdChjb2xvciA9IGNvbG9yX3BhbGV0dGVbMV0pKSAlPiUgCiAgICBsYXlvdXQodGl0bGUgPSAiTGFuZGluZ3MgdGlwcyAtIFRvcCAxMCBwYXRyb2NpbmFkb3JlcyA8YnI+PHN1Yj5PcmRlbmFkbyBwb3IgY2FudGlkYWQgZGUgaW1wcmVzaW9uZXM8L3N1Yj4iLAogICAgICAgICAgIG1hcmdpbiA9IGxpc3QoYXV0b2V4cGFuZCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgICB0ID0gMTAwLAogICAgICAgICAgICAgICAgICAgICAgICAgbCA9IDIwMCwKICAgICAgICAgICAgICAgICAgICAgICAgIHIgPSAxNTAsCiAgICAgICAgICAgICAgICAgICAgICAgICBiID0gMTAwKSwKICAgICAgICAgICB5YXhpcyA9IGxpc3QodGl0bGUgPSAnUGF0cm9jaW5hZG9yJywKICAgICAgICAgICAgICAgICAgICAgICAgYXV0b21hcmdpbiA9IFRSVUUpLAogICAgICAgICAgIHhheGlzID0gbGlzdCh0aXRsZSA9ICIiLAogICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gImxvZyIpLAogICAgICAgICAgIGJhcm1vZGUgPSAnZ3JvdXAnKQpgYGAK