Explorando os dados das Sessões, Buscas e Navegação da Wikimedia

No presente relatório é utilizada a exploração de dados do dataset disponibilizado pela Wikimedia Foundation. Além do dataset, eles apresentaram instruções e quatro perguntas a serem respondidas por meio dos dados disponibilizados.

Nas seções seguintes são apresentadas as bibliotecas e dados utilizados nas análises, bem como as respostas e análises para as quatro perguntas elencadas pela Wikimedia.

1. Bibliotecas utilizadas

library(tidyverse)
library(here)
library(lubridate)
library(ggplot2)
library(knitr)
theme_set(theme_bw())

2. Carregando os dados para análise

Para melhor compreensão da análise, foi adicionada uma nova coluna nos dados referente a data realizada da busca, onde foi excluida a informação de horas.

É necessário realizar a comparação do número de clicks ifelse(num_clicks>0,1,0) e criar uma nova coluna (clicks) para armazenar esses dados de ‘0’ e ‘1’, tendo em vista que será considerado apenas o valor de ‘1’ click, mesmo que o usuário tenha clicado ‘2’ ou mais vezes.

buscas = read_csv(here::here("data/search_data.csv")) %>%
head(100000) %>% 
mutate(day = round_date(session_start_date, unit = "day")) %>% 
mutate (clicks = ifelse(num_clicks>0,1,0))

2.1 Variáveis utilizadas nas análises

group : Um marcador (“a” ou “b”);

results : Número de ocorrências retornadas para o usuário;

num_clicks: Número de ocorrências clicadas pelo usuário;

first_click: Posição da ocorrência que o usuário clicou primeiro;

session_start_date: Data do início da busca;

session_length: Duração da sessão.

3. Respostas para as questões

3.1 Qual é a taxa de cliques geral diária? Como isso varia entre os grupos?

Primeiramente, para relizar a análise do taxa de cliques geral os dados foram agrupados por sessão, por meio da variável session_id. A partir disso, foi criado um sumário para armazenar o valor máximo de cliques (ou seja, com valor 1), com também o dia e grupo por sessão. Logo em seguida, foi feito o agrupamento por dia, para que fosse possível realizar o cálculo da taxa de cliques geral diária. Por fim, a partir das análises efetuadas foi possível gerar o gráfico da Figura 1, em que no geral a taxa encontra-se entre 40%, havendo uma pequena variação de um dia para o outro.

clicks_rate = buscas %>%
    group_by(session_id) %>%
    summarise(click = max(clicks),
              day = max(day),
              group = max(group))
clickthrough_rate = clicks_rate %>%
    group_by(day) %>%
    summarise(clickthrough_rate = (sum(click)/length(session_id)))
clickthrough_rate %>%
    ggplot(aes(x = day ,y = clickthrough_rate)) +
    geom_bar(stat = "identity", fill = "#008B8B") +
    labs(x = "day", y = "clickthrough rate", title = "Figura 1 - Taxa de cliques geral diária")

Enquanto na relação por grupos, um novo sumário foi criado por meio do anterior, onde os dados além de serem agrupados por dia, foram agrupados também por grupo. Dessa forma, foi gerado o gráfico de barras da Figura 2, em que é possível observar que o grupo ‘a’ apresenta a taxa de clique diária superior que o grupo ‘b’.

clicks_rate = buscas %>%
    group_by(session_id) %>%
    summarise(click = max(clicks),
              day = max(day),
              group = max(group))
clickthrough_rate_group = clicks_rate %>%
    group_by(day, group) %>%
    summarise(clickthrough_rate = (sum(click)/length(session_id)))
clickthrough_rate_group %>%
    ggplot(mapping = aes(x = day, y = clickthrough_rate, fill = group)) +
    geom_bar(stat = "identity", position = position_dodge(), color = "black") +
    scale_fill_manual(values = c("#999999", "#FF8C00")) +
    labs(x = "day", y = "clickthrough rate", title = "Figura 2 - Taxa de cliques geral diária entre os grupos")

3.2 Quais resultados as pessoas tendem a tentar primeiro? Como isso muda no dia-a-dia?

Como o objetivo da questão é realizar o levantamento de quais resultados as pessoas tendem a tentar primeiro, a variável first_click é responsável por armazenar o primeiro resultado de busca clicada por sessão. Dessa maneira, foi aplicado dois filtros para que somente sejam retornados os valores diferentes de NA e maiores que zero.

Na Figura 3 é verificado de forma mais clara, através de escala logarítmica, que a maioria tedem a tentar o primeiro resultado.

results = buscas %>%
    filter(!is.na(first_click)) %>%
    filter(first_click != 0)
glimpse(dados)
Observations: 24,268
Variables: 11
$ session_id              <chr> "0001382e027b2ea4", "0001e8bb90445cb2", "00064fe77404...
$ search_index            <dbl> 1, 1, 2, 1, 1, 1, 2, 2, 1, 3, 2, 1, 1, 1, 1, 1, 2, 1,...
$ session_length          <dbl> 303, 435, 43, 339, 444, 112, 213, 443, 439, 84, 197, ...
$ session_start_timestamp <dbl> 2.016031e+13, 2.016031e+13, 2.016031e+13, 2.016030e+1...
$ session_start_date      <dttm> 2016-03-07 08:49:55, 2016-03-05 09:24:15, 2016-03-05...
$ group                   <chr> "b", "b", "a", "a", "b", "a", "a", "a", "b", "a", "a"...
$ results                 <dbl> 18, 20, 1, 20, 20, 20, 20, 20, 9, 20, 1, 20, 20, 7, 7...
$ num_clicks              <dbl> 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1,...
$ first_click             <dbl> 1, 1, 1, 1, 5, 1, 1, 1, 1, 4, 1, 1, 2, 1, 1, 2, 1, 1,...
$ day                     <dttm> 2016-03-07, 2016-03-05, 2016-03-05, 2016-03-04, 2016...
$ clicks                  <dbl> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,...
results %>%
    ggplot(aes(x=first_click)) + 
    geom_histogram(binwidth = 1, fill = "#CD5C5C") + 
    scale_x_log10() +
    labs(y = "quantity", x = "first click", title = "Figura 3 - Resultados que as pessoas tendem a tentar primeiro")

Considerando a distribuição dos cliques por dia, é verificado no histograma da Figura 4 que na maioria dos dias os usuários continuam tentar o primeiro resultado, como também os 10 primeiros links.

buscas %>%
    ggplot(aes(x = first_click, fill = day)) +
    geom_histogram(binwidth = 2, fill = "#CD5C5C") +
    scale_x_continuous(limits=c(0,30)) +
    scale_y_continuous(limits=c(0, 1000)) +
    facet_grid(~day) +
    labs(x = "first click", y = "quantity", title = "Figura 4 - Distribuição diária") +        
    theme_grey()

3.3 Qual a taxa de resultados zero no geral? Como isso varia entre os grupos?

De acordo com a Wikimedia, a taxa de resultados zero trata-se da proporção de buscas que renderam em 0 resultados. Assim, na Figura 5 foi verificada esta distribuição por dia e observou-se que a taxa encontra-se entre 15% a 21%, com maiores destaques para o primeiro e último dia.

results_rate = buscas %>%
    group_by(day) %>%
    summarise(sessions = length(session_id), 
              results_zero = sum(results == 0), 
              rate = (results_zero/sessions) * 100)
glimpse (results_rate)
Observations: 9
Variables: 4
$ day          <dttm> 2016-03-01, 2016-03-02, 2016-03-03, 2016-03-04, 2016-03-05, 201...
$ sessions     <int> 5515, 13580, 13793, 13822, 10724, 10191, 12199, 13888, 6288
$ results_zero <int> 1160, 2573, 2534, 2580, 1877, 1915, 2209, 2474, 1255
$ rate         <dbl> 21.03354, 18.94698, 18.37164, 18.66589, 17.50280, 18.79109, 18.1...
results_rate %>%
    ggplot(aes(x = day, y = rate)) +
    geom_bar(stat = "identity", fill = "#008B8B") +
    labs(x = "day", y = "zero results rate", title = "Figura 5 - Taxa de resultados zero geral por dia")

Já com relação a variação entre os grupos ‘a’ e ‘b’, foi gerado um sumário onde os dados foram agrupados por dia, grupo e resultados, realizando o cálculo de proporção entre o somatório da variável criada session_group dividido por length(group).

Nesta Figura 6, é possível observar que nenhum grupo encontra-se acima ou abaixo do outro. No quinto dia o grupo ‘a’ apresentou maior taxa quando comparado a ‘b’, enquanto para o grupo ’b’o sexto dia mostra-se como maior taxa.

results_rate = buscas %>%
    group_by(day, group, results) %>%
    summarise(session_group = length(group)) %>%
    mutate(rate_group = sum(session_group)/session_group)
glimpse (results_rate)
Observations: 477
Variables: 5
Groups: day, group [18]
$ day           <dttm> 2016-03-01, 2016-03-01, 2016-03-01, 2016-03-01, 2016-03-01, 20...
$ group         <chr> "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a", "a"...
$ results       <dbl> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 1...
$ session_group <int> 835, 242, 136, 86, 58, 64, 33, 25, 31, 24, 15, 20, 23, 17, 13, ...
$ rate_group    <dbl> 4.649102, 16.041322, 28.544118, 45.139535, 66.931034, 60.656250...
results_rate %>%filter(results==0) %>%
    ggplot(mapping = aes(x = day, y = rate_group, fill = group)) +
    geom_bar(stat = "identity", position = position_dodge(), color = "black") +
    scale_fill_manual(values = c("#999999", "#FF8C00")) +
    labs(x = "day", y = "zero results rate", title = "Figura 6 - Taxa de resultados zero geral por dia entre os grupos")

3.4 A duração da sessão é aproximadamente o tempo entre o primeiro e o último evento de uma sessão. Escolha uma variável do conjunto de dados e descreva sua relação com o tamanho da sessão. Visualize o relacionamento.

Na Figura 7, a variável first_click foi relacionada com a duração da sessão (session_length), de modo a investigar se quando o usuário clica nos primeiros resultados ele passa a durar mais tempo ou não na sessão.

Ao observar o gráfico gerado, é visto que os usuários terminam passando mais tempo nos primeiros resultados. Tendo em vista que há uma maior concentração dos dados no intervalo de 0 à 10 no eixo vertical com relação ao eixo horizontal com maior concentração dos dados no intervalo de 0 à 1000.

buscas %>%
    filter(first_click <= 50)  %>%
    ggplot(aes(x = session_length, y = first_click)) +
    geom_point(alpha = .2, size = 2, color = "#A52A2A") +
    scale_y_continuous(limits=c(0, 50)) +
    scale_x_continuous(limits=c(0,1000)) +
    labs(x = "session length (sec)", y = "first click", title = "Figura 7 - Relação da duração da sessão em segundos e cliques") 

LS0tDQp0aXRsZTogIkZ1bmRhbWVudG9zIGRlIFBlc3F1aXNhIGVtIENpw6puY2lhIGRhIENvbXB1dGHDp8OjbyBJSSINCmF1dGhvcjogIkwyUDIgLSBHw6lzc2ljYSBBbHZlcyINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCiNFeHBsb3JhbmRvIG9zIGRhZG9zIGRhcyBTZXNzw7VlcywgQnVzY2FzIGUgTmF2ZWdhw6fDo28gZGEgV2lraW1lZGlhDQoNCk5vIHByZXNlbnRlIHJlbGF0w7NyaW8gw6kgdXRpbGl6YWRhIGEgZXhwbG9yYcOnw6NvIGRlIGRhZG9zIGRvIGRhdGFzZXQgZGlzcG9uaWJpbGl6YWRvIHBlbGEgV2lraW1lZGlhIEZvdW5kYXRpb24uIEFsw6ltIGRvIGRhdGFzZXQsIGVsZXMgYXByZXNlbnRhcmFtIGluc3RydcOnw7VlcyBlIHF1YXRybyBwZXJndW50YXMgYSBzZXJlbSByZXNwb25kaWRhcyBwb3IgbWVpbyBkb3MgZGFkb3MgZGlzcG9uaWJpbGl6YWRvcy4NCg0KTmFzIHNlw6fDtWVzIHNlZ3VpbnRlcyBzw6NvIGFwcmVzZW50YWRhcyBhcyBiaWJsaW90ZWNhcyBlIGRhZG9zIHV0aWxpemFkb3MgbmFzIGFuw6FsaXNlcywgYmVtIGNvbW8gYXMgcmVzcG9zdGFzIGUgYW7DoWxpc2VzIHBhcmEgYXMgcXVhdHJvIHBlcmd1bnRhcyBlbGVuY2FkYXMgcGVsYSBXaWtpbWVkaWEuIA0KDQojIDEuIEJpYmxpb3RlY2FzIHV0aWxpemFkYXMNCg0KYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGhlcmUpDQpsaWJyYXJ5KGx1YnJpZGF0ZSkNCmxpYnJhcnkoZ2dwbG90MikNCmxpYnJhcnkoa25pdHIpDQp0aGVtZV9zZXQodGhlbWVfYncoKSkNCmBgYA0KDQojIDIuIENhcnJlZ2FuZG8gb3MgZGFkb3MgcGFyYSBhbsOhbGlzZSANCg0KUGFyYSBtZWxob3IgY29tcHJlZW5zw6NvIGRhIGFuw6FsaXNlLCBmb2kgYWRpY2lvbmFkYSB1bWEgbm92YSBjb2x1bmEgbm9zIGRhZG9zIHJlZmVyZW50ZSBhIGRhdGEgcmVhbGl6YWRhIGRhIGJ1c2NhLCBvbmRlIGZvaSBleGNsdWlkYSBhIGluZm9ybWHDp8OjbyBkZSBob3Jhcy4gIA0KDQrDiSBuZWNlc3PDoXJpbyByZWFsaXphciBhIGNvbXBhcmHDp8OjbyBkbyBuw7ptZXJvIGRlIGNsaWNrcyBpZmVsc2UobnVtX2NsaWNrcz4wLDEsMCkgZSBjcmlhciB1bWEgbm92YSBjb2x1bmEgKGNsaWNrcykgcGFyYSBhcm1hemVuYXIgZXNzZXMgZGFkb3MgZGUgJzAnIGUgJzEnLCB0ZW5kbyBlbSB2aXN0YSBxdWUgc2Vyw6EgY29uc2lkZXJhZG8gYXBlbmFzIG8gdmFsb3IgZGUgJzEnIGNsaWNrLCBtZXNtbyBxdWUgbyB1c3XDoXJpbyB0ZW5oYSBjbGljYWRvICcyJyBvdSBtYWlzIHZlemVzLg0KDQpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQ0KYnVzY2FzID0gcmVhZF9jc3YoaGVyZTo6aGVyZSgiZGF0YS9zZWFyY2hfZGF0YS5jc3YiKSkgJT4lDQpoZWFkKDEwMDAwMCkgJT4lIA0KbXV0YXRlKGRheSA9IHJvdW5kX2RhdGUoc2Vzc2lvbl9zdGFydF9kYXRlLCB1bml0ID0gImRheSIpKSAlPiUgDQptdXRhdGUgKGNsaWNrcyA9IGlmZWxzZShudW1fY2xpY2tzPjAsMSwwKSkNCmBgYA0KDQojIDIuMSBWYXJpw6F2ZWlzIHV0aWxpemFkYXMgbmFzIGFuw6FsaXNlcw0KDQpncm91cCA6IFVtIG1hcmNhZG9yICjigJxh4oCdIG91IOKAnGLigJ0pOw0KDQpyZXN1bHRzIDogTsO6bWVybyBkZSBvY29ycsOqbmNpYXMgcmV0b3JuYWRhcyBwYXJhIG8gdXN1w6FyaW87DQoNCm51bV9jbGlja3M6IE7Dum1lcm8gZGUgb2NvcnLDqm5jaWFzIGNsaWNhZGFzIHBlbG8gdXN1w6FyaW87DQoNCmZpcnN0X2NsaWNrOiBQb3Npw6fDo28gZGEgb2NvcnLDqm5jaWEgcXVlIG8gdXN1w6FyaW8gY2xpY291IHByaW1laXJvOw0KDQpzZXNzaW9uX3N0YXJ0X2RhdGU6IERhdGEgZG8gaW7DrWNpbyBkYSBidXNjYTsNCg0Kc2Vzc2lvbl9sZW5ndGg6IER1cmHDp8OjbyBkYSBzZXNzw6NvLg0KDQojIDMuIFJlc3Bvc3RhcyBwYXJhIGFzIHF1ZXN0w7Vlcw0KDQojIDMuMSBRdWFsIMOpIGEgdGF4YSBkZSBjbGlxdWVzIGdlcmFsIGRpw6FyaWE/IENvbW8gaXNzbyB2YXJpYSBlbnRyZSBvcyBncnVwb3M/DQoNClByaW1laXJhbWVudGUsIHBhcmEgcmVsaXphciBhIGFuw6FsaXNlIGRvIHRheGEgZGUgY2xpcXVlcyBnZXJhbCBvcyBkYWRvcyBmb3JhbSBhZ3J1cGFkb3MgcG9yIHNlc3PDo28sIHBvciBtZWlvIGRhIHZhcmnDoXZlbCBzZXNzaW9uX2lkLiBBIHBhcnRpciBkaXNzbywgZm9pIGNyaWFkbyB1bSBzdW3DoXJpbyBwYXJhIGFybWF6ZW5hciBvIHZhbG9yIG3DoXhpbW8gZGUgY2xpcXVlcyAob3Ugc2VqYSwgY29tIHZhbG9yIDEpLCBjb20gdGFtYsOpbSBvIGRpYSBlIGdydXBvIHBvciBzZXNzw6NvLiBMb2dvIGVtIHNlZ3VpZGEsIGZvaSBmZWl0byBvIGFncnVwYW1lbnRvIHBvciBkaWEsIHBhcmEgcXVlIGZvc3NlIHBvc3PDrXZlbCByZWFsaXphciBvIGPDoWxjdWxvIGRhIHRheGEgZGUgY2xpcXVlcyBnZXJhbCBkacOhcmlhLiBQb3IgZmltLCBhIHBhcnRpciBkYXMgYW7DoWxpc2VzIGVmZXR1YWRhcyBmb2kgcG9zc8OtdmVsIGdlcmFyIG8gZ3LDoWZpY28gZGEgRmlndXJhIDEsIGVtIHF1ZSBubyBnZXJhbCBhIHRheGEgZW5jb250cmEtc2UgZW50cmUgNDAlLCBoYXZlbmRvIHVtYSBwZXF1ZW5hIHZhcmlhw6fDo28gZGUgdW0gZGlhIHBhcmEgbyBvdXRyby4NCg0KYGBge3J9DQpjbGlja3NfcmF0ZSA9IGJ1c2NhcyAlPiUNCiAgICBncm91cF9ieShzZXNzaW9uX2lkKSAlPiUNCiAgICBzdW1tYXJpc2UoY2xpY2sgPSBtYXgoY2xpY2tzKSwNCiAgICAgICAgICAgICAgZGF5ID0gbWF4KGRheSksDQogICAgICAgICAgICAgIGdyb3VwID0gbWF4KGdyb3VwKSkNCg0KY2xpY2t0aHJvdWdoX3JhdGUgPSBjbGlja3NfcmF0ZSAlPiUNCiAgICBncm91cF9ieShkYXkpICU+JQ0KICAgIHN1bW1hcmlzZShjbGlja3Rocm91Z2hfcmF0ZSA9IChzdW0oY2xpY2spL2xlbmd0aChzZXNzaW9uX2lkKSkpDQoNCmNsaWNrdGhyb3VnaF9yYXRlICU+JQ0KICAgIGdncGxvdChhZXMoeCA9IGRheSAseSA9IGNsaWNrdGhyb3VnaF9yYXRlKSkgKw0KICAgIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCBmaWxsID0gIiMwMDhCOEIiKSArDQogICAgbGFicyh4ID0gImRheSIsIHkgPSAiY2xpY2t0aHJvdWdoIHJhdGUiLCB0aXRsZSA9ICJGaWd1cmEgMSAtIFRheGEgZGUgY2xpcXVlcyBnZXJhbCBkacOhcmlhIikNCmBgYA0KDQpFbnF1YW50byBuYSByZWxhw6fDo28gcG9yIGdydXBvcywgdW0gbm92byBzdW3DoXJpbyBmb2kgY3JpYWRvIHBvciBtZWlvIGRvIGFudGVyaW9yLCBvbmRlIG9zIGRhZG9zIGFsw6ltIGRlIHNlcmVtIGFncnVwYWRvcyBwb3IgZGlhLCBmb3JhbSBhZ3J1cGFkb3MgdGFtYsOpbSBwb3IgZ3J1cG8uIERlc3NhIGZvcm1hLCBmb2kgZ2VyYWRvIG8gZ3LDoWZpY28gZGUgYmFycmFzIGRhIEZpZ3VyYSAyLCBlbSBxdWUgw6kgcG9zc8OtdmVsIG9ic2VydmFyIHF1ZSBvIGdydXBvICdhJyBhcHJlc2VudGEgYSB0YXhhIGRlIGNsaXF1ZSBkacOhcmlhIHN1cGVyaW9yIHF1ZSBvIGdydXBvICdiJy4NCg0KYGBge3J9DQpjbGlja3NfcmF0ZSA9IGJ1c2NhcyAlPiUNCiAgICBncm91cF9ieShzZXNzaW9uX2lkKSAlPiUNCiAgICBzdW1tYXJpc2UoY2xpY2sgPSBtYXgoY2xpY2tzKSwNCiAgICAgICAgICAgICAgZGF5ID0gbWF4KGRheSksDQogICAgICAgICAgICAgIGdyb3VwID0gbWF4KGdyb3VwKSkNCg0KY2xpY2t0aHJvdWdoX3JhdGVfZ3JvdXAgPSBjbGlja3NfcmF0ZSAlPiUNCiAgICBncm91cF9ieShkYXksIGdyb3VwKSAlPiUNCiAgICBzdW1tYXJpc2UoY2xpY2t0aHJvdWdoX3JhdGUgPSAoc3VtKGNsaWNrKS9sZW5ndGgoc2Vzc2lvbl9pZCkpKQ0KDQpjbGlja3Rocm91Z2hfcmF0ZV9ncm91cCAlPiUNCiAgICBnZ3Bsb3QobWFwcGluZyA9IGFlcyh4ID0gZGF5LCB5ID0gY2xpY2t0aHJvdWdoX3JhdGUsIGZpbGwgPSBncm91cCkpICsNCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpLCBjb2xvciA9ICJibGFjayIpICsNCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTk5OTk5IiwgIiNGRjhDMDAiKSkgKw0KICAgIGxhYnMoeCA9ICJkYXkiLCB5ID0gImNsaWNrdGhyb3VnaCByYXRlIiwgdGl0bGUgPSAiRmlndXJhIDIgLSBUYXhhIGRlIGNsaXF1ZXMgZ2VyYWwgZGnDoXJpYSBlbnRyZSBvcyBncnVwb3MiKQ0KYGBgDQoNCiMgMy4yIFF1YWlzIHJlc3VsdGFkb3MgYXMgcGVzc29hcyB0ZW5kZW0gYSB0ZW50YXIgcHJpbWVpcm8/IENvbW8gaXNzbyBtdWRhIG5vIGRpYS1hLWRpYT8NCg0KQ29tbyBvIG9iamV0aXZvIGRhIHF1ZXN0w6NvIMOpIHJlYWxpemFyIG8gbGV2YW50YW1lbnRvIGRlIHF1YWlzIHJlc3VsdGFkb3MgYXMgcGVzc29hcyB0ZW5kZW0gYSB0ZW50YXIgcHJpbWVpcm8sIGEgdmFyacOhdmVsIGZpcnN0X2NsaWNrIMOpIHJlc3BvbnPDoXZlbCBwb3IgYXJtYXplbmFyIG8gcHJpbWVpcm8gcmVzdWx0YWRvIGRlIGJ1c2NhIGNsaWNhZGEgcG9yIHNlc3PDo28uIERlc3NhIG1hbmVpcmEsIGZvaSBhcGxpY2FkbyBkb2lzIGZpbHRyb3MgcGFyYSBxdWUgc29tZW50ZSBzZWphbSByZXRvcm5hZG9zIG9zIHZhbG9yZXMgZGlmZXJlbnRlcyBkZSBOQSBlIG1haW9yZXMgcXVlIHplcm8uDQoNCk5hIEZpZ3VyYSAzIMOpIHZlcmlmaWNhZG8gZGUgZm9ybWEgbWFpcyBjbGFyYSwgYXRyYXbDqXMgZGUgZXNjYWxhIGxvZ2Fyw610bWljYSwgcXVlIGEgbWFpb3JpYSB0ZWRlbSBhIHRlbnRhciBvIHByaW1laXJvIHJlc3VsdGFkby4gDQoNCmBgYHtyfQ0KcmVzdWx0cyA9IGJ1c2NhcyAlPiUNCiAgICBmaWx0ZXIoIWlzLm5hKGZpcnN0X2NsaWNrKSkgJT4lDQogICAgZmlsdGVyKGZpcnN0X2NsaWNrICE9IDApDQoNCmdsaW1wc2UoZGFkb3MpDQoNCnJlc3VsdHMgJT4lDQogICAgZ2dwbG90KGFlcyh4PWZpcnN0X2NsaWNrKSkgKyANCiAgICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEsIGZpbGwgPSAiI0NENUM1QyIpICsgDQogICAgc2NhbGVfeF9sb2cxMCgpICsNCiAgICBsYWJzKHkgPSAicXVhbnRpdHkiLCB4ID0gImZpcnN0IGNsaWNrIiwgdGl0bGUgPSAiRmlndXJhIDMgLSBSZXN1bHRhZG9zIHF1ZSBhcyBwZXNzb2FzIHRlbmRlbSBhIHRlbnRhciBwcmltZWlybyIpDQpgYGANCg0KQ29uc2lkZXJhbmRvIGEgZGlzdHJpYnVpw6fDo28gZG9zIGNsaXF1ZXMgcG9yIGRpYSwgw6kgdmVyaWZpY2FkbyBubyBoaXN0b2dyYW1hIGRhIEZpZ3VyYSA0IHF1ZSBuYSBtYWlvcmlhIGRvcyBkaWFzIG9zIHVzdcOhcmlvcyBjb250aW51YW0gdGVudGFyIG8gcHJpbWVpcm8gcmVzdWx0YWRvLCBjb21vIHRhbWLDqW0gb3MgMTAgcHJpbWVpcm9zIGxpbmtzLg0KDQpgYGB7cn0NCmJ1c2NhcyAlPiUNCiAgICBnZ3Bsb3QoYWVzKHggPSBmaXJzdF9jbGljaywgZmlsbCA9IGRheSkpICsNCiAgICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDIsIGZpbGwgPSAiI0NENUM1QyIpICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMCwzMCkpICsNCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPWMoMCwgMTAwMCkpICsNCiAgICBmYWNldF9ncmlkKH5kYXkpICsNCiAgICBsYWJzKHggPSAiZmlyc3QgY2xpY2siLCB5ID0gInF1YW50aXR5IiwgdGl0bGUgPSAiRmlndXJhIDQgLSBEaXN0cmlidWnDp8OjbyBkacOhcmlhIikgKyAgICAgICAgDQogICAgdGhlbWVfZ3JleSgpDQpgYGANCg0KIyAzLjMgUXVhbCBhIHRheGEgZGUgcmVzdWx0YWRvcyB6ZXJvIG5vIGdlcmFsPyBDb21vIGlzc28gdmFyaWEgZW50cmUgb3MgZ3J1cG9zPw0KDQpEZSBhY29yZG8gY29tIGEgV2lraW1lZGlhLCBhIHRheGEgZGUgcmVzdWx0YWRvcyB6ZXJvIHRyYXRhLXNlIGRhIHByb3BvcsOnw6NvIGRlIGJ1c2NhcyBxdWUgcmVuZGVyYW0gZW0gMCByZXN1bHRhZG9zLiBBc3NpbSwgbmEgRmlndXJhIDUgZm9pIHZlcmlmaWNhZGEgZXN0YSBkaXN0cmlidWnDp8OjbyBwb3IgZGlhIGUgb2JzZXJ2b3Utc2UgcXVlIGEgdGF4YSBlbmNvbnRyYS1zZSBlbnRyZSAxNSUgYSAyMSUsIGNvbSBtYWlvcmVzIGRlc3RhcXVlcyBwYXJhIG8gcHJpbWVpcm8gZSDDumx0aW1vIGRpYS4NCg0KYGBge3J9DQpyZXN1bHRzX3JhdGUgPSBidXNjYXMgJT4lDQogICAgZ3JvdXBfYnkoZGF5KSAlPiUNCiAgICBzdW1tYXJpc2Uoc2Vzc2lvbnMgPSBsZW5ndGgoc2Vzc2lvbl9pZCksIA0KICAgICAgICAgICAgICByZXN1bHRzX3plcm8gPSBzdW0ocmVzdWx0cyA9PSAwKSwgDQogICAgICAgICAgICAgIHJhdGUgPSAocmVzdWx0c196ZXJvL3Nlc3Npb25zKSAqIDEwMCkNCg0KZ2xpbXBzZSAocmVzdWx0c19yYXRlKQ0KDQpyZXN1bHRzX3JhdGUgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gZGF5LCB5ID0gcmF0ZSkpICsNCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgZmlsbCA9ICIjMDA4QjhCIikgKw0KICAgIGxhYnMoeCA9ICJkYXkiLCB5ID0gInplcm8gcmVzdWx0cyByYXRlIiwgdGl0bGUgPSAiRmlndXJhIDUgLSBUYXhhIGRlIHJlc3VsdGFkb3MgemVybyBnZXJhbCBwb3IgZGlhIikNCmBgYA0KDQpKw6EgY29tIHJlbGHDp8OjbyBhIHZhcmlhw6fDo28gZW50cmUgb3MgZ3J1cG9zICdhJyBlICdiJywgZm9pIGdlcmFkbyB1bSBzdW3DoXJpbyBvbmRlIG9zIGRhZG9zIGZvcmFtIGFncnVwYWRvcyBwb3IgZGlhLCBncnVwbyBlIHJlc3VsdGFkb3MsIHJlYWxpemFuZG8gbyBjw6FsY3VsbyBkZSBwcm9wb3LDp8OjbyBlbnRyZSBvIHNvbWF0w7NyaW8gZGEgdmFyacOhdmVsIGNyaWFkYSBzZXNzaW9uX2dyb3VwIGRpdmlkaWRvIHBvciBsZW5ndGgoZ3JvdXApLiANCg0KTmVzdGEgRmlndXJhIDYsIMOpIHBvc3PDrXZlbCBvYnNlcnZhciBxdWUgbmVuaHVtIGdydXBvIGVuY29udHJhLXNlIGFjaW1hIG91IGFiYWl4byBkbyBvdXRyby4gTm8gcXVpbnRvIGRpYSBvIGdydXBvICdhJyBhcHJlc2VudG91IG1haW9yIHRheGEgcXVhbmRvIGNvbXBhcmFkbyBhICdiJywgZW5xdWFudG8gcGFyYSBvIGdydXBvICdiJ28gc2V4dG8gZGlhIG1vc3RyYS1zZSBjb21vIG1haW9yIHRheGEuDQoNCmBgYHtyfQ0KDQpyZXN1bHRzX3JhdGUgPSBidXNjYXMgJT4lDQogICAgZ3JvdXBfYnkoZGF5LCBncm91cCwgcmVzdWx0cykgJT4lDQogICAgc3VtbWFyaXNlKHNlc3Npb25fZ3JvdXAgPSBsZW5ndGgoZ3JvdXApKSAlPiUNCiAgICBtdXRhdGUocmF0ZV9ncm91cCA9IHN1bShzZXNzaW9uX2dyb3VwKS9zZXNzaW9uX2dyb3VwKQ0KDQpnbGltcHNlIChyZXN1bHRzX3JhdGUpDQoNCnJlc3VsdHNfcmF0ZSAlPiVmaWx0ZXIocmVzdWx0cz09MCkgJT4lDQogICAgZ2dwbG90KG1hcHBpbmcgPSBhZXMoeCA9IGRheSwgeSA9IHJhdGVfZ3JvdXAsIGZpbGwgPSBncm91cCkpICsNCiAgICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IiwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSgpLCBjb2xvciA9ICJibGFjayIpICsNCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjOTk5OTk5IiwgIiNGRjhDMDAiKSkgKw0KICAgIGxhYnMoeCA9ICJkYXkiLCB5ID0gInplcm8gcmVzdWx0cyByYXRlIiwgdGl0bGUgPSAiRmlndXJhIDYgLSBUYXhhIGRlIHJlc3VsdGFkb3MgemVybyBnZXJhbCBwb3IgZGlhIGVudHJlIG9zIGdydXBvcyIpDQpgYGANCg0KIyAzLjQgQSBkdXJhw6fDo28gZGEgc2Vzc8OjbyDDqSBhcHJveGltYWRhbWVudGUgbyB0ZW1wbyBlbnRyZSBvIHByaW1laXJvIGUgbyDDumx0aW1vIGV2ZW50byBkZSB1bWEgc2Vzc8Ojby4gRXNjb2xoYSB1bWEgdmFyacOhdmVsIGRvIGNvbmp1bnRvIGRlIGRhZG9zIGUgZGVzY3JldmEgc3VhIHJlbGHDp8OjbyBjb20gbyB0YW1hbmhvIGRhIHNlc3PDo28uIFZpc3VhbGl6ZSBvIHJlbGFjaW9uYW1lbnRvLg0KDQpOYSBGaWd1cmEgNywgYSB2YXJpw6F2ZWwgZmlyc3RfY2xpY2sgZm9pIHJlbGFjaW9uYWRhIGNvbSBhIGR1cmHDp8OjbyBkYSBzZXNzw6NvIChzZXNzaW9uX2xlbmd0aCksIGRlIG1vZG8gYSBpbnZlc3RpZ2FyIHNlIHF1YW5kbyBvIHVzdcOhcmlvIGNsaWNhIG5vcyBwcmltZWlyb3MgcmVzdWx0YWRvcyBlbGUgcGFzc2EgYSBkdXJhciBtYWlzIHRlbXBvIG91IG7Do28gbmEgc2Vzc8Ojby4gDQoNCkFvIG9ic2VydmFyIG8gZ3LDoWZpY28gZ2VyYWRvLCDDqSB2aXN0byBxdWUgb3MgdXN1w6FyaW9zIHRlcm1pbmFtIHBhc3NhbmRvIG1haXMgdGVtcG8gbm9zIHByaW1laXJvcyByZXN1bHRhZG9zLiBUZW5kbyBlbSB2aXN0YSBxdWUgaMOhIHVtYSBtYWlvciBjb25jZW50cmHDp8OjbyBkb3MgZGFkb3Mgbm8gaW50ZXJ2YWxvIGRlIDAgw6AgMTAgbm8gZWl4byB2ZXJ0aWNhbCBjb20gcmVsYcOnw6NvIGFvIGVpeG8gaG9yaXpvbnRhbCBjb20gbWFpb3IgY29uY2VudHJhw6fDo28gZG9zIGRhZG9zIG5vIGludGVydmFsbyBkZSAwIMOgIDEwMDAuDQoNCg0KYGBge3J9DQpidXNjYXMgJT4lDQogICAgZmlsdGVyKGZpcnN0X2NsaWNrIDw9IDUwKSAgJT4lDQogICAgZ2dwbG90KGFlcyh4ID0gc2Vzc2lvbl9sZW5ndGgsIHkgPSBmaXJzdF9jbGljaykpICsNCiAgICBnZW9tX3BvaW50KGFscGhhID0gLjIsIHNpemUgPSAyLCBjb2xvciA9ICIjQTUyQTJBIikgKw0KICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHM9YygwLCA1MCkpICsNCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGltaXRzPWMoMCwxMDAwKSkgKw0KICAgIGxhYnMoeCA9ICJzZXNzaW9uIGxlbmd0aCAoc2VjKSIsIHkgPSAiZmlyc3QgY2xpY2siLCB0aXRsZSA9ICJGaWd1cmEgNyAtIFJlbGHDp8OjbyBkYSBkdXJhw6fDo28gZGEgc2Vzc8OjbyBlbSBzZWd1bmRvcyBlIGNsaXF1ZXMiKSANCg0KYGBgDQoNCg0KDQo=