LAMFO's Blog2021-05-20T21:50:05+00:00http://lamfo-unb.github.io/blogLAMFOlamfo/(at)unb/(dot)brDados em Painel - LAMFO2021-11-01T00:00:00+00:00http://lamfo-unb.github.io/2021/11/01/Dados em painel# Dados em Painel
Dados em painel são úteis e sua aplicabilidade é ubíqua. Aparecem em análise de políticas públicas, ajuda humanitária, finanças; mas são simples. Dados em painel são simplesmente dados em que temos *algumas* observações de indivíduos i e as acompanhamos *por um período de tempo* t. Diferem dos dados cross-section pois esse coleta observações de um único período de tempo. Podemos dizer que um dado cross-section é um dado em painel com t = 1. Diferem também das séries de tempo, os quais coletam variáveis para apenas um indivíduo (ou país, ou entidade, ou empresa...). Podemos dizer que séries de tempo são dados em painel com a quantidade de indivíduos = 1.
As vantagens dos dados assim são, dados por Hsiao (2005), os seguintes:
1. Melhor acurácia para inferência de parâmetros. Uma vez que dados em painel tendem a ter mais graus de liberdade e menos multi-colinearidade que as suas contrapartidas cross-section
2. Maior capacidade em capturar a complexidade do comportamento humano que uma série de tempo ou um cross-section.
+ Constructing and testing more complicated behavioral hypotheses. For instance,
consider the example of Ben-Porath (1973) that a cross-sectional
sample of married women was found to have an average yearly labor-force
participation rate of 50 percent. These could be the outcome of random
draws from a homogeneous population or could be draws from heterogeneous
populations in which 50% were from the population who always work
and 50% never work. If the sample was from the former, each woman would
be expected to spend half of her married life in the labor force and half out of
the labor force. The job turnover rate would be expected to be frequent and
the average job duration would be about two years. If the sample was from the latter, there is no turnover. The current information about a woman’s
work status is a perfect predictor of her future work status. A cross-sectional
data is not able to distinguish between these two possibilities, but panel data
can because the sequential observations for a number of women contain information
about their labor participation in different subintervals of their life
cycle..........................
+ Controlar o efeito das variáveis omitidas
+ Desvelar relações dinâmicas entre as variáveis. With panel
data, we can rely on the inter-individual differences to reduce the collinearity
between current and lag variables to estimate unrestricted time-adjustment
patterns (e.g. Pakes and Griliches (1984)).
+ Gerar maior acurácia, agregando os dados
+ Possibiltar a microfundamentação para a análise de dados. Como podemos aniquilar os efeitos fixos, não necessitamos supor que os agentes são homogêneos a priori.
3. Simplificando a computação e a inferência estatística
+ Análise de dados não estacionários em séries de tempo. Quando dados não são estacionários, ie, ... então a distribuição de mínimos quadrados e estimadores de máxima verossimilhança não funcionam. Havendo dados em painel, sendo então cada observação cross-section independente, pode-se usar o teorema do limite central. Assegurando que os estimadores são normais assintoticamente.
+ Erros de medida...
+ Modelos Tobit Dinâmicos. ...
# Motivação
Analisemos os dados em painel e poremos em prática os modelos utilizados para tomar proveito desse formato de dado.
Situe-se sediando uma posição de trabalho na Organização das Nações Unidas. Seu posto é, de alguma forma, diminuir a incidência de guerras e conflitos internos de alguma região. Intuitivamente, espera-se que instabilidade política, ... influenciem nessa questão. Todavia como garantir isso?
Os dados que temos em mão está disponível ..................
# Pooled Regression
O modelo mais simples que se pode usar em dados em painel é a regressão pooled. Essa é a regressão que ignora a colinearidade temporal e considera cada observação de tempo e país como independentes para derivar uma relação linear entre as variáveis explicativas $X_1, \dots, X_k$ e a variável dependente Y. Como temos as observações para tempos diferentes (t) e indivíduos diferentes (i), adicionamos os respectivos subscriptows nas variáveis explicativas e na variável dependente.
$$ Y_{it} = \beta_0 + \beta_1X_{1it} + ... \beta_kX_{kit} + u_i $$
O objetivo é estimar os valores dos $\beta_1, ...,\beta_k$, os quais representam o efeito das variáveis $X_1,...,X_k$. Como esperamos uma aleatoriedade dessa relação, colocamos um termo de erro $u_i$ que indica o desvio da nossa observação para o nosso modelo predito pelos betas estimados e as variáveis dependentes.
```{r}
library(plm)
library(haven)
library(stargazer)
library(knitr)
require(memisc)
library(shiny)
setwd("~/LAMFO/Riot_data")
repdata <- read_dta("repdata.dta")
guerra <- repdata
p1 <- plm(onset ~ warl + gdpenl + lpop + lmtnest + ncontig + Oil + nwstate + instab + polity2l + ethfrac + relfrac, data = guerra, index=c("country","year"), model = 'pooling')
stargazer(p1, type = 'html')
```
```{r}
stargazer::stargazer(p1, p2, p3, type = "html", title = "Results")
shiny::includeHTML("pp.html")
```
Uma preocupação que existe nesse modelo é o viés de variável omitida. Quiçá existe variáveis que são necessárias para explicar o modelo, mas não especificamos na equação. Quando esses efeitos decorrem de características que são fixas no tempo, podemos resolver com o seguinte modelo.
## Teste de Hausman
The test compares the consistent but inefficient estimator (fixed effects) to the potentially inconsistent but efficient estimator (OLS)................................
# Fixed Effects
Uma forma de eliminar os iiuv seria o modelo de Fixed Effects/ Within Estimator. Embora saber os efeitos de ser uma ex-colônia britânica ou francesa; ser de tal continente pode dar insights interessantes, acreditamos que mudá-los está além do nosso alcance. Por outro lado, estamos preocupados com variáveis que podemos mudar, especificamente estabilidade política.
Eis aqui o poder dos dados em painel. Podemos eliminar os vieses de efeitos que são fixos ao longo do tempo e assim isolarmos o efeito explicativo da nossa variável de interesse. Esse é o modelo de Efeitos Fixos:
$$ Y_{i t}=\beta_{1} X_{1i t} + ... + \beta_kX_{kit} +\alpha_{i}+u_{i t} $$
Em seguida calculamos a média dessa relação para cada indivíduo. Como o efeito fixo é o mesmo ao longo do tempo, permanece inalterado.
$$ \overline{Y}_i = \beta_1\overline{X}_{1i} + ... + \beta_k\overline{X}_{ki} + \alpha_i + \overline{u}_i $$
$$ Y_{it} - \overline{Y}_{1i} = \beta_1(X_{1it}-\overline{X}_{1i}) + ... + \beta_k(X_{kit} - \overline{X}_{ki}) + (u_{it}-\overline{u_i}) $$
Como os efeitos fixos sumiram, nós rearranjamos a equação acima para uma notação mais concisa:
$$ \tilde{Y}_i = \beta_1\tilde{X}_{1i} + ... + \beta_k\tilde{X}_{ki} + \tilde{u}_i $$
Computacionalmente:
feaffaef
aef
a
ef
aef
a
ef
aef
aef
ae
fa
f
ea
fea
# Random Effects
But suppose we think ai is uncorrelated with each explanatory variable
in all time periods. Then, using a transformation to eliminate ai results in inefficient
estimators.
$$ Y_{i t}= \beta_0 + \beta_{1} X_{1i t} + ... + \beta_kX_{kit} +\alpha_{i}+u_{i t} $$
composite error term as vit ai ui
$$
y_{i t}=\beta_{0}+\beta_{1} x_{i t 1}+\ldots+\beta_{k} x_{i t k}+v_{i t}
$$
$$
\operatorname{Corr}\left(v_{i t}, v_{i s}\right)=\sigma_{a}^{2} /\left(\sigma_{a}^{2}+\sigma_{u}^{2}\right), \quad t \neq s
$$
$$
\theta=1-\left[\sigma_{u}^{2} /\left(\sigma_{u}^{2}+T \sigma_{a}^{2}\right)\right]^{1 / 2}
$$
$$
\begin{aligned} y_{i t}-\theta \bar{y}_{i}=& \beta_{0}(1-\theta)+\beta_{1}\left(x_{i t 1}-\theta \bar{x}_{i 1}\right)+\ldots \\ &+\beta_{k}\left(x_{i k}-\theta \bar{x}_{i k}\right)+\left(v_{i t}-\theta \bar{v}_{i}\right) \end{aligned}
$$
# Dif in Dif
# Regression in Discontinuity
Outra vantagem de dados em painel é que eles podem
```{r}
library(rddtools)
```
Vamos deixar algumas libraries abertas:
```{r}
library(AER)
library(plm)
library(stargazer)
```
```{r}
setwd("~/LAMFO/Riot_data")
library(haven)
guerra <- read_dta("repdata.dta")
p1 <- plm(onset ~ warl + gdpenl + lpop + lmtnest + ncontig + Oil + nwstate + instab + polity2l + ethfrac + relfrac, data = guerra, index=c("country","year"), model = 'fd')
p2 <- plm(onset ~ warl + gdpenl + lpop + lmtnest + ncontig + Oil + nwstate + instab + polity2l + ethfrac + relfrac, data = guerra, index=c("country","year"), model = 'random')
p3 <- plm(onset ~ warl + gdpenl + lpop + lmtnest + ncontig + Oil + nwstate + instab + polity2l + ethfrac + relfrac, data = guerra, index=c("country","year"), model = 'pooling')
stargazer(p1,p2,p3)
```
stargazer(p1,p2,p3)
Algoritmos evolutivos e programação genética2021-05-08T23:59:07+00:00http://lamfo-unb.github.io/2021/05/08/AlgoritmoEvolutivos<h1 id="algoritmos-evolutivos-e-programação-genética">Algoritmos evolutivos e programação genética</h1>
<h2 id="conhecendo-o-tema-e-o-vídeo-da-oficina">Conhecendo o tema e o vídeo da oficina</h2>
<p>Muitas são as técnicas já consolidadas de otimização, mas o que fazer quando abordagens tradicionais não funcionam, ou não resolvem o problema em uma quantidade considerável de tempo?</p>
<p>A ideia de selecionar apenas os melhores indivíduos e que esses se reproduzam para gerar indivíduos ainda melhores não é uma ideia nova. Essa heurística simples e extremamente eficiente consegue explicar muito do mundo biológico.</p>
<p>O algoritmo genético usa essa ideia engenhosa para longas sequências de 0 e 1. Parece sem graça, certo? Não se esqueça que TUDO no computador é expresso com zeros e uns. Fotos, textos… e até música! Como aplicar esse algoritmo tão intuitivo e quais são as suas capacidades? Descubra no vídeo de hoje.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/4A3dxRY-hG8" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<p>Aproveite para ser membro do canal do LAMFO, dar o LIKE e clicar no sino de notificações! Compartilhe o vídeo com todos!!</p>
Backpropagation e algoritmos de otimização por gradiente descendente2021-04-24T23:59:07+00:00http://lamfo-unb.github.io/2021/04/24/Backpropagation<h1 id="backpropagation-e-algoritmos-de-otimização-por-gradiente-descendente">Backpropagation e algoritmos de otimização por gradiente descendente</h1>
<h2 id="vídeo-1---parte-teórica">Vídeo 1 - Parte teórica</h2>
<p>Um dos principais pilares de Machine Learning é o conceito de Backpropagation. Além de ter aberto uma gama de possibilidades para os cientistas de dados e cientistas da programação, ainda hoje é um conhecimento valiosíssimo para aqueles que se interessam sobre a área. Entretanto, para entender com plenitude a ideia da propagação reversa, é necessário entender o que vem por trás desse conceito. Por esse motivo, em primeiro lugar, apresentamos o conceito de Neural Networks (que é importante não só para o Backpropagation, mas para quase todos os assuntos em Machine Learning) e o conceito de Gradient Descent. Essa primeira introdução pode ser vista, de forma muito didática, pela apresentação de Jairo Alves feita para a oficina do LAMFO no dia 24 de abril de 2021.</p>
<p>Este vídeo é a primeira parte realizado pelo Pesquisador Jairo Alves. Ela apresenta a parte teórica de Backpropagation, suas características, teoria em torno e exercícios, mas antes também faz uma revisão dos conceitos de Redes Neurais, conteúdo indispensável para quem quer compreender sobre o tema.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Oe3NOIjK0zE" title="Parte Teórica" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
<h2 id="vídeo-2---parte-prática-i">Vídeo 2 - Parte Prática I</h2>
<p>Além do que foi apresentado na Parte I, para aqueles que querem se aprofundar nos estudos, é necessário entender quais são as estratégias de otimização. Conhecer quais as ideias e postulados que estão por trás da otimização, e quais são os modelos usados. Uma ideia geral da evolução da história do Gradient Descent permite que o cientista saiba qual modelo usar, quando usar, e quais suas limitações. O programador realmente eficiente será aquele que, além de conhecer o problema que enfrenta, sabe qual pode ser o melhor caminho para resolver o problema. O primeiro vídeo realizado pelo Vinícius Watanabe passa por essa evolução na história do Gradient Descent, familiarizando o interessado com os modelos mais usados para otimização.</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/Cd4S_EhCSos" title="Parte Prática I" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
Anova & Manova2021-04-10T23:59:07+00:00http://lamfo-unb.github.io/2021/04/10/Anova&Manova<h1 id="anova--manova">Anova & Manova</h1>
<p>O LAMFO apresenta no vídeo abaixo, a Análise de variância (Anova) e a Análise multivariada da variância (Manova). Elas são ferramentas estatísticas para ajudar na comparação de médias amostrais. Veja o vídeo abaixo:</p>
<p>Aproveite para ser membro do canal do LAMFO, dar o LIKE e clicar no sino de notificações! Vamos à oficina!</p>
<h2 id="vídeo">Vídeo</h2>
<iframe width="560" height="315" src="https://www.youtube.com/embed/tLcH6p2YIFs" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""></iframe>
Bibliometria e Meta Análise2021-03-06T23:59:07+00:00http://lamfo-unb.github.io/2021/03/06/bibliometria_meta_analise**Table of Contents**
[TOCM]
[TOC]
# Bibliometria e Meta Análise
As duas técnicas de pesquisa que iremos tratar aqui, embora sejam costumeiramente confundidas e muitas vezes consideradas semelhantes, possuem peculiaridades que possibilitam ao pesquisador que empreende revisões sistemáticas da literatura, ferramentas que o auxilem na análise de papers sobre um determinado tema.
Assim, o intuito aqui é tentar esclarecer e sintetizar as premissas destas duas técnicas, bem como apresentar uma aplicacao em R ao final, visando demonstrar como utilizar estas técnicas.
### O que é bibliometria?
É uma área de estudo da Ciência da Informação, que possui como premissa retratar o comportamento e a evolução de uma determinada área do conhecimento a partir da quantificação das características existentes nos estudos. Desta forma, é possível identificar lacunas teóricas e empíricas, bem como descrever a produção científica de um país, por exemplo.
Tendo em vista que as bibliometrias são parte essencial de uma revisão sistemática da literatura, alguns autores sugerem a adoção de protocolos norteadores que possibilitam a identificação de estudos relevantes sobre um tema específico. Dybå e Dingsøyr (2008), por exemplo, indicam quatro etapas de filtragem dos trabalhos selecionados. No estágio 1, é definido o banco de dados que será adotado, e a partir dele é iniciada a busca dos papers relevantes do tema. No estágio 2, após a seleção inicial, são excluídos os estudos avaliando-se apenas se o título corresponde ao tema analisado. No estágio 3, a exclusão de artigos é feita a partir da análise do resumo. No estágio 4, o último deste protocolo, há uma avaliação crítica dos trabalhos, sendo realizada uma leitura mais acurada do seu conteúdo a fim de identificar os artigos que tratam mais especificamente do tema de pesquisa.
O outro protocolo que merece destaque foi proposto por Cronin, Ryan e Coughlan (2008). Para estes autores são três etapas que devem ser adotadas para a revisão sistemática de literatura. Na primeira etapa temos a formulação da pergunta de pesquisa; haja vista que se trata de uma análise da literatura, a questão proposta deve versar pela busca da produção científica mais recente. Na segunda etapa são definidos os critérios de inclusão e exclusão de artigos, podendo estabelecer em que momento do texto deve estar presente o termo pesquisado (título, palavras-chave, resumo), o período de análise, qual a base de dados que será acessada etc. Na terceira etapa é o momento de definir os critérios de qualidade para a seleção dos artigos, onde devem ser avaliadas a pertinência e a elegibilidade dos artigos.
Uma vez compreendida a relevância dos protocolos para a elaboração de bibliometrias com rigor científico e metodológico, é possível incrementar esses resultados com análises gráficas geradas a partir de softwares voltados especificamente para esse fim. Um desses softwares é o Iramuteq, que é ligado ao R, e tem como principal função a análise textual utilizando estatística. Outro software é o UCINET, que promove a construção de redes sociais a partir dos dados. Em análises bibliométricas, por exemplo, é bastante utilizado para identificar a rede de parceria (interligação) entre autores e instituições, e assim visualizar onde está concentrada a produção daquele tema.
Também podemos mencionar o VOSviewer, que é voltado para revisões empreendidas na base de dados Web of Science. Dentre suas aplicações, podemos destacar o agrupamento dos artigos em clusters, possibilitando a análise de co-citação e o acoplamento bibliográfico. A análise de co-citação é aplicada para identificar os artigos fundamentais e mais eficientes na comunidade científica no tema. A interlocução de dois documentos sugere o estabelecimento de novas conexões no processo de formação de novos conhecimentos. Por sua vez, o acoplamento bibliográfico demonstra a relação entre artigos com base nas referências em comum entre eles.
### E o que é meta-análise?
É uma metodologia para avaliar quantitativamente os papers da literatura. Quando existe uma divergência em que determinado efeito de interesse é positivo, negativo ou nulo, o uso dessa técnica é extremamente importante para verificar de uma forma global o efeito. Essa técnica é muito usada em ciencias sociais e de saúde e vem ganhando popularidade com pacotes em softwares como R, Python e STATA, tornando mais acessivel o uso dela.
A ideia por trás da meta-análise é sintetizar estudos prévios com dados tratando cada estudo como se fosse uma observação. Portanto, trata-se de uma análise de uma amostra de estudos e não de apenas participantes como um estudo usual. A meta-análise resume vários anos de análise por meio de estimativas quantitativas (regressão e teste de hipótese) e gráficas. Geralmente, artigos científicos que utilizam essa técnica possuem uma grande quantidade de citações por realizarem uma síntese de um determinado tema.
O passo a passo para realizar a meta análise começa com uma grande revisão de literatura. É necessário decidir critérios objetivos para inclusão (tipo de análise feita, modelo, amostra,…) para quando realizada a pesquisa nos bancos de dados (Google Scholar, Web of Science, Open Grey, PsychInfo, Medline,…) as palavras chaves consigam trazer o máximo de papers relevantes para o estudo. Após a coleta dos papers, o próximo passo é remover aqueles que não se enquadram nos criterios de inclusao. Em seguida, é necessário calcular o tamanho dos efeitos e padronizar resultados dos estudos (OR, RR, B,…) para que estejam todos na mesma métrica e possam ser comparáveis. Uma vez que os papers possam ser comparáveis, basta aplicar o uso das técnicas de meta análise para ver o real efeito e depois escrever e reportar os resultados. Uma simulacao em R abaixo entrará nos detalhes de como pode ser feita a análise em si com base em um exemplo.
Outra grande vantagem da meta-análise é que pode ser feita para uma diversidade muito grande de tipos de estudos como:
- Efeitos fixos, aleatórios, mistos
- Proporção
- Incidence Rates and Rate Ratios
- Heterogeneity Estimation
- Mixture Models
- Outros…
Portanto, podemos inferir o seguinte:
A bibliometria consiste na análise da produção científica, quantificando as características existentes nos estudos. Por sua vez a meta-análise consiste na análise dos resultados numéricos dos estudos em conjunto, como se fosse um único estudo com uma enorme amostra de participantes.
### Aplicacao em R
Para o uso de Meta analise vamos usar o pacote metafor do R. Portanto, o primeiro passo é a importacao dele no R.
```{r}
#install.packages("metafor")
library(metafor)
```
Nesse exemplo, vamos usar a base de dados de exemplo do proprio pacote chamada "dat.bcg" que é uma base de estudo sobre efetividade da vacina BCG comtra tuberculose. A função escalc é usada para padronizar as medidas para Risco Relativo (RR).
```{r}
dat <- dat.bcg
dat <- escalc(measure="RR", ai=tpos, bi=tneg, ci=cpos, di=cneg, data=dat)
dat$vi <- with(dat, mean(tneg/tpos)/(tneg+tpos) +
mean(cneg/cpos)/(cneg+cpos))
```
Uma vez com a base pronta, podemos executar a meta analise. A função rma executa um modelo de regressao de efeitos aleatorios. O resultado pode ser interpretado como uma modelo de regressao usual, temos a estimativa geral do efeito de -0.5540, erro padrao de 0.1963 e p-valor de 0.0048.
Alem dessas metricas, temos a informacao sobre a variabilidade explicada pelo modelo, mensurado pela $I^2$, 89.17%.
```{r}
### random-effects model
res <- rma(yi, vi, data=dat) #method="EB" estimation process
res
```
Além do modelo em si, é usual gerar um grafico chamado funnel plot que verifica se existe uma assimetria nos dados. O ideal é que os dados estejam distribuidos em torno da reta central, indicando que existe de fato um efeito universal e que os estudos encontraram estimativas em torno dele (graficos mais assimetricos indicam ausencia desse efeito universal). O teste de Egger e Kendal também sao executados para testar a assimetria do funnel plot.¨
```{r}
### funnel plot
funnel(res)
# Egger regression using a meta-regression model with the standard error as predictor
regtest(res)
# Kendal, Non-parametric (Rank)
ranktest(res)
```
Uma forma de sumarizar bem os dados é realizando o forest plot. Esse grafico mostra em cada linha a estimativa de cada paper, além da informacao dos autores e ano de publicacao. É possivel também inserir os dados no grafico. Esse grafico mostra o efeito global e intervalo de confianca obtido pela regressao.
```{r}
### forest plot with extra annotations
forest(res,
atransf=exp,
at=log(c(.05, .25, 1, 4)),
xlim=c(-16,6),
ilab=cbind(dat.bcg$tpos, dat.bcg$tneg, dat.bcg$cpos, dat.bcg$cneg),
ilab.xpos=c(-9.5,-8,-6,-4.5),
cex=.75, header="Author(s) and Year",
mlab="")
```
Para finalizar, também é usual avaliar se existe p-hacking, ou seja, uma atitude de buscas por p-valores significativos (usualmente inferiores a 0.05) por parte dos pesquisadores. A ideia do teste é verificar se a distribuicao de p-valores é igual entre os valores de 0 e 0.05 ou se existe uma predominancia em torno de 0.05, indicando que os estudos possam ter sido manipulados de forma a se encontrar um modelo especifico que tornasse significativo, dando indicios que o efeito na verdade nao seja claro (o que causaria a nao publicacao de alguns papers muitas vezes).
Abaixo, é feito o teste com a funcao puniform usando dados simulados gerados de uma distribuicao normal. Os paramentros indicam os tamanhos do efeito (mi), tamanho da amostra (ni), desvio padrao (sdi) e o lado que sera testado a assimetria, no caso no valor 0.05 a direita (side). No exemplo, obtemos um p-valor do teste de 0.3094, nos levando a nao rejeitar a hipotese de assimetria, ou seja, nao conseguimos encontrar indicios de p-hacking.
```{r}
library(puniform)
### Generate example data for one-sample means design
set.seed(123)
ni <- 100
sdi <- 1
mi <- rnorm(8, mean = 0.2, sd = sdi/sqrt(ni))
tobs <- mi/(sdi/sqrt(ni))
### Apply p-uniform method based on sample means
puniform(mi = mi, ni = ni, sdi = sdi, side = "right", plot = T)
```
### Referencias
- Araújo, R. F., & Alvarenga, L. (2011). A bibliometria na pesquisa científica da pós-graduação brasileira de 1987 a 2007. Encontros Bibli: Revista Eletrônica de Biblioteconomia e Ciência da Informação, 16(31), 51-70.
- Cronin, P., Ryan, F., & Coughlan, M. (2008). Undertaking a literature review: a step-by-step approach. British journal of nursing, 17(1), 38-43.
- Dybå, T.; Dingsøyr, T. (2008). Streingth of evidence in Systematic Reviews in software engineering. Empirical Software Engineering and Measurement (ESEM), 8.
- Ramos-Rodríguez, A. R., & Ruíz-Navarro, J. (2004). Changes in the intellectual structure of strategic management research: A bibliometric study of the Strategic Management Journal, 1980-2000. Strategic Management Journal, 25(10), 981-1004.
- Projetos de meta-analise (https://www.metafor-project.org/doku.php/analyses)
- Pacote R Metafor (https://cran.r-project.org/web/packages/metafor/metafor.pdf)
- Funnel Plot (https://toptipbio.com/funnel-plot/)
Introdução ao reconhecimento de imagens2020-12-05T23:59:07+00:00http://lamfo-unb.github.io/2020/12/05/Captcha-Break<h1 id="introdução-ao-reconhecimento-de-imagens">Introdução ao reconhecimento de imagens</h1>
<h2 id="como-o-computador-vê-uma-imagem">Como o computador “vê” uma imagem?</h2>
<p>Para um computador a imagem é representada como um array numérico de 3 dimensões. Cada número que compõe o array varia entre 0 (preto) e 255 (branco). Na imagem do gato abaixo, ela apresenta uma largura de 248 pixels e uma altura de 400 pixels. Também possui 3 canais de cor Vermelho, Verde e Azul (RedGreenBlue - RGB). Portanto, multiplicando a largura pela altura e pela quantidade de canais de cor, temos 248 x 400 x 3 = 297.600 números que representam a imagem.</p>
<p><img src="https://i.imgur.com/8IdE5tW.png" alt="" />
<strong>Imagem 1</strong> Gato | Stanford University</p>
<p>A pergunta então é: como ensinar o computador a interpretar esses números como um gato?</p>
<p>Um ponto importante a ser observado é que do ponto de vista de um algoritmo, pequenos detalhes que muitas vezes são de fácil discernimento para o olho humano trazem desafios para o computador. Por exemplo, um objeto pode estar em diferentes ângulos com relação à câmera (variação de ângulo), o tamanho do objeto pode variar de imagem para imagem (escala), o objeto pode estar deformado (deformação), parte do objeto pode estar cortado ou ocultado na imagem (oclusão), a iluminação pode mudar (iluminação), o ambiente atrás do objeto pode se misturar com o mesmo entre outros.</p>
<p>Para que possamos classificar de forma satisfatória uma imagem, o classificador precisa manter a consistência no resultado sujeito às diferentes combinações desses fatores.</p>
<p><img src="https://i.imgur.com/FwE4A4Y.jpg" alt="" />
<strong>Imagem 2</strong> Desafios | Stanfod University</p>
<p>Uma observação importante é que em Aprendizado de Máquina, utiliza-se a variação de pixel (0-255) das imagens normalizada. Dessa forma, como estamos lidando com imagens, computa-se uma imagem média do conjunto de treino e depois ela é subtraída de todas as imagens. O resultado são imagens com pixels que variam entre -127 a 127 aproximadamente. Pode-se então, dependendo do caso, mudar a escala desses valores, fazendo-os variar entre -1 e 1.</p>
<h2 id="tratamento-de-imagens">Tratamento de Imagens</h2>
<p>Tratar imagens significa manipulá-las de modo a facilitar sua “visualização” pelo computador. Podemos girá-las, torná-las mais escuras ou mais claras, acentuar determinadas cores, “pixelar” a imagem, distorcer, entre vários outros métodos. Os tratamentos a serem aplicados dependem do objetivo ao qual se quer chegar. Citaremos alguns exemplos de aplicações utilizando o pacote OpenCV em Python.</p>
<p>Podemos filtrar imagens com diversos objetivos como, por exemplo, remover ruídos, embaçar imagens ou acentuar vértices de objetos. Para isso, utilizamos o que se chama de low-pass filters (LPF) e high-pass filters (HPF). Em nosso exemplo, LPFs ajudam a remover ruídos e embaçar imagens, enquanto HPFs acentuam vértices de objetos dentro da imagem.</p>
<p>A partir de agora utilizaremos um termo chamado de Convolução. A convolução é uma operação em que um operador linear utilizando-se de dois sinais gera um terceiro sinal. Portanto para fazer tal operação utilizaremos um kernel ou uma matriz de convolução.</p>
<h3 id="o-kernel-e-suas-funções">O Kernel e suas funções</h3>
<p>Um kernel é um filtro que utilizaremos em nossas imagens. Ele passará por toda a imagem, da esquerda para a direita, de cima para baixo, aplicando o produto da convolução. No final, teremos uma imagem filtrada.</p>
<p><img src="https://i.imgur.com/nvORWfF.png" alt="" />
<strong>Imagem 3</strong> Convolução | Data Science Stack Exchange</p>
<p>O kernel não precisa ter sua altura e largura de tamanhos iguais, isto é, não é necessário que seja um quadrado. A depender do sinal que se deseja analisar, pode-se alterar o formato do kernel para melhor o ajustar ao problema. Na prática, geralmente utiliza-se números ímpares para definir a altura e largura do kernel, com o intuito de deixar o output simétrico (ter pixel central).</p>
<p>Importante notar que geralmente o número de parâmetros cresce com o tamanho do kernel, assim como o tempo computacional. Isso acontece porque grande parte dos parâmetros de treinamento de uma camada convolucional está nos kernels.</p>
<h4 id="passo-stride">Passo (Stride)</h4>
<p>O movimento do kernel pelos pixels da imagem pode ser alterado. Geralmente o kernel se move da esquerda para a direita, de baixo para cima. Para alterar como o kernel se movimenta, alteramos seu “passo” (stride). Um stride de (1,5) significa um movimento do filtro de 5 por 5 pela horizontal e 1 por 1 pela vertical. O resultado disso é uma redução da dimensão em 5 vezes.</p>
<p>Quanto maior o stride, menor o tempo computacional.</p>
<h4 id="preenchimento-padding">Preenchimento (Padding)</h4>
<p>Em algumas ocasiões, o tamanho do output precisa ser do tamanho do input. Temos que lembrar que o kernel diminui o tamanho do input. O preenchimento (ou padding) é a ferramenta para adicionar (preencher) um determinado número de pixels nas laterais da imagem. Desse modo, o output fica com o mesmo tamanho que o input. Geralmente o padding é 0, não havendo a necessidade de igualar os tamanhos.</p>
<p>O tempo computacional aumenta com o aumento do preenchimento, apesar de na maioria das vezes o incremento ser marginal.</p>
<h4 id="dilatação-dilation">Dilatação (Dilation)</h4>
<p>A dilatação (dilation) pode ser entendida como a largura do núcleo do kernel. Não há muito impacto em tempo computacional, sendo como no Padding, marginal o incremento.</p>
<h4 id="grupos-groups">Grupos (Groups)</h4>
<p>A ideia de grupos é basicamente tratar dados diferentes independentemente e no final o output de cada processamento ser concatenado. Importante salientar que o número de grupos tem que ser divisor comum entre o número de inputs e o número de outputs.</p>
<h2 id="rede-neural-convolucional">Rede Neural Convolucional</h2>
<p>Um modelo de deep learning muito utilizado para visão computacional é a Rede Neural Convolucional (CNN). Podemos pensar na CNN como uma rede neural que utiliza diversas cópias de um mesmo neurônio, de modo a ter uma capacidade de complexidade grande, mantendo um número reduzido de parâmetros.</p>
<h3 id="estrutura-de-uma-cnn">Estrutura de uma CNN</h3>
<p>De acordo com o Deep Learning Book Brasil, “a arquitetura de uma ConvNet é análoga àquela do padrão de conectividade de neurônios no cérebro humano e foi inspirada na organização do Visual Cortex. Os neurônios individuais respondem a estímulos apenas em uma região restrita do campo visual conhecida como Campo Receptivo. Uma coleção desses campos se sobrepõe para cobrir toda a área visual”. De forma prática, uma Rede Neural Convolucional segue a seguinte estrutura.</p>
<p><img src="https://i.imgur.com/Ag1UKhk.png" alt="" />
<strong>Imagem 4</strong> Estrutura | A Beginner’s Guide To Understanding Convolutional Neural Networks - Adit Deshpande</p>
<h4 id="convolution">Convolution</h4>
<p>Convoluções são filtos que têm como objetivo identificar padrões. A convolução, do ponto de vista matemático, é uma operação linear entre duas funções.</p>
<h4 id="pooling-layers">Pooling Layers</h4>
<p>A camada chamada de “pooling layer” tem como objetivo reduzir a quantidade de variáveis por meio de amostragem. O método mais comum é conhecido como MaxPooling, que pega o maior valor dentro de um mapa de variáveis, permitindo a redução de variáveis, conforme demonstrado na figura abaixo. Essa etapa ajuda a reduzir a quantidade de informação da rede.</p>
<p><img src="https://i.imgur.com/HWQF4dO.png" alt="" />
<strong>Imagem 5</strong> Max pooling | Andrew Ng</p>
<h4 id="fully-connected-layers">Fully connected layers</h4>
<p>Fully conneted layers são camadas comuns em redes neurais, onde todos os inputs de uma camada estão conectados com as unidades da próxima camada. Em geral, sãos as últimas camadas de uma rede neural.</p>
<h2 id="aplicação">Aplicação</h2>
<p>A Rede Neural Convolucional pode ser aplicada utilizando-se o Framework TensorFlow. Um explicação simples e direta por ser encontrada <a href="https://www.tensorflow.org/tutorials/images/cnn">aqui</a>.</p>
<h2 id="referências-e-links-interessantes">Referências e links interessantes</h2>
<p><a href="https://cs231n.github.io/">Convolutional Neural Networks for Visual Recognition, Stanford</a></p>
<p><a href="https://docs.opencv.org/master/d4/d13/tutorial_py_filtering.html">Open CV</a></p>
<p><a href="https://matheusfacure.github.io/2017/03/12/cnn-captcha/">Resolvendo Captchas com Redes Neurais Convolucionais - Matheus Facure</a></p>
<p><a href="https://machinelearningmastery.com/pooling-layers-for-convolutional-neural-networks/">Definição de Pooling Layer</a></p>
<p><a href="http://deeplearningbook.com.br/introducao-as-redes-neurais-convolucionais/">Capítulo sobre Redes Neurais Convolucionais</a></p>
Autoencoder2020-11-21T23:59:07+00:00http://lamfo-unb.github.io/2020/11/21/Autoencoder<h1 id="autoencoder">Autoencoder</h1>
<p><em>Autoencoder</em> é uma rede neural que utiliza aprendizado não-supervisionado para treinamento e tem como objetivo aprender reconstruções próximas aos dados de entrada. Um Autoencoder possui um codificador e um decodificador, que podem ser representados como:</p>
\[Z=f_{\theta} =S(W X+b) (I) \\
Y′=f_{\theta}′=S(W′Z+b′) (II)\\
||X−Y′|| (III)\]
<p>A primeira equação (I) é a equação do codificador Z que faz o mapeamento dos dados de entrada X por meio a função de ativação S, com a matriz de pesos W e o vetor de viés b. A segunda equação (II) é a equação do decodificador que mapeia Z de volta ao espaço de entrada original, como uma reconstrução feita pela mesma transformação do codificador. O erro de reconstrução é calculado pela diferença entre os dados de entrada X e a reconstrução Y′.</p>
<p>O codificador reduz a dimensionalidade dos dados de entrada e o decodificador refaz os dados de entrada e o objetivo principal do algoritmo é minimizar o erro de reconstrução (LEJON; KYÖSTI; LINDSTRÖM, 2018; FAN et al., 2018).A figura abaixo mostra como funciona a estrutura do Autoenconder.</p>
<p><img src="https://i.imgur.com/7BoQhex.png" alt="" />
Fonte: FAN et al., 2018</p>
<p>A Figura evidencia dois tipos de arquiteturas possíveis para algoritmo de <em>Autoencoder</em>. A primeira arquitetura apresenta uma estrutura sub completa onde $p < m$, e o modelo aprende uma representação compacta dos dados de entrada ($X$). Já a segunda arquitetura apresenta uma estrutura completa, onde $p > m$, o modelo, neste caso, aprende uma representação esparsa (FAN et al., 2018). De acordo com Schölkopf, Platt e Hofmann (2007), representações esparsas viabilizam interpretações mais simples para os dados de entrada a partir de um pequeno número de ‘‘partes’’, dessa forma é extraída uma estrutura oculta dos dados. Um vantagem no uso deste método é devido a extração de recursos que são úteis para as interpretações e aprimoramento de recursos que não são úteis . Há várias possibilidades de arquitetura de algoritmos <em>Autoencoder</em>, o modelo mais simples é construído com 3 camadas conectadas (uma camada de entrada, uma camada oculta e uma camada de saída). Uma maneira de se melhorar a capacidade de reconstrução é adicionando novas camadas ocultas ou neurônios ocultos, entretanto é preciso um conhecimento específico dos dados para avaliar a melhor estrutura e testar quais geram melhores resultados (FAN et al., 2018).</p>
<h1 id="aplicação">Aplicação</h1>
<p>Dentre as diversas possíveis aplicações de <em>Autoencoder</em> está a redução de ruídos. Para demonstrar isso, utilizou-se a base de dados de textos em papeis amassados disponibilizada no <a href="https://www.kaggle.com/c/denoising-dirty-documents/data">Kaggle</a> junto a estrutura base do <em>Autoencoder</em>. Inicialmente, 144 imagens foram usadas para compor o train set, que foram redimensionalisadas em uma matriz para se adequarem à arquitetura.</p>
<p><img src="https://i.imgur.com/vwa60wZ.png" alt="" />.</p>
<p>Em seguida, elaborou-se a estrutura do <em>Autoencoder</em> utilizando camadas de Convoluções, de UpSampling e de MaxPooling de forma simétrica. Como otimizador, optou-se pela Adam, pois, mesmo agindo, por vezes, de forma agressiva, demandou menor capacidade do processador e apresentou resultados de forma mais rápida.</p>
<p><img src="https://i.imgur.com/eCdBNXj.png" alt="" /></p>
<p>Por fim, aplicando o <em>Autoencoder</em> elaborado à amostra de dados, usando um batch size de 8 e 50 epochs, observou-se os seguintes resultados.</p>
<p><img src="https://i.imgur.com/MIdSPLe.png" alt="" /></p>
<p>Que, quando aplicado às imagens de teste fornecidas, foi capaz de obter ótimos resultados. No último dos exemplos, pode-se observar a utilização de uma imagem real, que não obtem o resultado almejado, visto que a base de dados apresentou papéis em melhor estado que o fornecido e com características próprias, além da qualidade da foto tirada. Todavia, esperar-se-ia que, com uma base de dados maior e maior capacidade de processamento, o modelo seria capaz de limpá-la.</p>
<p><img src="https://i.imgur.com/VlX7Adx.png" alt="" /></p>
<p><img src="https://i.imgur.com/rFsE0DM.png" alt="" /></p>
<p><img src="https://i.imgur.com/84J2FRZ.png" alt="" /></p>
Fatos Estilizados em Finanças2020-11-07T23:59:07+00:00http://lamfo-unb.github.io/2020/11/07/Fatos Estilizados em Finanças<h1 id="fatos-estilizados-em-finanças">Fatos Estilizados em Finanças</h1>
<p>Padrões que ocorrem recorrentemente no mercado financeiro são de suma importância para praticantes e estudiosos da área. Eles possibilitam criar e ajustar modelos que ajudarão no melhor entendimento dos movimentos do mercado. Mas quais são alguns desses padrões e como são tratados no campo das Finanças?</p>
<p>Ao observar uma série de elementos em diferentes contextos e períodos, em determinados ocasiões é possível fazer formulações teóricas de fenômenos ou características observadas empiricamente. A essas formulações, dá-se o nome de fatos estilizados.</p>
<p>Em Finanças, os fatos estilizados referem-se a características de ativos financeiros que são consistentes tanto entre diferentes mercados quanto entre diferentes períodos, e que, devido a isso, são generalizadas. Essas generalizações são importantes, visto que norteiam o processo de modelagem estatística dos retornos.</p>
<p>Um ponto importante a se observar é que todas as características referem-se aos retornos dos ativos, e não seus preços. Isso porque uma característica importante nesse processo é a <em>estacionariedade</em>, ou seja, a “consistência” do objeto analisado ao longo do tempo. Os preços são muito afetados por fatores como a conjuntura econômica e o estado da arte tecnológico, por exemplo. Já os retornos costumam ser menos afetados, e portanto, manter uma constância maior.</p>
<p>Nesse texto, abordaremos os seguintes fatos estilizados:</p>
<ul>
<li>Insignificância de autocorrelações</li>
<li>Caudas grossas</li>
<li>Assimetria de ganhos e perdas</li>
<li>Gaussianidade agregacional</li>
<li>Agrupamento de volatilidade</li>
<li>Efeito alavancagem</li>
<li>Correlação Volume X Volatilidade</li>
</ul>
<h2 id="insignificância-de-autocorrelações">Insignificância de Autocorrelações</h2>
<p>Na estatística, o conceito de autocorrelação diz respeito a correlação entre uma série temporal e sua versão com lag em diferentes intervalos de tempo. Ou seja, ao medir a correlação entre os retorno de uma série no momento <em>t</em> e no momento <em>t-1</em> para vários valores de <em>t</em>, o resultado é baixíssimo, ao ponto de ser insignificante.</p>
<p>Talvez uma forma mais intuitiva de entender esse conceito seja pelo jargão “retornos passados não garantem retornos futuros”, ou seja, que o retorno de determinada série em determinado momento é insignificantemente influenciado pelo anterior.</p>
<h3 id="insignificância-de-autocorrelação-na-prática-momentum">Insignificância de autocorrelação na prática: <em>Momentum</em></h3>
<p><img src="https://i.imgur.com/tsHJggA.png" alt="Lo e MacKinlay, 1990" title="Lo e MacKinlay, 1990" /></p>
<h6 id="lo-e-mackinley-1990">Lo e MacKinley, 1990</h6>
<p><img src="https://i.imgur.com/AjQTBPD.png" alt="Lo e MacKinlay, 1990(2)" title="Lo e MacKinley, 1990" /></p>
<h6 id="lo-e-mackinley-1990-1">Lo e MacKinley, 1990</h6>
<h2 id="queda-cadenciada-de-volatilidade-das-autocorrelações-de-retornos-absolutos-ou-quadrados">Queda cadenciada de volatilidade das autocorrelações de retornos absolutos ou quadrados</h2>
<p>Importante observar que a insignificância das autocorrelações dos retornos é uma propriedade relacionadas ao valor dos retornos. Porém, ao observar os retornos absolutos ou quadrados há uma autocorrelação que decai lentamente.</p>
<p>Ou seja, o retorno em determinado período tem pouca correlação com o valor no período seguinte, mas a “dimensão” desses valores possuem correlações, que vai diminuindo a medida que a diferença temporal aumenta.</p>
<p><img src="https://i.imgur.com/fuxNfUd.png" alt="" /></p>
<h6 id="taylor-2005">Taylor, 2005</h6>
<h2 id="caudas-grossas">Caudas Grossas</h2>
<p>Quanto a distribuição de probabilidade dos retornos, é possível observar que eles não apresentam uma curva normal, mas sim uma curva com maior concentração nas caudas da distribuição. Na prática, mais retornos apresentam valores menores e menos retornos apresentam valores maiores #(muita gente tem baixos retornos e pouca gente tem altos retornos).</p>
<h3 id="caudas-grossas-na-prática">Caudas Grossas na prática</h3>
<p><img src="https://i.imgur.com/5X8DuJn.png" alt="Silva et al, 2019" /></p>
<h6 id="silva-et-al-2019">Silva <em>et al.</em>, 2019</h6>
<h2 id="assimetria-de-ganhos-e-perdas">Assimetria de ganhos e perdas</h2>
<p>Outra característica associada a distribuição dos retornos é a assimetria de ganhos e perdas, representada graficamente por uma das caudas possuir uma maior “inclinação” que a outra. Essa propriedade diz respeito aos movimentos de queda (fundos) serem maiores que os de subida (topos). Utilizando um outro jargão, é como se os retornos “subissem de escada e descessem de elevador”.</p>
<h2 id="gaussianidade-agregacional">Gaussianidade agregacional</h2>
<p>A distruibuição dos retornos são associadas, porém, a um intervalo de tempo determinado. A gaussianidade agregacional diz respeito a distribuição ir se aproximando de uma normal (também chamada de distribuição Gaussiana, daí o nome) a medida que o horizonte de tempo é expandido.</p>
<p>Visto que o aumento no intervalo de tempo está associado ao tamanho da amostra analisada, o Teorema Central do Limite garante essa propriedade.</p>
<h2 id="agrupamento-de-volatilidade">Agrupamento de volatilidade</h2>
<p><img src="https://i.imgur.com/UnBqz8h.png" alt="Nghi, 2012" /></p>
<h6 id="nghi-2012">Nghi, 2012</h6>
<h2 id="efeito-alavancagem">Efeito Alavancagem</h2>
<p>O Efeito Alavancagem foi explicado pela primeira vez em 1976 (Black, 1976) e atesta que existe uma correlação entre a alavancagem dos ativos da empresa e a volatilidade do preço de suas ações. Empresas com alavancagem financeira e operacional tendem a ficar mais alavancadas com a queda do valor da firma, o que aumenta a volatilidade dos retornos de suas ações.</p>
<h2 id="correlação-volume-x-volatilidade">Correlação Volume X Volatilidade</h2>
<p>De acordo com Cont(2001), o volume é correlacionado com todas as medidas de volatilidade. Importante notar que a intensidade da correlação positiva entra os dois fatores dificulta a separação dos efeitos de cada um sobre os ativos (Bianco e Renò,2006).</p>
<p><img src="https://i.imgur.com/SgE96Vr.png" alt="" />
http://businessforecastblog.com</p>
<h2 id="como-a-indústria-de-gestão-de-recursos-pode-utilizar-machine-learning">Como a indústria de gestão de recursos pode utilizar Machine Learning?</h2>
<p>A previsão de preços dos ativos talvez seja a aplicação mais popular. No entanto, existem diversas aplicações tão ou mais importantes como:</p>
<ul>
<li>construção de portfólio;</li>
<li>detecção de outliers;</li>
<li>análise de sentimento;</li>
<li>market making;</li>
<li>tamanho de “apostas”;</li>
<li>outros.</li>
</ul>
<blockquote>
<p>“Nós precisamos de aprendizado de máquinas para melhorar teorias financeiras, e precisamos de teorias financeiras para restringir a propensão que o aprendizado de máquinas tem de <em>sobreajustar</em>.”
Marcos López de Prado</p>
</blockquote>
<h2 id="referências">Referências</h2>
<p>Empirical properties of asset returns: stylized facts and statistical issuesin: Quantitative Finance, Vol 1, No 2, (March 2001) 223-236.</p>
<p>Lewellen, Jonathan. “Momentum and Autocorrelation in Stock Returns.”The Review of Financial Studies, vol. 15, no. 2, 2002, pp. 533–563.JSTOR, www.jstor.org/stable/2696788. Accessed 28 Oct. 2020.</p>
<p>Lo, Andrew MacKinlay, A. (1990). When Are Contrarian Profits Due ToStock Market Overreaction?. Review of Financial Studies. 3. 175-205.10.1093/rfs/3.2.175.</p>
<p>MALMSTEN, Hans; TERÄSVIRTA, Timo. Stylized Facts of FinancialTime Series and Three Popular Models of Volatility. European Journal ofPure and Applied Mathematics, [S.l.], v. 3, n. 3, p. 443-477, may 2010.ISSN 1307-5543.</p>
<p>Girard, Eric Biswas, Rita. (2007). Trading Volume and Market Volatility:Developed versus Emerging Stock Markets. The Financial Review. 42.429-459.</p>
<p>Sewell, Martin. Characterization of Financial Time Series. Research Note.January, 2011.</p>
<p>Black, Fisher. (1976). Studies in Stock Price Volatility Changes. Proceedings of The American Statistical Association, Business and Economic Statistics Section. 177.</p>
<p>Bianco, Simone & Renò, Roberto. (2006). Dynamics of intraday serial correlation in the Italian futures market. Journal of Futures Markets. 26. 61 - 84. 10.1002/fut.20182.</p>
Classificação de Imagens com Redes Neurais Convolucionais2020-10-26T00:00:00+00:00http://lamfo-unb.github.io/2020/10/26/CNN<h1 id="classificação-de-imagens-com-redes-neurais-convolucionais">Classificação de Imagens com Redes Neurais Convolucionais</h1>
<table class="tfo-notebook-buttons" align="left">
<td>
<a target="_blank" href="https://colab.research.google.com/drive/1rDaSRunPTsavs31_rUAbZ0kiELwJ8z1B?usp=sharing">
<img src="https://www.tensorflow.org/images/colab_logo_32px.png" />
Run in Google Colab</a>
</td>
<td>
<a target="_blank" href="https://gist.github.com/RafaelEstatistico/4faa5672aeedc34bff59b3df6d45d6f4">
<img src="https://www.tensorflow.org/images/GitHub-Mark-32px.png" />
View source on GitHub</a>
</td>
</table>
<h2 id="onde-queremos-chegar">Onde queremos chegar:</h2>
<p>Nosso objetivo aqui é entender, de forma ilustrada, como podemos passar uma imagem para um modelo de Inteligência Artificial e receber classificação.</p>
<p>O diagnóstico de exames de Raios-X é um ótimo exemplo de classificação de imagem. Por exemplo, com a radiografia dos pulmões o médico pode identificar se o paciente possui ou não câncer. Um cientista de dados não tem o conhecimento médico, mas caso tenhamos uma grande base de dados com imagens de pulmões juntamente de seus diagnósticos, saudável ou não, podemos treinar um modelo que aprenda a classificá-los. Ajustado o modelo, podemos retornar a probabilidade de um exame de pulmão apresentar câncer com base em milhares de casos já classificados, isso poderia auxiliar nos prognósticos médicos.</p>
<p>O reconhecimento de imagem ou vídeo possuí diversas outras aplicações sendo uma das mais claras a categorização de fotos do <a href="https://www.google.com/photos/about/">Google Photos</a> em sua galeria. Como podemos ver ele utiliza a classificação para agrupar e organizar as fotos em elementos em comum. Nem sempre o reconhecimento é perfeito e até por isso é comum aparecer uma mensagem do aplicativo solicitando para confirmar algumas fotos. Ao fazermos isto estamos melhorando o poder de classificação do modelo utilizado.</p>
<center>
![Algumas das Classificações atribuidas pelo Photos](img/img1.jpg)
</center>
<p><em>Exemplo de Classificação imagens na galeria do <a href="https://www.google.com/photos/about/">Google Photos</a></em></p>
<p>Neste texto vamos abordar como são representadas as imagens em dados para o modelo, as estruturas que compõe uma Rede Neural Convolucional e finalizamos com uma aplicação no conjunto de dados conhecido como <a href="https://www.cs.toronto.edu/~kriz/cifar.html">CIFAR-10</a>.</p>
<p>Todos os códigos ao longo do texto estão disponíveis no Google Colab e GitHub. Caso você possua uma conta Gmail vale muito acessar o Colab. Nele é possível executar códigos Python direto do navegador.</p>
<h2 id="trabalhando-com-imagens">Trabalhando com Imagens</h2>
<p>Uma forma útil de representar as imagens é utilizando matrizes compostas de porções de pixel, isso pode se dar em escala de cinzas, para imagens em preto e branco, ou escala RGB, para imagens coloridas. De forma bem simplificada, podemos entender o pixel como a menor unidade da imagem. Por exemplo, uma imagem de proporções 60x40 possuí 2400 pixels. Já o RGB ou <em>Red, Green, Blue</em> é um sistema que utiliza a combinação entre as cores vermelho, verde e azul para gerar todas as cores.</p>
<center>
![](img/img2.gif)
</center>
<p>Fonte: <a href="https://www.bennadel.com/blog/3780-getting-the-rgb-color-value-of-an-image-pixel-using-graphicsmagick-and-lucee-cfml-5-2-9-31.htm">Getting The RGB Color Value Of An Image Pixel</a></p>
<p>A imagem gif acima ilustra os diferentes pixels sendo escolhidos, a cada clique a altera-se a coordenada do pixel (“Pixek Offset”) em termos de largura e altura ou linha e coluna se visualizarmos como uma matriz. Os valores RGB que cada pixel pode assumir variam entre 0 e 255 para o verde, vermelho e azul. Duas cores se destacam por serem os extremos da escala, são elas o preto, representado por {0,0,0} e o branco, representado por {250,250,250}. Para imagens em preto e branco a matriz possuirá apenas uma dimensão de cor, também chamado de canal. Já para imagens coloridas teremos 3 matrizes de mesma altura e largura, variando apenas o canal para uma das cores básicas. A seguir temos um exemplo de diferentes tonalidades de cores sendo representadas em escala RGB.</p>
<p><img src="img/img3.png" alt="" /></p>
<p><em>No <a href="https://colab.research.google.com/drive/1rDaSRunPTsavs31_rUAbZ0kiELwJ8z1B?usp=sharing">código </a>vemos como decompor uma imagem nos três canais de cores</em></p>
<p>Podemos decompor uma imagem colorida em três novas, uma para cada canal de cor. É interessante notar que do ponto de vista de informação as três dimensões são importantes para recriar a imagem como conhecemos. Se na imagem acima utilizássemos apenas o filtro azul teríamos dificuldade de enxergar os detalhes do cachorro. Caso a figura fosse toda representada em tons de preto e branco a mesma imagem seria apresentada nos três canais e tornando redundante manter as 3 dimensões.</p>
<h2 id="modelo">Modelo</h2>
<p>O problema de classificar uma imagem em categorias é tarefa para um modelo de aprendizado de máquina supervisionado de classificação. Isto implica na necessidade de haver um conjunto de imagens previamente classificadas para que possamos treinar e calibrar o modelo. Inclusive, para que o modelo consiga generalizar a classificação é necessário um conjunto grande de dados de cada uma das categorias do modelo.</p>
<blockquote>
<p>Mais sobre tipos de modelos de <em>Machine Learning</em> em: <a href="https://lamfo-unb.github.io/2017/07/27/tres-tipos-am/">Os Três Tipos de Aprendizado de Máquina</a></p>
</blockquote>
<p>Redes Neurais Convolucionais - RNC (<em>Convolutional Neural Network - CNN</em>) é um caso de aprendizado profundo, em que temos a estrutura de rede neural com a presença de ao menos uma camada convolucional. Em outras palavras, assim como nas Redes Neurais tradicionais temos as diversas camadas ocultas entre os dados de entrada e saída, aqui temos essas camadas sucessivas com a introdução de duas novas operações: Convolução (<em>Convolution</em>) e Agrupamento (<em>Pooling</em>).</p>
<blockquote>
<p>Mais sobre Redes Neurais: <a href="https://lamfo-unb.github.io/2017/06/18/itro-ao-deep-learning/">Uma Abordagem Intuitiva às Redes Neurais</a></p>
</blockquote>
<p>Para ilustrar um típico modelo temos a seguir uma figura que apresenta uma RNC estruturada de pares de Convoluções e Agrupamentos seguido de duas camadas totalmente conectadas para finalmente ter a resposta em probabilidade em cada categoria:</p>
<p><img src="img/img4.png" alt="" /></p>
<p>Fonte: <a href="https://matheusfacure.github.io/2017/03/12/cnn-captcha/#ref">Resolvendo CAPTCHAs com Redes Neurais Convolucionais</a></p>
<h3 id="camada-de-convolução">Camada de Convolução</h3>
<p>O que seria a convolução? Na matemática podemos resumir que é a transformação resultante de duas funções. No caso de redes neurais temos a transformação entre o filtro de convolução e a matriz de entrada.</p>
<p>O filtro de convolução, também chamado de kernel, é uma matriz quadrada que vai “varrer” todos toda a figura de entrada a passos (<em>stride</em>) fixos. Por exemplo, na imagem a seguir temos a aplicação do kernel de dimensões 3x3 à uma matriz de 5x5. O kernel multiplica elemento a elemento de cada submatriz 3x3 da imagem e soma seus valores, o que resulta na matriz de características de dimensões 3x3. Note também que cada submatriz é dada ao ir para a imediata próxima coluna ou linha, nosso passo aqui é de 1.</p>
<center>
![](img/img5.gif)
</center>
<p>Fonte: <a href="https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53">A Comprehensive Guide to Convolutional Neural Networks</a></p>
<p>Caso a imagem esteja em RGB, isto é, possua 3 dimensões, a convolução será aplicada a cada canal de cor e a matriz resultante é a soma dos 3 canais. Tanto imagens coloridas quanto em preto e branco apresentarão as mesmas dimensões de saída.</p>
<p>Os valores de cada elemento do Kernel são definidos durante a etapa de treinamento do modelo. Alguns Kernels são conhecidos por resultarem em imagens com realce de borda, aumento do contraste, efeito desfoque na imagem e etc. Um site incrível para visualizar a sensibilidade da imagem resultante com diferentes parâmetros de kernel é este <a href="https://setosa.io/ev/image-kernels/">aqui</a>.</p>
<p>Na construção do modelo nos precisamos especificar três parâmetros para cada camada convolucional. Primeiramente, definimos a quantidade de filtros que devem ser utilizados, ou seja, quantos diferentes kernels serão utilizados. Em seguida, especificamos a dimensão de cada kernel, por exemplo 2x2, 3x3, 5x5 e etc. Finalmente, o tamanho do passo que deve ser considerado na operação de convolução, o mais usual é utilizar passos de tamanho 1.</p>
<p>Vale ressaltar que após a operação de convolução a imagem terá uma dimensão menor do que a de entrada. Isso se dá pela relação entre a dimensão do kernel e tamanho do passo. Na especificação do modelo podemos especificar a opção de preenchimento (<em>Padding</em>). Com essa opção o modelo vai incluir uma borda de forma que a convolução resulte em dimensões iguais a de entrada.</p>
\[O = \frac{W - K}{S} +1\]
<p>Em que:</p>
<p><strong>O</strong>: representa o tamanho de saída, altura/lagura;</p>
<p><strong>W</strong>: é a dimensão de entrada, altura/largura;</p>
<p><strong>K</strong>: tamanho do kernel;</p>
<p><strong>S</strong>: tamanho do passo.</p>
<p>No exemplo da figura temos W=5, K=3 e S=1 resultando em O=3 tanto para altura quanto para largura. Portanto, aplicada a convolução sem a opção de preenchimento teremos uma imagem 3x3 como resultado desta operação.</p>
<h3 id="camada-de-agrupamento">Camada de Agrupamento</h3>
<p>O próprio nome já nos dá uma intuição do que acontecerá aqui. Similar a camada de convolução, nessa camada vamos varrer matrizes de entrada considerando um tamanho e passo fixo, com a diferença que ao invés da convolução agruparemos os dados pelo valor máximo (<em>Max Pooling</em>) ou médio (Agerage Pooling).</p>
<p>Esse método de agrupamento será responsável por destacar as informações dominantes, ao passo que também reduz o ruído das imagens. A seguir um exemplo dos dois métodos de agrupamento considerando submatrizes de 2x2 e passo de tamanho 2.</p>
<center>
![](img/img6.jpg)
</center>
<p>Fonte: <a href="https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53">A Comprehensive Guide to Convolutional Neural Networks</a></p>
<p>A dimensão resultante dessa operação é expressa pela mesma relação apresentada na seção sobre convolução. Nesse caso, os parâmetros foram W=4, K=2 e S=2 resultando em O=2 para altura e largura.</p>
<p>Vale destacar que o mais usual é utilizar o tamanho do kernel igual ao tamanho da matriz, dessa forma as submatrizes não possuem elementos em comum e nem deixamos elementos de fora da operação.</p>
<p>O tamanho do kernel influenciará muito na imagem de saída e consequentemente na resolução. Na figura abaixo originalmente tínhamos 384x512 de resolução. Com o filtro 2x2 a imagem de saída terá metade do tamanho original e sem grandes perdas de informação. Em um caso mais extremo, utilizando um filtro 15x15 a imagem de saída será bem menor, mas ao custo da qualidade da imagem, ainda que a forma e cores lembrem a imagem original.</p>
<p>![]img/img7.png)</p>
<h2 id="aplicação-cifar-10">Aplicação: CIFAR-10</h2>
<p>O conjunto de dados conhecido como <a href="https://www.cs.toronto.edu/~kriz/cifar.html">CIFAR-10</a> é muito popular quando começamos a estudar RNC. Nossa aplicação é baseada no <a href="https://www.tensorflow.org/tutorials/images/cnn">tutorial</a> do Tensorflow com essa base. Vamos utilizar o pacote <strong>Keras</strong> com a estrutura <em>Sequential</em> para organizar as camadas.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import tensorflow as tf
from tensorflow.keras import datasets, layers, models
import matplotlib.pyplot as plt
</code></pre></div></div>
<h3 id="download-e-preparação-de-dados">Download e Preparação de dados</h3>
<p>O dataset CIFAR10 possui 60.000 imagens coloridas classificadas em 10 categorias balanceadas, isto é, cada categoria possui 6 mil imagens.
Os dados estão divididos em 50.000 imagens para treinamento e 10.000 para testes.</p>
<p>Vale ressaltar que as classes são mutualmente exclusivas, não há imagens com mais de uma categoria presente. Pela documentação sabemos que essas imagens devem ser classificadas em uma das seguintes categorias: avião, automóvel, pássaro, gato, cervo, cachorro, sapo, cavalo, navio e caminhão.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(train_images, train_labels), (test_images, test_labels) = datasets.cifar10.load_data()
# Normalização de Pixels entre 0 e 1
train_images, test_images = train_images / 255.0, test_images / 255.0
</code></pre></div></div>
<p>As imagens possuem dimensão 32x32x3 ou seja, 32 pixels de largura e altura e 3 canais de cores. Vamos plotar uma amostra dos dados de treinamento juntamente com a classificação dada:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Visualizando uma amostra dos dados
class_names = ['airplane', 'automobile', 'bird', 'cat', 'deer',
'dog', 'frog', 'horse', 'ship', 'truck']
plt.figure(figsize=(10,10))
for i in range(16):
plt.subplot(4,4,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i][0]], fontsize=15)
plt.show()
</code></pre></div></div>
<center>
![](img/img8.png)
</center>
<h3 id="modelo-1">Modelo</h3>
<p>Nossa estrutura de modelo é composta de dois pares de convolução e agrupamento seguido de duas camadas totalmente conectadas. O resultado do <code class="language-plaintext highlighter-rouge">model.summary()</code> nos resume muito bem os parâmetros que fixamos no modelo juntamente das dimensões do dado em cada camada:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>model = models.Sequential(name='CNN-CIFAR10')
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10))
model.summary()
</code></pre></div></div>
<p><img src="img/img9.png" alt="" /></p>
<p>A camada <code class="language-plaintext highlighter-rouge">layers.Flatten()</code> serve para empilhar os elementos que estão disposto em várias matrizes em um único vetor. Ao todo nosso modelo possui 167.562 parâmetros para serem calibrados.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
history = model.fit(train_images, train_labels, epochs=10,
validation_data=(test_images, test_labels))
</code></pre></div></div>
<p><img src="img/img10.png" alt="" /></p>
<h3 id="avaliando-modelo">Avaliando Modelo</h3>
<p>Em apenas 10 épocas de treino nos encontramos um modelo com 68,9% de acurácia nos dados de teste! Isso um modelo simples que pode ser executado em minutos.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plt.figure(figsize=(10,4))
plt.subplot(1,2,1)
plt.plot(history.history['accuracy'], label='Acurácia de Treino')
plt.plot(history.history['val_accuracy'], label = 'Acurácia de Validação')
plt.xlabel('Época')
plt.ylabel('Acurácia')
plt.ylim([0.5, 1])
plt.legend(loc='upper right')
plt.subplot(1,2,2)
plt.plot(history.history['loss'], label='Perda de Treino')
plt.plot(history.history['val_loss'], label = 'Perda de Validação')
plt.xlabel('Época')
plt.ylabel('Perda')
plt.legend(loc='upper right')
plt.show()
</code></pre></div></div>
<p><img src="img/img11.png" alt="" /></p>
<p>Uma visualização interessante é observar a predição da imagem juntamente da probabilidade associada a cada categoria.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>probability_model = tf.keras.Sequential([model, tf.keras.layers.Softmax()])
predictions = probability_model.predict(test_images)
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array, true_label[i][0], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.imshow(img, cmap=plt.cm.binary)
predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = 'blue'
else:
color = 'red'
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array, true_label[i][0]
plt.grid(False)
plt.xticks(range(10))
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)
thisplot[predicted_label].set_color('red')
thisplot[true_label].set_color('blue')
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Previsões corretas são marcadas em azul, erradas em vermelho
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2*num_cols, 2*i+1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(num_rows, 2*num_cols, 2*i+2)
plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()
</code></pre></div></div>
<center>
![](img/img12.png)
</center>
<p>É interessante notar que os erros cometidos geralmente estão associados a probabilidades de classificação mais dispersas. Isso indica uma incerteza do modelo frente às imagens mal classificadas.</p>
<p>Muitos outros modelos já foram aplicados a esse conjunto de dados com diferentes estratégias documentas. Através deste <a href="http://rodrigob.github.io/are_we_there_yet/build/classification_datasets_results.html#43494641522d3130">Ranking</a> podemos ver que o melhor modelo chega a uma acurácia de 96,5%.</p>
<h2 id="considerações-finais">Considerações finais</h2>
<p>Treinamos rapidamente um modelo capaz de classificar imagens do zero, mas como já é de se esperar podemos incluir vários procedimentos para aumentar o poder de generalização da máquina. Desde experimentar diferentes combinações de camadas e seus parâmetros até técnicas de regularização como <em>dropout, batch_normalization</em> e <em>data augmentation</em>.</p>
<p>Por fim, caso queira acompanhar um projeto do LAMFO que está utilizando Redes Neurais Convolucionais para classificar CAPTCHAS dê uma olhada no nosso <a href="https://github.com/lamfo-unb/captcha_break/">repositório</a>.</p>
<h2 id="referências">Referências</h2>
<ul>
<li>[Texto] https://towardsdatascience.com/a-comprehensive-guide-to-convolutional-neural-networks-the-eli5-way-3bd2b1164a53</li>
<li>[Texto] https://matheusfacure.github.io/2017/03/12/cnn-captcha/</li>
<li>
<table>
<tbody>
<tr>
<td>[Vídeo] [But what is a Neural Network?</td>
<td>Deep learning, chapter 1](https://www.youtube.com/watch?v=aircAruvnKk)</td>
</tr>
</tbody>
</table>
</li>
<li>[Vídeo] <a href="https://www.youtube.com/watch?v=m8pOnJxOcqY">Convolution Neural Networks - EXPLAINED</a></li>
<li>
<h2 id="tutorial-convolutional-neural-network-cnn">[Tutorial] <a href="https://www.tensorflow.org/tutorials/images/cnn">Convolutional Neural Network (CNN)</a></h2>
</li>
</ul>
Análise Discriminante Linear2020-10-10T23:59:07+00:00http://lamfo-unb.github.io/2020/10/10/Análise-Discriminante-Linear<h1 id="análise-discriminante-linear">Análise Discriminante Linear</h1>
<hr />
<h2 id="1-introdução">1. Introdução</h2>
<p>A Análise Discriminante Linear (em sua sigla em inglês, LDA) é uma ferramenta usada para classificação, redução de dimensão e visualização de dados. A meta em se aplicar técnicas de redução de dimensões é remover aquelas características redundantes e dependentes ao transformar características de um espaço dimensional maior para um espaço dimensional menor.</p>
<p>O método foi introduzido em sua forma inicial para problemas com duas classes por Robert Fisher em 1936, mas é particularmente útil com amostras de dados multivariados. Tem aplicações em diversos campos do conhecimento, como na biologia (para classificações taxonômicas), nas finanças (o Z-score de Altman para previsão de falências) e na tecnologia (para reconhecimento de dígitos), entre outros.</p>
<h2 id="2-classificação-por-análise-de-discriminante">2. Classificação por análise de discriminante</h2>
<p>Temos o seguinte problema: uma variável aleatória $\mathbf{X}$ pode ser incluída em uma de $\mathbf{J}$ classes, com densidade de probabilidade $f_{j}(\mathbf{x})$. A regra discriminatória tenta dividir o espaço de dados em $\mathbf{J}$ regiões que representam as classes. A análise de discriminante tem como objetivo alocar $\mathbf{x}$ à classe $j$ se $\mathbf{x}$ está na região de $j$.</p>
<p>Podemos seguir duas regras de alocação:</p>
<ol>
<li><strong>Regra de máxima verossimilhança:</strong> a hipótese é de que cada classe pode ocorrer com a mesma probabilidade. Então alocamos $\mathbf{x}$ para $j$ se $j = arg\, max_i\,f_i(\mathbf{x})$</li>
<li><strong>Regra Bayesiana:</strong> nesse caso, já temos as probabilidades de ocorrência $\pi_1,…,\pi_{\mathbf{J}}$ de cada classe; alocamos $\mathbf{x}$ a cada classe $j$ se $j = arg\,max\,\pi_{i}f_{i}(\mathbf{x})$</li>
</ol>
<h3 id="21-análise-discriminante-linear-vs-quadrática">2.1 Análise discriminante linear vs. quadrática</h3>
<p>Assumindo que os dados seguem uma distribuição Gaussiana multivariada, em que $\mathbf{X} \thicksim N(\mu, \Sigma)$, podemos obter funções de alocação. Seguindo a regra Bayesiana, classificamos $\mathbf{x}$ na classe $j$ se $j = arg\,max\,\delta_i(\mathbf{x})$ onde a função discriminatória $\delta_i(\mathbf{x})$ é dada por</p>
\[\delta_i(\mathbf{x}) = log\,f_{i}(\mathbf{x})+log\,\pi_i\]
<p>O <strong>LDA</strong> aparece no caso em que assumimos igual covariância entre as $\mathbf{J}$ classes – isso implica que assumimos igual grau de interdependência numérica entre as classes; a fronteira de decisão entre os pares de classes será uma função linear em $\mathbf{x}$. Assim, podemos obter a seguinte função discriminatória, usando a função de verossimilhança com distribuição Gaussiana:</p>
\[\delta_j(\mathbf{x}) = \mathbf{x}^{T}\Sigma^{-1}\mu_j - (1/2)\mu_j^{T}\,\Sigma^{-1}\mu_j + log\,\pi_j\]
<p>Sem a hipótese de mesma covariância entre as classes, a função discriminante resultante é uma função quadrática em $\mathbf{x}$, conhecida como análise discriminante quadrática (QDA):</p>
\[\delta_j(\mathbf{x}) = -(1/2)\,log|\Sigma_j| - (1/2)\,(\mathbf{x}-\mu_j)^{T}\,\Sigma^{-1}\,(\mathbf{x}-\mu_j) + log\,\pi_j\]
<p>Comparando ambas as análises podemos observar que, enquanto o QDA acomodaria fronteiras de decisão mais flexíveis em relação ao LDA, a quantidade de parâmetros a serem estimados na análise quadrática cresce a um ritmo mais rápido, com impactos sobre o desempenho da análise.</p>
<p>Outras extensões do LDA incluem a Análise Discriminatória Flexível (FDA), onde combinações não-lineares dos inputs são usadas, e a Análise Discriminatória Regularizada (RDA), que introduz regularização à estimação da covariância.</p>
<h3 id="22-computação-para-lda">2.2 Computação para LDA</h3>
<p>Podemos transformar os dados para deixá-los mais próximos a uma distirbuição Gaussiana, e padronizá-los para que apresentem média zero e desvio padrão unitário, de forma a facilitar a análise.</p>
<p>Além disso, podemos simplificar a computação de funções discriminatórias se diagonalizarmos as matrizes de covariância. O que faremos é transformar os dados de modo a obter uma matriz identidade de covariância (sem correlação e com variância unitária).</p>
<ol>
<li>Aplicamos auto-decomposição na matriz de covariância: $\mathbf{\hat{\Sigma} = UDU^{T}}$</li>
<li>Esferizamos os dados: $\mathbf{X^{*} \rightarrow D^{-\tfrac{1}{2}}U^{T}X}$</li>
<li>Obtemos as médias das classes no espaço transformado: $\hat{\mu}_1,…,\hat{\mu}_J$</li>
<li>Classificamos $\mathbf{x}$ segundo $\delta_j(\mathbf{x^{*}})$:</li>
</ol>
\[\delta_j(\mathbf{x^{*}}) = \mathbf{x^{*}}^{T}\hat{\mu}_j-(1/2)\,\hat{\mu}_j^{T}\hat{\mu}_j + log\,\hat{\pi}_j\]
<p>Vamos ver o princípio de alocação do LDA em termos matemáticos. Suponha que existam duas classes, $k$ e $l$, e queremos classificar os dados $\mathbf{x}$. Classificaremos em $k$ se:</p>
\[\delta_k(\mathbf{x^{*}}) - \delta_l(\mathbf{x^{*}}) > 0\]
<p>Onde</p>
<p>\begin{split}
\delta_k(\mathbf{x^{<em>}}) - \delta_l(\mathbf{x^{</em>}}) &= \mathbf{x^{<em>}}^{T}\hat{\mu}_k-(1/2)\,\hat{\mu}_k^{T}\hat{\mu}_k + log\,\hat{\pi}_k - \mathbf{x^{</em>}}^{T}\hat{\mu}_l-(1/2)\,\hat{\mu}_l^{T}\hat{\mu}_l + log\,\hat{\pi}_l<br />
&= \mathbf{x^{*}}^{T}\,(\hat{\mu}_k-\hat{\mu}_l) -(1/2)\,(\hat{\mu}_k^{T}\hat{\mu}_k-\hat{\mu}_l^{T}\hat{\mu}_l) + log\,\hat{\pi}_k/\hat{\pi}_l<br />
&> 0
\end{split}</p>
<p>Isto é, classificamos $\mathbf{x}$ em $k$ se:</p>
\[\mathbf{x^{*}}^{T}\,(\hat{\mu}_k-\hat{\mu}_l) > (1/2)\,(\hat{\mu}_k + \hat{\mu}_l)^{T}\,(\hat{\mu}_k-\hat{\mu}_l) - log\,\hat{\pi}_k/\hat{\pi}_l\]
<p>Na equação à esquerda, temos o comprimento da projeção ortogonal de $\mathbf{x}^{*}$ na linha de segmento que une as médias das classes. No lado direito, temos a locação do centro do segmento corrigida pelas probabilidades das classes.</p>
<p>Essencialmente, <strong>o LDA compara distâncias</strong> entre as médias dos dados e as médias das classes, e os classifica junto àquela que apresenta <strong>a média mais próxima</strong>.</p>
<h2 id="3-redução-de-dimensão-com-lda">3. Redução de dimensão com LDA</h2>
<p>A redução de dimensionalidade tem como objetivo facilitar a visualização e tratamento de dados com várias dimensões. Essa redução é inerente à técnica do LDA. Comparando a distância no subespaço dado pelas $J$ médias das classes, nota-se que distâncias ortogonais a esse subespaço não adicionam novas informações pois contribuem de igual forma para cada classe. Assim, podemos transformar um problema $p$-dimensional para um problema com $J-1$ dimensões ao projetar os dados ortogonalmente nesse subespaço.</p>
<p>Podemos ir além, e construir um subespaço $L$-dimensional $H_L$ (onde $L < J$). Esse subespaço é ótimo quando as médias das classes dos dados esfericizados têm máxima separação em termos de variância. As coordenadas do subespaço ótimo são encontradas aplicando um <em>Principal Component Analysis</em> (PCA) nas médias das classes esfericizadas, porque o PCA encontra a direção da variância máxima.</p>
<ol>
<li>Encontramos a matriz das médias das classes, $\mathbf{M}<em>{(J \times p)}$, e variância-covariância agrupada, $\mathbf{W}</em>{(p \times p)}$</li>
</ol>
\[\mathbf{W} = \sum_{j=1}^{J}\sum_{g_i=1}\,(x_i-\hat{\mu}_j)\,(x_i-\hat{\mu}_j)^{T}\]
<ol>
<li>
<p>Esferizamos as médias, usando uma auto-decomposição de $\mathbf{W}$: $\mathbf{M^{*}} = \mathbf{MW}^{-1/2}$</p>
</li>
<li>
<p>Computamos $\mathbf{B^{<em>}} = cov(\mathbf{M}^{</em>})$, a covariância entre classes das médias esfericizadas das classes:</p>
</li>
</ol>
\[\mathbf{B}^{*} = \sum_{k=1}^{J}\,(\hat{\mu}_j^{*}-\hat{\mu}^{*})\,(\hat{\mu}_j^{*}-\hat{\mu}_j)^{T}\]
<ol>
<li>
<p>PCA: obtemos $L$ autovetores $\mathbf{v}_l^{*}$, correspondendo aos $L$ maiores autovalores, que definem as coordenadas do subespaço ótimo</p>
</li>
<li>
<p>Obtemos as novas $L$ variáveis discriminantes $Z_l - (\mathbf{W}^{-1/2}\,\mathbf{v}_l^{*})^{T}\,X$, para $l = 1,…,L$</p>
</li>
</ol>
<p>Através desse procedimento, reduzimos nossos dados de $\mathbf{X}<em>{(n \times p)}$ para $\mathbf{Z}</em>{(n \times L)}$, reduzindo a dimensão do problema de $p$ para $L$.</p>
<p><img src="/img/LDA/three.jpg" style="display: block; margin: auto;" /></p>
<p>O <strong>LDA</strong> cria um novo eixo e projeta os dados ortogonalmente de forma a <strong>minimizar a variância e maximizar a distância entre as médias das classes</strong>. No exemplo acima, a simples projeção ortogonal no eixo horizontal não é ótima pois as informações atreladas à separação dos dados em classes foi perdida. No segundo caso, com a aplicação de um LDA, corrige-se esse problema.</p>
<p>O que se espera com a aplicação de um LDA é que a <strong>variância entre classes</strong> seja maximizada relativamente à <strong>variância intra-classe</strong>.</p>
<h2 id="4-exemplo">4. Exemplo</h2>
<p>Pode-se separar elementos de uma amostra em subgrupos no R utilizando o pacote MASS, como veremos no exemplo abaixo.</p>
<h3 id="41-carregar-pacotes-necessários">4.1 Carregar Pacotes necessários</h3>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">
</span><span class="c1">#o primeiro passo é instalar e chamar as bibliotecas necessárias</span><span class="w">
</span><span class="c1">#esse pacote contém a base de dados utilizada</span><span class="w">
</span><span class="n">install.packages</span><span class="p">(</span><span class="s2">"ISLR"</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s2">"ISLR"</span><span class="p">)</span><span class="w">
</span><span class="c1">#esse pacote contém a função lda</span><span class="w">
</span><span class="n">install.packages</span><span class="p">(</span><span class="s2">"MASS"</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="s2">"MASS"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<h3 id="42-preparar-a-base-de-dados">4.2 Preparar a base de dados</h3>
<p>Nesse exemplo, utilizaremos a base de dados Smarket, que apresenta os retornos percentuais diários para o índice de ações S&P 500 entre 2001 e 2005, para prever a direção do retorno do mercado.</p>
<p>$Direction$ ~ Um fator com níveis <em>Down</em> e <em>Up</em> que indica se o mercado teve um retorno positivo ou negativo em um determinado dia</p>
<p>As variáveis preditoras utilizadas são:</p>
<p>$Year$ ~ O ano em que a observação foi registrada</p>
<p>$Lag_i$ ~ Retorno percentual de i dias anteriores</p>
<p>$Volume$ ~ Volume de ações negociadas (número de ações diárias negociadas em bilhões)</p>
<p>$Today$ ~ Retorno percentual para hoje</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#chamando a base de dados Smarket</span><span class="w">
</span><span class="n">data</span><span class="p">(</span><span class="s2">"Smarket"</span><span class="p">)</span><span class="w">
</span><span class="o">?</span><span class="n">Smarket</span><span class="w">
</span><span class="c1">#essa função permite chamar as colunas pelo seus respectivos nomes sem a necessidade de informar a base de dados</span><span class="w">
</span><span class="n">attach</span><span class="p">(</span><span class="n">Smarket</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Após chamar os dados, serão feitos breves análises e tratamentos da base de dados antes de realisar a análise discriminante.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># primeiro passo, dividir a base de dados em train e test</span><span class="w">
</span><span class="c1">## note que não foi necessário colocar ISLR$Smarket, pois a função attach() simplificou o processo</span><span class="w">
</span><span class="n">Smarket_train</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">Smarket</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="m">1000</span><span class="p">,]</span><span class="w">
</span><span class="n">Smarket_test</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">Smarket</span><span class="p">[</span><span class="m">1001</span><span class="o">:</span><span class="m">1250</span><span class="p">,]</span><span class="w">
</span></code></pre></div></div>
<p>O algoritmo LDA começa encontrando direções que maximizam a separação entre as classes e, em seguida, usa essas direções para prever a classe de indivíduos. Essas direções, chamadas discriminantes lineares, são combinações lineares de variáveis preditoras.</p>
<h3 id="43-modelo">4.3 Modelo</h3>
<p>Abaixo será usada a regressão lda para explicar a variável $Direction$.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Direction é uma dummy que pode ser up ou down</span><span class="w">
</span><span class="n">modelo_analise</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lda</span><span class="p">(</span><span class="n">Direction</span><span class="o">~</span><span class="n">Lag1</span><span class="o">+</span><span class="n">Lag2</span><span class="o">+</span><span class="n">Lag3</span><span class="o">+</span><span class="n">Lag4</span><span class="o">+</span><span class="n">Lag5</span><span class="o">+</span><span class="w">
</span><span class="n">Volume</span><span class="o">+</span><span class="n">Today</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="o">=</span><span class="n">Smarket_train</span><span class="p">)</span><span class="w">
</span><span class="c1">#ao plotar, vemos que tem uma interceção muito pequena o que é bom</span><span class="w">
</span><span class="n">modelo_analise</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Call:
lda(Direction ~ Lag1 + Lag2 + Lag3 + Lag4 + Lag5 + Volume + Today,
data = Smarket_train)
Prior probabilities of groups:
Down Up
0.493 0.507
Group means:
Lag1 Lag2 Lag3 Lag4 Lag5 Volume Today
Down 0.04069777 0.03350101 -0.009764706 -0.009119675 0.0049249493 1.370938 -0.9232049
Up -0.03954635 -0.03132544 0.005834320 0.003110454 -0.0006508876 1.363210 0.8946864
Coefficients of linear discriminants:
LD1
Lag1 -0.02753403
Lag2 -0.03289355
Lag3 0.01128884
Lag4 0.01327753
Lag5 0.04349531
Volume -0.12206753
Today 1.20995907
</code></pre></div></div>
<pre><code class="language-{r}">plot(modelo_analise)
</code></pre>
<p><img src="/img/LDA/up_down.png" style="display: block; margin: auto;" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>modelo_analise$means
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Lag1 Lag2 Lag3 Lag4 Lag5 Volume Today
Down 0.04069777 0.03350101 -0.009764706 -0.009119675 0.0049249493 1.370938 -0.9232049
Up -0.03954635 -0.03132544 0.005834320 0.003110454 -0.0006508876 1.363210 0.8946864
</code></pre></div></div>
<p>O LDA determina as médias dos grupos e calcula, para cada indivíduo, a probabilidade de pertencer aos diferentes grupos. O indivíduo é então afetado ao grupo com a pontuação de probabilidade mais alta.</p>
<p>Coeficientes de discriminantes lineares : Mostra a combinação linear de variáveis preditoras que são usadas para formar a regra de decisão LDA.</p>
<p>Ao plotar o gráfico, pode-se observar que há uma pequena interseção entre os dados, o que representa que o modelo aparenta possuir uma boa acurácia, que será calculada posteriomente.</p>
<h3 id="44-previsões">4.4 Previsões</h3>
<p>Após utilizar o algoritmo de discriminante linear, pode-se usar o modelo para prever a probabilidade de uma observação x pertencer ao grupo $Down$ ou ao grupo $Up$.</p>
<p>A função $predict()$ retorna os seguintes elementos:</p>
<p>$class$ ~ classes previstas de observações.</p>
<p>$posterior$ ~ é uma matriz cujas colunas são os grupos, as linhas são os indivíduos e os valores são a probabilidade posterior de que a observação correspondente pertença aos grupos.</p>
<p>$x$ ~ contém os discriminantes lineares, descritos acima</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#utilizar a função predict para prever o modelo</span><span class="w">
</span><span class="n">modelo_predict</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo_analise</span><span class="p">,</span><span class="w"> </span><span class="n">Smarket_test</span><span class="p">[,</span><span class="m">-9</span><span class="p">])</span><span class="w">
</span><span class="nf">names</span><span class="p">(</span><span class="n">modelo_predict</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[1] "class" "posterior" "x"
</code></pre></div></div>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#após prever o modelo, utiliza-se a função table para comparar os valores previstos com o valor da amostra de teste</span><span class="w">
</span><span class="n">lda.class</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">modelo_predict</span><span class="o">$</span><span class="n">class</span><span class="w">
</span><span class="c1">#table apresenta os acertos do modelo</span><span class="w">
</span><span class="n">table</span><span class="p">(</span><span class="n">lda.class</span><span class="p">,</span><span class="w"> </span><span class="n">Smarket_test</span><span class="o">$</span><span class="n">Direction</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>lda.class Down Up
Down 108 7
Up 1 134
</code></pre></div></div>
<h3 id="45-acurácia-do-modelo">4.5 Acurácia do modelo</h3>
<p>Por fim, as funções predict e table foram utilizadas para prever os valores do modelo e comparar com a amostra <em>Smarket_test</em>. Note que o resultado confimou a observação feita pelo gráfico.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Cálculo da acurácia de 96,8%</span><span class="w">
</span><span class="m">1</span><span class="o">-</span><span class="p">(</span><span class="m">1+7</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="m">1+7+108+134</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[1] 0.968
</code></pre></div></div>
<p>Há 250 observações nos dados $Smarket_test$. Na matriz lda.class, observa-se que o modelo previu que 1 observação era Up, quando na realidade era Down, e outras 7 eram <em>Down</em>, quando na realidade deveria ser <em>Up</em>. De acordo com o gráfico, há uma interseção pequena entre os dados discriminados, o que foi confirmado pela acurácia de 96,8%.</p>
<h2 id="5-conclusão">5. Conclusão</h2>
<p>As principais vantagens do LDA são relacionadas à sua simplicidade como método de classificação, com limites de decisão lineares robustos e propriedades de redução de dimensão, que produzem uma ferramenta de fácil interpretação, visualização e modelagem.</p>
<p>As principais desvantagens também estão ligadas a essa relativa simplicidade do método, na medida em que a linearidade pode não ser adequada para determinados tipos de classificação e modelagem, o que implicaria na necessidade de adoção de análises mais complexas como forma de complementação.</p>
<hr />
<h2 id="referências">Referências</h2>
<p>Linear and Quadratic Discriminant Analysis. Scikit Learn. Disponível em:
<a href="https://scikit-learn.org/stable/modules/lda_qda.html">https://scikit-learn.org/stable/modules/lda_qda.html</a></p>
<p>BROWNLEE, Jason. <strong>Linear Discriminant Analysis for Machine Learning</strong>. Machine Learning Mastery, 2016.
Disponível em: <a href="https://machinelearningmastery.com/linear-discriminant-analysis-for- machine-learning/">https://machinelearningmastery.com/linear-discriminant-analysis-for- machine-learning/</a></p>
<p>SAWLA, Srishti. <strong>Linear Discriminant Analysis</strong>. Medium Data Sciene, 2018. Disponpivel em:
<a href="https://medium.com/@srishtisawla/linear-discriminant-analysis-d38decf48105">https://medium.com/@srishtisawla/linear-discriminant-analysis-d38decf48105</a></p>
<p>SCHLAGENHAUF, Tobias. <strong>Linear Discriminant Analysis (LDA)</strong>. Python Machine Learning Tutorial. Disponível em:
<a href="https://www.python-course.eu/linear_discriminant_analysis.php">https://www.python-course.eu/linear_discriminant_analysis.php</a></p>
<p>XIAOZHOU, Yang. <strong>Linear Discriminant Analysys, Explained</strong>. Xiaozhou’s Notes, 2019. Disponível em:
<a href="https://yangxiaozhou.github.io/data/2019/10/02/linear-discriminant-analysis.html">https://yangxiaozhou.github.io/data/2019/10/02/linear-discriminant-analysis.html</a></p>
Crash Course de Amostragem2020-09-27T23:59:15+00:00http://lamfo-unb.github.io/2020/09/27/Crash-Course-Amostragem<h3 id="amostragem-clássica">Amostragem clássica</h3>
<p>O censo é a coleta das informações de toda a população, enquanto a amostragem é a coleta de um sobconjunto representativo dessa população.</p>
<p>A principal vantagem do censo é a desvantagem da amostragem, e vice-versa. Por exemplo, ao coletarmos apenas um subconjunto da população, fazemos isso de forma mais <strong>rápida</strong> e com menor <strong>custo</strong>, quando comparamos com o censo. No entanto, ao realizarmos o censo, não há erro, pois foi coletada todas as informações da população. Já o processo de amostragem, as informações coletadas dependem da amostra, e por isso, há o chamado <strong>erro amostral</strong>.</p>
<p>O principal objetivo da teoria amostral é determinar um método de coleta de uma amostra, bem como calcular o <strong>erro que se comete</strong> ao coletar informações de um subconjunto da população. Chamamos essa amostragem de <strong>amostragem probabilística</strong>.</p>
<p>A população possui <strong>parâmetros</strong>, normalmente, desconhecidos, e por meio do processo de amostragem, temos <strong>estimadores amostrais</strong> que, baseado na amostra coletada, nos fornecem <strong>estimativas</strong>. Obviamente, essas estimativas depende da amostra, isto é, variam entre si e, principalmente, variam do valor real verdadeiro do parâmetro, denominado <strong>erro amostral</strong>.</p>
<p>A principal referência para o estudo clássico em amostragem é @cochran2007sampling. Nesse livro, o autor apresenta 11 etapas para o processo de amostragem. A seguir, apresentamos as principais:</p>
<ul>
<li>
<p>Definição dos objetivos da pesquisa</p>
</li>
<li>
<p>Definição da população a ser amostrada</p>
</li>
<li>
<p>Quais informações da população serão coletadas</p>
</li>
<li>
<p>Nível de precisão. Aqui temos o tão conhecido: <a href="https://www.youtube.com/watch?v=6x2IKleWgOQ">“O nível de confiança da pesquisa é de 95%”</a></p>
</li>
<li>
<p><a href="https://faculty.elgin.edu/dkernler/statistics/ch01/1-4.html">Plano amostral</a>.</p>
</li>
<li>
<p>Pré-teste</p>
</li>
<li>
<p>Análise dos dados</p>
</li>
</ul>
<p>Conforme detalhado em @cochran2007sampling e no <a href="https://faculty.elgin.edu/dkernler/statistics/ch01/1-4.html">link</a>, há inúmeras formas de se realizar a amostragem. A mais simples dela, é a amostragem aleatória simples, em que são selecionadas, aleatoriamente, elementos dessa população.</p>
<p><img src="SLID1.png" alt="*Parâmetro, estimador e erro amostral da amostragem aleatória simples. Fonte:@cochran2007sampling*" /></p>
<p>Outra forma de se realizar a amostragem é utilizando planos amostrais mais elaborados. A amostragem estratificada pode ser utilizada quando a população é naturalmente ou intensionalmente dividida por meio de atributos que criam subgrupos heterogêneos. A determinação desse atributo deve estar diretamente relacioada aos objetivos da pesquisa. Por exemplo, caso uma empresa de cosméticos deseje fazer uma pesquisa de mercado para um produto unisex, o atributo de <strong>sexo</strong> parece ser extremamente relevante, pois a opnião das mulheres pode ser completamente diferente dos homens. Dessa forma, se a população é formada por 200 homens e 800 mulheres, temos um estrato por sexo. Após a divisão da população em estratos, realiza-se o processo de amostragem simples em cada estrato.</p>
<p><img src="stratified.png" alt="*Processo de seleção estratificada. Fonte: [https://faculty.elgin.edu](https://faculty.elgin.edu/dkernler/statistics/ch01/1-4.html)*" /></p>
<p>Obviamente, para esse tipo de divisão precisamos <strong>conhecer tal atributo para cada elemento da população</strong>, para só então, realizarmos o processo de seleção estratificada.
A definição do tamanho a ser coletado em cada estrato para a amostra deve ser escolhido de acordo com os objetivos da pesquisa e podem ser encontrados em @cochran2007sampling. O mais utilizado é a alocação proporcional ao tamanho dos estratos, isto é, o tamanho amostral em cada estrato é proporcional ao tamanho do estrato.</p>
<p>Nas equações a seguir $N_h$ é o tamanho do estrato $i$ em uma população de tamanho $N$, e $n_h$ é o tamanho da amostra no estrato $h$ em uma amostra de tamanho $n$. Dessa forma, $n_h$ é proporcional a $N_h$. Além disso, o estimador amostral é uma combinação do estimador em cada estrato $h$ ponderado pelo peso do estrato na amostra $\frac{n_h}{n}$</p>
<p><img src="SLID2.png" alt="*Estimador e tamanho amostral da amostragem estratificada, sendo L o número de estratos. Fonte:@cochran2007sampling*" /></p>
<p>O erro amostral do processo de amostragem estratificado é feito combinando os erros de cada estrato.</p>
<p><img src="SLID3.png" alt="*Variância do estimador da amostragem estratificada, sendo L o número de estratos. Fonte:@cochran2007sampling*" /></p>
<p>Existem inúmeras formas de realizar amostragem. Neste <em>post</em>, vamos tratar da amostragem em múltiplos estágios, quando são realizados mais de uma etapa de selação. Por exemplo, no processo de seleção estratificada, acessamos todos os estratos e selecionamos aleatoriamente apenas 1 vez, isto é, dentro de cada estrato. No entanto, é possível que dentro de cada estágio a população esteja dividida em outros atributos, o que requer 2 ou mais estágios. Por exemplo, imagine que a população a ser coletada esta dividida em municípios (estratos), bairros (primeira unidade de seleção) e domicílios (segunda unidade de seleção). Todos os municípios serão selecionados na pesquisa, mas serão <strong>selecionados alguns</strong> bairros de cada município (aleatória simples, por exemplo), e em cada bairro selecionado, serão <strong>selecionados alguns</strong> domicílios (aleatória simples, por exemplo). Dessa forma, temos uma <strong>amostragem em múltiplos estágios</strong>.</p>
<p>O Instituto Brasileiro de Geografia e Estatística - IBGE em conjunto com o Sistema Integrado de Pesquisas Domiciliares por
amostragem (SIPD), tendo em conhecimento o Cadastro Nacional de Endereços para Fins Estatísticos (CNEFE), criaram a <a href="https://www.ibge.gov.br/arquivo/projetos/sipd/segundo_forum/segundo_amostra.php">Amostra Mestra</a> que é feita nas seguintes etapas.</p>
<ul>
<li>Estratos: Unidades da Federação (UFs) subdivididos em:
<ul>
<li>Capital;</li>
<li>Demais municípios pertencentes à RM ou à RIDE;</li>
<li>colar ou expansão metropolitana ou a outra RM;</li>
<li>à RIDE com sede em outra UF e</li>
<li>Demais municípios da UF.</li>
</ul>
</li>
<li>
<p>Etapa 1: Unidades Primárias de Amostragem (UPAs): selecionadas com probabilidade proporcional ao tamanho, medido pelo número de domicílios particulares permanentes ocupados e vagos (DPPs).</p>
</li>
<li>Etapa 2: selecionado amostra de 14 domicílios particulares permanentes ocupados dentro de cada UPA da amostra, por amostragem aleatória simples, baseado no cadastro CNEFE</li>
</ul>
<p>Dentre as pesquisas que utilizam esse planejamento amostral, temos Pesquisa de Orçamentos Familiares (POF), Pesquisa de Orçamentos Familiares
Simplificada (POFs), Pesquisa Nacional de Saúde (PNS), PME (Pesquisa Mensal de
Emprego), PNAD (Pesquisa Nacional por Amostra de Domicílios) e Pesquisa Nacional por Amostra de Domicílios Contínua (PNAD Contínua).</p>
<h3 id="aplicação-pnad-contínua">Aplicação PNAD contínua</h3>
<p>Adicionalmente, na PNAD contínua, tem-se o <a href="https://www.ibge.gov.br/arquivo/projetos/sipd/texto_discussao_23.pdf">grupo de rotação e número da visita</a>. Essas características foram planejadas pela periodicidade de coleta trimestral, isto é, os domicílios serão coletados ao longo de 3 meses. O esquema de rotação da amostra adotado onde $v=5$ seria o número de visitas a serem realizadas. Neste esquema o domicílio é entrevistado 1 mês e sai da amostra por 2 meses seguidos, sendo esta seqüência repetida $v=5$
vezes. Esse esquema é mais eficiente quando o interesse é a inferência considerando a mudanças dos indicadores ao longo de três meses, com sobreposição de 25% da amostra de um trimestre para
o mesmo trimestre entre anos @de2007amostra.</p>
<p>O estimador para o total considerando o plano amostral da Amostra Mestra é apresentado por @de2014amostra:</p>
\[\hat{Y}^{tri}_{r} = \sum_g\sum_i \sum_j\sum_k w^{**}_{gij}\times y_{gijk}\]
<ul>
<li>
<p>$y_{gijk}$ é o valor da variável de interesse $y$ para a pessoa $k$ do domicílio $j$ da UPA $i$ do
grupo de rotação $g$</p>
</li>
<li>
<p>Peso ajustado por calibração (totais populacionais):
\(w^{**}_{gij} = \frac{1}{m_g}\times \frac{N_g}{N_{gi}}\times
\frac{N^{*}_g}{n_{gi}}\times\frac{n^{*}_{gi}}{n^{**}_{gi}}\times\frac{P_a^{tri}}{\hat{P}_a^{tri}}\)</p>
</li>
<li>
<p>$P_a^{tri}$ é a estimativa populacional produzida pela Coordenação de População e
Indicadores Sociais (COPIS) para o nível geográfico a para o dia 15 do mês do meio do trimestre</p>
</li>
<li>
<p>$\hat{P}_a^{tri}$ é a estimativa populacional obtida com os dados da pesquisa para o nível geográfico ano trimestre</p>
</li>
</ul>
<p><img src="SLIDE10.png" alt="Estimador do erro amostral PNAD. Fonte:@de2014amostra" />
Variância do estimador da PNAD pode ser calculada pela aproximação apresentada por @de2014amostra:</p>
\[V(\hat{\theta}) = \sum_{h} \frac{m_h}{m_h - 1} \sum_{i} (\hat{Z}_{hi} - \bar{Z}_{h})^2\]
<p>Onde</p>
\[\hat{Z}_{hi} = \sum_{j} \sum_{k} w^{**}_{gij}\times z_{gijk}\]
\[\bar{Z}_{h} = \frac{1}{m_h}\sum_{i} \hat{Z}_{hi}\]
<p>Esse seria o processo manual para o cálculo do erro. No entanto, é possível calcular o erro amostral em planos amostrais complexos, como o plano de múltiplos estágios da amostra mestra utilizando o pacote @pkgsuurby.</p>
<p>Vamos utilizar os dados da PNAD contínua e comparar as estimativas do pacote Survey e utilizando os procedimentos de aproximação da variância do estimador por meio da Linearização de Taylor @de2014amostra, implementada por meio da função <strong>estimativaplano</strong>, apresentada a seguir.</p>
<p>```{r pacotes,message=FALSE,warning=FALSE}
library(PNADcIBGE)
library(readxl)
library(data.table)
library(tidyverse)
library(reldist)
library(survey)
library(knitr)</p>
<h1 id="função-para-cálculo-manual">Função para cálculo manual</h1>
<p>estimativaplano <- function(base,vars,y,flt=NULL){</p>
<p>.vars <- rlang::syms(vars)
base <- base %>%
mutate(bys = paste(!!!.vars, sep = “-“ ))</p>
<p>.vars <- rlang::syms(y)
base <- base %>%
mutate(y = as.numeric(!!!.vars))</p>
<p># DEPENDENCIA DA ANÁLISE
if(length(flt)>0){
for(itss in 1:length(flt)){
.vars <- rlang::syms(flt[itss])
base <- base %>%
filter(!is.na(!!!.vars))
}
}</p>
<p>base2 <- base %>%
group_by(UPA,Estrato,bys) %>%
summarise(N = sum(ifelse(is.na(y),0,1),na.rm = T),
peso = sum(ifelse(is.na(y),NA,V1028),na.rm = T),
zhi = sum(V1028*y,na.rm = T)) %>%
filter(N>0) %>% as.data.table()</p>
<p>base2[,mh:=length(unique(UPA)),by=c(“Estrato”,”bys”)]
base2[,zhb := sum(zhi*(1/mh),na.rm = T),by=c(“Estrato”,”bys”)]</p>
<p>base2_t <- base2 %>%
group_by(Estrato,mh,bys) %>%
summarise(vtheta = sum((zhi-zhb)^2,na.rm = T))</p>
<p>base2_t <- left_join(base %>%
group_by(bys) %>%
summarise(N=sum(ifelse(is.na(y),0,1),na.rm = T),
peso = sum(ifelse(is.na(y),NA,V1028),na.rm = T),
total = sum(y<em>V1028,na.rm = T)) ,
base2_t %>%
group_by(bys) %>%
summarise(SE= (sum(vtheta</em>(mh/(mh-1)),na.rm = T))^(0.5)),
by = “bys”) %>%
mutate(media = total/peso,
SEmedia = SE/peso,
CVmedia = (SEmedia/media))</p>
<p>a <- data.frame(do.call(
“rbind”,
(str_split(base2_t$bys, “-“,n=length(vars)))
))</p>
<p>names(a) <- vars
base2_t <- cbind(a,base2_t %>% select(-bys))</p>
<p>return(base2_t)</p>
<p>}</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
### Dados PNAD contínua
Inicialmente, os microdados da PNAD contínua e o dicionário de variáveis podem ser encontrados no [FTP do IBGE.](ftp://ftp.ibge.gov.br/Trabalho_e_Rendimento)
![Dicionário de variáveis.](dir.png)
Vamos utilizar a amostragem feita na PNAD para estimativas de renda por variáveis categóricas.A importação dos dados da PNAD são feitos utilizando o pacote @PNADcIBGE de forma direta do ftp do IBGE. Entre os principais parâmetros:
* ano e trimestre;
* variáveis do do questionário e que podem ser consultadas no [dicionário](ftp://ftp.ibge.gov.br/Trabalho_e_Rendimento) da PNAD
* data de referência (deflaciona IPCA para data específica)
Na programação a seguir vamos importar os dados do segundo trimestre de 2020, e colocando a preços de 2020. O processo de importação é fundamental para comparação de informações monetárias entre trimestres.
```{r ck0, echo=TRUE,warning=FALSE,message=FALSE}
anot <- 2020
trimestret <- 2
t0 <- Sys.time()
pnadc.svy <- get_pnadc(year=anot, quarter=trimestret,
vars=c("V2007","V3009A","V2005",
"V4074A","V4078A","V1028",
"V2010","VD4001","VD4002",
"VD4020",# renda total
"VD4030","VD3004",# escolaridade
"VD2003",# numero de pessoas no domicílio
"V1008",#numero do domicilio
"V1022",#Situação do domicílio
"V1023",#capital RIDE
"V2009",#idade
"V2001","V4010","VD4007",
"VD3006","VD4005","VD4002",
"VD4004A","VD3005","VD2002"),
labels=TRUE, design=TRUE)
print(Sys.time()-t0)
</code></pre></div></div>
<h2 id="tratamento">Tratamento</h2>
<p>O tratamento pode ser feito como em qualquer base de dados, utilizando, por exemplo, os pacotes @tidy e @datatable. O processo de importação do pacote @PNADcIBGE já faz a conversão dos códigos para as descrições. Muitas vezes essas conversão não é muito útil, por exemplo, na análise do tempo de estudo. Para isso, algumas transformações são necessárias.</p>
<p>Vamos criar uma nova variável relacionada à variável V2010 (raça) como “branca” e “não branca”. Além disso, a variável tempo de estudo foi convertida para numérica para podermos gerar medidas descritivas. Para isso, utilizamos algumas funções para tratamento de texto por meio de <a href="https://bookdown.org/davi_moreira/txt4cs/stringR.html">expressões regulares</a>.</p>
<p>```{r ck1, echo=TRUE,warning=FALSE,message=FALSE}</p>
<p>base <- pnadc.svy$variables</p>
<p>base <- base %>%
mutate(CODUF = substr(Estrato,1,2),
racabranca = ifelse(V2010==”Branca”,”Branca”,”Não Branca”),
tempestudo = as.numeric(ifelse(gsub(“(\d<em>)\s.</em>”,”\1”,VD3005)==”Sem”,0,gsub(“(\d<em>)\s.</em>”,”\1”,VD3005))))</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
## Totais
Baseado no plano da amostra mestra (múltiplos estágios), podemos verificar que o peso expansivos das observações permitem estimar verificar os quantitativos.
O primeiro total a ser analisado é a população total, somando os pesos de todos os registros. Fazemos isso por meio da função estimavaplano colocando como variávavel desagregadora a variável "Ano", que é a mesma para todos os registros, uma variável quantitativa "y" qualquer (peso após a pós-estratificação "V1028") e selecionando apenas a coluna "peso".
```{r total, echo=TRUE,message=FALSE,warning=FALSE}
# População total
vars <- c("Ano")
y <- c("V1028")
estimativaplano(base,vars,y) %>% select(peso) %>%kable()
</code></pre></div></div>
<p>Também é possível obter os totais de peso por estratos, isto é, as combinações de UF (UF) e tipo de municípios (V1023). Os totais, apresentandos na coluna “peso” são iguais as informações que são disponibilizadas na própria base de dados na variável “V1029”.</p>
<p>Por exemplo, para o estrato <strong>Acre e capital</strong>, temos 4045 registros que totalizam 412726 considerando a expansão dos pesos amostrais, que é exatamente igual ao total apresentado na V1029.</p>
<p>```{r total2, echo=TRUE,message=FALSE,warning=FALSE}</p>
<h1 id="população-uf-estrato">População UF (ESTRATO)</h1>
<p>vars <- c(“Ano”,”UF”,”V1029”,”V1023”)
y <- c(“V1028”)
UFS <- estimativaplano(base,vars,y)</p>
<p>head(UFS) %>% select(UF,V1029,V1023,N,peso)%>%kable()</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Unidades Primárias de Seleção (UPAs), selecionadas de por meio de aleatória simples e proporcional ao número de domicílios, são subdivisões de domicílios dentro de cada estrato. A UPA 120000037 do Acre tem 29 registros totalizam 2465.152 considerando a expansão dos pesos amostrais. Perceba que, diferente dos estratos, os pesos não são inteiros, pois a plano amostral da PNAD contínua é feito para, no máximo, estimativas a nível de UF.
```{r total3, echo=TRUE,message=FALSE,warning=FALSE}
# População UF (UPA)
vars <- c("Ano","UF","UPA")
y <- c("V1028")
UPAs <- estimativaplano(base,vars,y)
head(UPAs) %>% select(UF,UPA,N,peso) %>%kable()
</code></pre></div></div>
<p>Também é possível obter o total de domicílios selecionados em cada UPA. É importanto destacar que esse total é planejado para ser fixo. Após a coleta e com base nas informações coletadas, os pesos são ajustados pós-estratificação. Na UPA 110000016 foram amostrados 11 domicílios, que totalizam, considerando os pesos, um total de 6190.673 pessoas. Para a UPA 120000037, o domicílio 01 tem 2 pessoas que totalizam 170.0105 como peso.
Nessa mesma UPA, o domicílio 04 foram coletadas informações de 3 pessoas, que totalizam peso de 255.0157.</p>
<p>```{r total4, echo=TRUE,message=FALSE,warning=FALSE}</p>
<p>vars <- c(“Ano”,”UF”,”UPA”,”V1008”)
y <- c(“V1028”)
doms <- estimativaplano(base,vars,y)</p>
<h1 id="domicílios-e-pessoas-por-upa">Domicílios e pessoas por UPA</h1>
<p>domsUPAs <- doms %>%
group_by(UPA) %>%
summarise(domicilios = length(Ano),
pessoas = sum(peso))</p>
<p>head(domsUPAs) %>% kable()</p>
<p>head(doms) %>% select(UPA,V1008,N,peso) %>%kable()</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
## Referências e Pacotes
Baseado na referência de @de2014amostra, podemos comparar os resultados do pacote @pkgsuurby com o que a literatura sugere. A tabela a seguir compara a renda média dos brasileiros.
```{r ck2, echo=TRUE,message=FALSE,warning=FALSE}
vars <- c("Ano")
y <- "VD4020"
t0 <- Sys.time()
rendaBR <- estimativaplano(base,vars,y)
Sys.time() - t0
t0 <- Sys.time()
mediapacote <- survey::svymean(x=~VD4020, design=pnadc.svy, na.rm=TRUE)
Sys.time() - t0
#Pacote
mediapacote%>% kable()
#Função estimaplano
rendaBR %>% select(media,N,SEmedia,CVmedia) %>% kable()
</code></pre></div></div>
<p>Percebe-se que o erro estimado pela função “estimativaplano” é maior do que a observação pelo pacote @pkgsuurby. Há inúmeros explicações para tal diferença, a começar pela falta de conhecimento específico dos autores com relação às etapas de estimação em planos amostrais complexos. No entanto, baseado nas informações da aproximação proposta por @de2014amostra e tendo em vista que as estimativas dos erros são próximas, mas subestimados, considerando o pacote como verdadeiro, torna-se razoável a utilização da função proposta, principalmente pelos fins didáticos do post. Além disso, a função gera os valores é, pelo menos, 2 vezes mais rápido do que o pacote.</p>
<p>O exercício a seguir compara a renda média dos brasileiros por raça. . Os brasileiros que se declaram com raça “Branca” tem, em média, renda média de R$ 2971.044, enquanto os que se declaram com raça “Preta”, tem, em média, R$ 1718.876. As duas estimativas tem coeficiente de variação muito próximos. A diferença em mais de R$ 1000 apresenta evidências da diferença entre remuneração das raças.</p>
<p>```{r ck222, echo=TRUE,message=FALSE,warning=FALSE}</p>
<p>vars <- c(“V2010”)</p>
<p>y <- “VD4020”</p>
<p>t0 <- Sys.time()
rendaRACA <- estimativaplano(base,vars,y)
Sys.time() - t0</p>
<p>rendaRACA %>% select(V2010,N,media,SEmedia,CVmedia) %>% kable()</p>
<p>ggplot(rendaRACA) +
geom_bar(aes(weight = media,x = V2010))+
xlab(“Anos de estudo”) +
ylab(“Renda média (R$)”)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
No entanto, podemos melhorar essa análise, considerando outras variáveis que possam tornar mais comparável a remuneração recebida. E se a diferença de remuneração média for reflexo do tempo de estudo, e não da raça? Vamos verificar adicionado a desagregação de tempo de estudo.
```{r ck3, echo=TRUE,message=FALSE,warning=FALSE}
vars <- c("tempestudo","V2010")
y <- "VD4020"
rendaestudo <- estimativaplano(base,vars,y)
rendaestudo <- rendaestudo %>% mutate(tempestudo = as.numeric(tempestudo)) %>% select(V2010,tempestudo,N,media,SEmedia,CVmedia) %>% filter(V2010 %in% c("Branca","Preta") )
rendaestudo <- rendaestudo %>%
arrange(tempestudo)
ggplot(rendaestudo,aes(x = tempestudo, y = media,col=V2010)) +
geom_line(size=1)+
xlab("Anos de estudo") +
ylab("Renda média (R$)")
</code></pre></div></div>
<p>Por meio das tabela a seguir, percebe-se que aqueles que se declaram com raça “Preta” tem em média, 8.79 anos de estudo, enquanto os que se declaram com raça “Branca” têm, em média, 9.84 anos de estudo. Então, o fator tempo de estudo também pode explicar a diferença de remuneração.</p>
<p>Agora, vamos fazer a diferença entre as remuneração para cada nível de estudo. Percebe-se que a diferença é superior a R$ 1000 apenas nos que estudam mais de 15 anos.</p>
<p>```{r ck33, echo=TRUE,message=FALSE,warning=FALSE}</p>
<p>vars <- c(“V2010”)</p>
<p>y <- “tempestudo”
TEMestudo <- estimativaplano(base,vars,y)</p>
<p>TEMestudo %>% select(V2010,media,SEmedia) %>% kable()</p>
<p>difrendaestudo <- rendaestudo %>% select(tempestudo,V2010,media) %>%
filter(!is.nan(media)) %>% spread(key = “V2010”,value=”media”)</p>
<p>difrendaestudo$Dif <- difrendaestudo$Branca - difrendaestudo$Preta</p>
<p>difrendaestudo %>% kable()</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
Vamos fazer a mesma análise utilizando a variável sexo. A análise geral, a mulher ganha em média R$ 500 a menos do que o homem. No entanto, o tempo médio de estudo da mulher é maior do que o homem. Dessa forma, temos que para o mesmo tempo de estudo, a diferença entre sexo é maior do que entre raças.
```{r ck3333, echo=TRUE,message=FALSE,warning=FALSE}
vars <- c("V2007")
y <- "tempestudo"
TEMestudo <- estimativaplano(base,vars,y)
TEMestudo %>% select(V2007,media,SEmedia) %>% kable()
vars <- c("tempestudo","V2007")
y <- "VD4020"
rendasexo <- estimativaplano(base,vars,y)
rendasexo<- rendasexo %>% mutate(tempestudo = as.numeric(tempestudo)) %>%
select(V2007,tempestudo,media,SEmedia,CVmedia) %>% filter(!is.nan(media))
ggplot(rendasexo,aes(x = tempestudo, y = media,col=V2007)) +
geom_line(size=1)+
xlab("Anos de estudo") +
ylab("Renda média (R$)")
difrendasexo <- rendasexo %>% select(tempestudo,V2007,media) %>%
spread(key = "V2007",value="media")
difrendasexo$Dif <- difrendasexo$Homem - difrendasexo$Mulher
difrendasexo %>% kable()
</code></pre></div></div>
<h2 id="amostragem-em-machine-learning">Amostragem em <em>Machine Learning</em></h2>
<p>Apesar das técnicas de amostagem clássicas não estarem inseridas de forma convecional em <em>Machine Learning</em> (ML), muitos conceitos da área são utilizados. Esta seção relata algumas técnicas de ML que utilizam conceitos de amostragem por construção, não com objetivo de apresentar toda a extensa teoria de cada método, mas apresentá-los expondo a utilização de amostragem neste contexto.</p>
<h3 id="bootstrap"><em>Bootstrap</em></h3>
<p>O <em>bootstrap</em> foi desenvolvido por @efron1979 e ajuda a aprender sobre as características da amostra pela obtenção de reamostragem (reamostragem da amostra original com reposição) e utiliza-se essa informação para inferir sobre à população [@casella2011inferencia].</p>
<p>O Método é utilizado, em geral, para estimar o erro padrão de estimadores. Suponha que tenhamos uma amostra $\mathbf{x} = (x_1,x_2,\ldots, x_n)$ e uma estimativa $\hat{\theta}( x_1,x_2,\ldots, x_n) = \hat{\theta}$, ao selecionarmos $B$ reamostras (ou amostras <em>bootstrap</em> ) podemos calcular a variabilidade de $\hat{\theta}$:
\(Var^{*}_{B}(\hat{\theta}) = \frac{1}{B-1}\sum_{i=1}^{B} (\hat{\theta^{*}_i} - \overline{\hat{\theta^{*}}})^2.\)
A operacionalização da técnica pode ser resumida em $4$ passos:</p>
<p>(1). Iniciar com uma amostra;</p>
<p>```{r, echo=FALSE, message=FALSE, warning=FALSE}</p>
<p>set.seed(150)
library(ggplot2)
library(data.table)
library(dplyr)
library(tidyverse)</p>
<p>library(datarium)</p>
<p>amostra.original <- data.frame(x= rnorm(150,3,1))</p>
<p>ggplot(amostra.original, aes(x=x,y=..density..)) +
geom_histogram() + xlab(“Amostra Original”)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
(2). Reamostrar da amostra original B vezes;
```{r, message=FALSE, warning=FALSE}
B <- 1000
x.boot <- replicate(B,sample(amostra.original$x,replace=T)) #Não-Paramétrico
</code></pre></div></div>
<p>```{r, echo=FALSE, message=FALSE, warning=FALSE}
x.boot.sample <- data.frame(B=c(1,2,”3…”,”…101”,102,”103…”,”…501”,”502…”,”…B”),x = t(x.boot[,c(1:3,101:103,501:502,1000)])) %>% gather(“Cenario”,”Amostra Bootstrap”,-B)</p>
<p>ggplot(x.boot.sample %>% mutate(B=ordered(B, c(1,2,”3…”,”…101”,102,”103…”,”…501”,”502…”,”…B”))), aes(x=<code class="language-plaintext highlighter-rouge">Amostra Bootstrap</code>,y=..density..)) +
geom_histogram() + xlab(“Amostras Bootstrap”) + facet_wrap(~B)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
(3). Computar a estatística de interesse para cada amostra;
```{r, message=FALSE, warning=FALSE}
x.bar <- apply(x.boot,2,mean)
</code></pre></div></div>
<p>```{r, echo=FALSE, message=FALSE, warning=FALSE}
x.boot.sample <- data.frame(B=c(1,2,”3…”,”…101”,102,”103…”,”…501”,”502…”,”…B”),x = t(x.boot[,c(1:3,101:103,501:502,1000)])) %>% gather(“Cenario”,”Amostra Bootstrap”,-B)</p>
<p>ggplot(data.frame(x.bar=x.bar), aes(x=x.bar,y=..density..)) +
geom_histogram() + xlab(expression(paste(“Distribuição Bootstrap de “,bar(x),sep = “”)))</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
(4). Utilizar distribuição *bootstrap* para fazer inferência. A distribuição *bootstrap* se trata das **B** estimativas da estatísica de interesse, pois ao se aplicar o método não se tem apenar uma estimativa calculada, mas **B** baseadas nas reamostras.
```{r, message=FALSE, warning=FALSE}
(ep.bootstrap <- sqrt(var(x.bar))) # Estimativa bootstrap não-paramétrica para o erro padrão
round(quantile(x.bar,probs = c(.025,.975)),2) # Intervalor de Confiança Percentil Bootstrap
</code></pre></div></div>
<p>Apesar de apresentarmos um método simples para cálculo do intervalo de confiança bootstrap, alertarmos ao leitor
que é necessário muito cuidado quando calculamos estes intervalos em problemas mais complexos como
regresão linear, robusta ou não-linear.</p>
<p>Em muitos casos, <em>bootstrap</em> oferece um estimador razoável que é consistente.
\(Var^{*}_{B}(\hat{\theta}) \xrightarrow{B \xrightarrow{} \infty } Var^{*}(\hat{\theta}),\)
\(Var^{*}(\hat{\theta}) \xrightarrow{n \xrightarrow{} \infty } Var(\hat{\theta}),\)</p>
<p>no qual, $Var^{<em>}(\hat{\theta}) = \frac{1}{n^n-1}\sum_{i=1}^{n^n} (\hat{\theta^{</em>}_i} - \overline{\hat{\theta^{*}}})^2.$</p>
<p>Apesar do conceito ser intuitivo e de fácil aplicabilidade, a teoria por trás do <em>bootstrap</em> é bastante sofisticada, tendo como base as expansões de <em>Edgeworth</em>, expansões de funções de distribuição acumulada em torno de uma distribuição normal. A teoria recebe abordagem completa em @hall2013bootstrap.</p>
<p>@diciccio1988review cita quatro razões para popularidade do método Bootstrap:</p>
<ul>
<li>
<p>Elegância: como muitas das melhores idéias matemáticas, o princípio em que se baseia a técnica bootstrap,
de reamostragem (<em>resampling</em>) dos dados observados para estimaçãao da distribuição populacional,é
simples, elegante e muito poderoso;</p>
</li>
<li>
<p>Entendimento: o processo de <em>resampling</em> torna fácil a compreensão da idéia básica do método;</p>
</li>
<li>
<p>Sutileza Matemática: existe complexidade teórica suficiente no método para fascinar os intelectuais da
área de matemática;</p>
</li>
<li>
<p>Facilidade de uso: em contrapartida, para o prático, existe a esperança de uma metodologia automática
cuja implantação em softwares é questão de tempo.</p>
</li>
</ul>
<p>Sua fácil aplicabilidade torna o método uma poderosa ferramenta, com possibilidade de ser utilizado em muitas técnicas de <em>machine learning</em>, incluindo algumas que uma medida de variabilidade é difícil de se obter. Ressalta-se que a técnica de <em>Bootstrap</em> utiliza, basicamente, o conceito de amostragem aleatória simples com reposição.</p>
<h3 id="avaliação-da-qualidade-de-ajuste">Avaliação da Qualidade de Ajuste</h3>
<p>Com a concepção que nenhum método de ML domina todos os outros sobre todos possíveis conjuntos de dados, existe a necessidade de avaliar cada técnica testada e, assim, identificar a melhor para cada caso e propósito. O objetivo de muitas aplicações de <em>machine learning</em> é fazer previsões para observações não vistas anteriormente e, usualmente, utiliza-se alguma medida que dimensione o quanto o valor da resposta previsto para uma determinada observação está próximo do valor de resposta verdadeiro para essa observação. O erro quadrático médio, dado pela expressão abaixo, é amplamente utilizado no contexto de regressão.</p>
<p>\(EQM = \frac{1}{N}\sum_{i=1}^{N} ((y_i) - \hat{f}(x_i))^2,\)
no qual $\hat{f}(x_i)$ é a previsão para a observação $i$. Quanto menor o valor do $EQM$, mais perto a previsão está do valor verdadeiro. A utilização míope desta regra pode gerar conclusões equívocadas sobre a qualidade de ajuste, abaixo apresentamos um exemplo.</p>
<p><img src="regression.png" alt=" Dados simulados de uma função ($f$) hipotética, mostrada em preto. Três estimativas ($\hat{f}$) são mostradas: a linha de regressão linear (curva laranja) e dois ajustes da interpolação spline com suavização (curvas azul e verde). Fonte: @james2013introduction " /></p>
<p>Com parâmetros suficientes, um modelo ajusta qualquer conjuntos de dados e a utilização direta de um critério de seleção que minimize o erro quadrático médio pode incorporar <em>overfitting</em> a análise. Pode ser observado na imagem acima que a inclusão de mais termos ao modelo (linhas azul e verde) melhorou o ajuste, mas isso pode restringir a capacidade do modelo de generalização para novas situações. Johnny Von Neumann disse uma famosa frase: “com quatro parâmetros eu posso ajustar um elefante, e com cinco eu posso fazê-lo mexer seu tronco”[@mayer2010drawing].</p>
<p>Com objetivo de mitigar essa possível complicação, as técnicas de ML, em geral, utilizam a abordagem de dividir a amostra original em amostras de treino e de teste para avaliação da qualidade de ajuste. A técnica consite em utilizar o conceito de amostragem aleatória simples e dividir o conjuntos de dados em duas partes, uma para estimar os coeficientes do modelo e outra para avaliar a qualidade de previsão do modelo em observações que não fizeram parte do processo de estimação. O menor erro de teste (diferença entre valor previsto e verdadeito para amostra de teste) pode ser definido como critério de escolha do modelo.</p>
<h3 id="validação-cruzada">Validação Cruzada</h3>
<p>A estimativa do erro de teste (erro calculado utilizando a amostra de teste) pode apresentar alta variabilidade porque é dependente da amostragem realizada no conjuntos de dados. De forma mais específica, o processo de determinação das amostras de treino e teste envolve uma amostragem aleatória simples e, assim, se o processo for repetido $k$ vezes, ou seja, composiçaõ de $k$ amostras de teste, teremos $k$ diferentes estimativas de erro de teste as quais podem apresentar alta variabilidade. As técnicas de Validação Cruzada (<em>Cross Validation</em>) refinam o conceito de validação do modelo.</p>
<p>A técnica de <em>Leave-one-Out</em> é diretamente relacionada ao conceito de avaliação de qualidade de ajuste e divisão da amostra original em duas, mas ao invés de dividir a amostra original em duas de tamanho $m$ e $(n-m)$, divide a amostra em uma de tamanho $n-1$ e outra de tamanho $1$. Utiliza-se as $n-1$ observações para estimar o modelo e a observação deixada de fora para avaliar a qualidade de previsão fora da amostra (validação), repete-se esse processo iterativamente até que todas as observações tenham sido deixado de fora em algum momento. Dessa forma, se tem não apenas uma estimativa de erro de teste, mas $n$ que são utilizadas para estimar o erro de teste da validação cruzada (média dos erros individuais). Esse método reduz o viés da estimativa do erro de teste porque utiliza $n-1$ observações para estimar o modelo e não é afetado pela aleatoriedade característico de um processo de amostragem.</p>
<p>Uma desvantagem de <em>Leave-one-Out</em> é o custo computacional porque é necessário estimar o modelo $n$ vezes e no contexto de <em>big data</em> isto se torna impraticável. Uma alternativa é o método de <em>k-folds</em> que envolve dividir aleatoriamente o conjunto de observações em k grupos de tamanho aproximadamente igual. O primeiro grupo é tratado como um conjunto de validação e o método é ajustado nos k - 1 grupos restantes. As figuras abaixo ilustram as técnicas. Vale ressaltar que as técnicas de Validação Cruzada não são utilizadas apenas para avaliar a qualidade de ajuste, mas também para definir parâmetros de ajuste (<em>tuning parameter</em>) que não podem ser estimados diretamente da base de dados (ex. o parâmetro de penalidade de uma regressão <em>ridge</em>).</p>
<p><img src="loocv.png" alt=" *Leave-one-Out* " />{width=40%} <img src="kfolds.png" alt=" *k-folds* " />{width=40%}</p>
<p>O exemplo em R abaixo aplica o conceito no contexto de regressão linear. O código foi desenvolvio com objetivo de auxiliar no entendimento dos métodos, mas a maior parte das técnicas de Validação Cruzada estão implementadas de forma otimizada no pacote <em>caret</em>.</p>
<p>```{r, message=FALSE, warning=FALSE}</p>
<p>##BASE DE DADOS EXEMPLO
data(marketing) #Base de dados exemplo contendo o impacto de três mídias publicitárias (youtube, facebook e jornal) nas vendas.</p>
<p>#MÉTODO LEAVE ONE OUT</p>
<p>cv.errors.loo <- numeric()
for(i in 1:nrow(marketing)){
fit =lm(sales∼.,data=marketing[-i,])
pred=predict(fit,marketing[i,])
cv.errors.loo[i] = (marketing$sales[i]-pred)^2
}</p>
<p>mean(cv.errors.loo) #Erro Quadrático Médio Leave One Out</p>
<h1 id="método-k-folds">MÉTODO K-FOLDS</h1>
<p>k=10
set.seed(114)
folds=sample(1:k,nrow(marketing),replace =TRUE)#Amostra aleatória simples</p>
<p>cv.errors.kfolds <- numeric()
for(j in 1:k){
fit =lm(sales∼.,data=marketing[j!=folds,])
pred=predict(fit,marketing[j==folds,])
cv.errors.kfolds[j] = mean( (marketing$sales[folds ==j]-pred)^2)
}</p>
<p>mean(cv.errors.kfolds) #Erro Quadrático Médio K-Folds</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
### Árvore de Decisão
Técnica utilizada para problemas de classificação e regressão que consiste em dividir o espaço preditor em regiões (${X|X_j>s}$ e ${X|X_j<s}$) que fornecem a maior redução de alguma medida de erro. O método tende a fornecer boa interpretabilidade mas baixo poder de previsão.
De maneira simplificada, o método pode ser entendido em duas etapas: dividir o espaço preditor (determinar possíveis valores para as variáveis preditoras $X_1,X_2,...,X_k$) em $p$ regiões distintas e não sobrepostas $R_1,R_2,...,R_p$;para cada observação que ficar na região $R_p$, fazemos a mesma previsão, que é simplesmente a média dos valores de resposta para as observações de treinamento em $R_p$ [@james2013introduction].
```{r, message=FALSE, warning=FALSE}
library(tree)
marketing <- marketing %>% mutate(sales.c = factor(ifelse(sales<15,0,1)))
tree.mkt =tree(sales.c∼.-sales ,marketing)
summary(tree.mkt)
plot(tree.mkt)
text(tree.mkt,pretty = 0)
</code></pre></div></div>
<h3 id="bagging">Bagging</h3>
<p>Procedimento de propósito geral para reduzir a variância de um método de ML. Utilizando conceitos de inferência estatística (dado $x_1,x_2,…,x_n$ $iid$ normais então $\overline{x} \sim N(\mu,\mathbf{\frac{\sigma^2}{n}})$, ou seja, variânvia de $\overline{x}$ é menos do que variância de $x$), aplica-se o método de ML em B amostras <em>Bootstrap</em> e utiliza-se a média dos resultados como previsão.
\(\hat{f}(x) = \frac{1}{B}\sum_{b=1}^B \hat{f}^b(x).\)
Aplicado em árvore de decisão fornece melhorias na precisão ao combinar centenas ou mesmo milhares de árvores em um único procedimento.</p>
<p>```{r, message=FALSE, warning=FALSE}</p>
<p>library (randomForest)
set.seed (1)</p>
<p>bag.mkt =randomForest(sales.c∼.-sales,data=marketing, mtry=3, importance =TRUE) #mtry = 3 considera todas as variáveis (Bagging)
bag.mkt</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
### Floresta Aleatória
O método de *Bagging* tende a utilizar as mesmas variáveis para construir as árvores de decisão em cada amostra *Bootstrap*, gerando árvores correlacionadas o que impacta a redução de variância. As florestas aleatórias (FA) superam esse problema, forçando cada divisão a considerar apenas um subconjunto dos preditores.
$$
\hat{f}^{*}(x) = \frac{1}{B}\sum_{b=1}^B \hat{f}^{*}_b(x).
$$
Em geral utiliza-se um grupo de $m=\sqrt{p}$ variáveis para construir cada árvore de decisão.
```{r, message=FALSE, warning=FALSE}
library (randomForest)
set.seed (1)
rf.mkt =randomForest(sales.c∼.-sales,data=marketing, mtry=2, importance =TRUE)
rf.mkt
</code></pre></div></div>
<h3 id="floresta-aleatória-em-big-data">Floresta Aleatória em <em>Big</em> <em>Data</em></h3>
<p>A redução de correlação entre as árvores de decisão é a motivação para construção de FA. Entretanto o desempenho do método é dependente da performance de cada árvore de decisão, ou seja, se muitas árvores apresentarem baixo poder de previsão, o método irá apresentar estimativas ruins (ou classificações ruins).</p>
<p>No contexto de <em>Big Data</em>, uma grande proporção de preditores não são informativos para a análise e a utilização de amostragem aleatória simples tende a gerar árvores de decisão com baixo poder de previsão.
@ye2013stratified apresentam uma metodologia que utiliza amostragem <strong>estratificada</strong> para construção da floresta aleatória.</p>
<p>A ideia dos autores se baseia em dividir as $p$ variáveis em dois grupos: muito informativo e pouco informativo. Em seguida, selecionamos aleatoriamente variáveis de cada grupo, garantindo que temos características representativas de ambos. Esta abordagem garante que cada subespaço contenha informação suficiente para a finalidade.</p>
<p>Considera-se uma função não negativa $\phi$ que capture o grau de explicação da variável $p_i$ com respeito a variável resposta $Y$. Normaliza-se $\phi_i$:</p>
\[\theta_i = \frac{\phi_i}{\sum_{k=1}^N \phi_k}\]
<p>As variáveis preditoras são ordenadas segundo $\theta_i$ e determina-se um limiar $\alpha$ que irá dividir as variáveis em dois grupos. O algoritmo proposto constrói um modelo de floresta aleatório considerando os estratos para produzir cada árvore de decisão.</p>
<h3 id="referências">Referências</h3>
<p>@article{Hansen1982,
author = {Hansen, Lars Peter},
doi = {10.2307/1912775},
file = {:home/joaogabrielsouza/{'{A}}rea de Trabalho/PPGA/Doutorado{_}Financas/Tese - Financas Bancarias/Artigos Tese/Ensaio 2/Hansen - Large Sample Properties of Generalized Method of Moments Estimators - 1982 - Econometrica.pdf:pdf},
issn = {00129682},
journal = {Econometrica},
month = {jul},
number = {4},
pages = {1029-1054},
title = ,
url = {https://www.jstor.org/stable/1912775?origin=crossref},
volume = {50},
year = {1982}
}</p>
<p>@misc{Cochrane2017,
author = {Cochrane, John H},
file = {:home/joaogabrielsouza/{'{A}}rea de Trabalho/PPGA/Artigos/Cochrane - GMM_notes.pdf:pdf},
pages = {210–231},
title = ,
year = {2017}
}</p>
<p>@article{Newey1987,
author = {Newey, Whitney K and West, Kenneth D},
file = {:home/joaogabrielsouza/.local/share/data/Mendeley Ltd./Mendeley Desktop/Downloaded/Newey, West - 1987 - A Simple, Positive Semi-Definite, Heteroskedasticity and Autocorrelation Consistent Covariance Matrix.pdf:pdf},
journal = {Econometrica},
number = {3},
pages = {703–708},
title = ,
volume = {55},
year = {1987}
}</p>
<p>@article{Fama1993,
author = {Fama, Eugene F. and French, Kenneth R.},
doi = {10.1016/0304-405X(93)90023-5},
file = {:home/joaogabrielsouza/.local/share/data/Mendeley Ltd./Mendeley Desktop/Downloaded/Fama, French - 1993 - Common risk factors in the returns on stocks and bonds.pdf:pdf},
issn = {0304405X},
journal = {Journal of Financial Economics},
number = {1},
pages = {3–56},
pmid = {295138},
publisher = {Elsevier},
series = {Journal of Financial Economics},
title = ,
volume = {33},
year = {1993}
}</p>
<p>@article{mayer2010drawing,
title={Drawing an elephant with four complex parameters},
author={Mayer, J{"u}rgen and Khairy, Khaled and Howard, Jonathon},
journal={American Journal of Physics},
volume={78},
number={6},
pages={648–649},
year={2010},
publisher={American Association of Physics Teachers}
}</p>
<p>@book{james2013introduction,
title={An introduction to statistical learning},
author={James, Gareth and Witten, Daniela and Hastie, Trevor and Tibshirani, Robert},
volume={112},
year={2013},
publisher={Springer}
}</p>
Modelo CAPM: precificando ações2020-09-24T23:59:15+00:00http://lamfo-unb.github.io/2020/09/24/Modelo-CAPM-precificando-ações<h1 id="modelo-capm-precificando-ações">Modelo CAPM: precificando ações</h1>
<p>O CAPM (Capital Asset Pricing Model) é um modelo de precificação de ativos que relaciona o risco e retorno dos ativos. Esse modelo é relativamente novo, ao se comparar quando as ações surgiram.</p>
<p>O CAPM pode ser expresso por meio da equação abaixo:</p>
\[R_i = R_f + \beta_i(R_m – R_f)\]
<p>Em que:</p>
<ul>
<li>$R_i$ = taxa de retorno esperada do ativo.</li>
<li>$R_m$ = taxa de retorno esperada da carteira de mercado</li>
<li>$R_f$ = taxa de retorno de ativo sem risco</li>
<li>$\beta_i$ = coeficiente beta do ativo</li>
</ul>
<p>Assim, segundo o CAPM, o retorno esperado de ativo $i$ é taxa livre de risco $R_f$ mais um prêmio que é ponderado por um coeficiente $\beta_i$. Esse coeficiente incorpora uma medida de risco para o ativo $i$.</p>
<h3 id="interpretando-o-beta">Interpretando o $\beta$</h3>
<p>De modo geral, o $\beta$ mede a sensibilidade do retorno do ativo $i$ a variações dos retornos da carteira de mercado. Isto é, o beta de um ativo é a variação percentual esperada no retorno do ativo, dado a variação de $1\%$ no retorno da carteira de mercado.</p>
<p>Para uma compreensão mais profunda sobre o papel do $\beta$ é necessário relacioná-lo com os conceitos de risco sistêmico e risco idiossincrático. O risco de um ativo é dividido em duas partes: o idiossincrático, que é o risco associado a fatores que afetam apenas o ativo em questão; e o rico de sistêmico, que se devem a fatores que afetam todos ativos do mercado. Maiores detalhes podem ser encontrados nesse <a href="https://lamfo-unb.github.io/2020/01/22/Markowitz-selecao-carteiras/">post</a>.</p>
<p>Os investidores podem se livrar do risco idiossincrático através da diversificação, mas não podem se livrar do risco de mercado. Por essa razão, o risco idiossincrático e o risco sistêmico são conhecidos também como risco diversificável e risco não diversificável.</p>
<p>A frase que diz: “Quanto maior o risco, maior o retorno esperado” não está totalmente correta, uma vez que apenas o risco não diversificável é renumerado. Pois, caso o risco diversificável fosse renumerado, os agentes poderiam realizar arbitragem ao receberem a renumeração por esse tipo de risco e livrarem-se dele através da diversificação. Dessa forma, a frase mais correta seria: “Quanto maior o risco não diversificável, maior o retorno esperado”.</p>
<p>A razão para falar disso se deve à definição de carteira de mercado. Como discutido nesse <a href="https://lamfo-unb.github.io/2020/01/22/Markowitz-selecao-carteiras/">post</a>, a carteira de mercado é uma carteira pertencente a fronteira eficiente, sendo a mais diversificável possível. Portanto, ela contém apenas risco não diversificável.</p>
<p>Considerando isso, o $\beta$ de um ativo pode ser interpretado como a sensibilidade do retorno do ativo ao risco de mercado. Portanto, quanto maior o $\beta$ maior a renumeração esperada para o ativo.</p>
<p>Formalmente, o $\beta$ é dado por:</p>
\[\beta_i = \frac{Cov(R_i, R_m)}{Var(R_m)}\]
<p>Colocando o $\beta$ em termos de variâncias e correlações:</p>
\[\beta_i = \frac{\sigma_i \sigma_m \rho_{im}}{\sigma_m^2}\]
<p>Portanto,</p>
\[\beta_i = \frac{\sigma_i \rho_{im}}{\sigma_m}\]
<p>Tal que, $\sigma_i$ é a variância dos retornos do ativo $i$, $\sigma_m$ é a variância dos retornos da carteira de mercado e $\rho_{im}$ é a correlação entre os retornos do ativo $i$ e os retornos da carteira de mercado.</p>
<p>Na relação acima, o numerador $\sigma_i \rho_{im}$ é parte do risco do ativo que é comum com o risco de mercado e o denominador $\sigma_m$ é o risco de mercado. Assim, o $\beta_i$ é o risco sistemático do ativo $i$ ponderando pelo risco sistemático de todo o mercado $\sigma_m$. Desta forma, se $\beta_i > 1$, então o ativo $i$ possui mais risco de mercado que a carteira de mercado e, portanto, deve ter maior renumeração do que ela e vice-versa.</p>
<p>Além disso, o retorno do ativo tem relação linear com $\beta$. Podemos representar o retorno esperado como uma função linear do $\beta$:</p>
<figure>
<img src="https://i.imgur.com/EEGev1t.png" style="display: block; margin: auto; width: 70%; height: 70%;" />
</figure>
<p>A reta acima é conhecida como <em>Security Marketing Line (SML)</em>, ela mostra a relação entre $\beta$ e o retorno esperado. Para $\beta = 1$, o ativo correspondente tem mesmo risco de mercado que a carteira de mercado, portanto possui a mesma renumeração $R_m$. Além disso, a inclinação da reta é dada por $(R_m - R_f)$, que é a renumeração excedente em relação à taxa livre de risco $R_f$.</p>
<h3 id="pressupostos-do-capm">Pressupostos do CAPM</h3>
<p>O CAPM possui um conjunto fundamentos sobre a hipótese de mercados eficientes. Dentre eles, espera-se que os investidores sejam racionais e que estão dispostos a aceitar um prêmio pelo risco como medida de compensação. Além disso, são avessos ao risco, ou seja, desejam minimizar o risco, tudo mais constante.</p>
<p>Para que o mercado de capitais seja eficiente, espera-se que seja competitivo, exista um grande número de investidores que não têm poder para influenciar individualmente o mercado. E os preços reflitam todas as informações disponíveis e que os investidores tenham pleno acesso a essas informações. Ademais, presume-se que não há impostos sobre as transações, e se houver, que não gerem distorções.</p>
<p>O modelo também supõe que o retorno esperado do ativo e do mercado sejam previsíveis, ou calculáveis. Note que, na prática, é praticamente impossível atender todas essas premissas. Entretanto o modelo é uma ferramenta extensivamente utilizada e apresenta um referencial teórico de grande importância na avaliação de risco e retorno.</p>
<h3 id="usos-do-modelo-capm">Usos do modelo CAPM</h3>
<p>O modelo <em>CAPM</em> possui várias aplicações, entretanto, ele é frequentemente usando em duas situações: precificar e comparar ativos e estimar o custo de capital próprio.</p>
<p>No primeiro caso, o modelo CAPM fornece uma taxa de retorno esperada para o ativo. Suponha que um investidor deseja escolher um conjunto de ações para investir, um critério de escolha é usar o retorno esperado das ações. O CAPM fornece um meio de estimar esses retornos, além disso, fornece uma medida de risco de mercado para ação.</p>
<p>Uma medida de risco frequentemente utilizado para comparar a performance entre ativos é o índice de <em>Sharpe</em>. Ele mede a taxa de retorno por unidade de risco, assim dado uma carteira <em>P</em>, o índice de sharpe é calculado como:</p>
\[I_s(P) = \frac{R_m - R_p}{\sigma_p}\]
<p>Assim, quanto maior o $I_s$, melhor o desempenho da carteira ponderado pelo o seu próprio risco. Entretanto, essa medida não é mais acurada, uma vez que ela considera risco não renumerável. Dessa forma, o $\beta$ acaba sendo uma medida melhor.</p>
<p>No segundo caso, o CAPM é utilizado para estimar o custo de capital próprio de uma empresa.</p>
<p>O custo de capital próprio de uma empresa pode ser definido como a taxa de retorno que os acionistas esperam ganhar em troca por investir os seus recursos na empresa. O custo de capital $(K)$ própria é estimado como:</p>
\[K = R_f + \beta(R_m - R_f)\]
<p>Sendo facilmente estimado quando a empresa possui ações listadas no mercado.</p>
<p>Além disso, a taxa $K$ fornece uma forma de avaliar a viabilidade de projetos com capital próprio na empresa. O valor presente líquido (VPL) é uma técnica largamente empregado para avaliar a viabilidade de projetos, o critério de avaliação é se $VPL > 0$ o projeto é viável. Essa técnica consiste em descontar o valor dos fluxos de caixa futuros por uma taxa apropriada, que reflete a risco do projeto e a taxa $K$ é justamente isso. De forma mais abrangente, o VPL pode ser usado para estimar valor total da empresa.</p>
<p>Um empecilho para a aplicação do CAPM é a necessidade de uma carteira de mercado, que relativamente difícil de ser calculada. Na prática, os investidores usam uma <em>proxy</em> para essa carteira. Na Bovespa, o índice Ibovespa é bastante utilizado como <em>proxy</em>.</p>
<h3 id="aplicando-modelo-capm-na-bovespa">Aplicando modelo CAPM na <em>Bovespa</em></h3>
<p>O primeiro passo logo após importar as bibliotecas foi incluir os dados. As empresas escolhidas para essa demonstração didática foram:</p>
<ul>
<li>CMIG3 – Cemig (energia elétrica)</li>
<li>ELET3 – Eletrobrás (energia elétrica)</li>
<li>ITUB4 – Itaú Unibanco (setor bancário)</li>
<li>LREN3 – Lojas Renner (Varejista de roupas)</li>
</ul>
<p>Como carteira de mercado, será considerado o índice Bovespa (BVSP).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Importar as bibliotecas que serão utilizadas
</span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="n">sns</span>
<span class="c1">#Criar os Dataframes dos ativos analisados
#Data frames de 01-07-2019 a 30-07-2020
#Criar os Dataframes dos ativos analisados
</span><span class="s">'Data frames de 01-07-2019 a 30-07-2020'</span>
<span class="n">dir_data</span> <span class="o">=</span> <span class="s">"../data/"</span>
<span class="n">BVSP_df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">dir_data</span><span class="o">+</span><span class="s">'BVSP.csv'</span><span class="p">)</span>
<span class="n">CMIG_df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">dir_data</span><span class="o">+</span><span class="s">'CMIG3.SA.csv'</span><span class="p">)</span>
<span class="n">ELET_df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">dir_data</span><span class="o">+</span><span class="s">'ELET3.SA.csv'</span><span class="p">)</span>
<span class="n">ITUB_df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">dir_data</span><span class="o">+</span><span class="s">'ITUB4.SA.csv'</span><span class="p">)</span>
<span class="n">LREN_df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">dir_data</span><span class="o">+</span><span class="s">'LREN3.SA.csv'</span><span class="p">)</span>
<span class="c1">#Grafico com evolução do preço BVSP
</span><span class="n">Dias</span><span class="o">=</span><span class="nb">list</span><span class="p">(</span><span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="nb">len</span><span class="p">(</span><span class="n">BVSP_df</span><span class="p">)))</span>
<span class="n">Preco</span><span class="o">=</span><span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">Dias</span><span class="p">,</span><span class="n">BVSP_df</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">])</span>
<span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">"Preço BVSP X Tempo (dias)"</span><span class="p">)</span>
</code></pre></div></div>
<p><img src="https://i.imgur.com/U5f8xk3.png" alt="" /></p>
<p>Os dados foram importados do Yahoo! Finanças, do período de 01/07/2019 a 30/07/2020. Como o arquivo não incluí o retorno em porcentagem, a seguir foi adicionada uma coluna de retornos, a qual utilizou como base a coluna “Adj Close” que é fornecida pelo arquivo do Yahoo. “Adj Close” é o preço de fechamento somado aos dividendos que podem ter sido distribuídos no dia por ação, incluindo então esta outra forma de rendimento.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Adicionar uma coluna de retornos que é (new_Adj close / old_ Adj close) -1
</span><span class="n">BVSP_df</span> <span class="p">[</span><span class="s">'Returns'</span><span class="p">]</span> <span class="o">=</span> <span class="n">BVSP_df</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">].</span><span class="n">pct_change</span><span class="p">()</span>
<span class="n">CMIG_df</span> <span class="p">[</span><span class="s">'Returns'</span><span class="p">]</span> <span class="o">=</span> <span class="n">CMIG_df</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">].</span><span class="n">pct_change</span><span class="p">()</span>
<span class="n">ELET_df</span> <span class="p">[</span><span class="s">'Returns'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ELET_df</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">].</span><span class="n">pct_change</span><span class="p">()</span>
<span class="n">ITUB_df</span> <span class="p">[</span><span class="s">'Returns'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ITUB_df</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">].</span><span class="n">pct_change</span><span class="p">()</span>
<span class="n">LREN_df</span> <span class="p">[</span><span class="s">'Returns'</span><span class="p">]</span> <span class="o">=</span> <span class="n">LREN_df</span><span class="p">[</span><span class="s">'Adj Close'</span><span class="p">].</span><span class="n">pct_change</span><span class="p">()</span>
</code></pre></div></div>
<p>A fórmula do retorno foi:</p>
\[\frac{Adj\ close_t}{Adj\ close_{t-1}} – 1\]
<p>Como o cálculo possui o preço do dia anterior no divisor, a data mais antiga não terá um valor definido, e por isso será ignorada essa linha.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Ignorar os NaN
</span><span class="n">BVSP_returns</span> <span class="o">=</span> <span class="n">BVSP_df</span><span class="p">[</span><span class="s">'Returns'</span><span class="p">].</span><span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
<span class="n">CMIG_returns</span> <span class="o">=</span> <span class="n">CMIG_df</span><span class="p">[</span><span class="s">'Returns'</span><span class="p">].</span><span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
<span class="n">ELET_returns</span> <span class="o">=</span> <span class="n">ELET_df</span><span class="p">[</span><span class="s">'Returns'</span><span class="p">].</span><span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
<span class="n">ITUB_returns</span> <span class="o">=</span> <span class="n">ITUB_df</span><span class="p">[</span><span class="s">'Returns'</span><span class="p">].</span><span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
<span class="n">LREN_returns</span> <span class="o">=</span> <span class="n">LREN_df</span><span class="p">[</span><span class="s">'Returns'</span><span class="p">].</span><span class="n">values</span><span class="p">[</span><span class="mi">1</span><span class="p">:]</span>
</code></pre></div></div>
<p>Para continuar, serão considerados apenas os retornos percentuais calculados anteriormente.</p>
<p>É possível visualizar no seguinte exemplo como ocorre a regressão linear entre os retornos do ativo e retornos do Bovespa:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Retornos</span> <span class="o">=</span> <span class="p">[</span><span class="n">BVSP_returns</span><span class="p">,</span> <span class="n">CMIG_returns</span><span class="p">,</span> <span class="n">ELET_returns</span><span class="p">,</span> <span class="n">ITUB_returns</span><span class="p">,</span> <span class="n">LREN_returns</span><span class="p">]</span>
<span class="c1">#Usando SeaBorn para visualizar a regressão linear (Grafico de pontos)
</span><span class="n">regressao_linear</span><span class="o">=</span><span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">16</span><span class="p">,</span><span class="mi">6</span><span class="p">))</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">sns</span><span class="p">.</span><span class="n">regplot</span><span class="p">(</span><span class="n">BVSP_returns</span><span class="p">,</span> <span class="n">CMIG_returns</span><span class="p">,</span> <span class="n">scatter_kws</span><span class="o">=</span><span class="p">{</span><span class="s">"color"</span><span class="p">:</span><span class="s">"blue"</span><span class="p">},</span>
<span class="n">line_kws</span><span class="o">=</span><span class="p">{</span><span class="s">"color"</span><span class="p">:</span><span class="s">"orange"</span><span class="p">})</span>
<span class="n">ax</span><span class="p">.</span><span class="n">tick_params</span><span class="p">(</span><span class="n">axis</span> <span class="o">=</span> <span class="s">'x'</span><span class="p">,</span> <span class="n">color</span> <span class="o">=</span> <span class="s">'black'</span><span class="p">)</span>
<span class="n">ax</span><span class="p">.</span><span class="nb">set</span><span class="p">(</span><span class="n">xlabel</span><span class="o">=</span><span class="s">"BVSP Retornos"</span><span class="p">,</span> <span class="n">ylabel</span> <span class="o">=</span> <span class="s">"CMIG Retornos"</span><span class="p">,</span> <span class="n">title</span> <span class="o">=</span> <span class="s">'Retornos BVSP X CMIG'</span><span class="p">,</span>
<span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<p><img src="https://i.imgur.com/vLPUket.png" alt="" /></p>
<p>A seguir, o cálculo da matriz de variância e covariância, que será utilizada para calcular o Beta de cada ativo.
Para este exemplo, foi considerado o valor de 0.0054% de retorno diária, tendo a taxa Selic como renda fixa.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#CAPM: ERi = RFR + Bi * (ERm - RFR)
</span>
<span class="s">"""Lembrar que:
Bi = 0, o ativo não se relaciona com o mercado
Bi = 1, ativo perfeitamente correlacionado com o mercado
Bi > 1, ativo mais volátil que o mercado
Bi <1, ativo menos volátil que o mercado """</span>
<span class="c1">#Matriz de variancia e covariancia
</span><span class="n">vcov</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">cov</span><span class="p">(</span><span class="n">Retornos</span><span class="p">)</span>
<span class="c1">#Cálculo dos betas
</span><span class="n">Tamanho</span><span class="o">=</span><span class="mi">5</span>
<span class="n">variancias</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">Tamanho</span><span class="p">)</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">Tamanho</span><span class="p">):</span> <span class="c1">#Captura as variancias pra calcular
</span> <span class="n">variancias</span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="o">=</span><span class="n">vcov</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="n">n</span><span class="p">]</span>
<span class="n">beta</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">Tamanho</span><span class="p">)</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">Tamanho</span><span class="p">):</span> <span class="c1">#seleciona todos da primeira coluna de vcov
</span> <span class="n">beta</span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="o">=</span><span class="n">vcov</span><span class="p">[</span><span class="n">n</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span><span class="o">/</span><span class="n">variancias</span><span class="p">[</span><span class="n">n</span><span class="p">]</span>
<span class="n">rm</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">BVSP_returns</span><span class="p">)</span>
<span class="n">rf</span> <span class="o">=</span> <span class="mf">0.000054</span> <span class="c1">#taxa selic atual
</span><span class="n">ri</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="n">Tamanho</span><span class="p">)</span>
<span class="k">for</span> <span class="n">n</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">Tamanho</span><span class="p">):</span>
<span class="n">ri</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">rf</span> <span class="o">+</span> <span class="n">beta</span><span class="p">[</span><span class="n">n</span><span class="p">]</span> <span class="o">*</span> <span class="p">(</span><span class="n">rm</span> <span class="o">-</span> <span class="n">rf</span><span class="p">))</span><span class="o">*</span><span class="mi">100</span>
</code></pre></div></div>
<p>Os resultados de retorno esperado são pequenos, porém é preciso lembrar que foi calculado para o período diário.Dado o nível de risco e considerando as relações dos ativos com o mercado, os resultados foram:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Cria um DataFrame com os retornos
</span><span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">ri</span><span class="p">,</span><span class="n">columns</span><span class="o">=</span><span class="p">[</span> <span class="s">'Retorno Esperado'</span><span class="p">])</span>
<span class="n">dfnomes</span><span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">Nomes</span><span class="p">,</span><span class="n">columns</span><span class="o">=</span><span class="p">[</span><span class="s">'Papel'</span><span class="p">])</span>
<span class="n">df2</span><span class="o">=</span> <span class="n">dfnomes</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">df</span><span class="p">,</span><span class="n">how</span><span class="o">=</span><span class="s">'right'</span><span class="p">)</span>
<span class="c1">#Gera um grafico de retornos esperados
</span><span class="n">retorno_esperado_graf</span><span class="o">=</span><span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">()</span>
<span class="n">retorno_esperado_graf</span><span class="o">=</span><span class="n">plt</span><span class="p">.</span><span class="n">bar</span><span class="p">(</span><span class="n">df2</span><span class="p">[</span><span class="s">'Papel'</span><span class="p">],</span><span class="n">df2</span><span class="p">[</span><span class="s">'Retorno Esperado'</span><span class="p">])</span>
<span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">"Retorno esperado de cada papel"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">df2</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Papel Retorno Esperado
0 BVSP 0.049422
1 CMIG 0.031297
2 ELET 0.025346
3 ITUB 0.040241
4 LREN 0.031604
</code></pre></div></div>
<p><img src="https://i.imgur.com/3oD63TJ.png" alt="" /></p>
<h2 id="referências">Referências</h2>
<p>BERK, Jonathan B.;DEMARZO, Peter. Corporate finance. 3rd ed. Peason, 2014.
JORDAN, Ross W. Fundamentos de Administração Financeira. 9ª ed. AMGH, 2013.</p>
Self-organizing maps2020-08-29T23:59:07+00:00http://lamfo-unb.github.io/2020/08/29/Self-organizing maps<p><strong>Table of Contents</strong></p>
<p>[TOCM]</p>
<p>[TOC]</p>
<h1 id="self-organizing-maps">Self-organizing maps</h1>
<h2 id="definição">Definição</h2>
<p>O <em>self-organizing map</em> (SOM) é um modelo neural não supervisonado, ou seja, não demanda intervenção humana durante o treinamento. Além disso, o SOM utiliza aprendizado competitivo, onde os neurônios recebem padrões de entradas e competem tendo como resultado um vencedor, para cada padrão, que será ativado. Os neurônios vencedores podem representar diversos padrões de entrada formando <em>clusters</em> de padrões similares. Após ser determinado vencedor, esse neurônio tem seus pesos ajustados ficando mais próximo do padrão de entrada associado a ele. A repetição dessa lógica resulta em pesos que convergem para a estabilidade atuando como centros de massa dos agrupamentos de padrões de entrada.
A proposição do algoritmo de <em>self-organizing maps</em> (SOM) foi feita pelo acadêmico finlandês Teuvo Kohonen em 1982.</p>
<p><img src="https://hs.mediadelivery.fi/img/468/fc61cf87757b4e90a02b5918d78fe9de.jpg" alt="" /></p>
<h2 id="aplicações">Aplicações</h2>
<p>A simplicidade do método em processar parâmetros de entranda mais complexos e agrupá-los em clusters de dimensão menor, normalmente bidimensionais, fez com que o algoritmo tivesse grande aceitação e utilização. Por exemplo, utiliza-se o modelo em meteorologia na visualização de cenários climáticos e na oceanografia para visualização do mapeamento do solo marinho. A imagem abaixo representa a aplicação de <em>self-organizing map</em> na meterologia para vizualição de nuvens.</p>
<p><img src="https://i.imgur.com/UXBvgxD.png" alt="" />
Fonte: <em>Self-Organizing Maps: A Powerful Tool for the Atmospheric Sciences</em></p>
<h2 id="intuição-matemática">Intuição Matemática</h2>
<p>A idéia principal de um mapa auto-organizável é pegar dados multidimensionais e produzir uma representação desses dados em um espaço bidimensional (o “mapa”).
Como os dados não têm classes pré-definidas, queremos utilizar um algoritmo que seja capaz de se “auto-organizar”. Em outras palavras, como não temos um “supervisor” para indicar a saída esperada, o algoritmo tem de criar uma representação desses dados de acordo com suas características.</p>
<p>Formalmente, queremos encontrar um função que mapeie o espaço de entrada (<em>input space</em>) $\mathcal{X}$ pra um espaço de saída bidimensional (<em>output space</em>) $\mathcal{Y}$.
\(f: \mathcal{X} \rightarrow \mathcal{Y}, \mathcal{X} \in \mathbb{R}^D, \mathcal{Y} \in \mathbb{R}^2\)</p>
<p>Essa função $f$ realizará esse mapeamento utilizando uma série de parâmetros (pesos) $\mathbf{W}$. Uma das formas mais utilizadas para se aproximar uma função é usando uma rede neural artificial. Esse método é extremamente versátil e poderoso. Porém, a forma clássica de treinar esse modelo é utilizando <em>backpropagation</em>. Como não temos classes para utilizar no treinamento, não podemos usar essa técnica.</p>
<p>A grande questão é então como treinar uma rede neural sem usar o <em>backpropagation</em>? Isso é feito por meio do aprendizado competitivo.</p>
<p>Nessa técnica, cada neurônio da rede “compete” com outros neurônios para representar parte dos dados de entrada. Desse modo, com o passar do tempo, certos neurônios se especializam na representação de determinada parte do espaço de entrada dos dados.</p>
<h3 id="algoritmo">Algoritmo</h3>
<p>Suponha que queremos treinar um mapa com dados de entrada $\mathbf{X} = {X_1,X_2,…,X_N}$, e cada exemplo tem $D$ parâmetros $X_i = {x_{i,1},x_{i,2},…,x_{i,D}}$. O mapeamento será feito por meio de um conjunto de $M$ pesos, onde cada peso tem $D$ parâmetros. Ou seja, $\mathbf{W} = {W_1,W_2,…,W_M}, W_i \in \mathbb{R}^D ~\forall i \in {1,…,M}$.</p>
<p>O algoritmo para treinar um mapa auto-organizável é divido em 5 etapas.</p>
<ol>
<li>Inicializar os neurônios com pesos aleatórios e o número da iteração $n = 0$</li>
<li>Selecionar uma entrada $X_i aleatoriamente$</li>
<li>Calcular a distância entre $X_i$ e todos os pesos $\mathbf{W}$. O peso com menor distância é selecionado $L(X)$.</li>
<li>Atualizar os pesos usando \(W_v(n+1) = W_v(n) + \eta(n)h_{j,L(X)}(n)(X_i-W_v)\)</li>
<li>Incrementar $n$, repetir passos 2 à 5 até o número de iterações desejado</li>
</ol>
<p>A atualização dos pesos $\Delta W$ é composta de dois termos que merecem ser comentados mais detalhadamente.</p>
<p>O primeiro termo é a taxa de aprendizado $\eta$. No começo do treinamento, todos os pesos são iniciados aleatoriamente. Logo, é desejado que os pesos sejam atualizados mais rapidamente no começo e, a medida que o treinamento vai progredindo, as atualizações sejam menores. A taxa de aprendizado é decrescida após cada iteração seguindo um decaimento exponencial:</p>
\[\eta(n) = \eta_0 exp\left(\frac{-n}{\tau_\eta}\right),\]
<p>em que $\eta_0$ é a taxa de aprendizado inicial e $\tau_\eta$ é uma constante que controla o decaimento.</p>
<p>O segundo termo é a função de vizinhança $h_{j,L(X)}(n)$, definida como:</p>
\[h_{j,L(X)}(n) = exp\left(\frac{-d^2_{j,L(X)}}{2 \sigma(n)^2}\right),\]
<p>em que $d_{j,L(X)}$ representa a distância euclidiana entre o neurônio $W_j$ e o neurônio $L(X)$. Lembre-se que o neurônio $L(X)$ é o neurônio mais próximo do $X_i$ sorteado no passo 2 do algoritmo. Formalmente, podemos definir esse neurônio como:</p>
\[L(X) = W_k, ~k=\underset{j}{argmin}||X - W_j||_2\]
<p>Se observamos a equação de $h_{j,L(X)}(n)$, podemos notar que essa equação remete a uma distribuição normal centrada em zero e desvio padrão $\sigma(n)$. Quanto maior a distância do neurônio $W_j$ em relação ao neurônio $L(X)$, menor o valor de $h_{j,L(X)}(n)$. Desse modo, neurônios distantes entre si têm menos influência na atualização de seus respectivos pesos. A medida que o número de iterações aumenta, a largura dessa distribuição vai diminuindo seguindo um decaimento exponencial $\sigma(n) = \sigma_0 exp(\frac{-n}{\tau_0})$, similar a taxa de aprendizado. Ou seja, as atualizações vão ficando cada vez mais restritas à vizinhança do peso em questão.</p>
<h3 id="exemplo">Exemplo</h3>
<p>Para ilustrar o algoritmo, considere o seguinte exemplo onde temos 3 neurônios e 2 dados de entrada $X_1 = [1,1,2],X_2=[3,5,1]$.</p>
<p>Os pesos foram iniciados aleatoriamente.</p>
<p><img src="https://i.imgur.com/DphJaUB.png" alt="" /></p>
<p>Suponha que selecionamos $X_1$ na primeira iteração. O próximo passo é então medir a distância entre $X_1$ e todos os outros pesos.</p>
<p>Calcula-se então $d_{X_1,W_1},d_{X_1,W_2},d_{X_1,W_3}$. Os valores encontrados são $d_{X_1,W_1} = 1.80,d_{X_1,W_2}=1.48,d_{X_1,W_3}=1.87$. Logo, o neurônio mais próximo de $X_1$ é $W_2 = L(X)$.</p>
<p>Os pesos então são atualizados seguindo as seguinte equações:
\(\Delta W_1 = \eta(1)h_{1,2}(1)(X_1-W_1)\)
\(\Delta W_2 = \eta(1)h_{2,2}(1)(X_1-W_2)\)
\(\Delta W_3 = \eta(1)h_{3,2}(1)(X_1-W_3)\)</p>
<p>Incrementa-se $n$ e o processo de treinamento é repetido.</p>
<h3 id="representação-em-duas-dimensões">Representação em duas dimensões</h3>
<p>Tendo a distância entre neurônios e dados de entrada, conseguimos representar essas informações em um espaço bidimensional.</p>
<p>Suponha $d_{X_1,W_3} = 1, d_{X_1,W_2} = 1.5, d_{W_2,W_3} = 2$.</p>
<p>Podemos representar essas distância no gráfico abaixo:</p>
<p><img src="https://i.imgur.com/NJFIgwN.png" alt="" /></p>
<p>Desse modo, conseguimos transformar dados multidimensionais em distâncias e, consequentemente, em uma representação bidimensional.</p>
<h2 id="usando-som-para-visualizar-em-python-a-facilidade-de-abrir-negócios-no-mundo">Usando SOM para visualizar em Python a facilidade de abrir negócios no mundo</h2>
<p>Inicialmente vamos carregar os pacotes necessários. Além do <em>pandas</em> vamos carregar a função <code class="language-plaintext highlighter-rouge">scale</code> do <em>sklean</em> para transformar as variáveis para o mesmo range de valores, a classe <code class="language-plaintext highlighter-rouge">MiniSom</code> do biblioteca <em>minisom</em> para realizar o treinamento do <em>Self-organizing maps</em>, por fim, a classe <code class="language-plaintext highlighter-rouge">Mapa</code> que foi criada por nós para plotar os mapas.</p>
<p>A biblioteca <em>MiniSom</em> é uma implementação minimalista do algoritmo <em>Self-organizing maps</em>, você pode encontrar a página da biblioteca <a href="https://github.com/JustGlowing/minisom">aqui</a> e vários exemplos de uso <a href="https://github.com/JustGlowing/minisom/tree/master/examples">aqui</a>. Esta aplicação e a classe <code class="language-plaintext highlighter-rouge">Mapa</code> são fortemente baseadas no exemplo <em>Democracy Index</em>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">from</span> <span class="nn">sklearn.preprocessing</span> <span class="kn">import</span> <span class="n">scale</span>
<span class="kn">from</span> <span class="nn">minisom</span> <span class="kn">import</span> <span class="n">MiniSom</span>
<span class="kn">from</span> <span class="nn">modulos.mapa</span> <span class="kn">import</span> <span class="n">Mapa</span>
</code></pre></div></div>
<p>Agora que importamos as bibliotecas necessárias, vamos carregar os dados que serão usados. A seguir são apresentadas as primeiras 5 linhas dos dados:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">path_data</span> <span class="o">=</span> <span class="s">'data/processed/start-business.csv'</span>
<span class="n">read_params</span> <span class="o">=</span> <span class="p">{</span><span class="s">'sep'</span><span class="p">:</span> <span class="s">';'</span><span class="p">,</span> <span class="s">'decimal'</span><span class="p">:</span> <span class="s">','</span><span class="p">,</span> <span class="s">'encoding'</span><span class="p">:</span> <span class="s">'cp1252'</span><span class="p">}</span>
<span class="n">dados</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="n">path_data</span><span class="p">,</span> <span class="o">**</span><span class="n">read_params</span><span class="p">)</span>
<span class="n">dados</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>country_code</th>
<th>economy</th>
<th>region</th>
<th>income_group</th>
<th>facility_group</th>
<th>score</th>
<th>procedures_man</th>
<th>time_men</th>
<th>cost_men</th>
<th>procedures_woman</th>
<th>time_woman</th>
<th>cost_woman</th>
<th>paid_in_min</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>AFG</td>
<td>Afghanistan</td>
<td>South Asia</td>
<td>Low income</td>
<td>High facility</td>
<td>92.04130</td>
<td>4.0</td>
<td>8.0</td>
<td>6.4</td>
<td>5.0</td>
<td>9.0</td>
<td>6.4</td>
<td>0.0</td>
</tr>
<tr>
<th>1</th>
<td>ALB</td>
<td>Albania</td>
<td>Europe & Central Asia</td>
<td>Upper middle income</td>
<td>High facility</td>
<td>91.70203</td>
<td>5.0</td>
<td>4.5</td>
<td>11.3</td>
<td>5.0</td>
<td>4.5</td>
<td>11.3</td>
<td>0.0</td>
</tr>
<tr>
<th>2</th>
<td>DZA</td>
<td>Algeria</td>
<td>Middle East & North Africa</td>
<td>Upper middle income</td>
<td>Low facility</td>
<td>77.94755</td>
<td>12.0</td>
<td>18.0</td>
<td>11.8</td>
<td>12.0</td>
<td>18.0</td>
<td>11.8</td>
<td>0.0</td>
</tr>
<tr>
<th>3</th>
<td>AGO</td>
<td>Angola</td>
<td>Sub-Saharan Africa</td>
<td>Lower middle income</td>
<td>Low facility</td>
<td>79.04553</td>
<td>8.0</td>
<td>36.0</td>
<td>13.9</td>
<td>8.0</td>
<td>36.0</td>
<td>13.9</td>
<td>0.0</td>
</tr>
<tr>
<th>4</th>
<td>ATG</td>
<td>Antigua and Barbuda</td>
<td>Latin America & Caribbean</td>
<td>High income</td>
<td>Lower middle facility</td>
<td>81.74620</td>
<td>9.0</td>
<td>22.0</td>
<td>8.7</td>
<td>9.0</td>
<td>22.0</td>
<td>8.7</td>
<td>0.0</td>
</tr>
</tbody>
</table>
</div>
<p>O conjunto de dados é oriundo de uma pesquisa do Banco Mundial sobre a facilidade de fazer negócios na maioria dos países do mundo. Nesse exemplo, pegamos apenas os dados relacionados com a facilidade de abrir um negócio para o ano de 2019, mas você pode encontrar a pesquisa completa <a href="https://www.doingbusiness.org/">aqui</a> com todos os detalhes.</p>
<p>Nesta base, temos 13 variáveis das quais 8 são numéricas. A variável <em>score</em> mede a facilidade de construir negócio por cada país e é construída a partir das demais variáveis numéricas. Quanto maior a variável <em>score</em> maior a facilidade de abrir um negócio. Para esses dados, a Nova Zelândia ficou em primeiro lugar, já o Brasil ficou na posição 149 de 203 países em ordem decrescente de facilidade de abrir um negócio. A última posição é ocupada pela Venezuela.</p>
<p>O principal objetivo dessa aplicação é visualizar a posição relativa dos países com base nas sete variáveis que compõem o índice de facilidade de abrir negócios e verificar se as posições relativas dos países estão relacionadas com o índice.</p>
<p>Para isso, vamos selecionar apenas as variáveis que compõem o índice de facilidade e colocar essas variáveis na mesma escala.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">features</span> <span class="o">=</span> <span class="p">[</span><span class="s">'procedures_man'</span><span class="p">,</span> <span class="s">'time_men'</span><span class="p">,</span> <span class="s">'cost_men'</span><span class="p">,</span> <span class="s">'procedures_woman'</span><span class="p">,</span> <span class="s">'time_woman'</span><span class="p">,</span> <span class="s">'cost_woman'</span><span class="p">,</span><span class="s">'paid_in_min'</span><span class="p">]</span>
<span class="n">labels_contry</span> <span class="o">=</span> <span class="n">dados</span><span class="p">[</span><span class="s">'country_code'</span><span class="p">]</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">dados</span><span class="p">[</span><span class="n">features</span><span class="p">].</span><span class="n">values</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">scale</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
</code></pre></div></div>
<p>Agora vamos treinar o <em>Self-organizing maps</em> com um mapa $15X15$ usando uma função de vizinhança <em>gaussiana</em> e treinando $1.000$ <em>epochs</em>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">size</span> <span class="o">=</span> <span class="mi">15</span>
<span class="n">som</span> <span class="o">=</span> <span class="n">MiniSom</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">size</span><span class="p">,</span> <span class="n">y</span><span class="o">=</span><span class="n">size</span><span class="p">,</span> <span class="n">input_len</span><span class="o">=</span><span class="nb">len</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="mi">0</span><span class="p">]),</span> <span class="n">sigma</span><span class="o">=</span><span class="mf">1.5</span><span class="p">,</span> <span class="n">neighborhood_function</span><span class="o">=</span><span class="s">'gaussian'</span><span class="p">,</span> <span class="n">random_seed</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">som</span><span class="p">.</span><span class="n">pca_weights_init</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">som</span><span class="p">.</span><span class="n">train_random</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="mi">1000</span><span class="p">,</span> <span class="n">verbose</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> [ 1000 / 1000 ] 100% - 0:00:00 left
quantization error: 0.4487733862565572
</code></pre></div></div>
<p>Vamos agora instanciar a classe <code class="language-plaintext highlighter-rouge">Mapa</code> para plotar os mapas:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mapa</span> <span class="o">=</span> <span class="n">Mapa</span><span class="p">(</span><span class="n">som</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">labels_contry</span><span class="p">,</span> <span class="n">size</span><span class="p">)</span>
</code></pre></div></div>
<p>No gráfico vamos plotar a posição relativa dos países e atribuir uma cor para cada país de acordo com a variável <code class="language-plaintext highlighter-rouge">facility_group</code>. Essa variável foi construída a partir dos quartis da variável <code class="language-plaintext highlighter-rouge">score</code>: os países pertencentes ao primeiro quartil dessa variável foram classificados como <em>Low facility</em>, para indicar a baixa facilidade de abrir um novo negócio, e assim sucessivamente até o quarto quartil, no qual os países pertencentes a eles foram classificados como <em>High facility</em>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">facility_colors</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'Low facility'</span><span class="p">:</span> <span class="s">'#DC143C'</span><span class="p">,</span> <span class="s">'Lower middle facility'</span><span class="p">:</span> <span class="s">'#FFA500'</span><span class="p">,</span> <span class="s">'Upper middle facility'</span><span class="p">:</span> <span class="s">'#9370DB'</span><span class="p">,</span>
<span class="s">'High facility'</span><span class="p">:</span> <span class="s">'#4B0082'</span>
<span class="p">}</span>
<span class="n">country_start_colors</span> <span class="o">=</span> <span class="p">[</span><span class="n">facility_colors</span><span class="p">[</span><span class="n">facility</span><span class="p">]</span> <span class="k">for</span> <span class="n">facility</span> <span class="ow">in</span> <span class="n">dados</span><span class="p">[</span><span class="s">'facility_group'</span><span class="p">].</span><span class="n">to_list</span><span class="p">()]</span>
</code></pre></div></div>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mapa</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">country_start_colors</span><span class="p">,</span> <span class="n">facility_colors</span><span class="p">)</span>
</code></pre></div></div>
<p><img src="https://i.imgur.com/ZsuazxB.png" alt="" /></p>
<p>A posição relativa de cada país no gráfico é determinada pela proximidade de cada país no conjunto de dados original com sete variáveis. Assim, estamos representando um conjunto de dados de dimensão mais alta em um gráfico de duas dimensões.</p>
<p>De modo geral o gráfico mostra que o índice de facilidade de fazer negócio caracteriza bem as distâncias relativas entre os países. Isto porque os países que estão no mesmo grupo de facilidade de fazer negócios aparecem mais próximos entre si formando <em>clusters</em>.</p>
<p>A preenchimento de fundo do gráfico representa a matriz de dissimilaridade entre da região em relação às observações que a rodeiam. Essa matriz pode ser usada para clusterizar as observações no mapa por meio de clusterização hierárquico ou mesmo o <em>Kmeans</em>, assim, as áreas mais escuras forneceriam as fronteiras entre os clusters.</p>
<p>No gráfico a seguir vamos plotar a posição relativa dos países e atribuir uma cor para cada país de acordo com a variável <code class="language-plaintext highlighter-rouge">icome_group</code>. Essa variável é uma classificação de países do Banco Mundial de acordo com o nível de renda, os países são classificados como:</p>
<ul>
<li><strong>Low income</strong>: Países de renda baixa;</li>
<li><strong>Lower middle income</strong>: Países de renda média baixa;</li>
<li><strong>Upper middle income</strong>: Países de renda média alta, o Brasil se encontra nesse grupo;</li>
<li><strong>High income</strong>: Países de renda alta;</li>
</ul>
<p>Desta forma, o gráfico abaixo irá mostrar a relação entre o nível de renda e as posições relativas entre os países:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">income_colors</span> <span class="o">=</span> <span class="p">{</span>
<span class="s">'Low income'</span><span class="p">:</span> <span class="s">'#DC143C'</span><span class="p">,</span> <span class="s">'Lower middle income'</span><span class="p">:</span> <span class="s">'#FFA500'</span><span class="p">,</span> <span class="s">'Upper middle income'</span><span class="p">:</span> <span class="s">'#9370DB'</span><span class="p">,</span> <span class="s">'High income'</span><span class="p">:</span> <span class="s">'#4B0082'</span>
<span class="p">}</span>
<span class="n">country_income_colors</span> <span class="o">=</span> <span class="p">[</span><span class="n">income_colors</span><span class="p">[</span><span class="n">income</span><span class="p">]</span> <span class="k">for</span> <span class="n">income</span> <span class="ow">in</span> <span class="n">dados</span><span class="p">[</span><span class="s">'income_group'</span><span class="p">].</span><span class="n">to_list</span><span class="p">()]</span>
</code></pre></div></div>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">mapa</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">labels_colors</span><span class="o">=</span><span class="n">country_income_colors</span><span class="p">,</span> <span class="n">legend_colors</span><span class="o">=</span><span class="n">income_colors</span><span class="p">)</span>
</code></pre></div></div>
<p><img src="https://i.imgur.com/NBUtjIE.png" alt="" /></p>
<p>Diferentemente do primeiro gráfico, a relação entre a variável <code class="language-plaintext highlighter-rouge">income_group</code> e a posição relativa dos países não é tão clara. Isto significa que relação entre essa variável a facilidade de abrir um novo negócio não é tão direta. O que é esperado, uma vez que o nível de renda de um país é o resultado de um período relativamente longo de tempo em comparação ao tempo necessário para mudar a facilidade de abrir um negócio.</p>
<p>Em outras palavras, mesmo que a facilidade de abrir um novo negócio afetasse diretamente o nível de renda, caso esse efeito não produza efeitos imediatos é razoável esperar que o gráfico acima não capture esse efeito entre as variáveis.</p>
<p>Aqui encerra o nosso post. Os códigos e os dados usados nessa aplicação estão no nosso repositório no <a href="https://github.com/lamfo-unb/self-organizing-maps">GitHub</a>.</p>
Restricted Boltzmann Machine - RBM2020-07-29T23:59:07+00:00http://lamfo-unb.github.io/2020/07/29/Restricted-Boltzmann-Machine-RBM<h1 id="restricted-boltzmann-machine---rbm">Restricted Boltzmann Machine - RBM</h1>
<h2 id="motivação">Motivação</h2>
<p>Em 2009, um grupo de pesquisadores conseguiu aprimorar o sistema de recomendações de filmes da Netflix em 10,05%, utilizando a Máquina de Boltzmann restrita como um dos algoritmos.</p>
<h2 id="termodinâmica">Termodinâmica</h2>
<p>O nome Boltzmann, presente no nome do algoritmo, vem do físico austríaco Ludwig Eduard Boltzmann (1844-1906), que estabeleceu os principais conceitos da física clássica estatística, de onde a ideia geral do modelo foi retirada.</p>
<p>A Distribuição de Boltzmann descreve a probabilidade de se encontrar moléculas de um gás em um determinado estado energético. Essa distribuição, a menos de constantes, é dada por:</p>
<p>\begin{equation}
\frac{N_i}{N}=\frac{g_i e^{\frac{E_i}{KT}}}{Z(T)}
\end{equation}</p>
<p>A Máquina de Boltzmann leva esse nome, pois a distribuição de probabilidades utilizada é a Distribuição de Boltzmann, representada na figura abaixo:</p>
<p><img src="https://i.imgur.com/AiYzKhF.png" alt="" /></p>
<h2 id="máquina-de-boltzmann">Máquina de Boltzmann</h2>
<p>Máquinas de Boltzmann são modelos probabilísticos (ou geradores) não supervisionados, baseados em energia, representados por um sistema totalmente conectado.</p>
<p><img src="https://i.imgur.com/U0bGPhL.png" alt="" /></p>
<p>Para cada configuração do sistema, atribui-se um valor de energia e uma probabilidade associada a essa energia. Sendo assim, tem-se como objetivo, ajustar o modelo para que pouca energia represente alta probabilidade e muita energia represente baixa probabilidade.</p>
<h3 id="máquina-de-boltzmann-restrita">Máquina de Boltzmann Restrita</h3>
<p>Smolensky (1986), propôs alterações práticas na máquina de Boltzmann, a partir de restrições na sua topologia, forçando a inexistência de conexões intra-camada, conforme esquema abaixo.</p>
<p><img src="https://i.imgur.com/MDtJAVB.png" alt="" /></p>
<p>Além disso, de forma a viabilizar o processamento computacional do modelo, Hinton (2002), propôs um modelo de aprendizado eficiente e que vem sendo utilizado amplamente na academia e na indústria.</p>
<h4 id="estrutura-de-uma-rbm">Estrutura de uma RBM</h4>
<p>As RBM são formadas conjuntos de unidades visíveis e ocultas. A Figura abaixo, extraída de Borin (2016), fornece a representação gráfica de uma RBM, contendo duas unidades visíveis e três unidades ocultas.</p>
<p><img src="https://i.imgur.com/vZ6SoFx.png" alt="" /></p>
<p>De acordo com Borin (2016), “as linhas ligando parâmetros a unidades indicam que esses estão associados, de forma que os círculos representam as unidades e os pequenos quadrados, os parâmetros do modelo.”</p>
<h5 id="comparação-com-uma-rna">Comparação com uma RNA</h5>
<p>As RBM são frequentemente comparados à Redes Neurais Clássicas, e de acordo com Borion (2016), a diferença está nos neurônios.</p>
<p>Perceba que as RNA são formadas por neurônios que possuem como saída valores reais.</p>
<p><img src="https://i.imgur.com/56L2QmZ.png" alt="" /></p>
<p>Já nas RBM, conforme se observa na figura abaixo, os neurônios são estocásticos.</p>
<p><img src="https://i.imgur.com/eYD5iEO.png" alt="" /></p>
<h2 id="formalização-matemática">Formalização Matemática</h2>
<h3 id="energia-global">Energia Global</h3>
<p>De acordo com Borin (2016), as RBM fazem parte de uma classe de modelos probabilísticos que são baseados em energia.</p>
<p>A energia total é calculada por meio da equação:</p>
<p>\begin{equation}
E(v,h)=-\sum_{j=1}^{n_h}b_jh_j-\sum_{i=1}^{n_v}c_iv_i-\sum_{i=1}^{n_v}\sum_{j=1}^{n_h}h_jw_{ji}v_i
\end{equation}</p>
<p>E a distribuição de probabilidades pela equação:</p>
<p>\begin{equation}
P(v,h)=\frac{e^{-E(v,h)}}{Z}
\end{equation}</p>
<p>Ou seja, uma RBM fica totalmente especificada pelos seus vieses e
pesos de conexão, pelo conjunto de parâmetros <strong>W</strong>, <strong>b</strong>, <strong>c</strong>.</p>
<h3 id="aprendizado">Aprendizado</h3>
<p>Por meio de uma abordagem não supervisionada, o modelo é treinado com o Método do Gradiente Descendente Estocástico - SGD, aplicado na seguinte Função Perda.</p>
<p>\begin{equation}
\mathcal{L}\left(\boldsymbol{\theta} ; \mathbf{v}^{(t)}\right)=-\ln P\left(\mathbf{v}^{(t)}\right)
\end{equation}</p>
<p>Sendo o gradiente definido pela equação:</p>
<p>\begin{equation}\frac{\partial \mathcal{L}\left(\theta; \mathbf{v}^{(t)}\right)}{\partial \boldsymbol{\theta}}=\mathbb{E}<em>{P(\mathbf{h} | \mathbf{v})}\left[\frac{\partial E\left(\mathbf{v}^{(t)}, \mathbf{H}\right)}{\partial \theta} | \mathbf{v}^{(t)}\right]-\mathbb{E}</em>{p(\mathbf{v}, \mathbf{h})}\left[\frac{\partial E(\mathbf{V}, \mathbf{H})}{\partial \boldsymbol{\theta}}\right]
\end{equation}</p>
<p>A partir do gradiente calculado, os parâmetros são atualizados a cada rodada de treinos, respeitando a seguinte regra:</p>
<p>\begin{equation}\boldsymbol{\theta} \leftarrow \boldsymbol{\theta}-\lambda\left(\frac{\partial \mathcal{F}\left(\mathbf{v}^{(t)}\right)}{\partial \boldsymbol{\theta}}-\frac{\partial \mathcal{F}(\tilde{\mathbf{v}})}{\partial \boldsymbol{\theta}}\right)\end{equation}</p>
<p>Para acompanhar a evolução do treinamento, geralmente se utiliza
uma medida de erro de reconstrução:</p>
<p>\begin{equation}\varepsilon_{r}=\left|\tilde{\mathbf{v}}-\mathbf{v}^{(t)}\right|^{2}\end{equation}</p>
<h2 id="aplicação">Aplicação</h2>
<p>Uma aplicação interessante da RBM, utilizando TensorFlow, pode ser encontrada <a href="https://www.linkedin.com/pulse/criando-um-sistema-de-recomenda%C3%A7%C3%A3o-com-tensorflow-e-rbm-ricardo-ramos/">aqui</a>.</p>
<h2 id="referências">Referências</h2>
<p>Borin, R. G. (2016). Detecção de atividade vocal empregando máquinas de Boltzmann restritas (Doctoral dissertation, Universidade de São Paulo).</p>
<p>Smolensky, P. (1986). Information processing in dynamical systems: Foundations of harmony theory. Colorado Univ at Boulder Dept of Computer Science.</p>
<p>Hinton, G. E. (2002). Training products of experts by minimizing contrastive divergence. Neural computation, 14(8), 1771-1800.</p>
Random Forest2020-07-08T23:59:07+00:00http://lamfo-unb.github.io/2020/07/08/Random-Forest<h1 id="random-forest">Random Forest</h1>
<p><em>Random Forest</em> é um método de aprendizado de máquina utilizado para problemas que envolvam classificação ou regressão. Ele se baseia em uma coleção de árvores de decisão <img src="https://latex.codecogs.com/svg.latex?\{h(x,\Theta_k),k=1,...\}" title="\{h(x,\Theta_k),k=1,...\}" /> em que os <img src="https://latex.codecogs.com/svg.latex?\{\Theta_k\}" title="\{\Theta_k\}" /> são vetores aleatórios independentes e identicamente distribuídos. Podemos pensar em uma árvore de decisão como uma representação gráfica para um determinado processo de decisão. As árvores são formadas por nós, que armazenam informação (perguntas). O nó raiz é o nó que possui maior nível hierárquico e, a partir dele, ramificam-se os nós filhos. O nó que não possui filhos é conhecido como nó folha ou terminal. A imagem abaixo exemplifica a estrutura de uma árvore.</p>
<p><img src="https://miro.medium.com/max/1430/1*rSQIIAboJftqAv_BReNipg.png" alt="Árvore de decisão" /></p>
<font size="2"><center>Fonte: [Vebuso](https://www.vebuso.com/2020/01/decision-tree-intuition-from-concept-to-application/)</font></center>
Para se gerar um novo galho é necessário que ocorra um *split*, isto é, uma nova separação dos dados no plano. No entanto, essa separação precisa melhorar a separação anterior, caso contrário não faz sentido separar mais os dados. Desse modo, utiliza-se alguns critérios para auferir a qualidade do *split*. Para problemas de classificação, tem-se os critérios de Entropia e Impureza de Gini. Já para regresssão, tem-se o Erro Quadrático Médio (MSE) e o Erro Médio Absoluto (MAE).
A Impureza de Gini pode ser descrita pela equação,
<br />
<center><img src="https://latex.codecogs.com/svg.latex?G&space;=&space;\sum^C_{i=1}{p(i)*(1-p(i))}," title="G = \sum^C_{i=1}{p(i)*(1-p(i))}," /></center>
<br />
e representa a probabilidade de se classificar incorretamente uma amostra retirada aleatoriamente se esta fosse aleatoriamente classificada de acordo com a distribuição de classe dos dados.
A Entropia mede a desordem de um grupamento de variáveis e é dada por
<br />
<center><img src="https://latex.codecogs.com/svg.latex?Entropia&space;=&space;-\sum^C_{i=1}{p(i)*log_2p(i)}." title="Entropia = -\sum^C_{i=1}{p(i)*log_2p(i)}." /></center>
<br />
Por fim, para o MAE e o MSE, tem-se que
<br />
<center><img src="https://latex.codecogs.com/svg.latex?MAE&space;=&space;\frac{1}{n}\sum^N_{i=1}{|{y_i&space;-&space;\hat{y_i}}|}," title="MAE = \frac{1}{n}\sum^N_{i=1}{|{y_i - \hat{y_i}}|}," /></center>
<br />
<br />
<center><img src="https://latex.codecogs.com/svg.latex?MSE&space;=&space;\frac{1}{n}\sum^N_{i=1})^2}}." title="MSE = \frac{1}{n}\sum^N_{i=1})^2}}." /></center>
<br />
Importante notar que com relação as duas últimas, o MSE coloca mais peso em grandes erros, isto é, coloca mais importância a erros maiores do que a MAE. De modo que se para o problema em questão, um erro de (10-5) tem que ser analisado como um erro maior que 5, é melhor utilizar o MSE como critério. Mas caso a disparidade não tenha tanta importância no problema, então pode-se utiizar o MAE.
A ideia de *Random Forest* reside na junção de muitas árvores de decisão que, a partir de critérios de seleção, se ramificam e chegam cada uma a uma resposta para o problema. Em seguida, a resposta que tiver mais voto é a solução geral.
Portanto, cada árvore gera um voto unitário para a classe mais popular dos dados de entrada $x$. O modelo como um todo é formado por árvores de decisão que crescem a partir dos dados de entrada. Para que as árvores não tenham alta correlação, pois isso diminuiria o poder de generalização do modelo, alguns métodos são aplicados.
O *Bootstrap Aggregation* ou *Bagging* consiste em uma metodologia de amostragem aleatória para substituir as combinações de entrada dos dados de treinamento. De maneira mais informal, o *Bagging* faz com que cada árvore retire aleatóriamente uma amostra (com reposição) mantendo o tamanho original dos dados.
Com o *Feature Randomness*, cada árvore possui um sub conjunto aleatório de features para serem escolhidos. Dessa forma, existe uma maior variabilidade entre as árvores, o que resulta em uma menor correlação entre elas.
Há duas razões principais para o uso desses métodos em *Random Forest*, em primeiro lugar eles aumentam a acurácia dos resultados diminuindo a correlação de cada árvore e, além disso, fornecem estimativas dos erros de generalização das árvores de forma contínua.
Em suma, *Random Forest* é um algoritmo utilizado para classificação e regressão que consiste em diversas árvores de decisão. Utiliza métodos como Bagging e Feature Randomness para construir suas árvores, e assim, criar uma floresta com baixa correlação. Utiliza a ideia de que a decisão por voto para a previsão final é melhor do que a previsão individual de cada árvore.
Para demonstrar a capacidade do modelo de generalização, é necessário entender a função margem do modelo, que consiste em medir o nível em que o número médio de votos da classificação para a classe certa de $X$, sendo $Y, X$ um conjunto de treinamento, excede a classificação para outra classe. Dessa forma, dado um conjunto de classificadores <img src="https://latex.codecogs.com/svg.latex?h_1(\boldsymbol{X}),&space;h_2(\boldsymbol{X}),...,&space;h_k(\boldsymbol{X})" title="h_1(\boldsymbol{X}), h_2(\boldsymbol{X}),..., h_k(\boldsymbol{X})" />, tem-se que:
<br />
<center><img src="https://latex.codecogs.com/svg.latex?mg(\boldsymbol{X},Y)&space;=&space;P_{\Theta}(h(\boldsymbol{X},&space;\Theta)&space;=&space;Y)&space;-&space;max_{j&space;\neq&space;Y}&space;(P_{\Theta}(h(\boldsymbol{X},\Theta)&space;=&space;j)," title="mg(\boldsymbol{X},Y) = P_{\Theta}(h(\boldsymbol{X}, \Theta) = Y) - max_{j \neq Y} (P_{\Theta}(h(\boldsymbol{X},\Theta) = j)," /></center>
<br />
em que <img src="https://latex.codecogs.com/svg.latex?\Theta" title="\Theta" /> representa vetores aleatórios distribuídos de forma independente. O erro de generalização pode ser dado por:
<br />
<center><img src="https://latex.codecogs.com/svg.latex?PE&space;=&space;P_{\boldsymbol{X},Y}&space;(mg(\boldsymbol{X},Y))&space;<&space;0." title="PE = P_{\boldsymbol{X},Y} (mg(\boldsymbol{X},Y)) < 0." /></center>
<br />
É possível demonstrar que pela Lei Forte dos Grandes Números, que o erro de generalização converge para:
<br />
<center><img src="https://latex.codecogs.com/svg.latex?P_{\boldsymbol{X},Y}(P_{\Theta}(h(\boldsymbol{X},&space;\Theta)&space;=&space;Y)&space;-&space;max_{j&space;\neq&space;Y}&space;(P_{\Theta}(h(\boldsymbol{X},\Theta)&space;=&space;j))&space;<&space;0)." title="P_{\boldsymbol{X},Y}(P_{\Theta}(h(\boldsymbol{X}, \Theta) = Y) - max_{j \neq Y} (P_{\Theta}(h(\boldsymbol{X},\Theta) = j)) < 0)." /></center>
<br />
A principal mensagem da equação acima é a de que por mais que se aumente a quantidade de árvores, existe uma restrição para o erro de generalização, de modo a restringir também o *overfit*.
Por fim, é importante ter em mente que o objetivo principal de *Random Forest* é minimizar o erro de generalização com a menor perda de dados. Isso mostra a dependência do modelo aos dados, de modo que, caso tenha-se *garbage in*, no fim terá *garbage out*.
# Light Gradient Boosting Model
O Algoritmo *Light Gradient Boosting Model*, mais conhecido como *LightGBM* faz parte da família de algoritmos de Gradient Boosting Decision Tree (GBDT), assim como os algoritmos *XGBoost* e *pGBRT*. GBDT são um grupo de modelos que tem sido muito utilizado em técnicas de Aprendizado de Máquina principalmente pelo surgimento de novos estudos na área de tecnologia e *big data* (KE et al, 2017). A lógica dos modelos *Gradient Boosting* é a junção de vários modelos "fracos", o processo de aprendizado vai se ajustando a medida que os modelos são adicionados e o objetivo é produzir uma estimativa mais precisa das variável resposta. Os modelos são construídos em etapas e em cada etapa, os modelos são correlacionados com um gradiente negativo da função de perda. A função de perda é uma medida de ajuste dos coeficientes do modelo e é utilizada para que nas etapa do *Gradient Boosting* os erros sejam minimizados(FRIEDMAN, 2001; NATEKIN;KNOLL, 2013).
Algoritmos de GBDT utilizam da lógica de Aprendizado por Árvore de Decisão para modelagem preditiva e estes modelos precisam estudar todas as instâncias dos recursos (variáveis) para estimar qual seria o ganho de informação em cada nó de decisão. Isso mostra que a complexidade computacional destes modelos depende da quantidade de dados e dos recursos das bases de dados, logo os modelos com implementações muito demoradas devido ao uso de bases com muitos dados.
A diferença principal dos outros modelos baseados em Árvore de Decisão é que, no LightGBM, as árvores crescem "verticalmente" enquanto os outros algoritmos crescem "horizontalmente". Crescer verticalmente significa que a Árvore cresce *leaf-wise*, ou seja, que o Algoritmo vai selecionar a ''folha'' que tenha o máximo *delta loss to grow*.
![](https://i.imgur.com/FuD6zcz.png)
[Fonte](https://medium.com/@pushkarmandot/https-medium-com-pushkarmandot-what-is-lightgbm-how-to-implement-it-how-to-fine-tune-the-parameters-60347819b7fc)
Na tentativa de solucionar os problemas de com tempo de processamento e o uso da memória, Ke et al (2017)propõe o uso de duas técnicas para aprimorar os algoritmos de *Gradient Boosting*: Amostragem unilateral baseado em Gradiente (*Gradient-based One-Side Sampling* - GOSS) e Pacote de Recursos Exclusivos (*Exclusive Feature Bundling* - EFB). Algoritmos de *Gradient Boosting* que utilizam GOSS e EFB são denominados de *Light Gradient Boosting Models*, ou LightGBM. Este modelo se tornou muito popular em estudos e em competições na plataforma de competições de Ciência de Dados [Kaggle](https://www.kaggle.com/), principalmente pela velocidade de processamento, menor uso de memória e melhor acurácia das previsões.
A Amostragem unilateral baseado em Gradiente é utilizado dentro de um contexto que mostra que instâncias de dados com gradientes diferentes possuem desempenhos diferentes no ganho de informações. Isto significa que a instância com gradientes maiores, terão maior contribuição no ganho de informação, logo a amostragem focando nestas instância é benéfica para uma maior acurácia. Amostrasfem unilateral baseado em gradiente é uma técnica que vai focar nas instâncias de dados com gradientes maiores e eliminando aleatoriamente as instâncias com gradientes menores.
O Pacote de Recursos Exclusivos é uma técnica que se faz necessária tendo em vista que, em aplicações reais, embora haja um grande número de *features*, o espaço de *features* é escasso. Muitas *features* dentro do espaço acabam sendo exclusivas, isto é, em poucas situações recebem valores diferentes de zero simultaneamente. O Pacote de Recursos Exclusivos faz parte de um algoritmo eficiente que seleciona as *features* exclusivos em uma única *feature* e assim auxiliar com o uso de menos memória no processamento.
Estas técnicas fazem com que o LightGBM tenha uma maior velocidade de processamento, consiga lidar com grandes bases de dados, ocupe menos memória para executar e foque na acurácia dos resultados. Entretanto, o modelo é sensível a *overfitting* e, por isso, não é aconselhável de uso em bases com poucas observações
# Implementação Básica dos Modelos
Vamos fazer uma implementação breve dos modelos em Python e comparar o desempenho dos modelos.
A base utilizada foi a "Breast Cancer Dataset" criada para o Women Coders' Bootcamp organizado pelo PNUD de Nepal e retirada do Kaggle. Ela possui 5 colunas com características de tumores (*features*) e uma coluna com o resultado. Cada coluna possui 569 dados.
## Random Forest
Primeiro importamos os pacotes:
```
import numpy as np
import pandas as pd
from sklearn import preprocessing
from sklearn import metrics
from sklearn.model_selection import train_test_split, cross_val_score, cross_val_predict
```
Lemos o arquivo .csv contendo os dados e criamos o data frame:
```
data = pd.read_csv('breastcancer.csv')
datas = pd.DataFrame(preprocessing.scale(data.iloc[:,1:32]))
datas.columns = list(data.iloc[:,1:32].columns)
datas['diagnosis'] = data['diagnosis']
```
Estabelecemos as variáveis preditoras e a variável que queremos prever (*target*):
```
predictors = ['mean_texture', 'mean_perimeter', 'mean_area', 'mean_smoothness']
target = "diagnosis"
X = datas[predictors]
y = np.ravel(datas.loc[:, [target]])
```
Agora separamos os dados em conjuntos de teste e treino, de modo a termos 20% dos dados separados para teste:
```
# Split the dataset in train and test:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
print('Shape of training set : %i || Shape of test set : %i' % (X_train.shape[0], X_test.shape[0]))
```
Inicializamos o modelo Random Forest Classifier do pacote *sklearn* e estabelecemos os parêmetros. O único parâmetro levemente otimizado foi o número de estimadores. Ao final, imprimimos a Acurácia e a Matriz de Confusão:
```
# Initiating the model: Random Forest Classifier
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=18, criterion="gini", max_depth=None,
min_samples_split=2, min_samples_leaf=1, max_features="auto",
bootstrap=True, random_state=0, max_samples=455, verbose=1)
rf.fit(X_train, y_train)
prediction = rf.predict(X_test)
print('Accuracy:', round(metrics.accuracy_score(y_test, prediction), 4))
print('Confusion Matrix:\n', metrics.confusion_matrix(y_test, prediction))
```
Os resultados do modelo são:
```
Acurácia: 0.9474
Matriz de Confusão:
[[43 4]
[ 2 65]]
```
Assim, obtivemos 43 verdadeiros positivos (*true positives*), 65 verdadeiros negativos (*true negatives*), 4 falso positivos (*false positives*) e 2 falso negativos (*false negatives*). E uma acurácia de 94,7% no modelo.
## LightGBM
O modelo Light GBM foi exemplificado com o pacote
*scikit-learn* utilizando os seguintes parâmetros.
```
import lightgbm as lgb
d_train = lgb.Dataset(x_train, label=y_train)
params = {}
params['boosting_type'] = 'gbdt'
params['objective'] = 'binary'
params['metric'] = 'binary_logloss'
params['learning_rate'] = 0.02
params['min_data_in_leaf'] = 30
params['num_leaves'] = 31
params['feature_fraction']= 0.15
clf = lgb.train(params, d_train, num_boost_round=100)
```
A acurácia do modelos foi de 91,23%
```
LightGBM Model accuracy score: 0.9123
Training-set accuracy score: 0.9143
```
A Matriz de Confusão pode ser vista abaixo.
```
Confusion matrix
[[43 4]
[ 6 61]]
True Positives(TP) = 43
True Negatives(TN) = 61
False Positives(FP) = 4
False Negatives(FN) = 6
```
Ao analisarmos a acurácia dos modelos, o modelo Random Forest teve um desempenho melhor que o modelo Light GBM. No entanto, isso pode ser explicado principalemnte pelo tamanho da base de dados utilizada. O Modelo Light GBM tende a performar melhor com base de dados maiores. Em suma, mostramos como os modelos podem ser aplicados em Python e suas diferenças.
# Referências
BREIMAN, L. Random forests.Machine learning, Springer, v. 45, n. 1, p. 5–32, 2001
KE, G. et al. Lightgbm: A highly efficient gradient boosting decision tree. In:Advances inneural information processing systems. [S.l.: s.n.], 2017. p. 3146–3154.
</font>
Support Vector Machines2020-07-04T23:59:07+00:00http://lamfo-unb.github.io/2020/07/04/SVM<h1 id="support-vector-machines"><em>Support Vector Machines</em></h1>
<p>Support Vector Machine (ou Máquina de Vetores de Suporte) é um método de aprendizado de máquinas supervisionado usado principalmente para problemas de classificação. Surge como a generalização e automatização de outros modelos, que por sua vez, utilizam-se de determinados conceitos estruturantes.</p>
<h2 id="introdução-conceitos-estruturantes">Introdução: Conceitos estruturantes</h2>
<h3 id="dilema-viés-variância">Dilema Viés-Variância</h3>
<p>O Dilema Viés-Variância é um conceito fundamental ao se analisar a aplicação de um algoritmo de aprendizado de máquinas a determinado problema. Como um modelo é, por natureza, uma simplificação de uma relação real mais complexa, surge um trade-off relacionado à flexibilidade do modelo.</p>
<p>O <strong>Viés</strong> diz respeito a quão distante o modelo está de representar a relação real desejada. Ou seja, um modelo com muito viés tem dificuldade em representar as nuances de uma relação mais complexa, como um modelo linear e uma relação não-linear, por exemplo. Já a <strong>Variância</strong> diz respeito ao tamanho da variação entre os resultados obtidos pelo modelo para os dados de treino e os dados de teste.</p>
<p>Em problemas de classificação, no qual um conjunto de dados é utilizado para treinar o modelo, surge a necessidade de optar entre:</p>
<ul>
<li>Um modelo pouco flexível, que terá difícil adaptação à relação real (tendo um grande viés), mas pela inflexibilidade, não apresenta uma grande diferença em relação aos dados de teste (pouca variância).</li>
<li>Um modelo bem mais flexível, que se adapta bem aos dados de treino (minimizando o viés), mas apresenta uma grande diferença de resultado em relação aos dados de teste (apresentando uma grande variância). A esse fenômeno, é dado o nome de <em>overfitting</em>.</li>
</ul>
<p>Um modelo ótimo busca diminuir tanto o viés quanto a variância, visando uma boa representação do fenômeno estudado e um bom desempenho classificando novas entradas.</p>
<h3 id="método-de-validação-cruzada">Método de Validação Cruzada</h3>
<p>O Método de Validação Cruzada é uma ferramenta utilizada para avaliar o melhor modelo ou melhor combinação de parâmetros de um modelo. Em problemas de classificação, no qual o aprendizado supervisionado (ou seja, um conjunto de dados é utilizado para treinar e outro para testar o modelo) é empregado, é preciso determinar qual parte dos dados será usado para cada etapa desse processo.</p>
<p>Esse método resolve essa questão dividindo esse conjunto de dados em partes iguais (geralmente 10) e usando um a um como teste após utilizar os demais como treino. No final, os resultados são sumarizados e é determinado um modelo ou conjunto de parâmetros ótimo para o problema.</p>
<h2 id="maximal-margin-classifier"><em>Maximal Margin Classifier</em></h2>
<p>O <em>Maximal Margin Classifier</em> (ou Classificador da Margem Máxima) é o método utilizado em problemas de classificação, no qual seja possível utilizar um hiperplano para separar as observações baseado no aspecto desejado. No caso de uma observação com 2 variáveis (ou seja, um plano bidimensional), o hiperplano será uma reta (espaço unidimensional). Portanto, os dados precisam ser totalmente separáveis.</p>
<p>Como existe uma infinidade de posições possíveis para o hiperplano caso os dados sejam perfeitamente separáveis, esse classificador busca determinar essa posição a partir da maximização da margem.</p>
<p><img src="https://i.imgur.com/V3eiQ8T.jpg" alt="" />
<strong>Figura 2:</strong> Á esquerda, existem duas classes de observações, rosa e azul, cada uma delas possuem medidas de duas variáveis.Três hiperplanos possível, dentre vários, são mostrados em preto.À direita, um hiperplano é utilizado como um classificador.</p>
<p>A margem diz respeito ao espaço vazio que fica entre as observações do extremo interno de cada grupo (ou seja, as observações da “ponta” mais próxima ao outro grupo) e o hiperplano.</p>
<p>Como nesse classificador a margem é intransponível, utiliza-se otimização para alargá-la o máximo possível à fim de criar um espaço de segurança para as classificações. Assim, devemos resolver o seguinte problema:</p>
<p><img src="https://i.imgur.com/hpXpqxP.jpg" alt="" /></p>
<p>As restrições asseguram que cada observação estará no lado correto do hiperplano e, no mínimo, a uma distância M do mesmo. Consequentemente, M representa a margem, e o problema de otimização escolhe $\beta_0, \beta_1, \beta_2, …, \beta_p$ para maximizar M. Essa é a exata definição de margem máxima.</p>
<p><img src="https://i.imgur.com/WsowP0z.jpg" alt="" />
<strong>Figura 2:</strong> Existem duas classes de observações, rosa e azul. O hiperplano plano ótimo é representado pela linha sólida. A margem é a distância entre a linha sólida e a linha pontilhada de cada lado.</p>
<p>Porém, caso exista algum outlier no conjunto de dados ou os grupos não sejam completamente separáveis, esse método perde muito em eficiência ou até a aplicação, pois ou a margem fica pequena demais ou não é possível traçar o hiperplano.</p>
<p><img src="https://i.imgur.com/Hugo7Yn.jpg" alt="" />
<strong>Figura 3:</strong> À esquerda, duas classes de observações são classificadas por um hiperplano ótimo. À direita, uma observação em azul foi acrescentada, causando uma mudança dramática na escolha do hiperplano ótimo, da reta pontilhada para a negritada.</p>
<h2 id="support-vector-classifier"><em>Support Vector Classifier</em></h2>
<p>O Support Vector Classifier (ou Classificador dos Vetores de Suporte) é uma generalização do modelo anterior, visto que se aplica aos casos em que o Maximal Margin Classifier não se aplica.</p>
<p>Isso se dá pela flexibilização em relação à invasão da margem por parte de determinadas observações. Esse classificador, ao permitir isso busca um melhor mecanismo de classificação no longo prazo (permitindo a classificação “errada” de certas observações). Portanto, o problema de otimização do classificador anterior ganha uma nova forma, com um parâmetro que controlará o “grau” de permissão de invasão à margem.</p>
<p><img src="https://i.imgur.com/FhLJtZa.jpg" alt="" /></p>
<p>onde C é a um parâmetro não-negativo de ajustamento. Como no problema de otimização anterior, M é a vriável que representa a margem, que procuramos maximizar. $\epsilon_1$, $\epsilon_2$, …, $\epsilon_n$ são variáveis de erro que permitem observações com problemas de classificação.</p>
<p>Após a resolução do problema, classificamos uma observação teste, $x^*$a ao determinar de qual lado do hiperplano ela ficará. Ou seja, classificamos a observação com base no sinal da seguinte equação:</p>
\[f\left(x^{*}\right)=\beta_{0}+\beta_{1} x_{1}^{*}+\ldots+\beta_{p} x_{p}^{*}\]
<p>A partir disso, observa-se a aplicação dos dois conceitos estruturantes: o modelo permitirá que algumas observações sejam classificadas de maneira errada (com um maior viés) para que a classificação no longo prazo seja melhor (uma menor variância). O parâmetro que controla essa permissão, C, é determinado por validação cruzada, achando o ponto ótimo de equilíbrio entre essas duas características.</p>
<h2 id="support-vector-machine-svm"><em>Support Vector Machine (SVM)</em></h2>
<p>O <em>Support Vector Classifier</em> é um método natural de classificação para dois conjuntos de dados se o delimitador entre as classes é linear. Entretanto, na prática, lidamos com limites não lineares.</p>
<p><img src="https://i.imgur.com/qnGufaA.jpg" alt="" />
<strong>Figura 4:</strong> À esquerda, as observações são classificadas em duas classes, com um delimitador não linear entre elas. À direita, o Support Vector Classifier procura um classificador linear, mas tem um desempenho ruim.</p>
<p>Uma solução para esse problema é mapear o conjunto de treinamento de seu espaço original (não linear) para um novo espaço de maior dimensão, denominado espaço de características (feature space), que é linear.</p>
<p>Para isso, precisamos encontrar uma transformação não linear, $\boldsymbol{\varphi}(x)=\left[\varphi_{1}(x), \ldots, \varphi_{m}(x)\right]$. Essa transformação mapeia o espaço original das observações para um novo espaço de atributos $m$ - dimensional, o qual pode ser muito maior do que o espaço original. Nesse novo espaço, as observações passam a ser linearmente separáveis. Com a função de transformação, nosso problema de otimização recai pra uma SVM linear.</p>
<p><img src="https://i.imgur.com/12OhWgh.jpg" alt="" /></p>
<p>Ao analisar a estimação dos coeficientes no problema de otimização e a representação do classificador linear $f(x)$, que é dada por:</p>
\[f(x)=\beta_{0}+\sum_{i \in \mathcal{S}} \alpha_{i}\left\langle x, x_{i}\right\rangle\]
<p>onde $\mathcal{S}$ é a coleção de índices desses pontos de suporte, concluímos que apenas precisamos dos produtos escalares.</p>
<p>O algoritmo linear depende somente de $\left\langle x, x_{i}\right\rangle$, portanto o algoritmo transformado também dependerá somente de $\left\langle \boldsymbol{\varphi}(x), \boldsymbol{\varphi}(x_i)\right\rangle$.</p>
<p>Esse produto escalar entre os vetores transformados é chamado de função Kernel:</p>
\[K(x, x_i)=\left\langle \boldsymbol{\varphi}(x), \boldsymbol{\varphi}(x_i)\right\rangle\]
<p>A função Kernel nos permite operar no espaço original, sem precisar computar as coordenadas dos dados em um espaço dimensional superior. Esse método é chamado de truque de Kernel.</p>
<p>Por exemplo, vamos supor que $x$ e $y$ são observações em $3$ dimensões:</p>
\[\begin{array}{l}
\mathbf{x}=\left(x_{1}, x_{2}, x_{3}\right)^{T} \\
\mathbf{y}=\left(y_{1}, y_{2}, y_{3}\right)^{T}
\end{array}\]
<p>Vamos assumir que precisamos mapear $x$ e $y$ para um espaço 9-dimensional.</p>
<p>Para isso, precisamos realizar as seguintes operações para chegar ao resultado final, que é apenas um escalar:</p>
\[\phi(\mathbf{x})=\left(x_{1}^{2}, x_{1} x_{2}, x_{1} x_{3}, x_{2} x_{1}, x_{2}^{2}, x_{2} x_{3}, x_{3} x_{1}, x_{3} x_{2}, x_{3}^{2}\right)^{T}\]
\[\phi(\mathbf{y})=\left(y_{1}^{2}, y_{1} y_{2}, y_{1} y_{3}, y_{2} y_{1}, y_{2}^{2}, y_{2} y_{3}, y_{3} y_{1}, y_{3} y_{2}, y_{3}^{2}\right)^{T}\]
\[\phi(\mathbf{x})^{T} \phi(\mathbf{y})=\sum_{i, j=1}^{3} x_{i} x_{j} y_{i} y_{j}\]
<p>Porém, se usarmos a função Kernel, ao invés de fazer operações complexas em um espaço 9-dimensional, obtemos o mesmo resultado com um espaço 3-dimensional ao calcular o produto escalar do transposto de $x$ e y:</p>
<p>\begin{equation<em>}
\begin{aligned}
K(\mathbf{x}, \mathbf{y}) &=\left(\mathbf{x}^{T} \mathbf{y}\right)^{2} <br />
&=\left(x_{1} y_{1}+x_{2} y_{2}+x_{3} y_{3}\right)^{2} <br />
&=\sum_{i, j=1}^{3} x_{i} x_{j} y_{i} y_{j}
\end{aligned}
\end{equation</em>}</p>
<p>Um exemplo de Kernel é:</p>
\[K\left(x_{i}, x_{i^{\prime}}\right)=\left(1+\sum_{j=1}^{p} x_{i j} x_{i^{\prime} j}\right)^{d}\]
<p>que é conhecido como Kernel polinomial de grau $d,$ onde $d$ é um inteiro positivo.</p>
<p>Outra opção bastante popular é o Kernel radial, que possui a seguinte forma:</p>
\[K\left(x_{i}, x_{i^{\prime}}\right)=\exp \left(-\gamma \sum_{j=1}^{p}\left(x_{i j}-x_{i^{\prime} j}\right)^{2}\right)\]
<p>onde $\gamma$ é uma constante positiva.</p>
<p>Quando o <em>Support Vector Classifier</em> é combinado com uma função Kernel, como o polinomial, o classificador resultante é conhecido como <em>Support Vector Machine</em>.</p>
<p>Note que, de forma geral, a função do hiperplano terá a seguinte forma:</p>
\[f(x)=\beta_{0}+\sum_{i \in \mathcal{S}} \alpha_{i} K\left(x, x_{i}\right)\]
<p><img src="https://i.imgur.com/OdH1nET.jpg" alt="" />
<strong>Figura 5:</strong> À esquerda, um SVM com Kernel polinomial de grau 3 é aplicado a um conjunto de dados não-linear. À direita, um SVM com Jernel radial é utilizado.</p>
<h2 id="aplicação">Aplicação</h2>
<p>Iremos fazer uma aplicação do método SVM, utilizando R. Para isso, vamos precisar de alguns pacotes:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>library(tidyverse) # data manipulation and visualization
library(e1071) # SVM methodology
library(ISLR) # contains example data set "Khan"
library(RColorBrewer) # customized coloring of plots
</code></pre></div></div>
<p>Para demonstrar uma classificação não-linear, precisamos construir um conjunto de dados:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>x <- matrix(rnorm(200*2), ncol = 2)
x[1:100,] <- x[1:100,] + 2.5
x[101:150,] <- x[101:150,] - 2.5
y <- c(rep(1,150), rep(2,50))
dat <- data.frame(x=x,y=as.factor(y))
ggplot(data = dat, aes(x = x.2, y = x.1, color = y, shape = y)) +
geom_point(size = 2) +
scale_color_manual(values=c("#000000", "#FF0000")) +
theme(legend.position = "none")
</code></pre></div></div>
<p>Obtendo o seguinte gráfico:</p>
<p><img src="https://i.imgur.com/FRRGlEi.jpg" alt="" /></p>
<p>Vamos utilizar 100 amostras aleatórias para serem nossas observações de treinamento. Baseado no formato do nosso conjunto de dados, escolhemos o Kernel radial:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>set.seed(123)
train <- base::sample(200,100, replace = FALSE)
svmfit <- svm(y~., data = dat[train,], kernel = "radial", gamma = 1, cost = 1)
</code></pre></div></div>
<p>O gráfico após aplicação do SVM é dado por:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plot(svmfit, dat)
</code></pre></div></div>
<p><img src="https://i.imgur.com/eeRTOPD.jpg" alt="" /></p>
<p>Utilizamos a função tune() para encontrar a melhor condição para os parâmetros $C$ e $\gamma$.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tune.out <- tune(svm, y~., data = dat[train,], kernel = "radial",
ranges = list(cost = c(0.1,1,10,100,1000),
gamma = c(0.5,1,2,3,4)))
tune.out$best.model
</code></pre></div></div>
<p>A tabela criada, comparando os dados reais com os dados previstos, é chamada de Matriz de Confusão. Seu funcionamento é simples: é uma tabela de contingência em que na linha está o valor previsto e na coluna o valor observado</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(valid <- table(true = dat[-train,"y"], pred = predict(tune.out$best.model,
newx = dat[-train,])))
</code></pre></div></div>
<p>Para descobrirmos a porcentagem de acertos do nosso modelo, basta somarmos os valores da diagonal da tabela, e depois dividir o resultado pelo total de observações da amostra utilizada. No nosso exemplo, obtemos os seguintes valores:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> pred
true 1 2
1 55 28
2 12 5
</code></pre></div></div>
<p>Portanto, temos 65 acertos diante de um total de 100 observações. Dessa forma, ao aplicar o SVM na nossa amostra, 65% das classificações foram feitas de maneira correta.</p>
<h2 id="referências">Referências</h2>
<p>Gareth James et al. An introduction to statistical learning. Vol. 112. Springer, 2013.</p>
<p>Alexandre Kowalczyk. “Support vector machines succinctly”. Em: Syncfusion Inc(2017).</p>
Propensity Score Matching2020-06-10T23:59:07+00:00http://lamfo-unb.github.io/2020/06/10/Propensity-Score-Matching<p><strong>Table of Contents</strong></p>
<p>[TOCM]</p>
<p>[TOC]</p>
<h1 id="parte-i--estatística-experimental-e-estatística-observacional">Parte I – Estatística experimental e estatística observacional</h1>
<p>Uma aplicação de ferramentas estatísticas é a avaliação da eficácia de uma intervenção, tratamento ou política de ação. Ao separar os indivíduos de nossa amostra em dois grupos, trata-los de forma distinta, e estuda-los com respeito aos resultados obtidos, podemos inferir em como atua o tratamento em questão. Em um simples caso binário, temos um grupo que receberá o tratamento – denominado grupo de tratamento – e outro que não receberá o tratamento – o grupo de controle. Ao comparar os resultados ao fim de um determinado período e aplicar as devidas ferramentas estatísticas, poderemos determinar quão bem sucedido é o tratamento, dada a amostra em questão.</p>
<p>Como os dados chegam ao pesquisador? Eles podem ser provenientes de experimentos ou pela observação, caso no qual as variáveis independentes (isto é, explicativas) não estão sob controle do pesquisador. Um detalhe de grande importância quando da realização de estudos estatísticos é garantir a minimização de vieses, que podem surgir de várias formas. No caso aqui em discussão, uma fonte de viés pode surgir do modo como cada indivíduo é escolhido/alocado a pertencer a determinado grupo de estudo. Uma alocação enviesada pode ocasionar erros de inferência, já que a amostra não é representativa da população que se quer analisar, consequentemente tornando os resultados menos confiáveis, ou mesmo falsos, do ponto de vista estatístico. Queremos, portanto, encontrar modelos que auxiliem a solucionar esse problema de viés de seleção e que possam providenciar estimativas válidas do efeito médio de tratamento (Average Treatment Effect – ATE).</p>
<p>O ATE é calculado tomando-se a diferença da média entre os resultados obtidos no grupo de controle e grupo de tratamento; desta forma, obtemos uma medida dos efeitos entre ambos os grupos e podemos avaliar a eficácia do tratamento nos indivíduos.</p>
<p>Randomized Control Trials (RCT) são experimentos nos quais a alocação é randomizada – isso significa que a probabilidade do indivíduo pertencer ao grupo de controle ou ao grupo de tratamento é a mesma (50%) em nosso exemplo binário. A garantia de randomização diminui o risco de viés na análise, assim como de associações espúrias, já que temos uma maior certeza em afirmar que os grupos são parecidos em tudo, exceto sua exposição ao tratamento. Contudo, nem sempre a realização de um RCT é possível: os custos podem ser proibitivamente elevados, e em muitos casos o tema de estudo esbarra em questões éticas, inviabilizando a realização de experimentos.</p>
<h1 id="parte-ii--o-propensity-score-matching">Parte II – O Propensity Score Matching</h1>
<p>Quando não é possível randomizar a alocação dos indivíduos aos grupos, como no caso de estudos observacionais, não se pode realizar inferências causais, já que não é possível determinar se a diferença de resultados entre os grupos de tratamento e controle são provenientes de diferenças “ao acaso” entre os indivíduos participantes do estudo ou se são diferenças sistemáticas.</p>
<p>Devido a essas limitações, o Propensity Score Matching (PSM) é uma alternativa para estimar os efeitos causais de receber o tratamento em uma amostra de indivíduos. O método PSM foi introduzido na literatura por Paul Rosenbaum e Donald Rubin em 1983; a ideia é de atribuir uma probabilidade de receber o tratamento a cada indivíduo da amostra – o propensity score (PS) –, controlando para suas características observadas, e depois parear unidades de ambos os grupos com propensity scores similares, para em seguida comparar os resultados obtidos entre os pares. O modelo pode ajudar a solucionar o problema de viés de seleção e providenciar estimativas não enviesadas do efeito médio do tratamento.</p>
<p>O propensity score é uma probabilidade condicional de que o participante de um estudo receba o tratamento dadas as covariáveis observadas; assim, não só aos participantes que de fato receberam o tratamento lhes é atribuído um propensity score, mas àqueles que não receberam também lhes é atribuída essa probabilidade. Além disso, condicionando para o PS, cada participante apresenta a mesma probabilidade de alocação para o tratamento, assim como em um experimento randomizado. O propensity score pode ser encarado como um balancing score (cujo conceito é explicado mais à frente) representante de um conjunto de covariáveis; deste modo, um par de indivíduos do grupo de controle e de tratamento que apresentem um propensity score similar podem ser comparáveis, mesmo que apresentem diferenças nas covariáveis específicas.</p>
<p>O viés quando da estimação do ATE surge quando diferenças nos resultados possam ser consequência de caracterísiticas secundárias dos indivíduos do que realmente em razão do tratamento aplicado. O cenário ideal para mitigação desse problema seria a realização de um RCT, dado que a randomização permite balancear essas caracterísiticas secundárias quando da alocação nos grupos de tratamento ou controle. O método PSM surge como alternativa à realização de um RCT, na medida em que simula um experimento controlado; a atribuição de probabilidades aos indivíduos-teste de receber o tratamento influi no sentido de enfrentar o problema de viés de seleção e viés dos estimadores do ATE, já que por esse método estaremos comparando agentes com caracterísiticas semelhantes, porém diferentes quanto à sua participação no grupo de tratamento. Assim, a análise é realizada entre uma seleção de indivíduos de ambos os grupo com relativo grau de paridade – e, esperamos, comparabilidade – em termos de covariáveis observada.</p>
<p>Uma diferença chave entre os dois métodos, contudo, é que enquanto o RCT realiza um balanceamento para todas as caracterísitcas secundárias dos indivíduos, sejam eles participantes ou não do grupo de tratamento, o PSM permite somente o balanceamento daquelas características observáveis pelo pesquisador no momento do estudo. Aquilo que não for observável não será levado em consideração quando do cálculo das probabilidades condicionais, sendo portanto uma potencial fonte de viés quando da estimação do ATE.</p>
<p>Como dito anteriormente, o propensity score é uma medida de equilíbrio que sumariza a informação do vetor de covariáveis. Participantes do grupo de controle e do grupo de tratamento com o mesmo valor do propensity score têm a mesma distribuição das covariáves observadas; ou seja, em um set de pares que é homogêneo para o PS, ambos os indivíduos podem apresentar valores diferentes para as covariáveis, mas essas diferenças serão puramente por acaso, e não diferenças sistemáticas.</p>
<h1 id="parte-iii--exemplos-simples">Parte III – Exemplos simples</h1>
<p>O PSM pode ser aplicado a uma ampla gama de campos de estudo, desde análises na biologia e medicina, até mesmo em aplicações nas ciências sociais. Sejam os seguintes exemplos:</p>
<ol>
<li>Queremos avaliar a eficácia de um determinado tratamento médico em meio a uma amostra de pacientes que padeceram de uma doença. Ao seguir a metodologia do PSM, atribuiremos Z=1 àqueles pacientes que receberam o tratamento, e Z=0 àqueles que não receberam. Ao compararmos pacientes com características semelhantes, poderemos determinar o grau de sucesso do tratamento.</li>
<li>Queremos avaliar a eficácia da adoção do regime de metas de inflação no combate à inflação. Seja a variável binária Z; Z=1 para países que adotam esse regime de metas, e Z=0 para aqueles que não adotam. Ao aplicarmos a metodologia do PSM, poderemos comparar países em cada grupo semelhantes quanto às variáveis independentes escolhidas, de forma a determinar o grau de sucesso dessa política em reduzir a taxa de inflação.</li>
</ol>
<h1 id="parte-iv--run-through-metodológico-simples">Parte IV – Run-through metodológico simples</h1>
<p>Criamos aqui então um <strong>exemplo hipotético</strong>, mas atual para que pudéssemos entender aplicações do PSM. Imagine que queiramos entender o efeito do tratamento de da Cloroquina no tempo de recuperação de pacientes que tiveram o COVID-19 afim de enterdemos se essa intervenção/tratamento realmente tem eficácia.</p>
<p>Com isso criamos uma** base fake** com as seguintes colunas:</p>
<ul>
<li>Febre (X) - Sintoma</li>
<li>Idade (X) - Sintoma</li>
<li>Sexo (X) - Sintoma</li>
<li>Dor no peito (X) - Sintoma</li>
<li>Dificuldade Respirar (X) - Sintoma</li>
<li><strong>Cloroquina (A) - Intervenção</strong></li>
<li><strong>Tempo Recuperação (Y) - Variável a ser analisada</strong></li>
</ul>
<h2 id="passo-1---importar-as-bibliotecas">Passo 1 - Importar as bibliotecas</h2>
<hr />
<p>Mesmo importando algumas bibliotecas aqui agora, estarei importando ao longo do código para facilitar a compreensão, mas já importarei algumas bibliotecas que podem ser necessárias no trato das informações que usaremos</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">LogisticRegression</span>
<span class="o">%</span><span class="n">matplotlib</span> <span class="n">inline</span>
</code></pre></div></div>
<h2 id="passo-2---bases--logistic-regression">Passo 2 - Bases + Logistic Regression</h2>
<hr />
<p>Para calcular o propensity score, podemos fazer uso de um modelo de regressão logística ou de um modelo probit. Adicionamos covariáveis observadas apropriadas no modelo e com isso obtemos uma probabilidade de exposição ao tratamento para toda a amostra. É importante notar que, quando da construção do modelo, as variáveis a serem incluídas não devem ser efeitos do tratamento, e sim preditoras do resultado; podemos incluir termos de interação e não precisamos nos importar com parcimônia ou perda de graus de liberdade.</p>
<blockquote>
<p>Mas antes vamos estar tratando algumas informações para enfim aplicarmos a regressão logística</p>
</blockquote>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">base</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_excel</span><span class="p">(</span><span class="s">"Oficina_PSM.xlsx"</span><span class="p">)</span> <span class="c1">#abre a base
</span>
<span class="c1">## Tratamos o nosso X
</span><span class="n">x</span> <span class="o">=</span> <span class="n">base</span><span class="p">[[</span><span class="s">"Febre_(X)"</span><span class="p">,</span><span class="s">'Idade_(X)'</span><span class="p">,</span><span class="s">'Sexo_(X)'</span><span class="p">,</span><span class="s">"Dor_no_peito_(X)"</span><span class="p">,</span><span class="s">'Dificuldade_Respirar_(X)'</span><span class="p">]]</span> <span class="c1">#escolhe as colunas que queremos
</span><span class="n">X</span> <span class="o">=</span> <span class="n">x</span><span class="p">.</span><span class="n">values</span> <span class="c1">#transformamos em matriz
</span>
<span class="c1">## Tratamos o nosso Y
</span><span class="n">y</span> <span class="o">=</span> <span class="n">base</span><span class="p">[[</span><span class="s">"Cloroquina_(A)"</span><span class="p">]]</span> <span class="c1">#escolhe as colunas que queremos até a intervenção
</span><span class="n">y</span> <span class="o">=</span> <span class="n">y</span><span class="p">.</span><span class="n">values</span> <span class="c1">#transformamos em vetor
</span>
<span class="n">x</span><span class="p">.</span><span class="n">describe</span><span class="p">()</span> <span class="c1">#descreve a base
</span></code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>Febre_(X)</th>
<th>Idade_(X)</th>
<th>Sexo_(X)</th>
<th>Dor_no_peito_(X)</th>
<th>Dificuldade_Respirar_(X)</th>
</tr>
</thead>
<tbody>
<tr>
<th>count</th>
<td>100.000000</td>
<td>100.00000</td>
<td>100.000000</td>
<td>100.000000</td>
<td>100.000000</td>
</tr>
<tr>
<th>mean</th>
<td>0.470000</td>
<td>55.45000</td>
<td>0.490000</td>
<td>0.560000</td>
<td>0.580000</td>
</tr>
<tr>
<th>std</th>
<td>0.501614</td>
<td>20.39973</td>
<td>0.502418</td>
<td>0.498888</td>
<td>0.496045</td>
</tr>
<tr>
<th>min</th>
<td>0.000000</td>
<td>20.00000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
</tr>
<tr>
<th>25%</th>
<td>0.000000</td>
<td>38.75000</td>
<td>0.000000</td>
<td>0.000000</td>
<td>0.000000</td>
</tr>
<tr>
<th>50%</th>
<td>0.000000</td>
<td>54.00000</td>
<td>0.000000</td>
<td>1.000000</td>
<td>1.000000</td>
</tr>
<tr>
<th>75%</th>
<td>1.000000</td>
<td>73.25000</td>
<td>1.000000</td>
<td>1.000000</td>
<td>1.000000</td>
</tr>
<tr>
<th>max</th>
<td>1.000000</td>
<td>90.00000</td>
<td>1.000000</td>
<td>1.000000</td>
<td>1.000000</td>
</tr>
</tbody>
</table>
</div>
<p>Antes de estimar os efeitos do tratamento, temos de ajustar os propensity scores para diferenças entre os grupos de tratamento. Devemos checar se os propensity scores nos permitem balancear a distribuição das variáveis explicativas com respeito aos dois grupos; um balancing score (b(x)) é uma função das covariáveis (x) tal que a distribuição condicional das covariáveis dado b(x) é similar para ambos os grupos de estudo (de tratamento e de controle). Isso pode ser observado em um gráfico de distribuição das variáveis explicativas dentro de quintis do propensity score para ambos os grupos.</p>
<p>Um conceito importante é o de forte ignorabilidade (strong ignorability); se a alocação ao tratamento é fortemente ignorável dadas as covariáveis, então os resultados são condicionalmente independentes da variável binária Z (que indica a exposição ou não ao tratamento) dadas as variáveis explicativas. Feito isso aplicamos a regressão logística e teremos o scores.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">clf</span> <span class="o">=</span> <span class="n">LogisticRegression</span><span class="p">(</span><span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">).</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span> <span class="c1">#define o modelo
</span>
<span class="n">score</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">clf</span><span class="p">.</span><span class="n">predict_proba</span><span class="p">(</span><span class="n">X</span><span class="p">),</span> <span class="n">columns</span> <span class="o">=</span> <span class="p">([</span><span class="s">"P(0)"</span><span class="p">,</span><span class="s">"P(1)"</span><span class="p">]))</span> <span class="c1">#estimamos os scores
</span>
<span class="n">score</span> <span class="o">=</span> <span class="n">score</span><span class="p">[[</span><span class="s">"P(1)"</span><span class="p">]]</span> <span class="c1">#utilizamos somente o score referente a probabilidade do tratamento
</span>
<span class="n">base_identidade</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">concat</span><span class="p">([</span><span class="n">base</span><span class="p">,</span> <span class="n">score</span><span class="p">],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span><span class="c1">#concateno as bases
</span><span class="n">base_score</span> <span class="o">=</span> <span class="n">base_identidade</span><span class="p">[[</span><span class="s">"P(1)"</span><span class="p">,</span><span class="s">"Cloroquina_(A)"</span><span class="p">]]</span> <span class="c1">#crio uma base específica
</span><span class="n">base_tempo</span> <span class="o">=</span> <span class="n">base_identidade</span><span class="p">[[</span><span class="s">"P(1)"</span><span class="p">,</span><span class="s">"Cloroquina_(A)"</span><span class="p">,</span><span class="s">"Tempo_Recuperação_(Y)"</span><span class="p">]]</span> <span class="c1">#crio uma base específica
</span><span class="n">base_identidade</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>Febre_(X)</th>
<th>Idade_(X)</th>
<th>Sexo_(X)</th>
<th>Dor_no_peito_(X)</th>
<th>Dificuldade_Respirar_(X)</th>
<th>Cloroquina_(A)</th>
<th>Tempo_Recuperação_(Y)</th>
<th>P(1)</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>0</td>
<td>78</td>
<td>0</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>26</td>
<td>0.215053</td>
</tr>
<tr>
<th>1</th>
<td>1</td>
<td>88</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>20</td>
<td>0.434960</td>
</tr>
<tr>
<th>2</th>
<td>0</td>
<td>36</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>14</td>
<td>0.512854</td>
</tr>
<tr>
<th>3</th>
<td>0</td>
<td>69</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>20</td>
<td>0.313836</td>
</tr>
<tr>
<th>4</th>
<td>1</td>
<td>84</td>
<td>1</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>11</td>
<td>0.459133</td>
</tr>
<tr>
<th>...</th>
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
<td>...</td>
</tr>
<tr>
<th>95</th>
<td>1</td>
<td>81</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>22</td>
<td>0.581955</td>
</tr>
<tr>
<th>96</th>
<td>1</td>
<td>74</td>
<td>0</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>13</td>
<td>0.386607</td>
</tr>
<tr>
<th>97</th>
<td>0</td>
<td>40</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>11</td>
<td>0.501556</td>
</tr>
<tr>
<th>98</th>
<td>1</td>
<td>21</td>
<td>0</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>12</td>
<td>0.645221</td>
</tr>
<tr>
<th>99</th>
<td>0</td>
<td>45</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>23</td>
<td>0.374955</td>
</tr>
</tbody>
</table>
<p>100 rows × 8 columns</p>
</div>
<h3 id="overlap">Overlap</h3>
<hr />
<p>Então analisamos como estão os nossos dados através da etapa do Overlap. Um bom overlap significa que em qualquer lugar que olhemos da imagem teremos chance de acontecimento para os dois casos. E podemos ver que nesse exemplo ficou um pouco assim, pois se pegarmos qualquer lugar no gráfico teremos elementos para de ambos conjuntos, como veremos no gráfico mais abaixo.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">selecao_tratados</span> <span class="o">=</span> <span class="n">base_score</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">base_score</span><span class="p">[</span><span class="s">'Cloroquina_(A)'</span><span class="p">].</span><span class="n">isin</span><span class="p">([</span><span class="mi">1</span><span class="p">])]</span> <span class="c1">#filtro a base
</span><span class="n">selecao_tratados_tempo</span> <span class="o">=</span> <span class="n">base_tempo</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">base_score</span><span class="p">[</span><span class="s">'Cloroquina_(A)'</span><span class="p">].</span><span class="n">isin</span><span class="p">([</span><span class="mi">1</span><span class="p">])]</span> <span class="c1">#filtro a base
</span><span class="n">selecao_tratados</span> <span class="o">=</span> <span class="n">selecao_tratados</span><span class="p">[[</span><span class="s">"P(1)"</span><span class="p">]]</span> <span class="c1">#renomeio a coluna
</span>
<span class="n">selecao_n_tratados</span> <span class="o">=</span> <span class="n">base_score</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">base_score</span><span class="p">[</span><span class="s">'Cloroquina_(A)'</span><span class="p">].</span><span class="n">isin</span><span class="p">([</span><span class="mi">0</span><span class="p">])]</span> <span class="c1">#filtro a base
</span><span class="n">selecao_n_tratados_tempo</span> <span class="o">=</span> <span class="n">base_tempo</span><span class="p">.</span><span class="n">loc</span><span class="p">[</span><span class="n">base_score</span><span class="p">[</span><span class="s">'Cloroquina_(A)'</span><span class="p">].</span><span class="n">isin</span><span class="p">([</span><span class="mi">0</span><span class="p">])]</span> <span class="c1">#filtro a base
</span><span class="n">selecao_n_tratados</span> <span class="o">=</span> <span class="n">selecao_n_tratados</span><span class="p">[[</span><span class="s">"P(1)"</span><span class="p">]]</span> <span class="c1">#renomeio a coluna
</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Tratados %s e Não tratados:%s"</span><span class="o">%</span> <span class="p">(</span><span class="n">selecao_tratados</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span><span class="n">selecao_n_tratados</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]))</span>
</code></pre></div></div>
<p>Output: Tratados 45 e Não tratados:55</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="n">sns</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="n">plt</span><span class="p">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s">'figure.figsize'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">6</span> <span class="c1">#arruma fonte
</span><span class="n">plt</span><span class="p">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s">'font.size'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">13</span> <span class="c1">#arruma fonte
</span>
<span class="n">sns</span><span class="p">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">selecao_n_tratados</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">'Não Tratados'</span><span class="p">)</span> <span class="c1">#não tratados
</span><span class="n">sns</span><span class="p">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">selecao_tratados</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">'Tratados'</span><span class="p">)</span> <span class="c1">##tratados
</span><span class="n">plt</span><span class="p">.</span><span class="n">xlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">#escala
</span><span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">'Ditribuição do Propensity Score para Não tratados vs Tratados'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">'Densidade'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">'Scores'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<p><img src="/img/oficina-PMS/output_10_1.png" style="display: block; margin: auto;" /></p>
<h2 id="matching">Matching</h2>
<hr />
<p>Em seguida, pareamos os indivíduos de grupos distintos com base em similitude de propensity score (ou seja, realizamos um match de um indivíduo do grupo de tratamento com um do grupo de controle). Existem vários métodos de pareamento – nearest neighbour, greedy matching, caliper matching, kernel matching, stratified matching, etc; a escolha do procedimento cabe ao pesquisador. O pareamento tipicamente leva a uma perda por descarte de indivíduos da amostra original; assim, o processo de pareamento também é uma forma de reamostragem.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#rodamos o modelo de vizinhos mais próximos
</span>
<span class="kn">from</span> <span class="nn">sklearn.neighbors</span> <span class="kn">import</span> <span class="n">NearestNeighbors</span>
<span class="n">knn</span> <span class="o">=</span> <span class="n">NearestNeighbors</span><span class="p">(</span><span class="n">n_neighbors</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="c1">#importa o modelo
</span><span class="n">knn</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">selecao_n_tratados</span><span class="p">.</span><span class="n">values</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="c1"># faz o fit
</span>
<span class="n">distances</span><span class="p">,</span> <span class="n">indices</span> <span class="o">=</span> <span class="n">knn</span><span class="p">.</span><span class="n">kneighbors</span><span class="p">(</span><span class="n">selecao_tratados</span><span class="p">.</span><span class="n">values</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span> <span class="mi">1</span><span class="p">))</span> <span class="c1">#aplico o modelo
</span>
<span class="c1">#transformo em datafram
</span>
<span class="n">indices</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">indices</span><span class="p">,</span> <span class="n">columns</span> <span class="o">=</span> <span class="p">{</span><span class="s">"Indices"</span><span class="p">})</span> <span class="c1">#crio o dataframe
</span><span class="n">selecao_tratados</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">selecao_tratados</span><span class="p">)</span>
<span class="c1">#### Processo de identificacao dos Matching
</span>
<span class="c1">### merge do tempo Y para os tratados
</span>
<span class="n">lista_1</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1">#crio lista
</span><span class="n">lista_2</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1">#crio lista
</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">indices</span><span class="p">.</span><span class="n">Indices</span><span class="p">:</span><span class="c1">#preencho a lista
</span> <span class="n">lista_1</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">selecao_tratados</span><span class="p">[</span><span class="s">"P(1)"</span><span class="p">]:</span><span class="c1">#preencho a lista
</span> <span class="n">lista_2</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="n">tratados</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">lista_1</span><span class="p">,</span> <span class="n">lista_2</span><span class="p">)),</span>
<span class="n">columns</span> <span class="o">=</span><span class="p">[</span><span class="s">'Indices'</span><span class="p">,</span><span class="s">'Scores_Tratados'</span><span class="p">])</span>
<span class="c1">### merge do tempo Y para os tratados
</span>
<span class="n">lista_1</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1">#crio lista
</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">selecao_tratados_tempo</span><span class="p">[</span><span class="s">"Tempo_Recuperação_(Y)"</span><span class="p">]:</span><span class="c1">#preencho a lista
</span> <span class="n">lista_1</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span>
<span class="n">tratados_tempo</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">lista_1</span><span class="p">)),</span>
<span class="n">columns</span> <span class="o">=</span><span class="p">[</span><span class="s">'Tempo_Recuperação_(Y)'</span><span class="p">])</span>
<span class="c1">### merge do tempo Y para os não tratados
</span>
<span class="n">lista_3</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">lista_4</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">a</span><span class="o">=</span><span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">selecao_n_tratados_tempo</span><span class="p">[</span><span class="s">"P(1)"</span><span class="p">]:</span><span class="c1">#preencho a lista
</span> <span class="n">a</span><span class="o">+=</span> <span class="mi">1</span> <span class="c1">#regra para novo indice
</span> <span class="n">lista_3</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">selecao_n_tratados_tempo</span><span class="p">[</span><span class="s">"P(1)"</span><span class="p">]:</span> <span class="c1">#preencho a lista
</span> <span class="n">lista_4</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="c1">#faço o append
</span>
<span class="n">n_tratados</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">lista_3</span><span class="p">,</span> <span class="n">lista_4</span><span class="p">)),</span>
<span class="n">columns</span> <span class="o">=</span><span class="p">[</span><span class="s">'Indices'</span><span class="p">,</span><span class="s">'Score_Nao_Tratados'</span><span class="p">])</span> <span class="c1">#unifico as listas
</span>
<span class="n">lista_3</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">lista_4</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">a</span><span class="o">=</span><span class="mi">0</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">selecao_n_tratados_tempo</span><span class="p">[</span><span class="s">"P(1)"</span><span class="p">]:</span><span class="c1">#preencho a lista
</span> <span class="n">a</span><span class="o">+=</span> <span class="mi">1</span> <span class="c1">#regra para novo indice
</span> <span class="n">lista_3</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">selecao_n_tratados_tempo</span><span class="p">[</span><span class="s">"Tempo_Recuperação_(Y)"</span><span class="p">]:</span> <span class="c1">#preencho a lista
</span> <span class="n">lista_4</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="c1">#faço o append
</span>
<span class="n">n_tratados_tempo</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">lista_3</span><span class="p">,</span> <span class="n">lista_4</span><span class="p">)),</span>
<span class="n">columns</span> <span class="o">=</span><span class="p">[</span><span class="s">'Indices'</span><span class="p">,</span><span class="s">'Tempo_Recuperação_(Y)_N'</span><span class="p">])</span> <span class="c1">#unifico as listas
</span>
<span class="n">base_indices_Score</span> <span class="o">=</span> <span class="n">tratados</span><span class="p">.</span><span class="n">merge</span><span class="p">(</span><span class="n">n_tratados</span><span class="p">,</span> <span class="n">on</span><span class="o">=</span><span class="s">'Indices'</span><span class="p">,</span><span class="n">right_index</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">how</span><span class="o">=</span><span class="s">'left'</span><span class="p">)</span> <span class="c1">#mesclo os matches para verificação
</span><span class="n">base_indices_tempo</span> <span class="o">=</span> <span class="n">base_indices_Score</span><span class="p">.</span><span class="n">merge</span><span class="p">(</span><span class="n">n_tratados_tempo</span><span class="p">,</span> <span class="n">on</span><span class="o">=</span><span class="s">'Indices'</span><span class="p">,</span><span class="n">right_index</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">how</span><span class="o">=</span><span class="s">'left'</span><span class="p">)</span> <span class="c1">#mesclo os matches para verificação
</span>
<span class="c1">#### Processo de identificacao dos Matching Finalizado
</span>
<span class="n">base_indices_tempo_final</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">concat</span><span class="p">([</span><span class="n">base_indices_tempo</span><span class="p">,</span> <span class="n">tratados_tempo</span><span class="p">],</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">join</span><span class="o">=</span><span class="s">'inner'</span><span class="p">)</span> <span class="c1">#concateno os dataframes
</span><span class="n">base_indices_tempo_final</span><span class="p">[</span><span class="s">"Cloroquina_(A)_T"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">base_indices_tempo_final</span><span class="p">[</span><span class="s">"Cloroquina_(A)_NT"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1">#Agora já temos a base geral, mas precisamos ajeita-la, padronizando as colunas que representam a mesma coisa
</span>
<span class="n">base_indices_tempo_final</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>Indices</th>
<th>Scores_Tratados</th>
<th>Score_Nao_Tratados</th>
<th>Tempo_Recuperação_(Y)_N</th>
<th>Tempo_Recuperação_(Y)</th>
<th>Cloroquina_(A)_T</th>
<th>Cloroquina_(A)_NT</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>48</td>
<td>0.512854</td>
<td>0.509889</td>
<td>29</td>
<td>14</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<th>1</th>
<td>8</td>
<td>0.459133</td>
<td>0.457321</td>
<td>28</td>
<td>11</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<th>2</th>
<td>29</td>
<td>0.357378</td>
<td>0.356476</td>
<td>17</td>
<td>24</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<th>3</th>
<td>45</td>
<td>0.555223</td>
<td>0.555844</td>
<td>11</td>
<td>20</td>
<td>1</td>
<td>0</td>
</tr>
<tr>
<th>4</th>
<td>28</td>
<td>0.484609</td>
<td>0.481999</td>
<td>29</td>
<td>11</td>
<td>1</td>
<td>0</td>
</tr>
</tbody>
</table>
</div>
<h3 id="o-que-é-essa-base">O que é essa base?</h3>
<ul>
<li>Indices = Indice do score nao tratado gerado pelo KNN</li>
<li>Scores_Tratados = Scores_Tratados</li>
<li>Scores_Nao_Tratados = Scores_Nao_Tratados</li>
<li>Tempo_Recuperação_(Y)_N = Tempo de recuperacao para os n_tratados</li>
<li>Tempo_Recuperação_(Y) = Tempo de recuperacao para os tratados</li>
<li>Cloroquina_(A)_T = Cloroquina para os tratados</li>
<li>Cloroquina_(A)_T = Cloroquina para os n_tratados</li>
</ul>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">tratados</span> <span class="o">=</span> <span class="n">base_indices_tempo_final</span><span class="p">[[</span><span class="s">"Scores_Tratados"</span><span class="p">,</span><span class="s">"Cloroquina_(A)_T"</span><span class="p">,</span><span class="s">"Tempo_Recuperação_(Y)"</span><span class="p">]]</span> <span class="c1">#filtro as colunas que eu
#quero
</span><span class="n">tratados</span><span class="p">.</span><span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="s">"Score"</span><span class="p">,</span><span class="s">"Cloroquina_(A)"</span><span class="p">,</span><span class="s">"Tempo_Recuperação_(Y)"</span><span class="p">]</span> <span class="c1">#renomeio as colunas
</span>
<span class="n">n_tratados</span> <span class="o">=</span> <span class="n">base_indices_tempo_final</span><span class="p">[[</span><span class="s">"Score_Nao_Tratados"</span><span class="p">,</span><span class="s">"Cloroquina_(A)_NT"</span><span class="p">,</span><span class="s">"Tempo_Recuperação_(Y)_N"</span><span class="p">]]</span><span class="c1">#filtro as colunas que eu
#quero
</span><span class="n">n_tratados</span><span class="p">.</span><span class="n">columns</span> <span class="o">=</span> <span class="p">[</span><span class="s">"Score"</span><span class="p">,</span><span class="s">"Cloroquina_(A)"</span><span class="p">,</span><span class="s">"Tempo_Recuperação_(Y)"</span><span class="p">]</span> <span class="c1">#renomeio as colunas
</span>
<span class="c1"># Geramos nossa babse final com todos os casos encaixados nas tres variaveis
</span>
<span class="n">base_final_1</span> <span class="o">=</span> <span class="n">tratados</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">n_tratados</span><span class="p">)</span>
<span class="n">base_final_1</span><span class="p">.</span><span class="n">describe</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>Score</th>
<th>Cloroquina_(A)</th>
<th>Tempo_Recuperação_(Y)</th>
</tr>
</thead>
<tbody>
<tr>
<th>count</th>
<td>90.000000</td>
<td>90.000000</td>
<td>90.000000</td>
</tr>
<tr>
<th>mean</th>
<td>0.476043</td>
<td>0.500000</td>
<td>18.733333</td>
</tr>
<tr>
<th>std</th>
<td>0.090493</td>
<td>0.502801</td>
<td>6.363166</td>
</tr>
<tr>
<th>min</th>
<td>0.273230</td>
<td>0.000000</td>
<td>10.000000</td>
</tr>
<tr>
<th>25%</th>
<td>0.397510</td>
<td>0.000000</td>
<td>12.000000</td>
</tr>
<tr>
<th>50%</th>
<td>0.485462</td>
<td>0.500000</td>
<td>18.000000</td>
</tr>
<tr>
<th>75%</th>
<td>0.551437</td>
<td>1.000000</td>
<td>23.750000</td>
</tr>
<tr>
<th>max</th>
<td>0.645221</td>
<td>1.000000</td>
<td>30.000000</td>
</tr>
</tbody>
</table>
</div>
<h2 id="após-o-matching">Após o Matching</h2>
<hr />
<p>Poderíamos usar o Caliper que basicamente é a a distância que iremos tolerar entre os matches, filtrando assim melhor a base. Mas nesse caso não usaremos. Vamos dar uma olhada como ficou o gráfico após o match:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">plt</span><span class="p">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s">'figure.figsize'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="mi">6</span> <span class="c1">#arruma fonte
</span><span class="n">plt</span><span class="p">.</span><span class="n">rcParams</span><span class="p">[</span><span class="s">'font.size'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">13</span> <span class="c1">#arruma fonte
</span>
<span class="n">sns</span><span class="p">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">n_tratados</span><span class="p">[</span><span class="s">"Score"</span><span class="p">],</span> <span class="n">label</span><span class="o">=</span><span class="s">'Não Tratados'</span><span class="p">)</span> <span class="c1">#não tratados
</span><span class="n">sns</span><span class="p">.</span><span class="n">distplot</span><span class="p">(</span><span class="n">selecao_tratados</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="s">'Tratados'</span><span class="p">)</span> <span class="c1">##tratados
</span><span class="n">plt</span><span class="p">.</span><span class="n">xlim</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">#escala
</span><span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">'Ditribuição do Propensity Score para Não tratados vs Tratados'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">'Densidade'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">'Scores'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">tight_layout</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<p><img src="/img/oficina-PMS/output_17_1.png" style="display: block; margin: auto;" /></p>
<p>Um pouco diferente, não?</p>
<p>Por fim, calculamos então a média do efeito do tratamento por meio de uma análise multivariada dentro dessa nova amostra. A média da diferença dos resultados entre os pares é uma medida não enviesada do efeito médio do tratamento.</p>
<blockquote>
<p>Nesse momento então tiramos a prova conceito adaptando ao modelo de reg linear e vendo seus p-valor e o seu beta</p>
</blockquote>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">statsmodels.api</span> <span class="k">as</span> <span class="n">sm</span> <span class="c1">#chamo o modelo
</span>
<span class="n">X_base</span><span class="o">=</span> <span class="n">base_final_1</span><span class="p">[[</span><span class="s">"Score"</span><span class="p">,</span> <span class="s">"Cloroquina_(A)"</span><span class="p">]]</span> <span class="c1">#filtro as colunas
</span><span class="n">y_base</span><span class="o">=</span> <span class="n">base_final_1</span><span class="p">[[</span><span class="s">"Tempo_Recuperação_(Y)"</span><span class="p">]]</span> <span class="c1">#filtro as colunas
</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">sm</span><span class="p">.</span><span class="n">add_constant</span><span class="p">(</span><span class="n">X_base</span><span class="p">.</span><span class="n">values</span><span class="p">.</span><span class="n">ravel</span><span class="p">())</span> <span class="c1">#aplicamos o modelo
</span><span class="n">results</span> <span class="o">=</span> <span class="n">sm</span><span class="p">.</span><span class="n">OLS</span><span class="p">(</span><span class="n">y_base</span><span class="p">,</span><span class="n">X_base</span><span class="p">).</span><span class="n">fit</span><span class="p">()</span> <span class="c1">#computamos os resultados
</span><span class="n">results</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span> <span class="c1">#visualizamos os resultados
</span></code></pre></div></div>
<table class="simpletable">
<caption>OLS Regression Results</caption>
<tr>
<th>Dep. Variable:</th> <td>Tempo_Recuperação_(Y)</td> <th> R-squared: </th> <td> 0.856</td>
</tr>
<tr>
<th>Model:</th> <td>OLS</td> <th> Adj. R-squared: </th> <td> 0.853</td>
</tr>
<tr>
<th>Method:</th> <td>Least Squares</td> <th> F-statistic: </th> <td> 261.5</td>
</tr>
<tr>
<th>Date:</th> <td>Sun, 26 Apr 2020</td> <th> Prob (F-statistic):</th> <td>9.37e-38</td>
</tr>
<tr>
<th>Time:</th> <td>00:22:57</td> <th> Log-Likelihood: </th> <td> -309.10</td>
</tr>
<tr>
<th>No. Observations:</th> <td> 90</td> <th> AIC: </th> <td> 622.2</td>
</tr>
<tr>
<th>Df Residuals:</th> <td> 88</td> <th> BIC: </th> <td> 627.2</td>
</tr>
<tr>
<th>Df Model:</th> <td> 2</td> <th> </th> <td> </td>
</tr>
<tr>
<th>Covariance Type:</th> <td>nonrobust</td> <th> </th> <td> </td>
</tr>
</table>
<table class="simpletable">
<tr>
<td></td> <th>coef</th> <th>std err</th> <th>t</th> <th>P>|t|</th> <th>[0.025</th> <th>0.975]</th>
</tr>
<tr>
<th>Score</th> <td> 35.8065</td> <td> 2.301</td> <td> 15.564</td> <td> 0.000</td> <td> 31.235</td> <td> 40.378</td>
</tr>
<tr>
<th>Cloroquina_(A)</th> <td> 1.8723</td> <td> 1.576</td> <td> 1.188</td> <td> 0.238</td> <td> -1.260</td> <td> 5.005</td>
</tr>
</table>
<table class="simpletable">
<tr>
<th>Omnibus:</th> <td>19.945</td> <th> Durbin-Watson: </th> <td> 2.153</td>
</tr>
<tr>
<th>Prob(Omnibus):</th> <td> 0.000</td> <th> Jarque-Bera (JB): </th> <td> 4.685</td>
</tr>
<tr>
<th>Skew:</th> <td> 0.014</td> <th> Prob(JB): </th> <td> 0.0961</td>
</tr>
<tr>
<th>Kurtosis:</th> <td> 1.883</td> <th> Cond. No. </th> <td> 2.60</td>
</tr>
</table>
<p><br /><br />Warnings:<br />[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.</p>
<h2 id="conclusão-do-exemplo">Conclusão do Exemplo</h2>
<p>Em geral testamos a hipótese nula: O tratamento não tem efeito.</p>
<p>Se rejeitarmos a hipótese nula, dizemos que ele tem efeito. Em termos pratico, um p-valor abaixo de 0.05 nos leva a rejeitar a hipótese nula, essa hipótese é testada em cima daquele coeficiente beta ( 1.8723 ). Então a conta que ele faz é ( Beta / Erro padrão ). Na tabela, 1.8723 / 1.576 que irá dar exatamente o valor t.</p>
<table>
<tbody>
<tr>
<td>Ai olhamos a probabilidade desse valor ocorrer um valor maior que</td>
<td>t</td>
<td>-> (**P></td>
<td>t</td>
<td><strong>), ou seja, maior que t positivo e menor que t negativo, se ela for alta (em termos práticos, acima de 0.05) dizemos que esse Beta não é diferente de zero, ou seja, **nesse caso FICTÍCIO o tratamento não tem efeito</strong>.</td>
</tr>
</tbody>
</table>
<h1 id="parte-v--vantagens-e-desvantagens-do-psm">Parte V – Vantagens e desvantagens do PSM</h1>
<p>Dentre as principais vantagens do PSM, podemos incluir: a sumarização dos dados em uma “pontuação”, o propensity score, para estimar os efeitos do tratamento ao invés de observar e comparar múltiplas covariáveis; a amostra de indivíduos participantes do estudo pode ser mais representativa da população do que em um RCT; o cálculo do PS não inclui qualquer informação do resultado, logo a estimação do efeito do tratamento não sofre viés; como o modelo usado para estimar o PS não é o foco do estudo, ele não necessita ser parcimonioso, o que permite a inclusão de um número maior de covariáveis e termos de interação entre elas; entre outros.</p>
<p>As principais desvantagens do PSM surgem a partir de sua natureza não randômica de alocação dos indivíduos aos grupos de controle ou tratamento. De fato, o método PSM balanceia a análise com base em covariáveis observadas, enquanto experimentos randômicos balanceiam tanto sobre covariáveis conhecidas como desconhecidas. Ao não controlar para covariáveis desconhecidas, há o risco de viés afetando a probabilidade dos indivíduos receberam tratamento ou não. Além disso, é preferível, senão necessário, que o método seja aplicado em amostras grandes. Há a necessidade de sobreposição significativa entre os propensity scores dos grupos, de modo a melhor realizar o pareamento. O próprio pareamento, ao ser feito apenas em observância das variáveis observadas, abre a possibilidade de aumento do viés devido à existência de covariáveis não observadas.</p>
<h2 id="referências">Referências</h2>
<ul>
<li>COWLING, Ben. Propensity Score Analysis. The University of Hong Kong. 2017. Disponível em : <a href="http://web.hku.hk/~bcowling/examples/propensity.htm">http://web.hku.hk/~bcowling/examples/propensity.htm</a></li>
<li>FRASER, Mark W.; GUO, Shenyang. Propensity Score Analysis: statistical methods and applications - 2nd edition. SAGE Publications, 2015.</li>
<li>PROPENSITY score. Columbia Mailman School of Public Health, 2012. Disponível em: <a href="https://www.mailman.columbia.edu/research/population-health-methods/propensityscore">https://www.mailman.columbia.edu/research/population-health-methods/propensityscore</a></li>
<li>PROPENSITY Score Matching: Definition & Overview . Statistics How To, 2017. Disponível em: <a href="https://www.statisticshowto.com/propensity-score-matching/">https://www.statisticshowto.com/propensity-score-matching/</a></li>
<li>THAVANESWARAN, Arane. Propensity Score Matching in Observational Studies. Faculty of Health and Sciences, University of Manitoba, 2008. Disponível em: <a href="https://www.umanitoba.ca/faculties/health_sciences/medicine/units/chs/departmental_units/mchp/protocol/media/propensity_score_matching.pdf">https://www.umanitoba.ca/faculties/health_sciences/medicine/units/chs/departmental_units/mchp/protocol/media/propensity_score_matching.pdf</a></li>
<li>ROSEMBAUM, Paul R.; RUBIN, Donald B. The central role of the propensity score in observational studies for causal effects. Biometrika, 1983; 70:41-55</li>
</ul>
Credit Risk - Estimating Bank Default Models2020-05-26T00:00:00+00:00http://lamfo-unb.github.io/2020/05/26/Credit-Risk-Estimating-Bank-Default-Models<h2 id="introduction">Introduction</h2>
<p>In this post, I intruduce the calculation measures of default banking. In particular, this post considers the <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x"> Merton (1974) </a> probability of default method, also known as the Merton model, the default model KMV from Moody’s, and the Z-score model of <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=571342"> Lown et al. (2000) </a> and of <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426613002598"> Tabak et al. (2013) </a>, which is an adaptation of the <a href="https://onlinelibrary.wiley.com/doi/abs/10.1111/j.1540-6261.1968.tb00843.x"> Altman (1968) </a> model.</p>
<p>The data used in the study are utilized in three stages. In the foreground, we use the values extracted from the balance of payments, then we use the financial statements, and lastly, we use the stock price history of world banks listed on the stock exchange, all extracted from the database of Bloomberg. The analysis period covers the first quarter of 2000 until the third quarter of 2016 with a periodicity of 67 quarters in 2,325 banks and 92 countries. Note that the assembled panel is unbalanced, containing 155,775 observations.</p>
<h2 id="merton-model">Merton Model</h2>
<p>The <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x"> Merton (1974) </a> model aims to find the values of assets and their volatilities in a dynamic process following <a href="https://www.jstor.org/stable/1831029?seq=1#metadata_info_tab_contents"> Black and Scholes (1973) </a>. In the Merton model, it is assumed that the total value of the firm follows a geometric Brownian motion process.</p>
\[dV = \mu Vdt +\sigma_V VdW\]
<p>where \(V\) is the total value of the firm’s assets (random variable), \(\mu\) is the expected continuous return of \(V\), \(\sigma_V\) is the firm value volatility, and \(dW\) is the standard process of Gauss–Wiener.</p>
<p>The Merton model uses the <a href="https://www.jstor.org/stable/1831029?seq=1#metadata_info_tab_contents"> Black and Scholes (1973) </a> model of options in which the firm’s equity value follows the stipulated process of <a href="https://www.jstor.org/stable/1831029?seq=1#metadata_info_tab_contents"> Black and Scholes (1973) </a> for call options. A call option on the underlying assets has the same properties as a caller has, namely, a demand on the assets after reaching the strike price of the option. In this case, the exercise price of the option equals the book value of the firm’s obligations. If the value of the assets is insufficient to cover the firm’s obligations, then shareholders with a call option do not exercise their option and leave the firm to their creditors.</p>
\[E = V\mathcal{N}(d_1)- e^{-rT}F\mathcal{N}(d_2)\]
<p>where \(E\) is the market value of the equity of the firm (or free cash flow to the shareholder), \(F\) is the face value of the debt securities, \(r\) is the risk-free interest rate, and \(\mathcal {N} (.)\) is the standardized cumulative normal distribution; \(d_1\) is given by</p>
\[d_1 = \frac{ln(\frac{V}{F})+(r+0.5\sigma^2_V)T}{\sigma_V\sqrt{T}}\]
<p>and \(d_2\) is simply \(d_1-\sigma_V\sqrt{T}\).</p>
<p>Applying the Itô Lemma in the dynamic process of \(V\) and manipulating the terms of Equation of \(d_1\), we obtain the following equation of the variability of the free cash flows of the shareholders (\(\sigma_E\)) <a href="https://academic.oup.com/rfs/article-abstract/21/3/1339/1566804?redirectedFrom=fulltext"> (Bharath and Shumway, 2008) </a>.</p>
\[\sigma_E=\left(\frac{V}{E}\right)\frac{\partial E}{\partial V}\sigma_V\]
<p>Given that <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x"> Merton (1974) </a>, it can be shown that \(\frac{\partial E}{\partial V} = \mathcal{N} (d_1)\); then, Equation of \(\sigma_E\) can be written as follows <a href="https://academic.oup.com/rfs/article-abstract/21/3/1339/1566804?redirectedFrom=fulltext"> (Bharath and Shumway, 2008) </a>:</p>
\[\sigma_E = \left(\frac{V}{E}\right)\mathcal{N}(d_1)\sigma_V\\]
<p>Basically, the algorithm works with Equations of \(E\) and \(\sigma_E\) to find the value terms of the asset \(V\) and the volatility of the asset value \(\sigma_V\). In this study, I use the Newton method to solve Equations \(E\) and \(\sigma_E\), the same algorithm that was used by <a href="https://www.sciencedirect.com/science/article/pii/S1572308914000266"> Anginer and Demirguc-Kunt (2014) </a>.</p>
<p>Equations \(E\) and \(\sigma_E\) have numerical solutions only for the values of \(V\) and \(\sigma_ {V}\). Once the numerical solution is found, the distance of default is calculated as follows:</p>
\[DD = \frac{ln\left(\frac{V}{F}\right) + (\mu - \frac{1}{2}\sigma^{2}_{V})T}{\sigma_{V} \sqrt{T}}\]
<p>According to <a href="https://academic.oup.com/rfs/article-abstract/21/3/1339/1566804?redirectedFrom=fulltext">Bharath and Shumway (2008)</a>, the distance to the default model of <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> accurately measures the probability of firms defaulting.</p>
\[\pi_{Merton} = \mathcal{N}(-DD)\]
<p>The default probability measure of <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> is simply the probability function of the normal minus the distance to default, Equation of $DD$. According to <a href="https://academic.oup.com/rfs/article-abstract/21/3/1339/1566804?redirectedFrom=fulltext">Bharath and Shumway (2008)</a>, this probability of default (Equation of \(\pi_{Merton}\)) should be a sufficient statistic for the default prognostic.</p>
<p>The starting point of the algorithm follows an adaptation of <a href="https://academic.oup.com/rfs/article-abstract/21/3/1339/1566804?redirectedFrom=fulltext">Bharath and Shumway (2008)</a> and <a href="https://www.sciencedirect.com/science/article/pii/S1572308914000266">Anginer and Demirguc-Kunt (2014)</a>, where the initial kicks of \(V\) assume \(V = market \ capitalization + total \ liabilities\) and \(\sigma_ {V}\) assume \(\sigma_{V} = \sigma_{asset \ price \ return} \times (market \ capitalization + total \ liabilities).\)</p>
<h3 id="application-in-r">Application in R</h3>
<pre><code class="language-rscript=1">#######################
### Script Merton Model
#######################
## packages require
library(adagio)
library(nleqslv)
library(reshape2)
library(dplyr)
library(plyr)
library(pbapply)
library(stringdist)
library(xlsx)
# read the bank data
bank_panel_2000<- read.csv2("new_bank_panel_v18.csv",
stringsAsFactors=FALSE, sep = ";")
# make the DD_base
DD_base<- bank_panel_2000[,which(colnames(bank_panel_2000)%in%c("acao", "indice", "tempo", "quarter", "year", "cap_mercado", "passivo_total","retorno_med", "retorno_med_d", "sd", "sd_d", "retorno_tri", "t_bill", "t") == TRUE)]
DD_base[which(colnames(DD_base)%in%c("acao", "indice", "tempo", "quarter") == F)][]<- lapply(DD_base[which(colnames(DD_base)%in%c("acao", "indice", "tempo", "quarter") == F)], as.numeric)
DD_base<- DD_base[complete.cases(DD_base), ]
DD_base<- DD_base[which(DD_base$passivo_total != 0), ]
DD_base<- DD_base[which(DD_base$sd != 0),]
# create the t variable in one quarter
DD_base$t = 1
##########################
##### p_merton ###########
##########################
# make the inicial p_merton
base_merton<- DD_base[,which(colnames(DD_base)%in%c("acao", "tempo", "quarter", "year") == TRUE)]
base_merton$valor_ativo_bailout<- NA
base_merton$vol_impl_ativo_bailout<- NA
base_merton$DD_merton_bailout<- NA
base_merton$p_merton_bailout<- NA
pb <- txtProgressBar(min = 0, max = nrow(base_merton), style = 3)
index <- 1
#i<- 1
for (i in 1:nrow(DD_base))
{
D1<- DD_base$passivo_total[i]
t<- DD_base$t[i]
R<- DD_base$t_bill[i]
Sigmas<- DD_base$sd[i]
SO1<- DD_base$cap_mercado[i]
fnewton <- function(x){
y <- numeric(2)
d1 <- (log(x[1]/D1)+(R+0.5*(x[2]^2))*t)/(x[2]*sqrt(t))
d2 <- d1-x[2]*sqrt(t)
y[1] <- SO1 - (x[1]*pnorm(d1) - (exp(-R*t))*D1*pnorm(d2))
y[2] <- Sigmas*SO1 - pnorm(d1)*x[2]*d1
y
}
xstart <- c(DD_base$cap_mercado[i] + DD_base$passivo_total[i] , DD_base$sd[i]*((DD_base$cap_mercado[i] + DD_base$passivo_total[i])))
var_temp_merton<- nleqslv(xstart, fnewton, control=list(btol=.01), method="Newton")
base_merton$valor_ativo_bailout[i]<- var_temp_merton$fvec[1]
base_merton$vol_impl_ativo_bailout[i]<- var_temp_merton$fvec[2]
# DD
DD<- (log(base_merton$valor_ativo_bailout[i]/D1)+(DD_base$retorno_tri[i]-(0.5*(base_merton$vol_impl_ativo_bailout[i]^2)))*t)/base_merton$vol_impl_ativo_bailout[i]*sqrt(t)
base_merton$DD_merton_bailout[i]<- DD
# p_merton
p_merton_bailout<- pnorm(- base_merton$DD_merton_bailout[i])
base_merton$p_merton_bailout[i]<- p_merton_bailout
index <-index+ 1
setTxtProgressBar(pb, index)
}
close(pb)
# clean the base_merton
base_merton[is.na(base_merton)] <- NA
base_merton$DD_merton_bailout[is.infinite(base_merton$DD_merton_bailout)]<- NA
</code></pre>
<h2 id="kmv-model">KMV Model</h2>
<p>The KMV model is calculated from the total value of the firm’s assets \(V\) and the volatility of the asset value \(\sigma_{V}\) from the iteration between Equations \(E\) and \(\sigma_E\). We can observe the same process in <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> Model.</p>
\[DD_{KMV it} = \frac{(V_{it} - TL_{it})}{(V_{it} \cdot \sigma_{V it})}\]
<p>where \(V_ {it}\) represents the market value of asset \(i\) in period \(t\), \(\sigma_ {V it}\) represents the volatility of asset value \(i\) in period \(t\), and \(TL_ {it}\) is total liabilities to asset \(i\) in period \(t\). As indicated by Equation \(DD_{KMV it}\), with higher \(DD_ {kMV it}\), the distance to default from bank \(i\) in period \(t\) is greater.</p>
<p>To normalize the variable to have a parallel effect and correlation analysis, normalization similar that elaborated by <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> is used. In other words, the probability of default of the KMV model is</p>
\[\pi_{kmv} = \mathcal{N}(-DD_{KMV})\]
<p>The default KMV measure is the normal probability function minus the default distance, as well as the <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> model.</p>
<h3 id="application-in-r-1">Application in R</h3>
<pre><code class="language-rscript=98">################################
######## kmv_model #############
################################
base_kmv = base_merton
base_kmv$kmv_model_bailout<- (base_merton$valor_ativo_bailout - DD_base$passivo_total)/(base_merton$valor_ativo_bailout*base_merton$vol_impl_ativo_bailout)
base_kmv$kmv_model_bailout[is.na(base_kmv$kmv_model_bailout)] <- NA
base_kmv$kmv_model_bailout[is.infinite(base_kmv$kmv_model_bailout)]<- NA
kmv_model<- base_kmv[,which(colnames(base_kmv)%in%c("acao", "tempo", "kmv_model_bailout") == TRUE)]
# kmv_normalized
kmv_model$p_kmv<- pnorm(- kmv_model$kmv_model_bailout)
</code></pre>
<h2 id="z-score-model">Z-Score Model</h2>
<p>Another way to measure the default is the Z-score indicator, similar to <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=571342">Lown et al. (2000)</a> and <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426613002598">Tabak et al. (2013)</a>. According to <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=571342">Lown et al. (2000)</a> and <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426613002598">Tabak et al. (2013)</a>, this indicator represents the probability of bank failure. The Z-score measure has the following formulation:</p>
\[Z-score_{it}=\frac{ROA_{it}+EQUAS_{it}}{\sigma_{ROA_i}}\]
<p>where \(EQUAS = \left(\frac{E_{it}-E_{it-1}}{TA_{it}-TA_{it-1}}\right)\). In this model, \(E_ {it}\) represents bank equity \(i\) in period \(t\), \(E_{it-1}\) represents bank equity \(i\) in period \(t-1\), \(TA_ {it}\) represents total assets of bank \(i\) in period \(t\), and \(TA_{it-1}\) represents total assets of bank \(i\) in period \(t-1\).</p>
<p>Parameter \(ROA_ {it}\) is expressed as the following relation:</p>
\[ROA_{it}=\frac{2\pi_{it}}{(TA_{it}-TA_{it-1})}\]
<p>\(ROA_ {it}\) is the return on assets in period \(t\) for bank \(i\) and \(\sigma_ {ROA it}\) is the standard deviation of \(ROA\) of bank \(i\) in period \(t\). As the formula indicates, the higher the Z-score value, the lower the probability of bank failure \(i\). For <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426613002598">Tabak et al. (2013)</a>, the Z-score is a risk default measure accepted by the literature. The Z-score measures the number of standard deviations of \(ROA\) that must decrease in order for banks become insolvent, which can be interpreted as the inverse of the probability of insolvency <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426613002598">(Tabak et al., 2013)</a>.</p>
<p>Both the default probability measure of <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> and the KMV measure have a direct relationship with the default, that is, the higher their values, the greater the likelihood of a financial institution falling. Meanwhile, the Z-score model has an inverse relationship with the default bank, that is, the higher its values, the more distant the bank is from the default. This inverse relationship between the Merton Models, Model KMV and Model Z-score occurs because the first two represent a normalization of the distances from the default, making them directly linked to the default. In the Z-score model, on the other hand, the relationship is inverse because it measures the distance from the default, that is, the probability of banks being further from the default and not the direct probability of default.</p>
<p>The <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> model and the KMV model are default proxies that do not directly calculate the probability of default, but rather measure it implicitly, by looking at bank liabilities and how the market prices these liabilities <a href="https://www.sciencedirect.com/science/article/pii/S1572308913000442?via%3Dihub">(Milne, 2014)</a>. According to <a href="https://www.sciencedirect.com/science/article/abs/pii/S1057521916301326?via%3Dihub">Wang et al. (2017)</a>, to measure the default risk, a common proxy should not be used, but a flexible enough measure to quantify most firms in the market.</p>
<p>The Z-score model, despite being an accepted measure in the risk measurement literature, especially of bank risk, does not express the market relationship, but the banks’ accounting relationship.</p>
<h3 id="application-in-r-2">Application in R</h3>
<pre><code class="language-rscript=1">########################
### Script Z-Score Model
########################
# construct the temp ROA data
temp_bank_ROA<- bank_panel_2000[, c(1:3, 30)]
temp_bank_ROA$quarter<- substring(temp_bank_ROA$tempo, first = 1, last = 3)
temp_bank_ROA$year<- substring(temp_bank_ROA$tempo, first = 5, last = 8)
temp_bank_ROA<- arrange(temp_bank_ROA,acao, year, quarter)
temp_bank_ROA_duplic<- ddply(temp_bank_ROA, .(acao), transform, ativo_total = c( NA, ativo_total[-length(ativo_total)]))
temp_bank_ROA_duplic<- temp_bank_ROA_duplic[, -c (4:6)]
temp_bank_ROA<- arrange(temp_bank_ROA,acao, year, quarter)
temp_bank_ROA<- merge(temp_bank_ROA, temp_bank_ROA_duplic, by.x=c("acao", "tempo"), by.y=c("acao", "tempo"), all.x=T,all.y=T)
rm(temp_bank_ROA_duplic)
# creat a for to make a ROA
acoes_list<- unique(temp_bank_ROA$acao)
tempo_list<- unique(temp_bank_ROA$tempo)
temp_ROA<- temp_bank_ROA[1,]
temp_ROA$at_ROA<- NA
temp_ROA<- temp_ROA[-c(1),]
pb <- txtProgressBar(min = 0, max = length(acoes_list), style = 3)
index <- 1
#i <- acoes_list[1]
#y<- tempo_list[1]
for (i in acoes_list)
{
temp_assets<- temp_bank_ROA[which(temp_bank_ROA$acao == i),]
temp_assets$at_ROA<- NA
for(y in tempo_list)
{
if (y == "CQ1.2000")
{
temp_assets$at_ROA[which(temp_assets$tempo == y)]<- temp_assets$ativo_total.x[which(temp_assets$tempo == y)] * 2
}else {temp_assets$at_ROA[which(temp_assets$tempo == y)]<- sum(temp_assets$ativo_total.x[which(temp_assets$tempo == y)], temp_assets$ativo_total.y[which(temp_assets$tempo == y)], na.rm = TRUE)}
}
temp_ROA<- rbind(temp_ROA, temp_assets)
index <-index+ 1
setTxtProgressBar(pb, index)
}
close(pb)
temp_ROA<- temp_ROA[, -c(3:4, 7)]
temp_ROA$at_ROA[temp_ROA$at_ROA == 0]<- NA
# make a merge with the bank_2000
temp_bank_panel_2000<- merge(bank_panel_2000, temp_ROA, by.x=c("acao", "tempo"), by.y=c("acao", "tempo"), all.x=T,all.y=T)
temp_bank_panel_2000<- arrange(temp_bank_panel_2000,acao, year, quarter)
# make the ROA data - Lown (2007)
temp_bank_panel_2000$ROA<- (2*temp_bank_panel_2000$ni)/(temp_bank_panel_2000$at_ROA)
bank_panel_2000<- temp_bank_panel_2000
# remove the extra data
rm(temp_bank_ROA, temp_bank_ROA_duplic, temp_assets, temp_bank_panel_2000)
# construct the temp ROE data
temp_bank_ROE<- bank_panel_2000[, c(1:2, 10, 30:32)]
temp_bank_ROE_duplic<- ddply(temp_bank_ROE, .(acao), transform, patrimonio_liquido = c( NA, patrimonio_liquido[-length(patrimonio_liquido)]))
temp_bank_ROE_duplic<- temp_bank_ROE_duplic[, c (1:3)]
temp_bank_ROE<- merge(temp_bank_ROE, temp_bank_ROE_duplic, by.x=c("acao", "tempo"), by.y=c("acao", "tempo"), all.x=T,all.y=T)
temp_bank_ROE<- arrange(temp_bank_ROE,acao, year, quarter)
rm(temp_bank_ROE_duplic)
# creat a for to make a ROE
acoes_list<- unique(temp_bank_ROA$acao)
tempo_list<- unique(temp_bank_ROA$tempo)
temp_ROE<- temp_bank_ROE[1,]
temp_ROE$at_ROE<- NA
temp_ROE<- temp_ROE[-c(1),]
pb <- txtProgressBar(min = 0, max = length(acoes_list), style = 3)
index <- 1
#i <- acoes_list[1]
#y<- tempo_list[1]
for (i in acoes_list)
{
temp_assets<- temp_bank_ROE[which(temp_bank_ROE$acao == i),]
temp_assets$at_ROE<- NA
for(y in tempo_list)
{
if (y == "CQ1.2000")
{
temp_assets$at_ROE[which(temp_assets$tempo == y)]<- temp_assets$patrimonio_liquido.x[which(temp_assets$tempo == y)] * 2
}else {temp_assets$at_ROE[which(temp_assets$tempo == y)]<- sum(temp_assets$patrimonio_liquido.x[which(temp_assets$tempo == y)], temp_assets$patrimonio_liquido.y[which(temp_assets$tempo == y)], na.rm = TRUE)}
}
temp_ROE<- rbind(temp_ROE, temp_assets)
index <-index+ 1
setTxtProgressBar(pb, index)
}
close(pb)
temp_ROE<- temp_ROE[, -c(3:7)]
temp_ROE$at_ROE[temp_ROE$at_ROE == 0]<- NA
# make a merge with the bank_2000
temp_bank_panel_2000<- merge(bank_panel_2000, temp_ROE, by.x=c("acao", "tempo"), by.y=c("acao", "tempo"), all.x=T,all.y=T)
temp_bank_panel_2000<- arrange(temp_bank_panel_2000,acao, year, quarter)
# make the ROE data - Lown (2007)
temp_bank_panel_2000$ROE<- (2*temp_bank_panel_2000$ni)/(temp_bank_panel_2000$at_ROE)
bank_panel_2000<- temp_bank_panel_2000
# remove the extra data
rm(temp_bank_ROE, temp_assets, temp_bank_panel_2000)
########################################################################################
########################### make the "Outdated" data ###################################
########################################################################################
bank_panel_2000$mtb<-((bank_panel_2000$ativo_total)/(bank_panel_2000$passivo_total))/(bank_panel_2000$cap_mercado)
# make a log(at)
bank_panel_2000$log_at<- log(bank_panel_2000$ativo_total)
# make a lev_ratio
bank_panel_2000$lev_ratio<- (bank_panel_2000$passivo_total/bank_panel_2000$patrimonio_liquido)
# make the EQAS variable
bank_panel_2000$EQAS<- bank_panel_2000$at_ROE/bank_panel_2000$at_ROA
# make the z-score variable
sd_roa<- ddply(bank_panel_2000, .(acao), summarize, sd_roa = sd(ROA, na.rm = TRUE))
sd_roa$sd_roa[is.na(sd_roa$sd_roa)] <- 0
sd_roa$sd_roa[sd_roa$sd_roa == 0]<- NA
temp_zscore_bank2000<- merge(bank_panel_2000, sd_roa, by.x=c("acao"), by.y=c("acao"), all.x=T,all.y=T)
bank_panel_2000<- temp_zscore_bank2000
rm(temp_zscore_bank2000)
bank_panel_2000$z_score<- (bank_panel_2000$ROA + bank_panel_2000$EQAS)/bank_panel_2000$sd_roa
</code></pre>
<h2 id="a-cross-country-application">A Cross-Country Application</h2>
<p>In this section, I discuss the descriptive analyzes of the inputs that comprise the calculation of the default variables. In the foreground, I discuss the inputs that make up the default probability variable of <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> and the KMV model. The parameters are listed in Table 1. The inputs, as previously mentioned, follow the proposal of <a href="https://academic.oup.com/rfs/article-abstract/21/3/1339/1566804?redirectedFrom=fulltext">Bharath and Shumway (2008)</a> and <a href="https://www.sciencedirect.com/science/article/pii/S1572308914000266">Anginer and Demirguc-Kunt (2014)</a>.</p>
<center>
\begin{array}{lccccc}
\hline
& r_{i.t} & E_{i.t} & F_{i.t} & T_{bill.i.t} & sd_{i.t} \\ \hline
Min & -4.3820 & 0.0000 & 0.0000 & 0.0056 & 0.00 \\
1º \ \ Quartile & -0.081587 & 64.5 & 649 & 0.0074 & 0.01 \\
Median & 0.0042 & 300.2 & 2,243 & 0.0101 & 0.02 \\
Mean & -0.0067 & 4,332 & 43,255 & 0.0098 & 0.02 \\
3º \ \ Quartile & 0.0878 & 1,588 & 10,683 & 0.0116 & 0.03 \\
Max & 2.5451 & 338,916 & 3,538,000 & 0.0159 & 0.14 \\ \hline
\end{array}
</center>
<p><strong>Tabel 1-</strong> Summary of Inputs in the \(\pi_{Merton}\) and KMV Models. All returns are continuos and monetary data are in milons of USD.</p>
<p>In the background, I approach the inputs that make up the variable Z-score of <a href="https://papers.ssrn.com/sol3/papers.cfm?abstract_id=571342">Lown et al. (2000)</a> and of <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426613002598">Tabak et al. (2013)</a>. The parameters are listed in Table 2.</p>
<center>
\begin{array}{lcccc}
\hline
& ROA_{i.t} & \sigma_{ROA.i.t} & ROE_{i.t} & EQAS_{i.t} \\ \hline
Min & -136.80 & -230.53 & -230.50 & -19.90 \\
1º \ \ Quartile & 0.0009 & 0.01141 & 0.01 & 0.07 \\
Median & 0.002 & 0.02321 & 0.02 & 0.09 \\
Mean & 0.0005 & 0.017 & 0.02 & 0.10 \\
3º \ \ Quartile & 0.003 & 0.03662 & 0.04 & 0.12 \\
Max & 70.61 & 21.09 & 148.21 & 1.00 \\ \hline
\end{array}
</center>
<p><strong>Tabel 2-</strong> Summary of Inputs to \(Z-score\). All returns are continuos and monetary data are in milons of USD.</p>
<p>In Table 3 The values of the <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> model and KMV vary between \([0.1]\) probabilities of default. The values of the \(\log(Z-score)\) model are presented in values of deviations from default.</p>
<center>
\begin{array}{lccc}
\hline
& \pi_{Merton.i.t.j} & log(z-score_{i.t.j}) & \pi_{kmv.i.t.j} \\ \hline
Min & 0.00 & -10.16 & 0.00 \\
1º \ \ Quartile & 0.00 & 3.20 & 0.00 \\
Median & 0.00 & 3.90 & 0.00 \\
Mean & 0.46 & 3.74 & 0.49 \\
3º \ \ Quartile & 1.00 & 4.44 & 1.00 \\
Max & 1.00 & 9.73 & 1.00 \\ \hline
\end{array}
</center>
<p><strong>Tabel 3-</strong> Descriptive Analysis of Default Variables.</p>
<p>In Table 3 The values of the <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> model and KMV vary between \([0.1]\) probabilities of default. The values of the \(log(Z-score)\) model are presented in values of deviations from default.</p>
<p>As an illustration, Figure 1 shows the temporal evolution of the default indicators. It can be noticed that, near the period of the financial crisis of 2008, the indicators present a higher probability of default. The greater the \(\pi_ {Merton}\) indicator, the greater the probability that the bank defaults. The \(Z-score\) indicator is the inverse: the larger the indicator, the lower the probability of default. However, it is observed from Figure 1 that at some time points, the indicators move in the same direction. The \(Z-score\) indicator may have a slower response than the \(\pi_{Merton}\) indicator, since it has only accounting data sets, whereas the \(\pi_{Merton}\) indicator uses market data as well; these kind of data have faster responses to the default measures.</p>
<p><img src="/img/CR/dmz.png" alt="" />
<em><strong>Figure 1</strong>: Temporal Evolution of the Default Measures</em></p>
<p>Another analysis was undertaken of the probabilities of default by economic region. Figure 2 shows the evolution of the average default probability of <a href="https://onlinelibrary.wiley.com/doi/10.1111/j.1540-6261.1974.tb03058.x">Merton (1974)</a> in economic regions. It can be observed that in general, banks of North America, South Asia and Sub-Saharan Africa have higher indexes of default relative to other regions, such as Latin America, the Caribbean, North Africa, Middle East, Europe and Central Asia. This effect can be observed since, in general, regions that have the highest average indicators of default have larger numbers of financial institutions than do those of other regions.</p>
<p><img src="/img/CR/dmr.png" alt="" />
<em><strong>Figure 2</strong>: Temporal Evolution of Default Measures per Region</em></p>
<h2 id="final-remarks">Final Remarks</h2>
<p>In this post I show the main models of estimation and calculation of probability of default of banks. These measures are widely used in the scientific literature and practiced by financial institutions for making credit risk.</p>
<p>Such models usually work with the measurement of bank default taking credit risk into account, although banks are the main operating income there are other methods for banks to generate revenue, so these measures underreport the effects of these other forms of bank earnings.</p>
The dual market2020-05-10T23:59:07+00:00http://lamfo-unb.github.io/2020/05/10/The-dual-market<h1 id="the-dual-market">THE DUAL MARKET:</h1>
<h3 id="an-analysis-of-the-presence-of-market-gender-segmentation-and-the-impact-of-the-motherhood-in-the-wages-determination-process">An analysis of the presence of market gender segmentation and the impact of the motherhood in the wages determination process</h3>
<hr />
<h2 id="methodology">Methodology</h2>
<p>The mapping of the data aimed to verify the presence of gender segmentation in the Brazilian labor market and to analyze how motherhood affects women’s engagement and her earnings over time. For this purpose, the model was created with datas from the Pesquisa Nacional por Amostra de Domicílios (National Household Sample Survey - PNAD / IBGE) 2015 and 2014, and to achive the results were used Ordinary Least Squares (OLS) and Propensity Score Match (PSM) as econometric’s methods of estimation.</p>
<p>One of the arguments that supports the wage gap is the existence of a discriminatory factor for economic agents, imposing a different wage for individuals with the same marginal productivity. The duality of the labor market can be defined, in general, as a scenario in which equally qualified workers receive different wages just because they belong to a different gender. For the analysis of the existence of duality in the Brazilian labor market, the research method sought to measure the wage differences observed among workers that are not explained only by differences in their productive attributes.</p>
<p><img src="https://i.imgur.com/X4JE2RF.jpg" alt="" /><a href="https://www.austinchronicle.com/news/2016-08-12/the-boys-club/">Source</a></p>
<p>Another argument is that women have more maternal responsibilities than men, bring on less involvement in the labor market. So, when women considers the optimal choice between leisure and work, there is an internal choice, associaded with this others resposabilites, who ponders more for utility in form of leisure than utility in form of work, resulting in a reduced labor supply.</p>
<p>The economic reasoning behind this approach is that an individual obtains satisfaction with consumption of goods $(C )$ and leisure $(L)$. In this model, leisure includes all activities carry out outside the labor market, such as activities related to househood and domestic duties. The supply of hours $(h)$ for the labor market occurs at the point of greatest individual utility among them. The total time $(T)$ is the combination of hours worked and the chosen leisure amount $T = H + L$. Thereafter, maximizing the worker’s utility depends on non-work income $(V)$, the number of hours worked $(H)$ and the wage per hours $(w)$. This process can be defined by the following equation:</p>
<p><img src="https://i.imgur.com/U7FRdYl.png" alt="" /></p>
<p>The first order condition of consumption and leisure finds the marginal rate of substitution between goods. The number of hours worked and the quantity of goods consumed occurs at the point of tangency between the indifference curve and the problem’s restriction. Thus, the wage gap is not associated with a market failure, but with the different slopes of the utility curve between men and women.</p>
<p><img src="https://i.imgur.com/CJShWkj.png" alt="" />
<a href="https://www.impactbnd.com/blog/gender-equality-in-workplace-starts-with-company-culture-infographic">Source</a></p>
<p>For the he empirical approach of the motherhood impact, control groups were created, comparing the performance of women outside the period of maternity and mothers in the labor market. As a consequence, since they both belong to the same discrimination group and are affected in a similar way by socio-cultural factors, such as the high burden of household duties, when comparing women who had children with women who did not have children, the difference observed would be, then, the impact of motherhood on the mother’s job offer and, consequently, on her salary.</p>
<p><img src="https://i.imgur.com/TwDUHhX.png" alt="" /></p>
<p>Being i equal to the mother’s group referring to the child’s age and $\mathbf{X}$ the matrix of characteristics of the individuals in the sample, which are: age, age squared, years of study, years of study squared, south, southeast, north , northeast, black, white, brown, yellow, lives with spouse, potential experience and natural income logarithm of the house, when $Y$ is equal to the amount of hours offered, or quantity of hours offered, when Y is equal to natural logarithm of income, and $\beta$ the slope parameter determined by the model.</p>
<h2 id="results">Results</h2>
<p>Assuming non-appearance of discrimination factors in the process of determining employers’ own wages, the remuneration of the production would be genuinely dependent on the productive characteristics and the preferences of individuals. However, when comparing the behavior of normal wages with the entrepreneur class, the appearance of the gender wage gap was noted.</p>
<p><img src="https://i.imgur.com/bHk1iPt.png" alt="" /></p>
<p>Source: Own Elaboration based in Data from PNAD 2014 and 2015.</p>
<p>As a result, the argument of structural market segmentation or differentiation on the part of employers has weakened, pointing out that there are others dominant factors determining wages in contradistinction
to the theory of discrimination by the contracting firm. The method adopted showed the magnitude of the wage differences between workers and employers that are not explained only by differences in their observable productive attributes. The purpose of this methodology was to investigate structural wage inequality, between genders and as well as between women with and without children.</p>
<p>The distinction between factors attached to market segmentation and factors attached to individual preferences is essential to determine what is the best strategy to reduce the wage gap between men and women. Based on the results obtained, the persistence of the gender pay gap in the entrepreneur class would then be due to other factors, such as the intrinsic factors boarded in the neoclassical theory, determined by the process of maximizing the utility of individuals. Thefore, the presence of a dual market caused by a discriminatory agent when determining wages is weakened and does not appear to be able to explain the causes of the gender pay gap.</p>
<p>The results found show that the effect of motherhood reduces the amount of hours offered by the mother, in the short and medium run. Despite the low magnitude of the reduction in the work hours, whether in the short or medium run, motherhood proved to be a relevant factor in the final determination of women’s wages. It is also observed that in the long run, the difference in the average treatment effect in the treaties is not significant at 5 \%. This may mean that mothers, in the long run, rebuild themselves in the labor market.</p>
<p><img src="https://i.imgur.com/oNuH8I9.png" alt="" /></p>
<p>Source: Own Elaboration based in Data from PNAD 2014 and 2015.</p>
<p>The results indicate the non-parity of wages between groups in the short, medium and long run. The wage gap between women who had children against women who did not have children stands out and grows in the long run. In other words, motherhood has long-lasting effects that modify the woman’s salary not only in the period when the mother chooses to offer less hours of work, but also, later, when she returns to the same number of hours offered in the labor market. This results is either observed in the sample complete and in the subsample of wome employers.</p>
<p>However, the question of causality remains. Would mothers who offer fewer hours of work during the week be less engaged in the labor market because of their children, or would they naturally be more willing to dedicate themselves less to work because of their ambitions for the family? Due to the results measured by the PSM technique, the mother starts from an initially higher salary, in the subsample of women employers, and over the years she suffers a salary reduction due to the effects of motherhood. In the long run, the effects of this reduction are around $-10 \%$ of income in the complete sample and $-28 \%$ in the employers subsample.</p>
<p>This relationship brighten the argument of the natural wage gap between men and women and guides the public policies to contain wage inequalities between genders. Motherhood proved to be a more relevant factor in determining engagement and wages than the presence of a discriminating agent. These results may indicate that policies to support mothers, such as day-care centers and a more legal equal paternity leave, may mitigate the negative effect of the gender pay gap.</p>
Os dois mercados2020-05-10T17:29:00+00:00http://lamfo-unb.github.io/2020/05/10/Os-dois-mercados<h1 id="os-dois-mercados">OS DOIS MERCADOS:</h1>
<h3 id="uma-análise-da-presença-de-segmentação-de-gênero-e-do-impacto-da-maternidade-na-determinação-dos-salários">Uma análise da presença de segmentação de gênero e do impacto da maternidade na determinação dos salários</h3>
<hr />
<h2 id="metodologia">Metodologia</h2>
<p>O mapeamento dos dados visou verificar a presença de segmentação de gêneros no mercado de trabalho brasileiro e analisar como a maternidade afeta o engajamento e os ganhos das mulheres ao longo do tempo. Para tal, foi empregado os métodos econométricos de estimação por <em>Ordinary Least Squares</em> (OLS) e <em>Propensity Score Match</em> (PSM). Para construir o modelo foram utilizados dados da Pesquisa Nacional por Amostra de Domicílios (PNAD/IBGE) do ano de 2015 e 2014.</p>
<p>Um dos argumentos que sustenta a disparidade do salário é a existência de um fator discriminatório dos agentes econômicos, impondo um salário diferente para indivíduos com a mesma produtividade marginal. A dualidade do mercado de trabalho pode ser definida, de modo geral, como um cenário no qual trabalhadores igualmente qualificados recebem salários distintos apenas por pertencerem a um gênero diferente. Para a analise da existência de dualidade no mercado de trabalho brasileiro, o método de pesquisa adotado buscou avaliar em que medida são observadas diferenças salariais entre trabalhadores que não são explicadas apenas por diferenças nos seus atributos produtivos.</p>
<p><img src="https://i.imgur.com/X4JE2RF.jpg" alt="" /><a href="https://www.austinchronicle.com/news/2016-08-12/the-boys-club/">Fonte</a></p>
<p>Outro argumento abordado é o das mulheres terem mais responsabilidades maternas do que os homens, ocasionando um menor engajamento da mãe no mercado de trabalho. Ou seja, na hora de ponderar a escolha ótima entre lazer e trabalho, há uma escolha interna do individuo mulher que pondera mais para a utilidade em forma de lazer, resultando em uma oferta de mão-de-obra reduzida.</p>
<p>Por meio desta abordagem, indivíduo obtém satisfação com o consumo de bens (C) e de lazer (L). O lazer neste modelo inclui todas as atividades realizadas fora do mercado de trabalho, como atividades relacionadas com os afazeres domésticos e familiares. A oferta de tempo (H) destinado ao mercado de trabalho se dá no ponto de maior utilidade individual entre eles. O tempo total (T) é a combinação entre horas trabalhadas e a quantidade de lazer T = H + L. A maximização da utilidade do trabalhador está sujeita a uma restrição orçamentária que depende da renda do não trabalho (V), do número de horas trabalhadas (h) e da taxa de salário-hora (w). Este processo pode ser definido pela equação a seguir:</p>
<p><img src="https://i.imgur.com/U7FRdYl.png" alt="" /></p>
<p>A razão das condições de primeira ordem do consumo e do lazer localiza a taxa marginal de substituição entre os bens. O número de horas trabalhadas e a quantidade de bens que é consumida se dá no ponto de tangência entre a curva de indiferença e a restrição do problema. Desta forma, a diferença salarial não estaria associada a uma falha de mercado e sim nas diferentes inclinações da curva de utilidade entre os homens e as mulheres.</p>
<p><img src="https://i.imgur.com/CJShWkj.png" alt="" />
<a href="https://www.impactbnd.com/blog/gender-equality-in-workplace-starts-with-company-culture-infographic">Fonte</a></p>
<p>Para a abordagem empírica do impacto da maternidade foram criados grupos de controle que permitiram observar o comportamento das mulheres fora do período de maternidade e compará-las com o desempenho das mães no mercado de trabalho. Desta forma, por ambas pertencerem ao mesmo grupo de discriminação e serem afetadas de maneira similar pelos os fatores socioculturais, como a elevada carga de afazeres domésticos, ao comparar as mulheres que tiveram filhos com as mulheres que não tiveram filhos, a diferença observada seria, então, o impacto da maternidade sobre a oferta de trabalho da mãe e, consequentemente, sobre seu salário.</p>
<p><img src="https://i.imgur.com/o2NXPqL.png" alt="" /></p>
<p>Sendo i igual ao grupo referente a faixa etária da criança e <strong>X</strong> uma matriz de características dos indivíduos da amostra, sendo elas: idade, idade ao quadrado, anos de estudos, anos de estudo ao quadrado, sul, sudeste, norte, nordeste, negro, branco, pardo, amarelo, vive com o cônjuge, experiência potencial e logaritmo natural da renda da casa, quando Y for igual a quantidade de horas ofertadas, ou quantidade de horas ofertadas, quando Y for igual a logaritmo natural da renda, e $\beta $ o parâmetro de inclinação determinado pelo modelo.</p>
<h2 id="resultados">Resultados</h2>
<p>Assumindo a ausência da interferência de fatores de segmentação e de discriminação no processo de determinação de salários dos empregadores, a remuneração dos fatores de produção seria genuinamente dependente das características produtivas ou das preferências dos indivíduos. Entretanto, mesmo quando comparado o comportamento dos salários na classe empresarial foi constatado o aparecimento da disparidade salarial entre gêneros.</p>
<p><img src="https://i.imgur.com/09KuOMo.png" alt="" /></p>
<p>Sendo assim, o argumento de segmentação estrutural de mercado ou diferenciação por parte dos empregadores se enfraqueceu, ressaltando que há fatores dominantes na determinação dos salários para além da discriminação da firma contratante. O método de estimação por escore de propensão adotado evidenciou qual a magnitude dos diferençais salariais entre trabalhadores e empregadores que não são explicadas apenas por diferenças nos seus atributos produtivos observáveis. O intuito desta metodologia foi investigar a desigualdade salarial estrutural, tanto entre gêneros, como também entre as mulheres com e sem filhos.</p>
<p>A distinção entre fatores ligados a segmentação de mercado e fatores ligados a preferências individuais é fundamental para determinar qual a melhor estratégia para reduzir o <em>gap</em> salarial entre homens e mulheres. Pelos resultados obtidos, a persistência da disparidade salarial entre os gêneros na classe empresarial seria, então, oriunda de outros fatores, como os fatores intrínsecos abordados na teoria neoclássica, determinados pelo processo de maximização da utilidade dos indivíduos. Desta forma, a presença da dualidade de mercado provocado por um agente discriminador na hora da determinação do salário se enfraquece e não aparenta ser capaz de explicar as causas da disparidade salarial entre homens e mulheres.</p>
<p>Os resultado apontam que o efeito da maternidade reduz a quantidade de horas ofertadas pela mãe, no curto e no médio prazo. Apesar da baixa magnitude na redução da oferta de mão de obra, seja no curto ou médio prazo, a maternidade demonstrou ser um fator relevante na determinação final dos salários das mulheres. Observa-se, também, que no longo prazo, a diferença do efeito médio de tratamento nos tratados não é significante a 5\%. Isto pode significar que as mães, no longo prazo, se reconstroem no mercado de trabalho.</p>
<p><img src="https://i.imgur.com/GWse4Vj.png" alt="" /></p>
<p>Os resultados indicam a não paridade dos salários entre os grupos no curto, médio e no longo prazo. A disparidade salarial entre as mulheres que tiveram filhos contra as mulheres que não tiveram filhos se sobressai e cresce no longo prazo. Isto é, a maternidade tem efeitos duradouros que modificam o salário da mulher não apenas no período que a mãe escolhe ofertar menos horas de trabalho, como também, posteriormente, quando ela retorna ao mesmo número de horas ofertadas no mercado de trabalho, seja na amostra completa, seja na subamostra de mulheres empregadoras.</p>
<p>Entretanto, remanesce a questão da causalidade. As mães que ofertam menos horas de trabalho durante a semana estariam menos engajadas no mercado de trabalho por causa dos filhos ou elas seriam naturalmente mais dispostas a se dedicarem menos no trabalho por suas ambições à família? Pelos resultados, a mãe parte de um salário inicialmente maior, na subamostra de mulheres empregadoras, e ao longo dos anos sofre uma redução salarial pelos efeitos da maternidade. No longo prazo, os efeitos desta redução está em torno de -10\% da renda na amostra completa e de -28\% na subamostra de empregadoras.</p>
<p>Está relação ilumina o argumento da diferença salarial natural entre os homens e mulheres e orienta o foco das políticas públicas para a contenção das desigualdades salariais entre os gêneros. A maternidade demonstrou ser um fator mais relevante para da determinação do engajamento e dos salários, do que a presença de um agente discriminador na ponta. Estes resultados podem indicar que políticas de apoio às mães, como creches e uma licença paternidade mais igualitária podem amenizar o efeito negativo da disparidade salarial entre gêneros.</p>
An Econometric Approach by Propensity Score2020-05-10T14:00:07+00:00http://lamfo-unb.github.io/2020/05/10/An-Econometric-Approach-by-Propensity-Score<h1 id="an-econometric-approach-by-propensity-score">An Econometric Approach by Propensity Score</h1>
<h2 id="a-brief-review-behind-the-model">A brief review behind the model</h2>
<p>Besides the classical Ordinary Least Square (OLS) in econometrics estimation, the approach by Propensity Score is widely used to develop research in the area of policy evaluation and measurement of the impact of some treatment. The technique of propensity score is used when the assumption of random distribution of treatment is not applied. In this case, when we use Ordinary Least Square the coefficient estimated will not be the true expected value because it will carry the correlation of not being a random distribution.</p>
<p>OLS approach:</p>
\[Y = \mathbb X\beta + \delta Treatment + \mu\]
\[\mathbb{E} (\delta) = \frac { \sum_{i=0}^n (Tratament_i-\bar{Tratament_i})y_i } {\sum_{i=0}^n (Tratament_i-\bar{Tratament_i})²}\]
<p>Where <strong>X</strong> is a matrix with $n$ variables and $i$ individuals and $\beta$ is a vector with the inclinations of the parameters estimated. In this case, when the goal of the analysis is just to calculate the result of a treatment, the first order condition brings $\delta$ as our parameter of interest.</p>
<p>First order condition:</p>
\[\frac {\partial Y }{\partial Treatment} = \ \delta\]
<p>In other words:</p>
\[Average \ Effect = \mathbb{E}(Y | treatment= 0) - \mathbb{E}(Y | treatment= 1) = \delta\]
<p>But to get this result, the treatment can not be correlationated with the action of receive or not receive the treatment. The assumption of randomize distribution of the treatment implies that the expected value of the both groups would be the same if there was or was no receive the treatment. Mathematically this means that:</p>
\[\mathbb{E}(Y_{(t-1)} | treatment= 0) - \mathbb{E}(Y_{(t-1)} | treatment= 1) = 0\]
<p>Where $(t-1)$ would be the period before the treatment selection. It’s important to note that in most of the case the data set don’t have the prior period to compare the results before and after the policy. If the research have this kind of data that follow the individual before and after the policy, other instruments, like Fixed Effects or Random Effects could be more efficient than Propensity Score Matching.</p>
<p>The Propensity Score Matching comes as a solution when the data set does not follow the individual and we know that the treatment was not random. In order to remove the selection bias from the expected value of the result, the technique of pairing aim to search for agents treated and controlled based on their observable characteristics ($X$).</p>
<p>To illustrate this case, let’s suppose a governmental policy that gives a scholarship for some students. In order to receive this scholarship the student must to prove some knowledge making some test. The success in this phase allows the student to recive the scholarship. After the policy has been implemented, the politician wants to know the impact of scholarship in the quality of developing research. To do that, he compare the results of all students, as a control, with the students who received the scholarship.</p>
<pre><code class="language-graphviz">digraph hierarchy {
nodesep=1.0 // increases the separation between nodes
node [color=Red,fontname=Courier,shape=box] //All nodes will this shape and colour
edge [color=Blue, style=dashed] //All the lines look like this
Individuals->{Application No_application}
Application->{Accepted}
-> Traetment
Application-> {Denied}-> Control
No_application ->{Control}
{rank=same;Control } // Put them on the same level
}
</code></pre>
<p>The question that remains here is, it’s reasonable suppose that the treatment group and the control group have the same expected quality developing researches? Comparing the two groups as they are similar implies that, without the treatment, the expected result of both must be the same. Instead of that, the process to achieving the treatment probability implies that:</p>
\[Pr(\vec x_i) = \mathbb{P}(treatment= 1 |\vec x_i)\]
\[\mathbb{E}(Y_{(treatment=1)} | \mathbb {X} ) - \mathbb{E}(Y_{(treatment=0)} | \mathbb X ) \neq 0\]
<p>Angrist and Pischke (2009) point out that the estimation by propensity score occurs in two steps: first, it is estimated with some parametric model, such as <em>Probit</em> or <em>Logit</em>. Then, the estimation of the treatment effect can be computed either by matching the value found in the first step or using some weight scheme. Therefore, the matching technique, propensity score matching, compares the effects in the matched groups, differing only by the defined control variable.</p>
<p>Propensity Score Matching (PSM) is a statistical matching tool that tries to estimate the Average Treatment Effect (ATT), assuming a probable selection bias. The conditional probability of receiving treatment is calculated to try to imitate randomization, that is, to produce an experiment analogous to randomization, pairing similar individuals based in the observed characteristics, differentiating only in the treatment. Doing that, the propensity score gives a balancing score, meaning among subjects with the same propensity to be exposed, treatment is conditionally independent of the covariates.</p>
<p>Rather than treatment is randomize, the Propensity Score suppose the Conditional Independence Hypothesis, that is an easier assumption to avoid the selection bias. The hypothesis follows this structure:</p>
<table>
<tbody>
<tr>
<td>$$ \mathbb{E}(Y_{(t=0)}</td>
<td>\mathbb X, t ) = E(Y_{(t=0)}</td>
<td>\mathbb X ) $$</td>
</tr>
<tr>
<td>$$ \mathbb{E}(Y_{(t=1)}</td>
<td>\mathbb X, t ) = E(Y_{(t=1)}</td>
<td>\mathbb X ) $$</td>
</tr>
<tr>
<td>$$ \mathbb X_i \bot t_i</td>
<td>Pr(x_i) \therefore ( Y_{(0)}, Y_{(1)}) \bot t</td>
<td>Pr(x) $$</td>
</tr>
</tbody>
</table>
<p>Where $t$ is the treatment, and $Pr(x)$ is the propensity score. Conditional to the propensity score, covariates are independent of participation in the treatment. Therefore, for observations with the same propensity scores, the distribution of covariates must be the same in both groups. Depending on the propensity score, each individual has the same probability of participating in the treatment, as in a random experiment.</p>
\[\tau_{att} = \mathbb{E} \Biggl[\frac{(t-Pr(x))y}{\delta(t-Pr(x))}\Biggl]\]
\[\hat\tau_{att} = \frac{ \sum_{i=0}^n [(t_i-\hat p(x))y_i] }{\sum_{i=0}^n [\hat \delta(t_i-\hat p(x))]}\]
<p>Where $δ = Pr(t=1)$ and:</p>
\[\hat \delta = \frac{1}{n} \sum_{i=0}^n t_i\]
<p>In this way, any difference in outcome between the exposed and unexposed individuals is not attributable to the measured intercorrelation. Then the average difference in the results over the two groups is compared to obtain the true expected effect of the program treatment.</p>
<p>Although the method of pairing by propensity score is limited to the variables present in the database. When the potential gain of a pairing is related with an intrinsic and unobserved characteristic, the pairing technique does not solve the problem and does not make the modeling closest to the true expected value.</p>
<h2 id="psm-to-measure-the-gender-gap-in-wages">PSM to measure the gender gap in wages</h2>
<p>For this example, a model was created with datas from the Pesquisa Nacional por Amostra de Domicílios (National Household Sample Survey - PNAD / IBGE) 2015 and 2014, and to achieve the results were used Ordinary Least Squares (OLS) and Propensity Score Match (PSM) as econometric’s methods of estimation.</p>
<p>One of the arguments that supports the wage gap is the existence of a discriminatory factor for economic agents, imposing a different wage for individuals with the same marginal productivity. In an attempt to minimize the effect of selection bias and measure the impact of motherhood more closely to the true population value, we used the method of matching by propensity score. Assuming that all hypotheses are satisfied for each value of the propensity score, the measurement of the Average Treatment Effect (ATT) will converge to the true expected value of the treatment.</p>
<p>The example measure the impact in 3 different models:</p>
<p><img src="https://i.imgur.com/SO5HGQY.png" alt="" /></p>
<p>Being i equal to the mother’s group referring to the child’s age and $\mathbf{X}$ the matrix of characteristics of the individuals in the sample, which are: age, age squared, years of study, years of study squared, south, southeast, north , northeast, black, white, brown, yellow, lives with spouse, potential experience and natural income logarithm of the household. $Y$ is equal to natural logarithm of income, and $\beta$ the slope parameter determined by the model.</p>
<p>To create the wages determination model, the wage were transformed in natural logarithm scale. This approximates the sample distribution to the normal distribution, resulting in greater robustness of the results obtained and providing greater efficiency in the inference of the tests.</p>
<p>Regressions can be influenced by peak distribution, outliers, scale, among others. Then, in order to approximate a normal distribution, the application of the transformation can draw nearer this distribution. Note that despite losing efficiency, the PSM estimator does not need the assumption of normality to be an unbiased and consistent estimator.</p>
<p><img src="https://i.imgur.com/ybUdQJF.png" alt="" /></p>
<p>As shown in the previous table, in the general sample, comparing men to women, after the pairing method, the wage gap increases, growing from -26\% to -38\%. This implies that, when individuals are paired by the propensity score method, the woman variable is the only variable that differentiates between groups, and when comparing individuals with the same characteristics, being a woman would imply a salary 38\% less than men’s wages and not just 26\%.</p>
<p>In the second model, where only men and women without children are analyzed, the disparity also increases after matching, from -17\% to -24\%. Despite having a smaller magnitude, when comparing with the previous model, where men’s salaries are compared to the salaries of all women, there is still a large and statistically significant difference between the OLS estimation and PSM estimation.</p>
<p>In the third model, the analysis is between the wages of women without children and the wages of mothers. In a sense, there is not such a big difference in the last group, where women without children are compared with women with children. This result may be a consequence of a more homogeneous sample, where only women are compared. Therefore, the need for pairing is more critical when the model proposes to isolate the impact of treatment between more distinct groups.</p>
<h3 id="conclusion">Conclusion</h3>
<p>The aim of this study was to demonstrate and compare the results obtained when regressing a model without pairing and a model with pairing. For estimate by propensity score, first a logistic was created to find the probability of an individual receive the treatment, reducing the selection bias. Then, in a second stage, with the probability estimation the values was regressed to calculate the slope of the parameter of interest. In this way, it is more reliable to infer that the real impact in the salary remuneration is closer to the calculated values by the propensity score match method than by the direct result of the regression by ordinary least squares.</p>
<p>Although the instrument provides a good way to isolate the selection bias, the PSM estimation method is limited to an estimation under observable variables. In this context, when the differences between individuals are not differences that are quantified in the database, approaching individuals with the same observable characteristics but with unobserved intrinsic differences, the approach by PSM may not solve the selection bias and then it will suffer the same issues of the simple OLS estimation.</p>
Abordagem econométrica via escore de propensão2020-05-10T13:59:07+00:00http://lamfo-unb.github.io/2020/05/10/Abordagem-econométrica-via-escore-de-propensão<h1 id="abordagem-econométrica-via-escore-de-propensão">Abordagem econométrica via escore de propensão</h1>
<h2 id="um-olhar-por-dentro-do-modelo">Um olhar por dentro do modelo</h2>
<p>Além da clássica métrica por Mínimo Quadrado Ordinários (MQO) nos modelos de regressões econométricas, a ferramenta de pareamento estatístico via escore de propensão é amplamente usada para desenvolver pesquisas na área de avaliação de políticas e mensuração do impacto de algum tratamento. A técnica do escore de propensão é utilizada quando a hipótese de distribuição aleatória do tratamento não é verificada. Nesse caso, ao usarmos o Mínimo Quadrado Ordinário, o coeficiente estimado não será o verdadeiro valor esperado, pois carregará dentro do valor calculado a correlação de não ser uma distribuição aleatória.</p>
<p>Mínimos Quadrados Ordinários:</p>
\[Y = \mathbb X\beta + \delta Tratamento + \mu\]
\[\mathbb{E} (\delta) = \frac { \sum_{i=0}^n (Tratamento_i-\bar{Tratamento_i})y_i } {\sum_{i=0}^n (Tratamento_i-\bar{Tratamento_i})²}\]
<p>Onde <strong>X</strong> é uma matrix com $n$ variáveis e $i$ indivíduos e $\beta$ é um vetor com as inclinações dos parametros estimados. Nesse caso, quando o objetivo da análise é apenas calcular o resultado de um tratamento, a condição de primeira ordem traz $\delta$ como nosso parâmetro de interesse.</p>
<p>Condição de primeira ordem:</p>
\[\frac {\partial Y }{\partial Tratamento} = \ \delta\]
<p>Em outras palavras:</p>
\[Efeito \ Médio = \mathbb{E}(Y |tratamento= 0) - \mathbb{E}(Y |tratamento= 1) = \delta\]
<p>Para obter esse resultado, o tratamento não pode ser correlacionado com a ação de receber ou não receber o tratamento. A suposição de distribuição aleatória do tratamento implica que o valor esperado de ambos os grupos seria o mesmo se houvesse ou não recebesse o tratamento.</p>
<p>Matematicamente:</p>
\[\mathbb{E}(Y_{(t-1)} | tratamento= 0) - \mathbb{E}(Y_{(t-1)} | tratamento= 1) = 0\]
<p>Onde $(t-1)$ é o período antes do tratamento. É importante observar que, na maioria dos casos, o conjunto de dados não possui período anterior para comparar os resultados antes e depois da política. Se a pesquisa tiver esse tipo de dado que segue o indivíduo antes e depois da política, outros instrumentos, como Efeitos Fixos (EF) ou Efeitos Aleatórios (EA), poderiam ser mais eficientes do que o Propensity Score Matching.</p>
<p>O Propensity Score Matching vem como uma solução quando o conjunto de dados não seguem os indivíduos e se supõe que o tratamento não foi organizado de forma aleatória. A fim de remover o viés de seleção, do valor esperado do resultado, a técnica de pareamento tem como objetivo de randomizar artificialmente os indivíduos tratados e os não tratados base em suas características observáveis ($X$).</p>
<p>Para ilustrar esse caso, vamos supor uma política governamental que ofereça uma bolsa de estudos para alguns estudantes. Para receber essa bolsa, o aluno deve provar algum conhecimento fazendo algum teste. O sucesso nesta fase permite que o aluno receba a bolsa de estudos. Após a implementação da política, o político deseja conhecer o impacto da bolsa de estudos na qualidade do desenvolvimento de pesquisas. Para fazer isso, ele comparou os resultados de todos os alunos que não receberam bolsas, como controle, com os alunos que receberam a bolsa.</p>
<pre><code class="language-graphviz">digraph hierarchy {
nodesep=1.0 // increases the separation between nodes
node [color=Red,fontname=Courier,shape=box] //All nodes will this shape and colour
edge [color=Blue, style=dashed] //All the lines look like this
Indivíduos->{Aplicação Não_Aplicação}
Aplicação->{Aceito}
-> Traetmento
Aplicação-> {Negado}-> Controle
Não_Aplicação ->{Controle}
{rank=same;Controle } // Put them on the same level
}
</code></pre>
<p>Agora, a questão que o pesquisador precisa refletir é: Seria razoável supor que o grupo de tratamento e o grupo de controle tenham a mesma qualidade esperada no desenvolvimento de pesquisas? Comparar os dois grupos, pois são semelhantes, implica que, sem o tratamento, o resultado esperado de ambos deve ser o mesmo. Em outras palavras, os alunos que aplicaram para receber a bolsa, e os alunos que não aplicaram para receber a bolsa são semelhantes no processo de desenvolvimento de pesquisas?</p>
<p>A probabilidade de participar do tratamento é baseado nas características do próprio indivíduo:</p>
\[Pr(\vec x_i) = \mathbb{P}(treatment= 1 |\vec x_i)\]
\[\mathbb{E}(Y_{(treatment=1)} | \mathbb {X} ) - \mathbb{E}(Y_{(treatment=0)} | \mathbb X ) \neq 0\]
<p>Angrist and Pischke (2009) apontam que a estimativa pelo escore de propensão ocorre em duas etapas: primeiro, é estimada com algum modelo paramétrico, como <em>Probit</em> ou <em>Logit</em>. Então, a estimativa do efeito do tratamento passa a ser calculada combinando o valor encontrado na primeira etapa ou usando algum esquema de peso. Portanto, a técnica de escore de propensão, compara os efeitos nos grupos pareados, diferindo apenas pela variável de controle definida.</p>
<p>O pareamento por escore de propensão é uma ferramenta de correspondência estatística que tenta estimar o efeito médio do tratamento <em>(Average Treatment Effect, ATT)</em>, assumindo um provável viés de seleção. A probabilidade condicional de receber tratamento é calculada para tentar imitar um distribuição aleatória do tratamento, ou seja, produzir um experimento análogo à randomização, emparelhando indivíduos semelhantes com base nas características observadas, diferenciando-se apenas no tratamento.</p>
<p>Enquanto a regressçao por Mínimos Quadrados Ordinários requer que o tratamento seja destribuido de forma randomizada, o escore de propensão supõe apenas uma hipótese de independência condicional. Esta suposição permite contornar o viés de seleção.</p>
<p>A hipótese segue esta estrutura:</p>
<table>
<tbody>
<tr>
<td>$$ \mathbb{E}(Y_{(t=0)}</td>
<td>\mathbb X, t ) = E(Y_{(t=0)}</td>
<td>\mathbb X ) $$</td>
</tr>
<tr>
<td>$$ \mathbb{E}(Y_{(t=1)}</td>
<td>\mathbb X, t ) = E(Y_{(t=1)}</td>
<td>\mathbb X ) $$</td>
</tr>
<tr>
<td>$$ \mathbb X_i \bot t_i</td>
<td>Pr(x_i) \therefore ( Y_{(0)}, Y_{(1)}) \bot t</td>
<td>Pr(x) $$</td>
</tr>
</tbody>
</table>
<p>Onde $t$ é o tratamento e $Pr(x)$ é o escore de propensão. Sendo dependentes do escore de propensão, as covariáveis são independentes da participação no tratamento. Portanto, para observações com os mesmos escores de propensão, a distribuição de covariáveis deve ser a mesma nos dois grupos. Dependendo do escore de propensão, cada indivíduo tem a mesma probabilidade de participar do tratamento, simulando assim a distribuição aleatória do tratamento.</p>
\[\tau_{att} = \mathbb{E} \Biggl[\frac{(t-Pr(x))y}{\delta(t-Pr(x))}\Biggl]\]
\[\hat\tau_{att} = \frac{ \sum_{i=0}^n [(t_i-\hat p(x))y_i] }{\sum_{i=0}^n [\hat \delta(t_i-\hat p(x))]}\]
<p>Onde $δ = Pr(t=1)$ e:</p>
\[\hat \delta = \frac{1}{n} \sum_{i=0}^n t_i\]
<p>Dessa forma, qualquer diferença no resultado entre os indivíduos tratados e não tratados não é atribuível ao viés de seleção. Em seguida, calcula-se a diferença média dos resultados nos dois grupos para obter o verdadeiro efeito esperado do tratamento do programa.</p>
<p>Quando o ganho potencial da técnica do escore de propensão está relacionado a uma característica intrínseca e não observada, a técnica de pareamento não resolve o problema do viés de seleção e não torna a modelagem mais próxima do verdadeiro valor esperado. O método de pareamento pelo escore de propensão é limitado às variáveis presentes no banco de dados.</p>
<h2 id="um-exemplo-do-método-de-escore-de-propensão">Um exemplo do método de escore de propensão:</h2>
<h3 id="impacto-do-gênero-na-determinação-de-salários">Impacto do gênero na determinação de salários</h3>
<p>Para ilustrar o que foi discutido acima, o exemplo a seguir se propõe a mapear o impacto de gênero e da maternidade no processo de determinação de salários. O exemplo compara a técnica da regressão sem o pareamento com o método de regressão com o escore de propensão. Supondo que todas as hipóteses sejam atendidas para cada valor do escore de propensão, a medida do Efeito Médio do Tratamento (ATT) convergirá para o verdadeiro valor esperado do tratamento, minimizando o efeito do viés de seleção.</p>
<p>Um dos argumentos que sustenta a disparidade do salário é a existência de um fator discriminatório dos agentes econômicos, impondo um salário diferente para indivíduos com a mesma produtividade marginal. Para a análise, foram utilizados dados da Pesquisa Nacional por Amostra de Domicílios (PNAD/IBGE) do ano de 2015 e 2014.</p>
<p>Para a comparação dos efeitos, foram regredidos três modelos diferentes:</p>
<p><img src="https://i.imgur.com/o2NXPqL.png" alt="" /></p>
<p>Sendo i igual ao grupo referente a faixa etária da criança e <strong>X</strong> uma matriz de características dos indivíduos da amostra, sendo elas: idade, idade ao quadrado, anos de estudos, anos de estudo ao quadrado, sul, sudeste, norte, nordeste, negro, branco, pardo, amarelo, vive com o cônjuge, experiência potencial e logaritmo natural da renda da casa. $Y$ é o logaritmo natural da renda do agente, e $\beta$ o parâmetro de inclinação determinado pelo modelo.</p>
<p>Em seguida, para criar o modelo de determinação de salários, foi transformado o valor do salário em escala de logaritmo natural. Isso aproxima a distribuição da amostra da distribuição normal, resultando em maior robustez dos resultados obtidos e proporcionando maior eficiência na inferência dos testes. Esta transformação é feita pois regressões podem ser influenciadas por distribuição de picos, outliers, escala, entre outros. Então, para aproximar uma distribuição normal, a aplicação da transformação pode se aproximar dessa distribuição. Observe que, apesar de perder a eficiência, o estimador PSM não precisa da suposição de normalidade para ser um estimador imparcial e consistente.</p>
<p><img src="https://i.imgur.com/GALy3PI.png" alt="" /></p>
<p>Como mostra a tabela anterior, na amostra geral, comparando homens e mulheres, após o método de pareamento, a diferença salarial aumenta, passando de -26\% para -38\%. O resultado indica que, quando os indivíduos são pareados pelo método do escore de propensão, a variável mulher é a única variável que se diferencia entre os grupos e, ao comparar indivíduos com as mesmas características sob o mesmo escore de propensão, ser mulher implicaria um salário de 38\% a menos do que homens, não apenas 26\%.</p>
<p>No segundo modelo, onde apenas homens e mulheres sem filhos são analisados, a disparidade também aumenta após o pareamento, de -17\% para -24\%. Apesar de ter uma magnitude menor, quando comparado ao modelo anterior, onde os salários dos homens são comparados aos de todas as mulheres, ainda existe uma diferença grande e estatisticamente significante entre a estimativa de MQO e a estimativa por escore de propensão.</p>
<p>No terceiro modelo, a análise é entre os salários de mulheres sem filhos e os salários das mulheres que são mães. De certa forma, não existe uma diferença tão grande no último grupo, em que mulheres sem filhos são comparadas com mulheres com filhos. Esse resultado pode ser consequência de uma amostra mais homogênea, na qual apenas as mulheres são comparadas. Este resultado é interessante pois ressalta que a necessidade do pareamento é mais crítica quando o modelo propõe comparar o impacto do tratamento entre grupos mais distintos.</p>
<h3 id="conclusão">Conclusão</h3>
<p>O objetivo deste estudo foi demonstrar e comparar os resultados obtidos ao regredir um modelo sem pareamento e um modelo com pareamento. Para estimar pelo escore de propensão, primeiro uma regressão logística foi criada para afim de encontrar a probabilidade de um indivíduo receber o tratamento, isolando o viés de seleção. Em seguida, com a estimativa de probabilidade estimada, os valores foram regredidos para calcular a inclinação do parâmetro de interesse. Dessa forma, é mais confiável inferir que o impacto real na remuneração salarial está mais próximo dos valores calculados pelo método de escore de propensão do que pelo resultado direto, obtidos por meio da regressão por mínimos quadrados ordinários.</p>
<p>Embora o instrumento ofereça uma boa maneira de isolar o viés de seleção, o método de estimativa por escore de propensão é limitado a um pareamento sob variáveis observáveis. Nesse contexto, quando as diferenças entre indivíduos não são quantificadas no banco de dados, abordando indivíduos com as mesmas características observáveis, mas com diferenças intrínsecas não observadas, a abordagem do PSM pode não solucionar o viés de seleção e sofrerá os mesmos problemas que os modelos mais simples e diretos como o modelo de MQO.</p>
Regressão Logística2020-04-30T23:59:07+00:00http://lamfo-unb.github.io/2020/04/30/Regressão-Logística<h1 id="regressão-logística">Regressão Logística</h1>
<h2 id="introdução">Introdução</h2>
<p>A análise de regressão tem como principal função, a relação entre uma variável dependente e as outras chamadas independentes. Como parte disso, existem diferentes formas de regressão. A forma estudada nesta postagem é a logística, um tipo de classificação supervisionada. O objetivo desse post é dar uma ideia sobre as compreensões básicas do que seria uma regressão logística e a sua aplicação, tanto no viés acadêmico como no profissional.</p>
<p>A regressão logística é importante no sentido de classificar de maneira discreta a variável de interesse(0 ou 1, verdadeiro ou falso, etc) . Sua aplicação tem viabilidade em diferentes campos e uma abertura pra aplicar diferentes formas de encaixe na modelagem. Um exemplo clássico considerado seria a maior ou menor chance de sobreviver ao desastre do navio de passageiros Titanic baseado em características como sexo, idade, habilidades, etc.</p>
<p>A postagem divide-se em uma abordagem do que é a regressão logística, uma explicação breve de sua forma linear, a versão logística (alvo desse trabalho) e as diferenças existentes entre os dois tipos de regressão. Por último, é aplicado um exemplo de regressão logística na análise da taxa de mortalidade da COVID-19.</p>
<h2 id="regressão-linear-uma-primeira-abordagem">Regressão Linear: uma primeira abordagem</h2>
<p>A regressão linear consiste na forma de expressar um padrão de comportamento dentro de uma correlação de uma variável dependente sobre outra independente. Caso fossemos fazer um raciocínio rápido, seria como entender a quantidade de vendas (dependente) pelos dias de uma pizzaria em um período determinado (independente) ou compreender o aumento ou a diminuição de uma taxa de juros em um ano. Isso em função de variáveis independentes (as quais queremos saber como/se influenciam a variável dependente). O exercício proposto pela regressão é possibilitar tanto a análise atual (descritiva), quanto prover uma estimativa de um fenômeno (preditiva). Ademais, a lógica usada nesse modelo em termos de relação entre as variáveis é replicada nos níveis mais baixos de quase todos os modelos mais avançados de aprendizado de máquina, incluindo as redes neurais.</p>
<p>Um ponto a se destacar é a diferença entre a regressão e a correlação. A primeira explica a forma da relação entre as variáveis, enquanto o segundo entende a quantificação da força ou grau da relação entre as variáveis. Com isso, precisa-se criar uma relação entre as variáveis, o que pode ser feito com um diagrama de dispersão. Tal fator permite que possa determinar uma relação entre os dois aspectos, e se essa relação é fraca ou forte, conforme os pontos constados na reta que se cria pelos pontos formados. No entanto, esse post se focará somente na regressão em si. Em oportunidades, retornaremos com uma explicação sobre correlações. Dessa maneira, a equação principal de uma regressão é a da reta. Assim:
\begin{equation}
y = \alpha*(x)+\beta
\end{equation}
Em que $\alpha$ é a inclinação da reta, $x$ é a variável (assumidamente) independente e $\beta$ é o ponto que a reta corta o eixo das ordenadas (Y). Um ponto a mais seria que a linha da regressão é o que minimiza o erro quadrático. Dessa forma, o resultado se conformaria em um gráfico como o exemplo abaixo.</p>
<center>
![i6](https://upload.wikimedia.org/wikipedia/commons/thumb/4/41/LinearRegression.svg/1280px-LinearRegression.svg.png)
***Imagem 1**: [Regressão linear](https://en.wikipedia.org/wiki/Linear_regression)*
</center>
<p>A regressão linear tem, dessa forma, a função também de ser preditiva. Ela apresenta a evolução de um processo a partir dos dados existentes e da relação entre as variáveis.</p>
<h2 id="regressão-logística-1">Regressão Logística</h2>
<p>A regressão logística é compreendida, basicamente, como uma regressão linear ajustada por um parâmetro (log). Ela foi uma maneira de resolver um problema comum dentro da forma linear: a existência de uma variável dependente categórica binário como por exemplo 0 ou 1 (ao invés de variáveis contínuas). No modelo padrão de regressão linear, temos somente uma variável contínua e o entendimento é conformado em torno de uma reta imaginária como na imagem 2.</p>
<center>
![i6](https://miro.medium.com/max/1280/0*gKOV65tvGfY8SMem.png)
***Imagem 2**: [Regressão Logística com Python](https://medium.com/@ODSC/logistic-regression-with-python-ede39f8573c7)*
</center>
<p>No caso da versão logística, há mais de um valor discreto para a variável observada (chamada de variável categórica) em que se faz necessário algo que as una como uma função de ativação sigmoid (formato de um S), pois cada variável de Y corresponde assim a um mínimo e a um máximo (y0 = 0 e y1 = 1), em uma nova situação, agora entendida como uma probabilidade de algo ocorrer em um teste de hipótese binário.</p>
<center>
![i6](https://upload.wikimedia.org/wikipedia/commons/thumb/8/88/Logistic-curve.svg/1280px-Logistic-curve.svg.png)
***Imagem 3**: [Regressão Logística](https://en.wikipedia.org/wiki/Logistic_regression)*
</center>
<p>Alguns aspectos são importantes ao considerar uma regressão logística, como o formato dos dados, a existência ou não de correlação entre as variáveis, entre outros. Em um primeiro ponto, enquanto em uma regressão linear, não é (usualmente) necessário ter um banco de dados grande; já no caso da versão logística ter uma quantidade maior de observações. Outros pontos a se considerar também estaria na classificação ser binária, ou seja, apresentar mais de uma variável (no caso duas), serem relevantes no sentido de determinar resultados e explicações claras. No entanto, podem ter mais n’s.</p>
<p>Os pontos descritos acima dão as características para compreender que a regressão logística tem um papel determinante em exemplos como o caso do Titanic(famoso naufrágio ocorrido no Oceano Atlântico em 1912), em que uma mulher teria 12,4 mais chances de sobreviver à tragédia do que um homem, ou seja, a existência de uma razão de probabilidade que demonstraria o quanto uma variável é mais ou menos passível de ocorrência que a outra.</p>
<p>Tal aspecto é acrescido da criação do chamado <em>odds ratio</em>, uma razão de probabilidade concebida a partir da chance de dar certo como errado. Isso ocorre por regressão logística ser parte da família exponencial de Generalized Linear Models (GLM), o que o possibilita fazer uso da função de ligação “logit” e gera a interpretação dos resultados em função da Razão de Chances (Odds Ratio).</p>
<p>Isso é importante porque age como um qualificador da possibilidade de ocorrer. No exemplo do Titanic, a chance de ser uma mulher a sobreviver seria maior do que a de um homem. Em outra análise, as pessoas da primeira classe tinham mais chances que as demais. Tal aspecto partiria da fórmula de relação abaixo aplicado à função logit que ajustaria o modelo:
\begin{equation}
log(y) = log(p/1-p)
\end{equation}</p>
<h2 id="aplicação-prática-em-python">Aplicação prática em Python</h2>
<p>O código utilizado para apresentação da oficina aplicou o processo de aprendizado em um data-set de casos de coronavírus, utilizando as informações de sexo e idade para prever os casos de óbitos.</p>
<p>Os dados utilizados para os casos de cornavírus são disponibilizados no Kaggle.</p>
<ul>
<li>https://www.kaggle.com/sudalairajkumar/novel-corona-virus-2019-dataset/version/47</li>
</ul>
<p>Primeiramente importamos os dados e procuramos por valores inadequados.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">random</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s">"COVID19.csv"</span><span class="p">,</span><span class="n">usecols</span><span class="o">=</span><span class="p">[</span><span class="s">"age"</span><span class="p">,</span><span class="s">"death"</span><span class="p">,</span><span class="s">"gender"</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="c1">#checando dataframe
</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">death</span><span class="p">.</span><span class="n">unique</span><span class="p">())</span> <span class="c1">#checando por valores ruins
</span><span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">age</span><span class="p">.</span><span class="n">unique</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">gender</span><span class="p">.</span><span class="n">unique</span><span class="p">())</span>
</code></pre></div></div>
<p>Agora corrigimos os valores onde precisamos</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">dropna</span><span class="p">(</span><span class="n">subset</span><span class="o">=</span><span class="p">[</span><span class="s">'gender'</span><span class="p">])</span> <span class="c1">#tirando linhas que não tenham informação sobre o gênero ..
</span>
<span class="k">def</span> <span class="nf">gender</span><span class="p">(</span><span class="n">x</span><span class="p">):</span> <span class="c1"># função para converter as variável categórica para valor numérico
</span> <span class="k">if</span> <span class="n">x</span> <span class="o">==</span> <span class="s">"male"</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">0</span>
<span class="k">else</span><span class="p">:</span>
<span class="k">return</span> <span class="mi">1</span>
<span class="n">data</span><span class="p">[</span><span class="s">'gender'</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">'gender'</span><span class="p">].</span><span class="nb">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">gender</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="c1">#aplica a função gender no dataframe data coluna gender
</span><span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">gender</span><span class="p">.</span><span class="n">unique</span><span class="p">())</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">[(</span><span class="n">data</span><span class="p">[</span><span class="s">"death"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"1"</span> <span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">data</span><span class="p">[</span><span class="s">"death"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"0"</span> <span class="p">)]</span> <span class="c1"># deixamos apenas os resultados para 1 e 0.
</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">death</span><span class="p">.</span><span class="n">unique</span><span class="p">())</span>
<span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">mean</span><span class="p">())</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">fillna</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">mean</span><span class="p">())</span> <span class="c1">#completamos valores não disponíveis pela média de cada coluna.
</span>
</code></pre></div></div>
<p>Em seguida preparamos os dados para serem processados. X são nossas observações (teoricamente) independentes (informações que possam explicar o fenômeno de interesse) e y as observações dependentes (nesse caso, a informações sobre a morte ou não-morte de um paciente, sendo a morte (1) ou não morte (0)).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">y</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">"death"</span><span class="p">]</span> <span class="c1">#coluna Death
</span><span class="n">X</span> <span class="o">=</span> <span class="n">data</span><span class="p">.</span><span class="n">drop</span><span class="p">(</span><span class="s">"death"</span><span class="p">,</span><span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span> <span class="c1">#Todas as colunas exceto Death
</span></code></pre></div></div>
<p>Separamos os dados em dois: Treino e teste. Aqui, usamos 10% para teste, e 90% para treinamento. Mais sobre a utilização de dados de treino e teste em <a href="https://becominghuman.ai/what-is-training-data-its-types-and-why-it-is-important-f998424c3c9">What is Training Data its types and why it is important?</a></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">train_test_split</span>
<span class="n">X_train</span><span class="p">,</span> <span class="n">X_test</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span> <span class="n">y_test</span> <span class="o">=</span> <span class="n">train_test_split</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">test_size</span> <span class="o">=</span> <span class="mf">0.1</span><span class="p">,</span> <span class="n">random_state</span> <span class="o">=</span> <span class="mi">42</span><span class="p">)</span>
<span class="c1"># print(X_test)
</span></code></pre></div></div>
<p>Antes de converter nossos dados para um vetor que possa ser analisado pelo modelo, precisamos fazer com que todos os valores de X estejam na mesma proporção (<a href="https://medium.com/@urvashilluniya/why-data-normalization-is-necessary-for-machine-learning-models-681b65a05029">Why Data Normalization is necessary for Machine Learning models</a>). Para isso, fazemos com que eles fiquem entre -1 e 1, para qualquer variável em X usando a função StandardScaler().</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.preprocessing</span> <span class="kn">import</span> <span class="n">StandardScaler</span>
<span class="n">sc_X</span> <span class="o">=</span> <span class="n">StandardScaler</span><span class="p">()</span>
<span class="n">X_train</span> <span class="o">=</span> <span class="n">sc_X</span><span class="p">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">X_train</span><span class="p">)</span>
<span class="n">X_test</span> <span class="o">=</span> <span class="n">sc_X</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
</code></pre></div></div>
<p>Agora treinamos o modelo, e predizemos os resultados para os valores de treinamento</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">LogisticRegression</span>
<span class="n">classifier</span> <span class="o">=</span> <span class="n">LogisticRegression</span><span class="p">(</span><span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">,</span><span class="n">class_weight</span> <span class="o">=</span> <span class="s">"balanced"</span><span class="p">)</span>
<span class="n">classifier</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">)</span>
<span class="n">y_pred</span> <span class="o">=</span> <span class="n">classifier</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
</code></pre></div></div>
<p>Para avaliar a precisão do modelo, utilizamos uma matriz de confusão.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">confusion_matrix</span>
<span class="n">cm</span> <span class="o">=</span> <span class="n">confusion_matrix</span><span class="p">(</span><span class="n">y_test</span><span class="p">,</span> <span class="n">y_pred</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">cm</span><span class="p">)</span>
</code></pre></div></div>
<p>Por último, plotamos os resulados para conferir visualmente nosso classificador (verde é saudável e vermelho indica óbito).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">from</span> <span class="nn">matplotlib.colors</span> <span class="kn">import</span> <span class="n">ListedColormap</span>
<span class="n">X_set</span><span class="p">,</span> <span class="n">y_set</span> <span class="o">=</span> <span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span>
<span class="n">X1</span><span class="p">,</span> <span class="n">X2</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">meshgrid</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="n">start</span> <span class="o">=</span> <span class="n">X_set</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">].</span><span class="nb">min</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">stop</span> <span class="o">=</span> <span class="n">X_set</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">].</span><span class="nb">max</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">step</span> <span class="o">=</span> <span class="mf">0.01</span><span class="p">),</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="n">start</span> <span class="o">=</span> <span class="n">X_set</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">].</span><span class="nb">min</span><span class="p">()</span> <span class="o">-</span> <span class="mi">1</span><span class="p">,</span> <span class="n">stop</span> <span class="o">=</span> <span class="n">X_set</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">].</span><span class="nb">max</span><span class="p">()</span> <span class="o">+</span> <span class="mi">1</span><span class="p">,</span> <span class="n">step</span> <span class="o">=</span> <span class="mf">0.01</span><span class="p">))</span>
<span class="n">plt</span><span class="p">.</span><span class="n">contourf</span><span class="p">(</span><span class="n">X1</span><span class="p">,</span> <span class="n">X2</span><span class="p">,</span> <span class="n">classifier</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">X1</span><span class="p">.</span><span class="n">ravel</span><span class="p">(),</span> <span class="n">X2</span><span class="p">.</span><span class="n">ravel</span><span class="p">()]).</span><span class="n">T</span><span class="p">).</span><span class="n">reshape</span><span class="p">(</span><span class="n">X1</span><span class="p">.</span><span class="n">shape</span><span class="p">),</span> <span class="n">alpha</span> <span class="o">=</span> <span class="mf">0.75</span><span class="p">,</span> <span class="n">cmap</span> <span class="o">=</span> <span class="n">ListedColormap</span><span class="p">((</span><span class="s">'green'</span><span class="p">,</span> <span class="s">'red'</span><span class="p">)))</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlim</span><span class="p">(</span><span class="n">X1</span><span class="p">.</span><span class="nb">min</span><span class="p">(),</span> <span class="n">X1</span><span class="p">.</span><span class="nb">max</span><span class="p">())</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylim</span><span class="p">(</span><span class="n">X2</span><span class="p">.</span><span class="nb">min</span><span class="p">(),</span> <span class="n">X2</span><span class="p">.</span><span class="nb">max</span><span class="p">())</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">unique</span><span class="p">(</span><span class="n">y_set</span><span class="p">)):</span>
<span class="n">plt</span><span class="p">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">X_set</span><span class="p">[</span><span class="n">y_set</span> <span class="o">==</span> <span class="n">j</span><span class="p">,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">X_set</span><span class="p">[</span><span class="n">y_set</span> <span class="o">==</span> <span class="n">j</span><span class="p">,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">c</span> <span class="o">=</span> <span class="n">ListedColormap</span><span class="p">((</span><span class="s">'green'</span><span class="p">,</span> <span class="s">'red'</span><span class="p">))(</span><span class="n">i</span><span class="p">),</span> <span class="n">label</span> <span class="o">=</span> <span class="n">j</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">'(COVID) Logistic Regression (Training set)'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">'Sexo'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">'Idade'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">legend</span><span class="p">()</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<center>
![](https://i.imgur.com/q9blpwt.png)
***Imagem 4**: Mortes vs Idade-Sexo.*
</center>
<p>Como observado na imagem acima, podemos ver que nosso modelo é capaz de corretamente traçar uma reta que parece separar bem os dois grupos. É possível ainda perceber que existe uma leve tendência para uma taxa de mortalidade mais elevada de homens começando em uma faixa etária mais jovem que as das mulheres, conforme <a href="https://g1.globo.com/bemestar/coronavirus/noticia/2020/03/01/coronavirus-por-que-ha-mais-homens-que-mulheres-infectados.ghtml">algumas evidências recentem tendem a corroborar</a>.</p>
<p>No entanto, é importante lembrar que este modelo é de grande simplicidade, apresentando apenas duas colunas de informação (Sexo e Idade) por questões didáticas. Isso implica numa menor variação na otimização do nosso modelo (o que tende a ser positivo), porém em um maior viés (tanto explicito, ao escolhermos o que é importante ou não entrar no modelo; quanto implícito, ao incorrermos no risco de usarmos dados auto-correlacionados ou falsamente correlacionados por questões de amostragem inadequadada).</p>
<center>
![i6](https://files.ai-pool.com/a/eba93f5a75070f0fbb9d86bec8a009e9.png)
***Imagem 5**: [Bias-Variance Tradeoff in Machine Learning](https://ai-pool.com/a/s/bias-variance-tradeoff-in-machine-learning).*
</center>
<p>Como explicado no post <a href="https://lamfo-unb.github.io/2017/04/29/Um-Olhar-Descontraido-Sobre-o-Dilema-Vies-Variancia/"><em>Um Olhar Descontraído Sobre o Dilema Viés-Variância</em></a>, nosso objetivo principal não é descrever os dados, mas sim os utilizar de maneira que possamos generalizar o modelo para que este possa ser aplicado a dados não utilizados no treinamento. Na prática, é preciso achar um equilíbrio que nos permita treinar o modelo da maneira mais efetiva possível, buscando uma variação adequada dos dados (fornecendo variáveis indepentes suficientes), ao mesmo tempo sem produzir um (grande) viés que prejudique a generalização do modelo.</p>
<h1 id="apêndice">Apêndice</h1>
<h3 id="máxima-verossimilhança">Máxima Verossimilhança</h3>
<p>Na regressão linear, para estimar os parâmetros desconhecidos $\beta_{i}$ utiliza-se como critério de estimação o modelo de <a href="https://lamfo-unb.github.io/2020/02/07/O-M%C3%A9todo-dos-M%C3%ADnimos-Quadrados-Ordin%C3%A1rios-e-Regress%C3%A3o-Linear-Simples/">Mínimos Quadrados Ordinários</a>.</p>
<p>Já para a Regressão Logística, utilizamos o método da Máxima Verossimilhança. Esse método fornece valores para os parâmetros desconhecidos que maximizam a probabilidade de se obter determinado conjunto de dados.</p>
<h4 id="definição"><em>Definição</em></h4>
<p>A verossimilhança $(L)$ de um conjunto de parâmetros $(\theta)$, dado observação $(x)$ é igual a probabilidade daquela observação ter ocorrido dados os valores daqueles parâmetros.</p>
\[L (\theta;x)= P(x;\theta)\]
<p>A função de Verossimilhança $L$ é definida como:</p>
\[L (\theta;x)=\prod_{i=1}^{n}{f(x_{i;\theta})}\]
<p>Uma vez que a função $log$ é contínua e crescente, maximizar a verossimilhança é equivalente a maximizar o seu logaritmo.</p>
\[l(\theta;x) = log \ L(\theta;x)\]
<p>Derivando:</p>
\[l'(\theta;x) = \frac {\delta \ {l(\theta;x)}}{\delta \ \theta} = 0\]
<p>Ao calcular a primeira derivada, tem-se um candidato a ponto máximo. Esse é o valor que maximiza a probabilidade de uma determinada amostra ser observada.</p>
<h3 id="coeficientes">Coeficientes</h3>
<p>A variável resposta da regressão logística possui distribuição de Bernoulli, com probabilidade de sucesso $p$ e probabilidade de fracasso $1-p$.</p>
\[P(y_{i}) = p_i^{y_{i}} (1-p_i)^{1-y_{i}} \\
P(y_{i} = 1) = p_i^1 (1-p_i)^{1-1} = p_{i} \\
P(y_{i} = 0) = p_i^0 (1-p_i)^{1-0} = 1- p_{i}\]
<p>A probabilidade de observar uma amostra e dada pelo produto das probabilidades individuais:</p>
\[P(y_{1}, ..., y_{n} ) = \prod^{n}_{i=1}{p_i^{y_{i}} (1-p_i)^{1-y_{i}}}\]
<p>Sabe-se que $L (\theta;x)= P(x;\theta)$, portanto,</p>
<p>\(L (\beta;x) = \prod^{n}_{i=1}{p_i^{y_{i}} (1-p_i)^{1-y_{i}}}\)
Aplicando $log$ dos dois lados</p>
\[l (\beta;x) = \sum^{n}_{i=1} \log p_i} + ({1-y_{i})\log(1-p_i)}}\]
<p>Ao maximizar a função log-verossimilhança, encontra-se os parâmetros $b_{0}, b_{1}, …, b_{n}$ para os quais a função $L (\beta;x)$ atinge um valor máximo.</p>
<h3 id="erro">Erro</h3>
<p>Na regressão linear pode-se encontrar o erro através dos mínimos quadrados
ordinários (MQO).</p>
\[(\hat{y}-y)^2\]
<p>Já na regressão logística, não é possível utilizar esse mesmo método, é utilizado a <em>“Binary Cross Entropy”</em> que pode ser representada pela seguinte expressão:</p>
\[-y \ log(\hat{y}) -(1-y) \ log(1-\hat{y})\]
<p>Como na regressão os valores são contínuos, é possivel calcular o erro como a diferença do valor previsto da hipótese e o valor real.</p>
<p>Note que quando $y = 1$, a expressão acima pode ser representada como:</p>
\[\begin{split}
-1 \ log(\hat{y}) -(1-1) \ log(1-\hat{y}) = \\
-1 \ log(\hat{y}) -(0) \ log(1-\hat{y}) = \\
-1 \ log(\hat{y})
\end{split}\]
<p>e quando $y = 0$</p>
\[\begin{array}
= - \ 0 \ log(\hat{y}) -(1-0) \ log(1-\hat{y}) \\
= -1 \ log(1-\hat{y}) \\
\end{array}\]
<p>O custo total (Logistic Loss) é representado por</p>
\[\frac{1}{N} \sum_{i=1}^{N}-y \ log(\hat{y}) -(1-y) \ log(1-\hat{y})\]
<p>Ao minizarmos os erros com a <em>função de custo</em>, por não termos mais uma solução única (como no caso da regressão linear), temos de considerar uma curva não-convexa com mínimos e máximos locais. Essa função, no caso da regressão logística, se chama <em>Logistic Loss</em>. A diferença reside no fato de, ao sabermos que as probabilidades da função sigmoid são complementares (P=1 - P’), usarmos ambas as função simulâneamente na função Logistic Loss para chegar no mínimo global. Mais em <a href="https://towardsdatascience.com/optimization-loss-function-under-the-hood-part-ii-d20a239cde11">Loss Function (Part II): Logistic Regression</a>.</p>
<h2 id="referências">Referências</h2>
<ul>
<li>https://www.marktechpost.com/2019/06/12/logistic-regression-with-a-real-world-example-in-python/</li>
<li>https://towardsdatascience.com/introduction-to-logistic-regression-66248243c148</li>
<li>https://dataaspirant.com/2017/03/02/how-logistic-regression-model-works/</li>
<li>https://g1.globo.com/bemestar/coronavirus/noticia/2020/03/01/coronavirus-por-que-ha-mais-homens-que-mulheres-infectados.ghtml</li>
<li>https://lamfo-unb.github.io/2017/04/29/Um-Olhar-Descontraido-Sobre-o-Dilema-Vies-Variancia/</li>
<li>https://towardsdatascience.com/optimization-loss-function-under-the-hood-part-ii-d20a239cde11</li>
</ul>
Statistical analysis of the Chinese COVID-19 data with Benford's Law and clustering.2020-04-21T00:00:00+00:00http://lamfo-unb.github.io/2020/04/21/COVID-China-EN<h3 id="真金不怕火煉">“真金不怕火煉”</h3>
<h4 id="chinese-saying-true-gold-does-not-fear-the-test-of-fire"><em>(Chinese saying: “True gold does not fear the test of fire”)</em></h4>
<hr />
<h6 id="the-views-expressed-in-this-work-are-of-entire-responsibility-of-the-authors-and-do-not-necessarily-reflect-those-of-their-respective-affiliated-institutions-nor-those-of-its-members">The views expressed in this work are of entire responsibility of the authors and do not necessarily reflect those of their respective affiliated institutions nor those of its members.</h6>
<hr />
<h2 id="motivation">Motivation</h2>
<p>COVID-19 (SARS-CoV-2) is an ongoing pandemic that infected more than 2.5 million people around the world and claimed more than 170,000 lives as of 21 April 2020. Unlike all other pandemics recorded in history, a large volume of data and news concerning COVID-19 are flowed in with great speed and coverage, mobilizing scholars from various fields of knowledge to focus their efforts on analyzing those data and proposing solutions.</p>
<p>In epidemic data, it is natural to observe an exponential growth in the infected cases, especially in the early stages of the disease. As addressed in posts like <a href="https://medium.com/@tomaspueyo/coronavirus-the-hammer-and-the-dance-be9337092b56">this</a>, measures of social isolation seek to “flatten the curve”, reducing the number of affected at the peak, but prolonging the “wave” over time. Similarly, the number of deaths also follows an exponential trend.</p>
<p>Analyzing data from countries affected by the pandemic, it is possible to observe patterns that are common to all. Despite the existence of several peculiarities such as territorial extension, population density, temperature, season, degree of underreporting, social discipline to comply with isolation measures, etc., which differ significantly between different countries, the virus has not (yet) suffered radical mutations since its appearance in China, such that the general parameters of infectivity and lethality are similar between countries. However, <strong>the Chinese data are a notable exception</strong>, showing a behavior that differs from the others – despite being the first country affected by the disease, the number of infected people evolution remained close to a linear trend in the early stages, followed by <ins>few moments that suffered abrupt variation and prolonged periods marked by the absence of variance</ins>, both unusual patterns in nature. Here are some graphs:</p>
<p><img src="/img/covid19/f1.png" alt="" />
<em><strong>Image 1</strong>: Cumulative COVID-19 cases in China, as of 18 Apr 2020</em></p>
<p><img src="/img/covid19/f2.png" alt="" />
<em><strong>Image 2</strong>: Same as image 1, comparing the province of Hubei with all others</em></p>
<p><img src="/img/covid19/f3.png" alt="" />
<em><strong>Image 3</strong>: Same as image 2, with all provinces except Hubei, re-scaled for better viewing</em></p>
<p><strong>Image 1</strong> above shows the cumulative number of confirmed cases of COVID-19 in China (Taiwan not included). Note that the exponential pattern appears at the beginning but the concavity of the curve changes rapidly, contrary to expectations and to what was observed in almost all other countries. The growth happened with “jumps” at the beginning of the series, followed by a practically linear trend in the first days of February, a single day of great growth, and a long period with decreasing new cases per day, until the curve became practically a straight line since the early March.</p>
<p>Furthermore, looking at the decomposition of the aggregate data for province-level in <strong>image 2</strong>, we can notice that a single province – Hubei – is responsible for almost all cases from China, while all other provinces (which also differ considerably among themselves in area, population density, temperature, distance to the virus’ city of origin, etc.) exhibited practically the same pattern, resulting in a sigmoid curve with surgical precision.</p>
<p>At the provincial level, the only place that showed some degree of variance over time was Hong Kong; in Shandong, there was a great variation in a single day – 21 February 2020, when an outbreak of the virus was reported in the Rencheng Prison in the city of Jining: on that day 203 people were added to the confirmed statistic, an isolated point in a “well behaved” curve in all periods besides that day. In Guangdong (in southern China) and Heilongjiang (in northeastern China) the series returned to grow in late March and early April, respectively, both after a long period with virtually no variation. See the behavior of the series of these provinces in <strong>image 3</strong>.</p>
<p><img src="/img/covid19/f4.png" alt="" />
<em><strong>Image 4</strong>: Cumulative COVID-19 cases per state in the United States, as of 30 Mar 2020. Retrieved from <a href="https://medium.com/@tomaspueyo/coronavirus-out-of-many-one-36b886af37e9">“Coronavirus: Out of Many, One” by Tomas Pueyo</a></em></p>
<p><img src="/img/covid19/f5.png" alt="" />
<em><strong>Image 5</strong>: Same as image 4, with all states except New York and New Jersey. Retrieved from <a href="https://medium.com/@tomaspueyo/coronavirus-out-of-many-one-36b886af37e9">“Coronavirus: Out of Many, One” by Tomas Pueyo</a></em></p>
<p>It is well known that <ins>the derivative of an exponential function is also an exponential</ins>, so it is expected that the daily variation of the confirmed cases would also follow an exponential. The Chinese data, however, showed something quite different:</p>
<p><img src="/img/covid19/f6.png" alt="" />
<em><strong>Image 6</strong>: Daily variation of COVID-19 cases in China, as of 18 Apr 2020</em></p>
<p>The initial section of the series seems more like a straight line than an exponential curve, considering the two peaks on January 28 and February 02, while the number of new cases started to decrease rapidly and without major variations – except for the peak of 15136 new cases on 13 February 2020, which clearly differs from the other periods. Disregarding this anomalous point, we can see a practically linear trend between February 02 and February 23, from which the series resembles a straight line – again, a rare pattern in contagious diseases.</p>
<p>See below the same graph comparing Hubei with all other provinces:</p>
<p><img src="/img/covid19/f7.png" alt="" />
<em><strong>Image 7</strong>: Daily variation of COVID-19 cases in China, as of 18 Apr 2020, comparing Hubei with all other provinces</em></p>
<p><img src="/img/covid19/f8.png" alt="" />
<em><strong>Image 8</strong>: Same as image 7, with all provinces except Hubei, re-scaled for better viewing</em></p>
<p>It is worth noting that, <a href="http://www.xinhuanet.com/renshi/2020-02/13/c_1125568253.htm">on the same day that anomalous peak occurred, Jiang Chaoliang and Ma Guoqiang were exonerated</a>: they were the No. 1 and No. 2 in the Hubei command hierarchy (secretary-general and deputy secretary-general of the Party in the province, respectively).</p>
<p><strong>The Chinese data for deaths from COVID-19 are also anti-intuitive</strong>, see below in <strong>images 9 to 11</strong>. Note that the second province with the most recorded deaths after Hubei was its neighbor Henan, with only 22 deaths. The daily variation in deaths is a practically stationary series, with the extra spice of the bizarre “adjustment” of 1290 deaths on April 17 after more than a month with almost no official deaths:</p>
<p><img src="/img/covid19/f9.png" alt="" />
<em><strong>Image 9</strong>: Cumulative COVID-19 deaths in China, as of 18 Apr 2020, comparing Hubei with all other provinces</em></p>
<p><img src="/img/covid19/f10.png" alt="" />
<em><strong>Image 10</strong>: Same as image 9, with all provinces except Hubei, re-scaled for better viewing</em></p>
<p><img src="/img/covid19/f11.png" alt="" />
<em><strong>Image 11</strong>: Daily variation of COVID-19 deaths in China, as of 18 Apr 2020</em></p>
<p>The adoption of severe measures of social isolation influences the shape of the curves directly. However, the exponential pattern still remains at least in the initial stages, and the effects of those measures also take some time to become evident. Let’s compare the data from Japan, Singapore, and South Korea, which responded early to the disease, as well as from Italy, Spain, and the United Kingdom, which acted more intensely only in more advanced stages:</p>
<p><img src="/img/covid19/f12.png" alt="" />
<em><strong>Imagem 12</strong>: Cumulative COVID-19 cases in Spain, Italy, United Kingdom, China, South Korea, Japan, and Singapore, as of 18 Apr 2020</em></p>
<p><img src="/img/covid19/f13.png" alt="" />
<em><strong>Imagem 13</strong>: Same as image 12, with the Asian countries except for China. Note that Japan and Singapore also exhibited a late exponential growth. Only South Korea’s curve exhibited a similar shape to the Chinese data</em></p>
<p>With the visual analysis above, we can deduce the existence of some underlying “pattern” in the COVID-19 data, but for some reason, it does not appear in the Chinese data. Next, let’s do an exercise trying to identify this pattern using <strong>Benford’s Law</strong>.</p>
<h2 id="benfords-law">Benford’s Law</h2>
<p>Life is mysterious and unexpected patterns rule the world. As they say, “life imitates art”. However, when art tries to imitate life, we can feel something strange, as if the complexity of life cannot be replaced by naive human engineering.</p>
<p>One of those patterns that seem to “emerge” in nature is Benford’s Law, discovered by <a href="https://www.semanticscholar.org/paper/Note-on-the-Frequency-of-Use-of-the-Different-in-Newcomb/4136337f95c88d446a5577d9331c8fc0309c11af">Newcomb (1881)</a> and popularized by <a href="https://en.scribd.com/document/209534421/The-Law-of-Anomalous-Numbers">Benford (1938)</a>, and widely used to check frauds in databases.</p>
<p>Benford, testing for more than 20 variables from different contexts, such as river sizes, population of cities, physics constants, mortality rate, etc., found out that <strong>the chance of the first digit of a number to be equal to 1 was the highest, chance that decreased progressively for the subsequent numbers</strong>. That is, it is more likely that the first digit of a number is 1, then 2, and successively up to 9.</p>
<p><a href="https://www.nbp.pl/badania/seminaria/8ii2019.pdf">Okhrimenko and Kopczewski (2019)</a>, two behavioral economists, tested people’s ability to create false data in order to circumvent the tax base. The authors found evidence that by the criteria of Benford’s law, the system would easily identify false data. Other applications of Benford’s Law for manipulated data identification and fraud detection include <a href="https://www.sciencedirect.com/science/article/abs/pii/S0377221706011702">Hales et al. (2008)</a>, <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426611002032">Abrantes- Metz et al. (2012)</a>, and <a href="https://www.amazon.com/Benfords-Law-Applications-Accounting-Detection/dp/1118152859">Nigrini (2012)</a>.</p>
<p>How can we intuitively explain this seemingly random regularity? The answer is related to two known concepts: the exponential function and the logarithmic scale. Let’s review them as they are everywhere, especially during the current pandemic…</p>
<p><img src="/img/covid19/expo.jpg" alt="" /></p>
<p>Epidemics such as the Coronavirus, which we are experiencing at the moment, are classic examples to explain the exponential function. The modeling happens as follows: the amount of infected tomorrow, \(I_1\), can be modeled as a constant \(\alpha\) times the amount of infected today, \(I_0\); that is, \(I_1 = \alpha \cdot I_0\).</p>
<p>Assuming that the rate is the same for tomorrow (we can interpret it as having no new policies, or no changes in population habits have occurred), the number of people infected the day after tomorrow, \(I_2\), is a proportion of what will be tomorrow (\(I_2=\alpha \cdot I_1\)), which in turn can be substituted by \(I_2=\alpha \cdot I_1 = \alpha \cdot \alpha \cdot I_0\). This expression can be generalized for \(t\) days from now: being \(t\) any positive integer, the generalization is \(I_t=\alpha^t \cdot I_0\). The virtually omnipresent compound interest from the financial numbers also follows the same logic (\(F = P(1+i)^n\)).</p>
<p>Here is the secret of Benford’s law. Let’s look at an exponentially growing epidemic simulation, that is, the number of infected at each day is a fixed multiple of the previous day. Let’s look at the standard scale and the logarithmic scale over time (in this case we use exponentials of 2, but it could be any positive integer). Note that in both cases, each gradation of blue is the area referring to a digit. The first corresponds between 10 and 20, the second between 20 and 30, so on until 100. Note that the width of the bands is different between the standard scale and the logarithmic scale.</p>
<p><img src="/img/covid19/f14.png" alt="" />
<em><strong>Imagem 14</strong>: Exponential function and logarithmic scale</em></p>
<p>This graph already gives us a clue as to why exponential phenomena may obey Benford’s law. When we look through the logarithmic lens, an exponential function looks like a function that grows linearly, and each observation is equidistant from the previous and the next observations. However, in this same logarithmic lens, the area between 10 and 20 is bigger than the area between 20 and 30, and so on. This means that the probability of the variable falling in the first range is greater than falling in the following ranges.</p>
<p>Using a technical jargon, <ins><strong>the log mantissa is uniformly distributed</strong></ins>. For a number \(x\) taken from a sample, let’s apply his log – for example, apply the log to the number 150: \(log_{10}(150) \approx 2,176\). We can decompose the result into the integer part \(m = 2\) and decimal part \(d = 0.176\). The decimal part is what we call <em>mantissa</em>.</p>
<h3 id="mantissa-and-theoretical-distribution-d_t">Mantissa and theoretical distribution \(D_T\)</h3>
<p>From the logarithm properties, \(log_{10} (150) = log_{10}(100 \cdot 1.5) = log_{10}(100) + log_{10}(1.5) = 2 + 0.176\). Note that the base 10 log of any integer power of 10 (100, 1000, 10000 …) will result in an integer. In this sense, the integer part of the base 10 log returns the number of digits that the original number has (since the Hindu-Arabic numeral system has 10 digits). The mantissa, on the other hand, is responsible for saying which is the first digit.</p>
<p>For numbers at the hundreds, when the mantissa is in the \([0, 0.301)\) range, the original number will be between \([100, 200)\). Doing the same procedure as above, when the number reaches 200, its log will result in \(log_{10}(200) = log_{10}(100 \cdot 2) = log_{10}(100) + log_{10}(2)\) which results in \(2 + 0.301\).</p>
<p>Now that we know that the mantissa is decisive for knowing the first digit, we can finally understand Benford’s law. Its idea is that the mantissa has a uniform distribution for digits 1 to 9. Thus, it is easier for 1 to be the leading digit because it has the largest interval of the mantissa \([0, 0.301)\).</p>
<p>We can define, according to Benford’s law, the probability for a number to have first digit equal to \(d\), given by:</p>
<p>\begin{equation}
P(d)=\log_{10}\left(1+\frac{1}{d}\right), d = 1,…,9
\end{equation}</p>
<p>To save the reader’s time, we calculated the probability distribution for each digit to be the first according to Benford’s Law (\(D_T\)), as well as the respective intervals on the mantissa:</p>
<center>
\begin{array}{|c|c|c|c|}
\hline d & P(d) & Probability & Mantissa \\
\hline 1 & log_{10} (1+1) = 0.30103 & 30.1\% & [0, 0.301)\\
\hline 2 & \log _{10}\left(1+\frac{1}{2}\right) = 0.1760913 & 17.6\% & [0.301, 0.477)\\
\hline 3 & \log _{10}\left(1+\frac{1}{3}\right) = 0.1249387 & 12.5\% & [0.477, 0.602) \\
\hline 4 & \log _{10}\left(1+\frac{1}{4}\right) = 0.09691001 & 9.7\% & [0.602, 0.699)\\
\hline 5 & \log _{10}\left(1+\frac{1}{5}\right) = 0.07918125 & 7.9\% & [0.699, 0.778)\\
\hline 6 & \log _{10}\left(1+\frac{1}{6}\right) = 0.06694679 & 6.7\% & [0.778, 0.845)\\
\hline 7 & \log _{10}\left(1+\frac{1}{7}\right) = 0.05799195 & 5.8\% & [0.845, 0.912)\\
\hline 8 & \log _{10}\left(1+\frac{1}{8}\right) = 0.05115252 & 5.1\% & [0.912, 0.954)\\
\hline 9 & \log _{10}\left(1+\frac{1}{9}\right) = 0.04575749 & 4.6\% & [0.963, 1.00]\\
\hline
\end{array}
</center>
<p><em><strong>Table 1</strong> : First digit distribution according to Benford’s Law</em></p>
<p>For more details on Benford’s law and its applications, take a look at these links [<a href="http://prorum.com/?qa=2157/existem-formas-de-detectar-fraudes-em-bases-de-dados">1</a>; <a href="https://epublications.marquette.edu/cgi/viewcontent.cgi?article=1031&context=account_fac">2</a>; <a href="https://towardsdatascience.com/what-is-benfords-law-and-why-is-it-important-for-data-science-312cb8b61048">3</a>]</p>
<h2 id="empirical-distributions-d_e-of-covid-19-data">Empirical distributions \(D_E\) of COVID-19 data</h2>
<p>For this exercise, we picked the <ins>countries with more than 10,000 confirmed cases of COVID-19 as of April 18, 2020</ins>, according to the data available in <a href="https://github.com/RamiKrispin/coronavirus-csv">this link</a>. Let’s see below the first digit distributions of the time series of COVID-19 cases and deaths for the 24 selected countries:</p>
<p><img src="/img/covid19/f15.png" alt="" />
<em><strong>Image 15</strong>: First digit distributions of COVID-19 cases</em></p>
<p><img src="/img/covid19/f16.png" alt="" />
<em><strong>Image 16</strong>: First digit distributions of COVID-19 deaths</em></p>
<p><strong>No database follows Benford’s Law perfectly, but China’s empirical distributions appear to be particularly different from those of other countries</strong>. By visual inspection, the data from China seems to be significantly desynchronized with Benford’s Law. For greater robustness, we will compare the empirical distributions \(D_E\) with the theoretical distribution \(D_T\) that comes from Benford’s Law by performing some hypothesis tests.</p>
<h2 id="hypothesis-tests">Hypothesis tests</h2>
<p>For this exercise, we will perform three hypothesis tests:</p>
<ul>
<li>Chi-squared test</li>
<li>Kolmogorov–Smirnov test (two-tailed)</li>
<li>Kuiper’s test</li>
</ul>
<p>The three tests above are similar, <ins>all of them have as a null hypothesis of equality between the empirical (\(D_E\)) and theoretical (\(D_T\)) distributions</ins>. The chi-squared test is the most commonly used, however, it tends to reject the null hypothesis more easily, while the KS test is less sensitive to pointwise differences; Kuiper’s test works in the same way as the KS test, with the difference that it considers separately positive and negative differences between the distributions (the case “\(D_E\) greater than \(D_T\)” is seen as different from the case “\(D_T\) greater than \(D_E\)”). The tables with the associated p-values are displayed below:</p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-1wig{font-weight:bold;text-align:left;vertical-align:top}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-1wig">Country/Test</th>
<th class="tg-1wig">Chi-squared</th>
<th class="tg-1wig">Kolmogorov-Smirnov</th>
<th class="tg-1wig">Kuiper</th>
</tr>
<tr>
<td class="tg-1wig">Austria</td>
<td class="tg-0lax">0.1644</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Belgium</td>
<td class="tg-1wig">0.0004</td>
<td class="tg-1wig">0.0366</td>
<td class="tg-0lax">0.0521</td>
</tr>
<tr>
<td class="tg-1wig">Brazil</td>
<td class="tg-0lax">0.2685</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Canada</td>
<td class="tg-1wig">0.0117</td>
<td class="tg-0lax">1.0000</td>
<td class="tg-0lax">1.0000</td>
</tr>
<tr>
<td class="tg-1wig">China</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-1wig">0.0086</td>
<td class="tg-0lax">0.0521</td>
</tr>
<tr>
<td class="tg-1wig">France</td>
<td class="tg-1wig">0.0363</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">1.0000</td>
</tr>
<tr>
<td class="tg-1wig">Germany</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">India</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Iran</td>
<td class="tg-0lax">0.1284</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Ireland</td>
<td class="tg-0lax">0.8036</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Israel</td>
<td class="tg-0lax">0.5245</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Italy</td>
<td class="tg-0lax">0.0705</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.0521</td>
</tr>
<tr>
<td class="tg-1wig">Japan</td>
<td class="tg-0lax">0.0509</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">South Korea</td>
<td class="tg-1wig">0.0002</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Netherlands</td>
<td class="tg-0lax">0.4804</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Peru</td>
<td class="tg-0lax">0.9629</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Portugal</td>
<td class="tg-0lax">0.6247</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Russia</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Spain</td>
<td class="tg-1wig">0.0027</td>
<td class="tg-1wig">0.0366</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Sweden</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Switzerland</td>
<td class="tg-1wig">0.0111</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Turkey</td>
<td class="tg-0lax">0.6985</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">United Kingdom</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">United States</td>
<td class="tg-1wig">0.0156</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
</table>
</center>
<p><em><strong>Table 2</strong> : P-values of the hypothesis tests for COVID-19 cases data, rounded to 4 digits. Values with significance at 95% confidence level are marked in bold</em></p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-1wig{font-weight:bold;text-align:left;vertical-align:top}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-1wig">Country/Test</th>
<th class="tg-1wig">Chi-squared</th>
<th class="tg-1wig">Kolmogorov-Smirnov</th>
<th class="tg-1wig">Kuiper</th>
</tr>
<tr>
<td class="tg-1wig">Austria</td>
<td class="tg-0lax">0.2883</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Belgium</td>
<td class="tg-0lax">0.3746</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Brazil</td>
<td class="tg-0lax">0.9773</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">Canada</td>
<td class="tg-0lax">0.7868</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">China</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">France</td>
<td class="tg-1wig">0.0454</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Germany</td>
<td class="tg-0lax">0.5473</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">India</td>
<td class="tg-0lax">0.3685</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Iran</td>
<td class="tg-0lax">0.2098</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Ireland</td>
<td class="tg-0lax">0.7039</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">Israel</td>
<td class="tg-0lax">0.4175</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Italy</td>
<td class="tg-0lax">0.2414</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Japan</td>
<td class="tg-1wig">0.0203</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">South Korea</td>
<td class="tg-0lax">0.1442</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Netherlands</td>
<td class="tg-0lax">0.4993</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Peru</td>
<td class="tg-0lax">0.5246</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Portugal</td>
<td class="tg-0lax">0.3712</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Russia</td>
<td class="tg-0lax">0.6750</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Spain</td>
<td class="tg-0lax">0.1228</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Sweden</td>
<td class="tg-0lax">0.7078</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Switzerland</td>
<td class="tg-0lax">0.6034</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Turkey</td>
<td class="tg-0lax">0.5745</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">United Kingdom</td>
<td class="tg-0lax">0.8325</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">United States</td>
<td class="tg-0lax">0.9284</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.9761</td>
</tr>
</table>
</center>
<p><em><strong>Table 3</strong> : P-values of the hypothesis tests for COVID-19 deaths data, rounded to 4 digits. Values with significance at 95% confidence level are marked in bold</em></p>
<p>Basically, the <strong>smaller</strong> the p-value, the <strong>less</strong> the data for the respective country seems to “obey” Benford’s Law. <ins>Using this evaluation metric, the Chinese data are clearly anomalous regarding Benford’s Law, while the vast majority of other countries seem to follow it reasonably well.</ins></p>
<h2 id="kl-divergence-and-dbscan-clustering">KL divergence and DBSCAN clustering</h2>
<p>Now let’s see how “similar” the country data are to each other, using a metric called <strong>Kullback-Leibler divergence</strong> (henceforth “KL divergence”), which is a <ins>measure of relative entropy between two probability distributions</ins>. Its calculation for discrete distributions is given by the following expression:</p>
<p>\begin{equation}
KL(D_1||D_2) = \sum\limits_{x \in \mathcal{P}}{D_1(x)\cdot log\left(\frac{D_1(x)}{D_2(x)}\right)}
\end{equation}</p>
<p>The KL divergence gives the expected value of the logarithmic difference between two distributions \(D_1\) and \(D_2\) defined in the same probability space \(\mathcal{P}\); the theoretical discussion of this concept lies beyond the scope of this post, as it involves knowledge of information theory and measure theory. In simplified terms, the KL divergence measures how different two probability distributions are – the closer to zero its value, the more “similar” they are. As there are 24 countries, by comparing all empirical distributions \(D_E\) we yield 24x24 matrices that measure the “difference” between the data of the countries considered (one for the cases data and another for the deaths data), matrice whose main diagonals are all zero (the “difference” of something to itself is equal to zero!).</p>
<p>In <strong>table 4</strong> below we present the matrix of KL divergences between the empirical distributions of confirmed cases data from the 24 selected countries. To save space, we omitted the matrix calculated from the deaths data.</p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-1wig{font-weight:bold;text-align:left;vertical-align:top}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-0lax"></th>
<th class="tg-1wig">Austria</th>
<th class="tg-1wig">Belgium</th>
<th class="tg-1wig">Brazil</th>
<th class="tg-1wig">Canada</th>
<th class="tg-1wig">China</th>
<th class="tg-1wig">France</th>
<th class="tg-1wig">Germany</th>
<th class="tg-1wig">India</th>
<th class="tg-1wig">Iran</th>
<th class="tg-1wig">Ireland</th>
<th class="tg-1wig">Israel</th>
<th class="tg-1wig">Italy</th>
<th class="tg-1wig">Japan</th>
<th class="tg-1wig">South Korea</th>
<th class="tg-1wig">Netherlands</th>
<th class="tg-1wig">Peru</th>
<th class="tg-1wig">Portugal</th>
<th class="tg-1wig">Russia</th>
<th class="tg-1wig">Spain</th>
<th class="tg-1wig">Sweden</th>
<th class="tg-1wig">Switzerland</th>
<th class="tg-1wig">Turkey</th>
<th class="tg-1wig">United Kingdom</th>
<th class="tg-1wig">United States</th>
</tr>
<tr>
<td class="tg-1wig">Austria</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.0734</td>
<td class="tg-0lax">0.1005</td>
<td class="tg-0lax">0.5631</td>
<td class="tg-0lax">0.0387</td>
<td class="tg-0lax">0.0447</td>
<td class="tg-0lax">0.1739</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.0371</td>
<td class="tg-0lax">0.0395</td>
<td class="tg-0lax">0.0595</td>
<td class="tg-0lax">0.0921</td>
<td class="tg-0lax">0.0778</td>
<td class="tg-0lax">0.0313</td>
<td class="tg-0lax">0.0268</td>
<td class="tg-0lax">0.0146</td>
<td class="tg-0lax">0.1832</td>
<td class="tg-0lax">0.0362</td>
<td class="tg-0lax">0.0214</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.0826</td>
<td class="tg-0lax">0.1109</td>
<td class="tg-0lax">0.0410</td>
</tr>
<tr>
<td class="tg-1wig">Belgium</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0452</td>
<td class="tg-0lax">0.1612</td>
<td class="tg-0lax">0.7024</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.0956</td>
<td class="tg-0lax">0.1827</td>
<td class="tg-0lax">0.1964</td>
<td class="tg-0lax">0.0727</td>
<td class="tg-0lax">0.0819</td>
<td class="tg-0lax">0.0488</td>
<td class="tg-0lax">0.1466</td>
<td class="tg-0lax">0.1303</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.0704</td>
<td class="tg-0lax">0.0556</td>
<td class="tg-0lax">0.1564</td>
<td class="tg-0lax">0.0539</td>
<td class="tg-0lax">0.0455</td>
<td class="tg-0lax">0.0995</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.1662</td>
<td class="tg-0lax">0.1019</td>
</tr>
<tr>
<td class="tg-1wig">Brazil</td>
<td class="tg-0lax">0.0734</td>
<td class="tg-0lax">0.0452</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0981</td>
<td class="tg-0lax">0.5960</td>
<td class="tg-0lax">0.1057</td>
<td class="tg-0lax">0.1721</td>
<td class="tg-0lax">0.1647</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0601</td>
<td class="tg-0lax">0.0887</td>
<td class="tg-0lax">0.0252</td>
<td class="tg-0lax">0.0707</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0235</td>
<td class="tg-0lax">0.0650</td>
<td class="tg-0lax">0.0670</td>
<td class="tg-0lax">0.0532</td>
<td class="tg-0lax">0.0693</td>
<td class="tg-0lax">0.1201</td>
<td class="tg-0lax">0.0533</td>
<td class="tg-0lax">0.1100</td>
<td class="tg-0lax">0.0990</td>
<td class="tg-0lax">0.1111</td>
</tr>
<tr>
<td class="tg-1wig">Canada</td>
<td class="tg-0lax">0.1005</td>
<td class="tg-0lax">0.1612</td>
<td class="tg-0lax">0.0981</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.3342</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.1370</td>
<td class="tg-0lax">0.2187</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.1111</td>
<td class="tg-0lax">0.0376</td>
<td class="tg-0lax">0.1266</td>
<td class="tg-0lax">0.0310</td>
<td class="tg-0lax">0.0433</td>
<td class="tg-0lax">0.1267</td>
<td class="tg-0lax">0.0698</td>
<td class="tg-0lax">0.0839</td>
<td class="tg-0lax">0.2046</td>
<td class="tg-0lax">0.1453</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.1335</td>
<td class="tg-0lax">0.0830</td>
<td class="tg-0lax">0.0824</td>
<td class="tg-0lax">0.1181</td>
</tr>
<tr>
<td class="tg-1wig">China</td>
<td class="tg-0lax">0.5631</td>
<td class="tg-0lax">0.7024</td>
<td class="tg-0lax">0.5960</td>
<td class="tg-0lax">0.3342</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.7432</td>
<td class="tg-0lax">0.7605</td>
<td class="tg-0lax">0.6701</td>
<td class="tg-0lax">0.5725</td>
<td class="tg-0lax">0.6681</td>
<td class="tg-0lax">0.5067</td>
<td class="tg-0lax">0.6763</td>
<td class="tg-0lax">0.4182</td>
<td class="tg-0lax">0.3305</td>
<td class="tg-0lax">0.6036</td>
<td class="tg-0lax">0.5808</td>
<td class="tg-0lax">0.6312</td>
<td class="tg-0lax">0.8489</td>
<td class="tg-0lax">0.7006</td>
<td class="tg-0lax">0.7566</td>
<td class="tg-0lax">0.6211</td>
<td class="tg-0lax">0.6705</td>
<td class="tg-0lax">0.4789</td>
<td class="tg-0lax">0.6572</td>
</tr>
<tr>
<td class="tg-1wig">France</td>
<td class="tg-0lax">0.0387</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.1057</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.7432</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.1576</td>
<td class="tg-0lax">0.0771</td>
<td class="tg-0lax">0.0246</td>
<td class="tg-0lax">0.0361</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.1107</td>
<td class="tg-0lax">0.1180</td>
<td class="tg-0lax">0.0807</td>
<td class="tg-0lax">0.0137</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.2226</td>
<td class="tg-0lax">0.0879</td>
<td class="tg-0lax">0.0524</td>
<td class="tg-0lax">0.1224</td>
<td class="tg-0lax">0.0256</td>
<td class="tg-0lax">0.1278</td>
<td class="tg-0lax">0.0244</td>
</tr>
<tr>
<td class="tg-1wig">Germany</td>
<td class="tg-0lax">0.0447</td>
<td class="tg-0lax">0.0956</td>
<td class="tg-0lax">0.1721</td>
<td class="tg-0lax">0.1370</td>
<td class="tg-0lax">0.7605</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.2417</td>
<td class="tg-0lax">0.1751</td>
<td class="tg-0lax">0.0690</td>
<td class="tg-0lax">0.0461</td>
<td class="tg-0lax">0.1260</td>
<td class="tg-0lax">0.1635</td>
<td class="tg-0lax">0.1181</td>
<td class="tg-0lax">0.1170</td>
<td class="tg-0lax">0.0521</td>
<td class="tg-0lax">0.0420</td>
<td class="tg-0lax">0.2765</td>
<td class="tg-0lax">0.0858</td>
<td class="tg-0lax">0.0206</td>
<td class="tg-0lax">0.1607</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.1935</td>
<td class="tg-0lax">0.0691</td>
</tr>
<tr>
<td class="tg-1wig">India</td>
<td class="tg-0lax">0.1739</td>
<td class="tg-0lax">0.1827</td>
<td class="tg-0lax">0.1647</td>
<td class="tg-0lax">0.2187</td>
<td class="tg-0lax">0.6701</td>
<td class="tg-0lax">0.1576</td>
<td class="tg-0lax">0.2417</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.2459</td>
<td class="tg-0lax">0.2386</td>
<td class="tg-0lax">0.2244</td>
<td class="tg-0lax">0.0706</td>
<td class="tg-0lax">0.2892</td>
<td class="tg-0lax">0.2965</td>
<td class="tg-0lax">0.1888</td>
<td class="tg-0lax">0.2027</td>
<td class="tg-0lax">0.2205</td>
<td class="tg-0lax">0.3063</td>
<td class="tg-0lax">0.3947</td>
<td class="tg-0lax">0.2911</td>
<td class="tg-0lax">0.3474</td>
<td class="tg-0lax">0.1517</td>
<td class="tg-0lax">0.2098</td>
<td class="tg-0lax">0.2509</td>
</tr>
<tr>
<td class="tg-1wig">Iran</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.1964</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.5725</td>
<td class="tg-0lax">0.0771</td>
<td class="tg-0lax">0.1751</td>
<td class="tg-0lax">0.2459</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0947</td>
<td class="tg-0lax">0.0674</td>
<td class="tg-0lax">0.1353</td>
<td class="tg-0lax">0.0491</td>
<td class="tg-0lax">0.1192</td>
<td class="tg-0lax">0.1351</td>
<td class="tg-0lax">0.0598</td>
<td class="tg-0lax">0.1113</td>
<td class="tg-0lax">0.2188</td>
<td class="tg-0lax">0.1537</td>
<td class="tg-0lax">0.1645</td>
<td class="tg-0lax">0.1445</td>
<td class="tg-0lax">0.0292</td>
<td class="tg-0lax">0.1040</td>
<td class="tg-0lax">0.0680</td>
</tr>
<tr>
<td class="tg-1wig">Ireland</td>
<td class="tg-0lax">0.0371</td>
<td class="tg-0lax">0.0727</td>
<td class="tg-0lax">0.0601</td>
<td class="tg-0lax">0.1111</td>
<td class="tg-0lax">0.6681</td>
<td class="tg-0lax">0.0246</td>
<td class="tg-0lax">0.0690</td>
<td class="tg-0lax">0.2386</td>
<td class="tg-0lax">0.0947</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0321</td>
<td class="tg-0lax">0.0540</td>
<td class="tg-0lax">0.0644</td>
<td class="tg-0lax">0.0742</td>
<td class="tg-0lax">0.0472</td>
<td class="tg-0lax">0.0068</td>
<td class="tg-0lax">0.0459</td>
<td class="tg-0lax">0.1446</td>
<td class="tg-0lax">0.0583</td>
<td class="tg-0lax">0.0663</td>
<td class="tg-0lax">0.0632</td>
<td class="tg-0lax">0.0446</td>
<td class="tg-0lax">0.0790</td>
<td class="tg-0lax">0.0411</td>
</tr>
<tr>
<td class="tg-1wig">Israel</td>
<td class="tg-0lax">0.0395</td>
<td class="tg-0lax">0.0819</td>
<td class="tg-0lax">0.0887</td>
<td class="tg-0lax">0.0376</td>
<td class="tg-0lax">0.5067</td>
<td class="tg-0lax">0.0361</td>
<td class="tg-0lax">0.0461</td>
<td class="tg-0lax">0.2244</td>
<td class="tg-0lax">0.0674</td>
<td class="tg-0lax">0.0321</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.0621</td>
<td class="tg-0lax">0.0432</td>
<td class="tg-0lax">0.0809</td>
<td class="tg-0lax">0.0184</td>
<td class="tg-0lax">0.0456</td>
<td class="tg-0lax">0.2038</td>
<td class="tg-0lax">0.0847</td>
<td class="tg-0lax">0.0467</td>
<td class="tg-0lax">0.1104</td>
<td class="tg-0lax">0.0476</td>
<td class="tg-0lax">0.0952</td>
<td class="tg-0lax">0.0578</td>
</tr>
<tr>
<td class="tg-1wig">Italy</td>
<td class="tg-0lax">0.0595</td>
<td class="tg-0lax">0.0488</td>
<td class="tg-0lax">0.0252</td>
<td class="tg-0lax">0.1266</td>
<td class="tg-0lax">0.6763</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.1260</td>
<td class="tg-0lax">0.0706</td>
<td class="tg-0lax">0.1353</td>
<td class="tg-0lax">0.0540</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1031</td>
<td class="tg-0lax">0.1094</td>
<td class="tg-0lax">0.0357</td>
<td class="tg-0lax">0.0558</td>
<td class="tg-0lax">0.0724</td>
<td class="tg-0lax">0.1237</td>
<td class="tg-0lax">0.1236</td>
<td class="tg-0lax">0.1072</td>
<td class="tg-0lax">0.1077</td>
<td class="tg-0lax">0.0759</td>
<td class="tg-0lax">0.0870</td>
<td class="tg-0lax">0.1073</td>
</tr>
<tr>
<td class="tg-1wig">Japan</td>
<td class="tg-0lax">0.0921</td>
<td class="tg-0lax">0.1466</td>
<td class="tg-0lax">0.0707</td>
<td class="tg-0lax">0.0310</td>
<td class="tg-0lax">0.4182</td>
<td class="tg-0lax">0.1107</td>
<td class="tg-0lax">0.1635</td>
<td class="tg-0lax">0.2892</td>
<td class="tg-0lax">0.0491</td>
<td class="tg-0lax">0.0644</td>
<td class="tg-0lax">0.0621</td>
<td class="tg-0lax">0.1031</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0537</td>
<td class="tg-0lax">0.0528</td>
<td class="tg-0lax">0.0651</td>
<td class="tg-0lax">0.0831</td>
<td class="tg-0lax">0.0927</td>
<td class="tg-0lax">0.0679</td>
<td class="tg-0lax">0.1534</td>
<td class="tg-0lax">0.0386</td>
<td class="tg-0lax">0.1049</td>
<td class="tg-0lax">0.0596</td>
<td class="tg-0lax">0.1089</td>
</tr>
<tr>
<td class="tg-1wig">South Korea</td>
<td class="tg-0lax">0.0778</td>
<td class="tg-0lax">0.1303</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0433</td>
<td class="tg-0lax">0.3305</td>
<td class="tg-0lax">0.1180</td>
<td class="tg-0lax">0.1181</td>
<td class="tg-0lax">0.2965</td>
<td class="tg-0lax">0.1192</td>
<td class="tg-0lax">0.0742</td>
<td class="tg-0lax">0.0432</td>
<td class="tg-0lax">0.1094</td>
<td class="tg-0lax">0.0537</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0883</td>
<td class="tg-0lax">0.0726</td>
<td class="tg-0lax">0.0863</td>
<td class="tg-0lax">0.2317</td>
<td class="tg-0lax">0.1205</td>
<td class="tg-0lax">0.1145</td>
<td class="tg-0lax">0.1041</td>
<td class="tg-0lax">0.1254</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.1473</td>
</tr>
<tr>
<td class="tg-1wig">Netherlands</td>
<td class="tg-0lax">0.0313</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.0235</td>
<td class="tg-0lax">0.1267</td>
<td class="tg-0lax">0.6036</td>
<td class="tg-0lax">0.0807</td>
<td class="tg-0lax">0.1170</td>
<td class="tg-0lax">0.1888</td>
<td class="tg-0lax">0.1351</td>
<td class="tg-0lax">0.0472</td>
<td class="tg-0lax">0.0809</td>
<td class="tg-0lax">0.0357</td>
<td class="tg-0lax">0.0528</td>
<td class="tg-0lax">0.0883</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0457</td>
<td class="tg-0lax">0.0423</td>
<td class="tg-0lax">0.0785</td>
<td class="tg-0lax">0.0317</td>
<td class="tg-0lax">0.0859</td>
<td class="tg-0lax">0.0276</td>
<td class="tg-0lax">0.1009</td>
<td class="tg-0lax">0.0683</td>
<td class="tg-0lax">0.0821</td>
</tr>
<tr>
<td class="tg-1wig">Peru</td>
<td class="tg-0lax">0.0268</td>
<td class="tg-0lax">0.0704</td>
<td class="tg-0lax">0.0650</td>
<td class="tg-0lax">0.0698</td>
<td class="tg-0lax">0.5808</td>
<td class="tg-0lax">0.0137</td>
<td class="tg-0lax">0.0521</td>
<td class="tg-0lax">0.2027</td>
<td class="tg-0lax">0.0598</td>
<td class="tg-0lax">0.0068</td>
<td class="tg-0lax">0.0184</td>
<td class="tg-0lax">0.0558</td>
<td class="tg-0lax">0.0651</td>
<td class="tg-0lax">0.0726</td>
<td class="tg-0lax">0.0457</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0328</td>
<td class="tg-0lax">0.1594</td>
<td class="tg-0lax">0.0626</td>
<td class="tg-0lax">0.0530</td>
<td class="tg-0lax">0.0767</td>
<td class="tg-0lax">0.0290</td>
<td class="tg-0lax">0.0820</td>
<td class="tg-0lax">0.0257</td>
</tr>
<tr>
<td class="tg-1wig">Portugal</td>
<td class="tg-0lax">0.0146</td>
<td class="tg-0lax">0.0556</td>
<td class="tg-0lax">0.0670</td>
<td class="tg-0lax">0.0839</td>
<td class="tg-0lax">0.6312</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.0420</td>
<td class="tg-0lax">0.2205</td>
<td class="tg-0lax">0.1113</td>
<td class="tg-0lax">0.0459</td>
<td class="tg-0lax">0.0456</td>
<td class="tg-0lax">0.0724</td>
<td class="tg-0lax">0.0831</td>
<td class="tg-0lax">0.0863</td>
<td class="tg-0lax">0.0423</td>
<td class="tg-0lax">0.0328</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1745</td>
<td class="tg-0lax">0.0625</td>
<td class="tg-0lax">0.0453</td>
<td class="tg-0lax">0.0908</td>
<td class="tg-0lax">0.0611</td>
<td class="tg-0lax">0.0931</td>
<td class="tg-0lax">0.0314</td>
</tr>
<tr>
<td class="tg-1wig">Russia</td>
<td class="tg-0lax">0.1832</td>
<td class="tg-0lax">0.1564</td>
<td class="tg-0lax">0.0532</td>
<td class="tg-0lax">0.2046</td>
<td class="tg-0lax">0.8489</td>
<td class="tg-0lax">0.2226</td>
<td class="tg-0lax">0.2765</td>
<td class="tg-0lax">0.3063</td>
<td class="tg-0lax">0.2188</td>
<td class="tg-0lax">0.1446</td>
<td class="tg-0lax">0.2038</td>
<td class="tg-0lax">0.1237</td>
<td class="tg-0lax">0.0927</td>
<td class="tg-0lax">0.2317</td>
<td class="tg-0lax">0.0785</td>
<td class="tg-0lax">0.1594</td>
<td class="tg-0lax">0.1745</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0920</td>
<td class="tg-0lax">0.2830</td>
<td class="tg-0lax">0.0342</td>
<td class="tg-0lax">0.2555</td>
<td class="tg-0lax">0.1539</td>
<td class="tg-0lax">0.2438</td>
</tr>
<tr>
<td class="tg-1wig">Spain</td>
<td class="tg-0lax">0.0362</td>
<td class="tg-0lax">0.0539</td>
<td class="tg-0lax">0.0693</td>
<td class="tg-0lax">0.1453</td>
<td class="tg-0lax">0.7006</td>
<td class="tg-0lax">0.0879</td>
<td class="tg-0lax">0.0858</td>
<td class="tg-0lax">0.3947</td>
<td class="tg-0lax">0.1537</td>
<td class="tg-0lax">0.0583</td>
<td class="tg-0lax">0.0847</td>
<td class="tg-0lax">0.1236</td>
<td class="tg-0lax">0.0679</td>
<td class="tg-0lax">0.1205</td>
<td class="tg-0lax">0.0317</td>
<td class="tg-0lax">0.0626</td>
<td class="tg-0lax">0.0625</td>
<td class="tg-0lax">0.0920</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0725</td>
<td class="tg-0lax">0.0254</td>
<td class="tg-0lax">0.1403</td>
<td class="tg-0lax">0.1252</td>
<td class="tg-0lax">0.0915</td>
</tr>
<tr>
<td class="tg-1wig">Sweden</td>
<td class="tg-0lax">0.0214</td>
<td class="tg-0lax">0.0455</td>
<td class="tg-0lax">0.1201</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.7566</td>
<td class="tg-0lax">0.0524</td>
<td class="tg-0lax">0.0206</td>
<td class="tg-0lax">0.2911</td>
<td class="tg-0lax">0.1645</td>
<td class="tg-0lax">0.0663</td>
<td class="tg-0lax">0.0467</td>
<td class="tg-0lax">0.1072</td>
<td class="tg-0lax">0.1534</td>
<td class="tg-0lax">0.1145</td>
<td class="tg-0lax">0.0859</td>
<td class="tg-0lax">0.0530</td>
<td class="tg-0lax">0.0453</td>
<td class="tg-0lax">0.2830</td>
<td class="tg-0lax">0.0725</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1327</td>
<td class="tg-0lax">0.1115</td>
<td class="tg-0lax">0.1644</td>
<td class="tg-0lax">0.0723</td>
</tr>
<tr>
<td class="tg-1wig">Switzerland</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.0995</td>
<td class="tg-0lax">0.0533</td>
<td class="tg-0lax">0.1335</td>
<td class="tg-0lax">0.6211</td>
<td class="tg-0lax">0.1224</td>
<td class="tg-0lax">0.1607</td>
<td class="tg-0lax">0.3474</td>
<td class="tg-0lax">0.1445</td>
<td class="tg-0lax">0.0632</td>
<td class="tg-0lax">0.1104</td>
<td class="tg-0lax">0.1077</td>
<td class="tg-0lax">0.0386</td>
<td class="tg-0lax">0.1041</td>
<td class="tg-0lax">0.0276</td>
<td class="tg-0lax">0.0767</td>
<td class="tg-0lax">0.0908</td>
<td class="tg-0lax">0.0342</td>
<td class="tg-0lax">0.0254</td>
<td class="tg-0lax">0.1327</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1652</td>
<td class="tg-0lax">0.0918</td>
<td class="tg-0lax">0.1397</td>
</tr>
<tr>
<td class="tg-1wig">Turkey</td>
<td class="tg-0lax">0.0826</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.1100</td>
<td class="tg-0lax">0.0830</td>
<td class="tg-0lax">0.6705</td>
<td class="tg-0lax">0.0256</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.1517</td>
<td class="tg-0lax">0.0292</td>
<td class="tg-0lax">0.0446</td>
<td class="tg-0lax">0.0476</td>
<td class="tg-0lax">0.0759</td>
<td class="tg-0lax">0.1049</td>
<td class="tg-0lax">0.1254</td>
<td class="tg-0lax">0.1009</td>
<td class="tg-0lax">0.0290</td>
<td class="tg-0lax">0.0611</td>
<td class="tg-0lax">0.2555</td>
<td class="tg-0lax">0.1403</td>
<td class="tg-0lax">0.1115</td>
<td class="tg-0lax">0.1652</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1053</td>
<td class="tg-0lax">0.0319</td>
</tr>
<tr>
<td class="tg-1wig">United Kingdom</td>
<td class="tg-0lax">0.1109</td>
<td class="tg-0lax">0.1662</td>
<td class="tg-0lax">0.0990</td>
<td class="tg-0lax">0.0824</td>
<td class="tg-0lax">0.4789</td>
<td class="tg-0lax">0.1278</td>
<td class="tg-0lax">0.1935</td>
<td class="tg-0lax">0.2098</td>
<td class="tg-0lax">0.1040</td>
<td class="tg-0lax">0.0790</td>
<td class="tg-0lax">0.0952</td>
<td class="tg-0lax">0.0870</td>
<td class="tg-0lax">0.0596</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.0683</td>
<td class="tg-0lax">0.0820</td>
<td class="tg-0lax">0.0931</td>
<td class="tg-0lax">0.1539</td>
<td class="tg-0lax">0.1252</td>
<td class="tg-0lax">0.1644</td>
<td class="tg-0lax">0.0918</td>
<td class="tg-0lax">0.1053</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1764</td>
</tr>
<tr>
<td class="tg-1wig">United States</td>
<td class="tg-0lax">0.0410</td>
<td class="tg-0lax">0.1019</td>
<td class="tg-0lax">0.1111</td>
<td class="tg-0lax">0.1181</td>
<td class="tg-0lax">0.6572</td>
<td class="tg-0lax">0.0244</td>
<td class="tg-0lax">0.0691</td>
<td class="tg-0lax">0.2509</td>
<td class="tg-0lax">0.0680</td>
<td class="tg-0lax">0.0411</td>
<td class="tg-0lax">0.0578</td>
<td class="tg-0lax">0.1073</td>
<td class="tg-0lax">0.1089</td>
<td class="tg-0lax">0.1473</td>
<td class="tg-0lax">0.0821</td>
<td class="tg-0lax">0.0257</td>
<td class="tg-0lax">0.0314</td>
<td class="tg-0lax">0.2438</td>
<td class="tg-0lax">0.0915</td>
<td class="tg-0lax">0.0723</td>
<td class="tg-0lax">0.1397</td>
<td class="tg-0lax">0.0319</td>
<td class="tg-0lax">0.1764</td>
<td class="tg-0lax">0.0000</td>
</tr>
</table>
</center>
<p><em><strong>Table 4</strong>: Pairwise KL divergences between the analyzed countries COVID-19 cases first digit distributions, rounded to 4 digits</em></p>
<p>The matrix above does not have a very immediate practical interpretation, so we applied a clustering algorithm to define which countries are most similar to each other – pairs of countries with a larger KL divergence are less similar to each other than pairs of countries with a smaller KL divergence. The chosen algorithm was DBSCAN, which assigns each point in the sample to <em>clusters</em> based on the minimum number of points in each <em>cluster</em> (\(mp\)) and the maximum distance that a point have to another point of the same <em>cluster</em> (\(\varepsilon\)). <ins>Points that do not have at least \(mp\) points within the radius of \(\varepsilon\) are classified as <em>outliers</em> that belong to no <em>cluster</em></ins>. A good introductory material on DBSCAN can be found <a href="https://medium.com/@elutins/dbscan-what-is-it-when-to-use-it-how-to-use-it-8bd506293818">here</a>.</p>
<p>One of the advantages of DBSCAN is the fact that the <em>cluster</em> number is automatically defined instead of being chosen by the user, making it a good tool for anomaly detection. For this exercise, we used \(mp = 3\) and \(\varepsilon\) as the average of the KL divergences between countries plus three sample standard deviations. The result of this clustering is easier to interpret:</p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-c3ow{border-color:inherit;text-align:center;vertical-align:top}
.tg .tg-7btt{font-weight:bold;border-color:inherit;text-align:center;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-7btt">Country</th>
<th class="tg-7btt">Cluster</th>
</tr>
<tr>
<td class="tg-c3ow">Austria</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Belgium</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Brazil</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Canada</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">China</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">France</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Germany</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">India</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Iran</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Ireland</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Israel</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Italy</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Japan</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">South Korea</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Netherlands</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Peru</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Portugal</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Russia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Spain</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Sweden</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Switzerland</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Turkey</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">United Kingdom</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">United States</td>
<td class="tg-c3ow">1</td>
</tr>
</table>
</center>
<p><em><strong>Table 5</strong>: DBSCAN clustering between the KL divergences of COVID-19 cases time series first digit distributions of the analyzed countries</em></p>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-c3ow{border-color:inherit;text-align:center;vertical-align:top}
.tg .tg-7btt{font-weight:bold;border-color:inherit;text-align:center;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-7btt">Country</th>
<th class="tg-7btt">Cluster</th>
</tr>
<tr>
<td class="tg-c3ow">Austria</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Belgium</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Brazil</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Canada</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">China</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">France</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Germany</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">India</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Iran</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Ireland</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Israel</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Italy</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Japan</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">South Korea</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Netherlands</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Peru</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Portugal</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Russia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Spain</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Sweden</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Switzerland</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Turkey</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">United Kingdom</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">United States</td>
<td class="tg-c3ow">1</td>
</tr>
</table>
<p><em><strong>Table 6</strong>: DBSCAN clustering between the KL divergences of COVID-19 deaths time series first digit distributions of the analyzed countries</em></p>
<p>Again, as suggested by the visual inspection and hypothesis tests aforementioned, the results indicate that the data from China show distinct patterns from the majority of the countries most affected by the pandemic, which in turn showed similar patterns of infectivity and lethality: the algorithm returned only one <em>cluster</em>, classifying China as “<em>outlier</em>” for both data of case numbers and death numbers. Indeed, countries categorized as “<em>cluster</em> 1” seem to follow the distribution of Benford’s Law better.</p>
<p>Although China is the place of origin of the disease, given the great divergence between its data and the data from other locations, Chinese data should be used with special caution for analyzes such as estimating COVID-19’s pathogen parameters (basic reproducing number, serial interval, and case-fatality ratio, for instance), modeling the geographic dispersion of the pathogen, diagnosing the effectiveness of intervention scenarios, etc.</p>
<h2 id="final-remarks">Final remarks</h2>
<p>As the pandemic affects more and more people and has an increasingly deeper impact on economic activities and social life at a global level, discussing the underreporting of COVID-19 data becomes especially relevant, both for the assessment of the situation severity and for the proposal of solutions and means to overcome the crisis. Given that scholars, researchers, and policy-makers around the world are dedicated to this cause, having accurate and reliable data at hand is of paramount importance, as the quality of the data directly affects the quality of all analyses derived from them. As the saying goes: <strong>“<em>Garbage in, garbage out!</em>“</strong></p>
<hr />
<p><strong>Sometimes, “coincidence” is just a way for someone to avoid the facts that he failed to explain.</strong></p>
<p><img src="https://cdn.shopify.com/s/files/1/1218/4290/products/GOLD13391_46faec9e-ca27-48f7-997d-e152c18f4349_800x.JPG?v=1515022654" alt="tsuru" /></p>
Análise estatística dos dados chineses do COVID-19 usando Lei de Benford e clusterização.2020-04-20T00:00:00+00:00http://lamfo-unb.github.io/2020/04/20/COVID-China-ptBR<h3 id="真金不怕火煉">“真金不怕火煉”</h3>
<h4 id="dito-chinês-o-ouro-verdadeiro-não-teme-o-teste-do-fogo"><em>(Dito chinês: “O ouro verdadeiro não teme o teste do fogo”</em>)</h4>
<hr />
<h6 id="as-opiniões-emitidas-neste-trabalho-são-de-inteira-responsabilidade-dos-autores-não-exprimindo-necessariamente-o-ponto-de-vista-das-instituições-às-quais-estão-ou-estiveram-vinculados">As opiniões emitidas neste trabalho são de inteira responsabilidade dos autores, não exprimindo, necessariamente, o ponto de vista das instituições às quais estão ou estiveram vinculados.</h6>
<hr />
<h2 id="motivação">Motivação</h2>
<p>COVID-19 (SARS-CoV-2) é uma pandemia vigente que já infectou mais de 2 milhões de pessoas em todo o mundo e já fez mais de 160 mil vítimas fatais. Diferentemente de todas as outras pandemias já registradas na história, grande volume de dados e notícias sobre o COVID-19 são disponibilizadas com grande velocidade e abrangência, mobilizando estudiosos de variados campos do conhecimento para concentrar seus esforços em analisar esses dados e propor soluções.</p>
<p>Em dados de epidemias, é natural observar um crescimento exponencial do número de infectados, em especial nos estágios iniciais da doença. Conforme abordado em posts como <a href="https://medium.com/@tomaspueyo/coronavirus-the-hammer-and-the-dance-be9337092b56">este</a>, medidas de isolamento social buscam “achatar a curva”, reduzindo o pico do número de infectados, mas prolongando a “onda” ao longo do tempo. Analogamente, o número de óbitos também segue uma tendência exponencial.</p>
<p>Analisando os dados dos países afetados pela pandemia, é possível observar padrões que são comuns a todos. Apesar da existência de várias peculiaridades como extensão territorial, densidade populacional, temperatura, estação do ano, grau de subnotificação, disciplina social para acatar medidas de isolamento, etc., as quais diferem significativamente entre os diferentes países, o vírus (ainda) não sofreu mutações radicais desde seu surgimento na China, de modo que os parâmetros gerais de infectividade e letalidade são similares entre os países. No entanto, <strong>os dados chineses são uma notória exceção</strong>, apresentando um comportamento que difere dos demais – apesar de ser o primeiro país afetado pela doença, o crescimento do número de infectados se manteve próximo de uma tendência linear em estágios iniciais, com <ins> poucos momentos que sofrem variação abrupta e prolongados períodos marcados pela ausência de variância</ins>, ambas tendências pouco usuais na natureza. Veja a seguir alguns gráficos:</p>
<p><img src="/img/covid19/f1.png" alt="" />
<em><strong>Imagem 1</strong>: Casos acumulados de COVID-19 na China, dados de 18/04/2020</em></p>
<p><img src="/img/covid19/f2.png" alt="" />
<em><strong>Imagem 2</strong>: Igual à imagem 1, comparando a província de Hubei com todas as outras províncias</em></p>
<p><img src="/img/covid19/f3.png" alt="" />
<em><strong>Imagem 3</strong>: Igual à imagem 2, com todas as províncias exceto Hubei, com escala ajustada para melhor visualização</em></p>
<p>A <strong>imagem 1</strong> acima mostra o número acumulado de casos confirmados de COVID-19 na China (não inclui Taiwan). Note que o padrão exponencial aparece no início mas a concavidade da curva muda rapidamente, ao contrário do esperado e observado em praticamente todos os outros países. O crescimento acontece com “saltos” no início da série, seguido por uma tendência praticamente linear nos primeiros dias de fevereiro, um único dia de grande crescimento, e um longo período com cada vez menos casos novos por dia, até se tornar praticamente uma linha reta a partir do início de março.</p>
<p>Ademais, vendo a decomposição do dado agregado para nível de província na <strong>imagem 2</strong>, é possível notar que uma única província – Hubei – puxa praticamente toda a série da China, enquanto que todas as outras províncias (as quais também diferem bastante em área, densidade populacional, temperatura, distância com a cidade de origem do vírus, etc.) apresentam praticamente o mesmo padrão, resultando numa curva sigmóide praticamente cirúrgica.</p>
<p>A nível de província, o único local que apresentou algum grau de variância ao longo do tempo foi Hong Kong; em Shandong, observou-se uma grande variação num único dia – 21/02/2020, quando foi notificado um surto do vírus na penitenciária de Rencheng da cidade de Jining: nesse dia 203 pessoas foram adicionadas à estatística de confirmados, um ponto isolado numa curva “bem comportada” em todos os períodos além desse dia. Em Guangdong (no sul da China) e em Heilongjiang (no nordeste da China) a série voltou a apresentar crescimento no fim de março e no início de abril, respectivamente, ambos após um longo período praticamente sem variações. Veja o comportamento das séries dessas províncias na <strong>imagem 3</strong>.</p>
<p>Para efeito de comparação, veja as séries dos casos de COVID-19 em cada estado dos Estados Unidos:</p>
<p><img src="/img/covid19/f4.png" alt="" />
<em><strong>Imagem 4</strong>: Casos acumulados de COVID-19 por estado dos Estados Unidos, dados de 30/03/2020. Retirado de <a href="https://medium.com/@tomaspueyo/coronavirus-out-of-many-one-36b886af37e9">“Coronavirus: Out of Many, One” por Tomas Pueyo</a></em></p>
<p><img src="/img/covid19/f5.png" alt="" />
<em><strong>Imagem 5</strong>: Igual à imagem 4, com todas as províncias exceto New York e New Jersey. Retirado de <a href="https://medium.com/@tomaspueyo/coronavirus-out-of-many-one-36b886af37e9">“Coronavirus: Out of Many, One” por Tomas Pueyo</a></em></p>
<p>É bem sabido que <ins>a derivada de uma função exponencial também é uma exponencial</ins>, então é de se esperar que a variação diária do número de confirmados também siga uma exponencial. Os dados chineses, porém, mostraram algo bem diferente:</p>
<p><img src="/img/covid19/f6.png" alt="" />
<em><strong>Imagem 6</strong>: Variação diária de casos de COVID-19 na China, dados de 18/04/2020</em></p>
<p>O segmento inicial da série mais se assemelha a uma reta do que uma exponencial considerando os dois picos em 28/01 e 02/02, enquanto que o número de novos casos diminuiu rapidamente e sem grandes variações – exceto o pico de 15136 novos casos no dia 13/02/2020, que claramente destoa dos demais períodos. Desconsiderando esse ponto anômalo, é possível enxergar uma tendência praticamente linear entre 02/02 e 23/02, data a partir da qual a série praticamente vira uma linha reta – novamente, um padrão raro em doenças contagiosas.</p>
<p>Veja abaixo o mesmo gráfico comparando a província de Hubei com todas as demais províncias:</p>
<p><img src="/img/covid19/f7.png" alt="" />
<em><strong>Imagem 7</strong>: Variação diária de casos de COVID-19 na China, dados de 18/04/2020, comparando Hubei com todas as outras províncias</em></p>
<p><img src="/img/covid19/f8.png" alt="" />
<em><strong>Imagem 8</strong>: Igual à imagem 7, com todas as províncias exceto Hubei, com escala ajustada para melhor visualização</em></p>
<p>Vale notar que, <a href="http://www.xinhuanet.com/renshi/2020-02/13/c_1125568253.htm">no mesmo dia que houve esse pico, Jiang Chaoliang e Ma Guoqiang foram exonerados</a>: eles eram o Nº 1 e o Nº 2 na hierarquia de comando de Hubei (secretário-geral e vice secretário-geral do Partido na província, respectivamente).</p>
<p><strong>Os dados chineses de óbitos por COVID-19 são igualmente anti-intuitivos</strong>, veja abaixo nas <strong>imagens 9 a 11</strong>. Note que a província com mais mortes registradas foi Henan, que é vizinha de Hubei, com apenas 22 óbitos. A variação diária de mortos é uma série praticamente estacionária, temperada com o bizarro “ajuste” de 1290 mortes em 17/04 após mais de um mês quase sem mortes oficiais:</p>
<p><img src="/img/covid19/f9.png" alt="" />
<em><strong>Imagem 9</strong>: Óbitos totais por COVID-19 na China, dados de 18/04/2020, comparando Hubei com todas as outras províncias</em></p>
<p><img src="/img/covid19/f10.png" alt="" />
<em><strong>Imagem 10</strong>: Igual à imagem 9, com todas as províncias exceto Hubei, com escala ajustada para melhor visualização</em></p>
<p><img src="/img/covid19/f11.png" alt="" />
<em><strong>Imagem 11</strong>: Variação diária de óbitos por COVID-19 na China, dados de 18/04/2020</em></p>
<p>A adoção de medidas severas de isolamento social influenciam diretamente no formato das curvas, porém o padrão exponencial se mantém pelo menos nos estágios iniciais, e seus efeitos também demoram um certo tempo para se tornarem evidentes. Compare abaixo com dados de Japão, Singapura e Coreia do Sul, que responderam à doença nos estágios iniciais, bem como da Itália, Espanha e Reino Unido, que agiram com maior intensidade apenas em estágios mais avançados:</p>
<p><img src="/img/covid19/f12.png" alt="" />
<em><strong>Imagem 12</strong>: Casos totais de COVID-19 na Espanha, Itália, Reino Unido, China, Coreia do Sul, Japão e Singapura, dados de 18/04/2020</em></p>
<p><img src="/img/covid19/f13.png" alt="" />
<em><strong>Imagem 13</strong>: Igual à imagem 12, com os países asiáticos exceto China. Note que Japão e Singapura também apresentaram um crescimento exponencial que começou mais tarde. Apenas a curva da Coreia do Sul apresentou um formato que se assemelha aos dados da China</em></p>
<p>Com a análise visual acima é possível deduzir que existe algum “padrão” subjacente aos dados do COVID-19, mas que por alguma razão não aparece nos dados da China. Vamos fazer a seguir um exercício de tentar identificar esse padrão usando a <strong>Lei de Benford</strong>.</p>
<h2 id="lei-de-benford">Lei de Benford</h2>
<p>A vida é misteriosa e padrões inesperados governam o mundo. Como dizem por aí, “a vida imita a arte”. Quando, entretanto, a arte tenta imitar a vida, podemos sentir algo estranho, como se a complexidade da vida não pudesse ser substituída pela ingênua engenhosidade humana.</p>
<p>Um desses padrões que parecem “emergir” na natureza é Lei de Benford, descoberta por <a href="https://www.semanticscholar.org/paper/Note-on-the-Frequency-of-Use-of-the-Different-in-Newcomb/4136337f95c88d446a5577d9331c8fc0309c11af">Newcomb (1881)</a> e popularizada por <a href="https://pt.scribd.com/document/209534421/The-Law-of-Anomalous-Numbers">Benford (1938)</a>, muito usada para verificar fraudes em base de dados.</p>
<p>Benford mostrou que, para mais de 20 variáveis de contextos, tais como tamanhos de rio, população de cidades, constantes da física, taxa de mortalidade, etc., <strong>a chance do primeiro dígito de um número ser 1 é a mais alta, chance que vai diminuindo progressivamente com os algarismos subsequentes</strong>. Ou seja, é mais provável que o primeiro algarismo do número seja o número 1. Em seguida, o 2, e sucessivamente até o 9.</p>
<p><a href="https://www.nbp.pl/badania/seminaria/8ii2019.pdf">Okhrimenko e Kopczewski (2019)</a>, dois economistas comportamentais, testaram a capacidade das pessoas de criar dados falsos, com o intuito de burlar a base tributária. Os autores encontraram clara evidência de que pelo critério da lei de Benford, o sistema facilmente identificaria os dados falsos. Outras aplicações da Lei de Benford para identificação de dados manipulados e detecção de fraudes incluem <a href="https://www.sciencedirect.com/science/article/abs/pii/S0377221706011702">Hales et al.(2008)</a>, <a href="https://www.sciencedirect.com/science/article/abs/pii/S0378426611002032">Abrantes-Metz et al. (2012)</a> e <a href="https://www.amazon.com/Benfords-Law-Applications-Accounting-Detection/dp/1118152859">Nigrini (2012)</a>.</p>
<p>Como explicar intuitivamente essa regularidade aparentemente sem sentido? A resposta está relacionada a dois conceitos conhecidos: a função exponencial e a escala logarítmica. Vamos revisá-las pois elas estão por toda a parte, em especial durante a presente pandemia…</p>
<p><img src="/img/covid19/expo.jpg" alt="" /></p>
<p>Epidemias como a do Coronavirus, a qual estamos vivendo nesse momento, são clássicos exemplos para explicar a função exponencial. A modelagem acontece da seguinte forma: a quantidade de infectados amanhã \(I_1\) é igual a uma constante \(\alpha\) vezes a quantidade de infectados hoje \(I_0\); ou seja, \(I_1 = \alpha \cdot I_0\).</p>
<p>Supondo que a taxa seja a mesma para amanhã (podemos interpretar como sendo que nenhuma política ou mudança de hábitos da população tenha ocorrido), A quantidade de pessoas infectadas depois de amanhã, \(I_2\), é uma proporção do que é amanhã (\(I_2=\alpha \cdot I_1\)), que por sua vez pode ser substituído por \(I_2=\alpha \cdot I_1 = \alpha \cdot \alpha \cdot I_0\). Com perspicácia, percebemos que podemos generalizar essa fórmula para daqui a \(t\) dias: sendo \(t\) qualquer número inteiro positivo que quisermos, a generalização é \(I_t=\alpha^t \cdot I_0\). O praticamente onipresente regime de juros compostos dos números financeiros também segue essa mesma lógica (\(F = P(1+i)^n\)).</p>
<p>Aqui está o segredo da lei de Benford. Vejamos a simulação de crescimento da epidemia exponencialmente, isso é, cada dia é um múltiplo fixo do dia anterior. Analisemos na escala padrão e na escala logarítmica ao longo do tempo (nesse caso usamos exponenciais de 2, mas poderia ser qualquer número-base). Veja que nos dois casos, cada gradação de azul é a área referente a um dígito. A primeira corresponde entre 10 e 20, a segunda entre 20 e 30, assim sucessivamente até o número 100. Veja que essa distância é diferente na escala padrão e na escala logarítmica.</p>
<p><img src="/img/covid19/f14.png" alt="" />
<em><strong>Imagem 14</strong>: Função exponencial e escala logarítmica</em></p>
<p>Esse gráfico já nos dá uma pista de porque fenômenos exponenciais podem obedecer a lei de Benford. Quando olhamos pelas lentes logarítmicas, uma função exponencial se parece uma função que cresce linearmente, que cada observação é equidistante das observações antes e depois. Todavia, nessa mesma lente logarítmica, a área que existe entre 10 e 20 é maior a que existe entre 20 e 30, e assim succesivamente. Isso quer dizer que a probabilidade da variável cair nas faixas iniciais é maior que nas faixas seguintes.</p>
<p>Usando um jargão técnico, <ins><strong>a mantissa dos logs é uniformemente distribuída</strong></ins>. Para o número \(x\) que conseguimos da amostra, vamos aplicar o seu log – por exemplo, apliquemos o log para o número 150: \(log_{10} (150) \approx 2.176\). Podemos decompor o resultado na parte inteira \(m = 2\) e na parte decimal \(d = 0.176\). A parte decimal é a que chamamos de <em>mantissa</em>.</p>
<h3 id="mantissa-e-distribuição-teórica-d_t">Mantissa e distribuição teórica \(D_T\)</h3>
<p>Pelas propriedades do logaritmo, \(log_{10} (150) = log_{10}(100 \cdot 1.5) = log_{10}(100) + log_{10}(1.5) = 2 + 0.176\). Observe que o log na base 10 de qualquer potência inteira de 10 (100, 1000, 10000…) vai resultar em um número inteiro. Nesse sentido, a parte inteira do log na base 10 retorna a quantidade de algarismos que o número original tem (já que o sistema numérico indo-arábico possui 10 algarismos). A mantissa, por outro lado, é o responsável por dizer qual é o primeiro algarismo.</p>
<p>Na casa das centenas, enquanto a mantissa estiver no intervalo \([0, 0.301)\), o número original estará entre \([100, 200)\). Fazendo o mesmo procedimento anterior, quando o número chegar em 200, o seu log resultará em \(log_{10}(200) = log_{10}(100 \cdot 2) = log_{10}(100) + log_{10}(2)\) que resulta em \(2 + 0.301\).</p>
<p>Como vimos que a mantissa é decisiva para saber o primeiro dígito, podemos finalmente entender a lei de Benford. A sua ideia é que a mantissa tem distribuição uniforme para os dígitos de 1 a 9. Assim, é mais fácil occorrer o dígito número 1 por que ele tem o maior intervalo da mantissa \([0, 0.301)\).</p>
<p>Podemos definir, de acordo com a lei de Benford, a probabilidade de um múnero possuir primeiro dígito \(d\), dada por:</p>
<p>\begin{equation}
P(d)=\log_{10}\left(1+\frac{1}{d}\right), d = 1,…,9
\end{equation}</p>
<p>Para poupar tempo do leitor, calculamos a distribuição de probabilidade de cada dígito ser o primeiro de acordo com a Lei de Benford (\(D_T\)), bem como os respectivos intervalos na mantissa:</p>
<center>
\begin{array}{|c|c|c|c|}
\hline d & P(d) & Probabilidade & Mantissa \\
\hline 1 & log_{10} (1+1) = 0.30103 & 30.1\% & [0, 0.301)\\
\hline 2 & \log _{10}\left(1+\frac{1}{2}\right) = 0.1760913 & 17.6\% & [0.301, 0.477)\\
\hline 3 & \log _{10}\left(1+\frac{1}{3}\right) = 0.1249387 & 12.5\% & [0.477, 0.602) \\
\hline 4 & \log _{10}\left(1+\frac{1}{4}\right) = 0.09691001 & 9.7\% & [0.602, 0.699)\\
\hline 5 & \log _{10}\left(1+\frac{1}{5}\right) = 0.07918125 & 7.9\% & [0.699, 0.778)\\
\hline 6 & \log _{10}\left(1+\frac{1}{6}\right) = 0.06694679 & 6.7\% & [0.778, 0.845)\\
\hline 7 & \log _{10}\left(1+\frac{1}{7}\right) = 0.05799195 & 5.8\% & [0.845, 0.912)\\
\hline 8 & \log _{10}\left(1+\frac{1}{8}\right) = 0.05115252 & 5.1\% & [0.912, 0.954)\\
\hline 9 & \log _{10}\left(1+\frac{1}{9}\right) = 0.04575749 & 4.6\% & [0.963, 1.00]\\
\hline
\end{array}
</center>
<p><em><strong>Tabela 1</strong> : Distribuição do primeiro dígito de acordo com a Lei de Benford</em></p>
<p>Para mais detalhes sobre a lei de Benford e suas aplicações, dê uma olhada nesses links [<a href="http://prorum.com/?qa=2157/existem-formas-de-detectar-fraudes-em-bases-de-dados">1</a>; <a href="https://epublications.marquette.edu/cgi/viewcontent.cgi?article=1031&context=account_fac">2</a>; <a href="https://towardsdatascience.com/what-is-benfords-law-and-why-is-it-important-for-data-science-312cb8b61048">3</a>]</p>
<h2 id="distribuições-empíricas-d_e-dos-dados-do-covid-19">Distribuições empíricas \(D_E\) dos dados do COVID-19</h2>
<p>Para este exercício, escolhemos os <ins> países com mais de 10000 casos confirmados de COVID-19 em 18/04/2020</ins>, de acordo com os dados disponíveis <a href="https://github.com/RamiKrispin/coronavirus-csv">neste link</a>. Vejamos a seguir como ficou a distribuição do primeiro dígito para as séries temporais de casos e óbitos por COVID-19 dos 24 países selecionados:</p>
<p><img src="/img/covid19/f15.png" alt="" />
<em><strong>Imagem 15</strong>: Distribuição do primeiro dígito das séries de casos de COVID-19</em></p>
<p><img src="/img/covid19/f16.png" alt="" />
<em><strong>Imagem 16</strong>: Distribuição do primeiro dígito das séries de óbitos por COVID-19</em></p>
<p><strong>Nenhuma base de dados segue perfeitamente a Lei de Benford, mas as distribuições empíricas da China parecem ser particularmente diferentes das dos demais países</strong>. Pela inspeção visual, os dados da China parecem destoar significativamente da Lei de Benford. Para maior robustez, vamos comparar as distribuições empíricas \(D_E\) com a distribuição teórica \(D_T\) que vem da Lei de Benford realizando alguns testes de hipóteses.</p>
<h2 id="testes-de-hipóteses">Testes de hipóteses</h2>
<p>Para este exercício, vamos realizar três testes de hipóteses:</p>
<ul>
<li>Teste qui-quadrado</li>
<li>Teste Kolmogorov-Smirnov (bicaudal)</li>
<li>Teste de Kuiper</li>
</ul>
<p>Os três testes acima são parecidos, <ins>todos têm como hipótese nula a igualdade entre as distribuições empírica (\(D_E\)) e teórica (\(D_T\))</ins>. O teste qui-quadrado é o mais comumente utilizado, porém tende a rejeitar a hipótese nula mais facilmente, enquanto que o teste KS é menos sensível a diferenças pontuais; o teste de Kuiper funciona da mesma forma que o teste KS, com a diferença que considera separadamente diferenças positivas e negativas entre as distribuições (o caso “\(D_E\) maior que \(D_T\)” é encarado como diferente do caso “\(D_T\) maior que \(D_E\)”). A tabela com os p-valores associados está abaixo:</p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-1wig{font-weight:bold;text-align:left;vertical-align:top}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-1wig">País/Teste</th>
<th class="tg-1wig">Qui-quadrado</th>
<th class="tg-1wig">Kolmogorov-Smirnov</th>
<th class="tg-1wig">Kuiper</th>
</tr>
<tr>
<td class="tg-1wig">Áustria</td>
<td class="tg-0lax">0.1644</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Bélgica</td>
<td class="tg-1wig">0.0004</td>
<td class="tg-1wig">0.0366</td>
<td class="tg-0lax">0.0521</td>
</tr>
<tr>
<td class="tg-1wig">Brasil</td>
<td class="tg-0lax">0.2685</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Canadá</td>
<td class="tg-1wig">0.0117</td>
<td class="tg-0lax">1.0000</td>
<td class="tg-0lax">1.0000</td>
</tr>
<tr>
<td class="tg-1wig">China</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-1wig">0.0086</td>
<td class="tg-0lax">0.0521</td>
</tr>
<tr>
<td class="tg-1wig">França</td>
<td class="tg-1wig">0.0363</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">1.0000</td>
</tr>
<tr>
<td class="tg-1wig">Alemanha</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Índia</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Irã</td>
<td class="tg-0lax">0.1284</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Irlanda</td>
<td class="tg-0lax">0.8036</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Israel</td>
<td class="tg-0lax">0.5245</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Itália</td>
<td class="tg-0lax">0.0705</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.0521</td>
</tr>
<tr>
<td class="tg-1wig">Japão</td>
<td class="tg-0lax">0.0509</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Coreia do Sul</td>
<td class="tg-1wig">0.0002</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Países Baixos</td>
<td class="tg-0lax">0.4804</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Peru</td>
<td class="tg-0lax">0.9629</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Portugal</td>
<td class="tg-0lax">0.6247</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Rússia</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Espanha</td>
<td class="tg-1wig">0.0027</td>
<td class="tg-1wig">0.0366</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Suécia</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Suíça</td>
<td class="tg-1wig">0.0111</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Turquia</td>
<td class="tg-0lax">0.6985</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Reino Unido</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">Estados Unidos</td>
<td class="tg-1wig">0.0156</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
</table>
</center>
<p><em><strong>Tabela 2</strong> : P-valores para os testes de hipótese para dados de casos de COVID-19, arredondado para quatro casas decimais. Valores significantes ao nível de confiança de 95% estão em negrito</em></p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-1wig{font-weight:bold;text-align:left;vertical-align:top}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-1wig">País/Teste</th>
<th class="tg-1wig">Qui-quadrado</th>
<th class="tg-1wig">Kolmogorov-Smirnov</th>
<th class="tg-1wig">Kuiper</th>
</tr>
<tr>
<td class="tg-1wig">Áustria</td>
<td class="tg-0lax">0.2883</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Bélgica</td>
<td class="tg-0lax">0.3746</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Brasil</td>
<td class="tg-0lax">0.9773</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">Canadá</td>
<td class="tg-0lax">0.7868</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">China</td>
<td class="tg-1wig">0.0000</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">França</td>
<td class="tg-1wig">0.0454</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Alemanha</td>
<td class="tg-0lax">0.5473</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">Índia</td>
<td class="tg-0lax">0.3685</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Irã</td>
<td class="tg-0lax">0.2098</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Irlanda</td>
<td class="tg-0lax">0.7039</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.9761</td>
</tr>
<tr>
<td class="tg-1wig">Israel</td>
<td class="tg-0lax">0.4175</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Itália</td>
<td class="tg-0lax">0.2414</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Japão</td>
<td class="tg-1wig">0.0203</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Coreia do Sul</td>
<td class="tg-0lax">0.1442</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Países Baixos</td>
<td class="tg-0lax">0.4993</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Peru</td>
<td class="tg-0lax">0.5246</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Portugal</td>
<td class="tg-0lax">0.3712</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.1797</td>
</tr>
<tr>
<td class="tg-1wig">Rússia</td>
<td class="tg-0lax">0.6750</td>
<td class="tg-0lax">0.3364</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Espanha</td>
<td class="tg-0lax">0.1228</td>
<td class="tg-0lax">0.1243</td>
<td class="tg-0lax">0.4969</td>
</tr>
<tr>
<td class="tg-1wig">Suécia</td>
<td class="tg-0lax">0.7078</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Suíça</td>
<td class="tg-0lax">0.6034</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Turquia</td>
<td class="tg-0lax">0.5745</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Reino Unido</td>
<td class="tg-0lax">0.8325</td>
<td class="tg-0lax">0.9794</td>
<td class="tg-0lax">0.7292</td>
</tr>
<tr>
<td class="tg-1wig">Estados Unidos</td>
<td class="tg-0lax">0.9284</td>
<td class="tg-0lax">0.6994</td>
<td class="tg-0lax">0.9761</td>
</tr>
</table>
</center>
<p><em><strong>Tabela 3</strong> : P-valores para os testes de hipótese para dados de óbitos por COVID-19, arredondado para quatro casas decimais. Valores significantes ao nível de confiança de 95% estão em negrito</em></p>
<p>Basicamente, quanto <strong>menor</strong> o p-valor, <strong>menos</strong> os dados do respectivo país parecem “obedecer” à Lei de Benford. <ins>Usando essa métrica de avaliação, os dados chineses claramente são anômalos em relação à Lei de Benford, ao passo que a grande maioria dos outros países parecem segui-la razoavelmente bem.</ins></p>
<h2 id="distância-kl-e-clusterização-por-dbscan">Distância KL e clusterização por DBSCAN</h2>
<p>Vamos ver agora o quão “parecidos” são os dados dos países entre si, utilizando uma métrica chamada <strong>Distância de Kullback-Leibler</strong> (doravante “distância KL”), a qual é uma <ins>medida de entropia relativa entre duas distribuições de probabilidade</ins>. Seu cálculo para distribuições discretas se dá mediante a seguinte expressão:</p>
<p>\begin{equation}
KL(D_1||D_2) = \sum\limits_{x \in \mathcal{P}}{D_1(x)\cdot log\left(\frac{D_1(x)}{D_2(x)}\right)}
\end{equation}</p>
<p>A distância KL fornece o valor esperado da diferença logarítmica entre duas distribuições \(D_1\) e \(D_2\) definidas no mesmo espaço de probabilidade \(\mathcal{P}\); a discussão teórica da esse conceito está além dos escopos deste post, pois envolve conhecimentos de teoria da informação e teoria da medida. Em termos simplificados, a distância KL mede o quão diferentes são duas distribuições de probabilidade – quanto mais próximo de zero, mais “parecidas” elas são. Como são 24 países, ao compararmos todas as distribuições empíricas \(D_E\) obtemos como resultado matrizes 24x24 que medem a “diferença” entre os dados dos países considerados (uma para dados de casos e outra para dados de óbitos), matrizes cujas diagonais principais são toda zero (a “diferença” de algo com ela mesma é igual a zero!).</p>
<p>Apresentamos na <strong>tabela 4</strong> abaixo a matriz de distâncias KL entre as distribuições empíricas dos dados de casos confirmados dos 24 países selecionados. Para economizar espaço, omitimos a matriz calculada a partir dos dados de óbitos.</p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-1wig{font-weight:bold;text-align:left;vertical-align:top}
.tg .tg-0lax{text-align:left;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-0lax"></th>
<th class="tg-1wig">Áustria</th>
<th class="tg-1wig">Bélgica</th>
<th class="tg-1wig">Brasil</th>
<th class="tg-1wig">Canadá</th>
<th class="tg-1wig">China</th>
<th class="tg-1wig">França</th>
<th class="tg-1wig">Alemanha</th>
<th class="tg-1wig">Índia</th>
<th class="tg-1wig">Irã</th>
<th class="tg-1wig">Irlanda</th>
<th class="tg-1wig">Israel</th>
<th class="tg-1wig">Itália</th>
<th class="tg-1wig">Japão</th>
<th class="tg-1wig">Coreia do Sul</th>
<th class="tg-1wig">Países Baixos</th>
<th class="tg-1wig">Peru</th>
<th class="tg-1wig">Portugal</th>
<th class="tg-1wig">Rússia</th>
<th class="tg-1wig">Espanha</th>
<th class="tg-1wig">Suécia</th>
<th class="tg-1wig">Suíça</th>
<th class="tg-1wig">Turquia</th>
<th class="tg-1wig">Reino Unido</th>
<th class="tg-1wig">Estados Unidos</th>
</tr>
<tr>
<td class="tg-1wig">Áustria</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.0734</td>
<td class="tg-0lax">0.1005</td>
<td class="tg-0lax">0.5631</td>
<td class="tg-0lax">0.0387</td>
<td class="tg-0lax">0.0447</td>
<td class="tg-0lax">0.1739</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.0371</td>
<td class="tg-0lax">0.0395</td>
<td class="tg-0lax">0.0595</td>
<td class="tg-0lax">0.0921</td>
<td class="tg-0lax">0.0778</td>
<td class="tg-0lax">0.0313</td>
<td class="tg-0lax">0.0268</td>
<td class="tg-0lax">0.0146</td>
<td class="tg-0lax">0.1832</td>
<td class="tg-0lax">0.0362</td>
<td class="tg-0lax">0.0214</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.0826</td>
<td class="tg-0lax">0.1109</td>
<td class="tg-0lax">0.0410</td>
</tr>
<tr>
<td class="tg-1wig">Bélgica</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0452</td>
<td class="tg-0lax">0.1612</td>
<td class="tg-0lax">0.7024</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.0956</td>
<td class="tg-0lax">0.1827</td>
<td class="tg-0lax">0.1964</td>
<td class="tg-0lax">0.0727</td>
<td class="tg-0lax">0.0819</td>
<td class="tg-0lax">0.0488</td>
<td class="tg-0lax">0.1466</td>
<td class="tg-0lax">0.1303</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.0704</td>
<td class="tg-0lax">0.0556</td>
<td class="tg-0lax">0.1564</td>
<td class="tg-0lax">0.0539</td>
<td class="tg-0lax">0.0455</td>
<td class="tg-0lax">0.0995</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.1662</td>
<td class="tg-0lax">0.1019</td>
</tr>
<tr>
<td class="tg-1wig">Brasil</td>
<td class="tg-0lax">0.0734</td>
<td class="tg-0lax">0.0452</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0981</td>
<td class="tg-0lax">0.5960</td>
<td class="tg-0lax">0.1057</td>
<td class="tg-0lax">0.1721</td>
<td class="tg-0lax">0.1647</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0601</td>
<td class="tg-0lax">0.0887</td>
<td class="tg-0lax">0.0252</td>
<td class="tg-0lax">0.0707</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0235</td>
<td class="tg-0lax">0.0650</td>
<td class="tg-0lax">0.0670</td>
<td class="tg-0lax">0.0532</td>
<td class="tg-0lax">0.0693</td>
<td class="tg-0lax">0.1201</td>
<td class="tg-0lax">0.0533</td>
<td class="tg-0lax">0.1100</td>
<td class="tg-0lax">0.0990</td>
<td class="tg-0lax">0.1111</td>
</tr>
<tr>
<td class="tg-1wig">Canadá</td>
<td class="tg-0lax">0.1005</td>
<td class="tg-0lax">0.1612</td>
<td class="tg-0lax">0.0981</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.3342</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.1370</td>
<td class="tg-0lax">0.2187</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.1111</td>
<td class="tg-0lax">0.0376</td>
<td class="tg-0lax">0.1266</td>
<td class="tg-0lax">0.0310</td>
<td class="tg-0lax">0.0433</td>
<td class="tg-0lax">0.1267</td>
<td class="tg-0lax">0.0698</td>
<td class="tg-0lax">0.0839</td>
<td class="tg-0lax">0.2046</td>
<td class="tg-0lax">0.1453</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.1335</td>
<td class="tg-0lax">0.0830</td>
<td class="tg-0lax">0.0824</td>
<td class="tg-0lax">0.1181</td>
</tr>
<tr>
<td class="tg-1wig">China</td>
<td class="tg-0lax">0.5631</td>
<td class="tg-0lax">0.7024</td>
<td class="tg-0lax">0.5960</td>
<td class="tg-0lax">0.3342</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.7432</td>
<td class="tg-0lax">0.7605</td>
<td class="tg-0lax">0.6701</td>
<td class="tg-0lax">0.5725</td>
<td class="tg-0lax">0.6681</td>
<td class="tg-0lax">0.5067</td>
<td class="tg-0lax">0.6763</td>
<td class="tg-0lax">0.4182</td>
<td class="tg-0lax">0.3305</td>
<td class="tg-0lax">0.6036</td>
<td class="tg-0lax">0.5808</td>
<td class="tg-0lax">0.6312</td>
<td class="tg-0lax">0.8489</td>
<td class="tg-0lax">0.7006</td>
<td class="tg-0lax">0.7566</td>
<td class="tg-0lax">0.6211</td>
<td class="tg-0lax">0.6705</td>
<td class="tg-0lax">0.4789</td>
<td class="tg-0lax">0.6572</td>
</tr>
<tr>
<td class="tg-1wig">França</td>
<td class="tg-0lax">0.0387</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.1057</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.7432</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.1576</td>
<td class="tg-0lax">0.0771</td>
<td class="tg-0lax">0.0246</td>
<td class="tg-0lax">0.0361</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.1107</td>
<td class="tg-0lax">0.1180</td>
<td class="tg-0lax">0.0807</td>
<td class="tg-0lax">0.0137</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.2226</td>
<td class="tg-0lax">0.0879</td>
<td class="tg-0lax">0.0524</td>
<td class="tg-0lax">0.1224</td>
<td class="tg-0lax">0.0256</td>
<td class="tg-0lax">0.1278</td>
<td class="tg-0lax">0.0244</td>
</tr>
<tr>
<td class="tg-1wig">Alemanha</td>
<td class="tg-0lax">0.0447</td>
<td class="tg-0lax">0.0956</td>
<td class="tg-0lax">0.1721</td>
<td class="tg-0lax">0.1370</td>
<td class="tg-0lax">0.7605</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.2417</td>
<td class="tg-0lax">0.1751</td>
<td class="tg-0lax">0.0690</td>
<td class="tg-0lax">0.0461</td>
<td class="tg-0lax">0.1260</td>
<td class="tg-0lax">0.1635</td>
<td class="tg-0lax">0.1181</td>
<td class="tg-0lax">0.1170</td>
<td class="tg-0lax">0.0521</td>
<td class="tg-0lax">0.0420</td>
<td class="tg-0lax">0.2765</td>
<td class="tg-0lax">0.0858</td>
<td class="tg-0lax">0.0206</td>
<td class="tg-0lax">0.1607</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.1935</td>
<td class="tg-0lax">0.0691</td>
</tr>
<tr>
<td class="tg-1wig">Índia</td>
<td class="tg-0lax">0.1739</td>
<td class="tg-0lax">0.1827</td>
<td class="tg-0lax">0.1647</td>
<td class="tg-0lax">0.2187</td>
<td class="tg-0lax">0.6701</td>
<td class="tg-0lax">0.1576</td>
<td class="tg-0lax">0.2417</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.2459</td>
<td class="tg-0lax">0.2386</td>
<td class="tg-0lax">0.2244</td>
<td class="tg-0lax">0.0706</td>
<td class="tg-0lax">0.2892</td>
<td class="tg-0lax">0.2965</td>
<td class="tg-0lax">0.1888</td>
<td class="tg-0lax">0.2027</td>
<td class="tg-0lax">0.2205</td>
<td class="tg-0lax">0.3063</td>
<td class="tg-0lax">0.3947</td>
<td class="tg-0lax">0.2911</td>
<td class="tg-0lax">0.3474</td>
<td class="tg-0lax">0.1517</td>
<td class="tg-0lax">0.2098</td>
<td class="tg-0lax">0.2509</td>
</tr>
<tr>
<td class="tg-1wig">Irã</td>
<td class="tg-0lax">0.1223</td>
<td class="tg-0lax">0.1964</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0409</td>
<td class="tg-0lax">0.5725</td>
<td class="tg-0lax">0.0771</td>
<td class="tg-0lax">0.1751</td>
<td class="tg-0lax">0.2459</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0947</td>
<td class="tg-0lax">0.0674</td>
<td class="tg-0lax">0.1353</td>
<td class="tg-0lax">0.0491</td>
<td class="tg-0lax">0.1192</td>
<td class="tg-0lax">0.1351</td>
<td class="tg-0lax">0.0598</td>
<td class="tg-0lax">0.1113</td>
<td class="tg-0lax">0.2188</td>
<td class="tg-0lax">0.1537</td>
<td class="tg-0lax">0.1645</td>
<td class="tg-0lax">0.1445</td>
<td class="tg-0lax">0.0292</td>
<td class="tg-0lax">0.1040</td>
<td class="tg-0lax">0.0680</td>
</tr>
<tr>
<td class="tg-1wig">Irlanda</td>
<td class="tg-0lax">0.0371</td>
<td class="tg-0lax">0.0727</td>
<td class="tg-0lax">0.0601</td>
<td class="tg-0lax">0.1111</td>
<td class="tg-0lax">0.6681</td>
<td class="tg-0lax">0.0246</td>
<td class="tg-0lax">0.0690</td>
<td class="tg-0lax">0.2386</td>
<td class="tg-0lax">0.0947</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0321</td>
<td class="tg-0lax">0.0540</td>
<td class="tg-0lax">0.0644</td>
<td class="tg-0lax">0.0742</td>
<td class="tg-0lax">0.0472</td>
<td class="tg-0lax">0.0068</td>
<td class="tg-0lax">0.0459</td>
<td class="tg-0lax">0.1446</td>
<td class="tg-0lax">0.0583</td>
<td class="tg-0lax">0.0663</td>
<td class="tg-0lax">0.0632</td>
<td class="tg-0lax">0.0446</td>
<td class="tg-0lax">0.0790</td>
<td class="tg-0lax">0.0411</td>
</tr>
<tr>
<td class="tg-1wig">Israel</td>
<td class="tg-0lax">0.0395</td>
<td class="tg-0lax">0.0819</td>
<td class="tg-0lax">0.0887</td>
<td class="tg-0lax">0.0376</td>
<td class="tg-0lax">0.5067</td>
<td class="tg-0lax">0.0361</td>
<td class="tg-0lax">0.0461</td>
<td class="tg-0lax">0.2244</td>
<td class="tg-0lax">0.0674</td>
<td class="tg-0lax">0.0321</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.0621</td>
<td class="tg-0lax">0.0432</td>
<td class="tg-0lax">0.0809</td>
<td class="tg-0lax">0.0184</td>
<td class="tg-0lax">0.0456</td>
<td class="tg-0lax">0.2038</td>
<td class="tg-0lax">0.0847</td>
<td class="tg-0lax">0.0467</td>
<td class="tg-0lax">0.1104</td>
<td class="tg-0lax">0.0476</td>
<td class="tg-0lax">0.0952</td>
<td class="tg-0lax">0.0578</td>
</tr>
<tr>
<td class="tg-1wig">Itália</td>
<td class="tg-0lax">0.0595</td>
<td class="tg-0lax">0.0488</td>
<td class="tg-0lax">0.0252</td>
<td class="tg-0lax">0.1266</td>
<td class="tg-0lax">0.6763</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.1260</td>
<td class="tg-0lax">0.0706</td>
<td class="tg-0lax">0.1353</td>
<td class="tg-0lax">0.0540</td>
<td class="tg-0lax">0.0719</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1031</td>
<td class="tg-0lax">0.1094</td>
<td class="tg-0lax">0.0357</td>
<td class="tg-0lax">0.0558</td>
<td class="tg-0lax">0.0724</td>
<td class="tg-0lax">0.1237</td>
<td class="tg-0lax">0.1236</td>
<td class="tg-0lax">0.1072</td>
<td class="tg-0lax">0.1077</td>
<td class="tg-0lax">0.0759</td>
<td class="tg-0lax">0.0870</td>
<td class="tg-0lax">0.1073</td>
</tr>
<tr>
<td class="tg-1wig">Japão</td>
<td class="tg-0lax">0.0921</td>
<td class="tg-0lax">0.1466</td>
<td class="tg-0lax">0.0707</td>
<td class="tg-0lax">0.0310</td>
<td class="tg-0lax">0.4182</td>
<td class="tg-0lax">0.1107</td>
<td class="tg-0lax">0.1635</td>
<td class="tg-0lax">0.2892</td>
<td class="tg-0lax">0.0491</td>
<td class="tg-0lax">0.0644</td>
<td class="tg-0lax">0.0621</td>
<td class="tg-0lax">0.1031</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0537</td>
<td class="tg-0lax">0.0528</td>
<td class="tg-0lax">0.0651</td>
<td class="tg-0lax">0.0831</td>
<td class="tg-0lax">0.0927</td>
<td class="tg-0lax">0.0679</td>
<td class="tg-0lax">0.1534</td>
<td class="tg-0lax">0.0386</td>
<td class="tg-0lax">0.1049</td>
<td class="tg-0lax">0.0596</td>
<td class="tg-0lax">0.1089</td>
</tr>
<tr>
<td class="tg-1wig">Coreia do Sul</td>
<td class="tg-0lax">0.0778</td>
<td class="tg-0lax">0.1303</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.0433</td>
<td class="tg-0lax">0.3305</td>
<td class="tg-0lax">0.1180</td>
<td class="tg-0lax">0.1181</td>
<td class="tg-0lax">0.2965</td>
<td class="tg-0lax">0.1192</td>
<td class="tg-0lax">0.0742</td>
<td class="tg-0lax">0.0432</td>
<td class="tg-0lax">0.1094</td>
<td class="tg-0lax">0.0537</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0883</td>
<td class="tg-0lax">0.0726</td>
<td class="tg-0lax">0.0863</td>
<td class="tg-0lax">0.2317</td>
<td class="tg-0lax">0.1205</td>
<td class="tg-0lax">0.1145</td>
<td class="tg-0lax">0.1041</td>
<td class="tg-0lax">0.1254</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.1473</td>
</tr>
<tr>
<td class="tg-1wig">Países Baixos</td>
<td class="tg-0lax">0.0313</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.0235</td>
<td class="tg-0lax">0.1267</td>
<td class="tg-0lax">0.6036</td>
<td class="tg-0lax">0.0807</td>
<td class="tg-0lax">0.1170</td>
<td class="tg-0lax">0.1888</td>
<td class="tg-0lax">0.1351</td>
<td class="tg-0lax">0.0472</td>
<td class="tg-0lax">0.0809</td>
<td class="tg-0lax">0.0357</td>
<td class="tg-0lax">0.0528</td>
<td class="tg-0lax">0.0883</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0457</td>
<td class="tg-0lax">0.0423</td>
<td class="tg-0lax">0.0785</td>
<td class="tg-0lax">0.0317</td>
<td class="tg-0lax">0.0859</td>
<td class="tg-0lax">0.0276</td>
<td class="tg-0lax">0.1009</td>
<td class="tg-0lax">0.0683</td>
<td class="tg-0lax">0.0821</td>
</tr>
<tr>
<td class="tg-1wig">Peru</td>
<td class="tg-0lax">0.0268</td>
<td class="tg-0lax">0.0704</td>
<td class="tg-0lax">0.0650</td>
<td class="tg-0lax">0.0698</td>
<td class="tg-0lax">0.5808</td>
<td class="tg-0lax">0.0137</td>
<td class="tg-0lax">0.0521</td>
<td class="tg-0lax">0.2027</td>
<td class="tg-0lax">0.0598</td>
<td class="tg-0lax">0.0068</td>
<td class="tg-0lax">0.0184</td>
<td class="tg-0lax">0.0558</td>
<td class="tg-0lax">0.0651</td>
<td class="tg-0lax">0.0726</td>
<td class="tg-0lax">0.0457</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0328</td>
<td class="tg-0lax">0.1594</td>
<td class="tg-0lax">0.0626</td>
<td class="tg-0lax">0.0530</td>
<td class="tg-0lax">0.0767</td>
<td class="tg-0lax">0.0290</td>
<td class="tg-0lax">0.0820</td>
<td class="tg-0lax">0.0257</td>
</tr>
<tr>
<td class="tg-1wig">Portugal</td>
<td class="tg-0lax">0.0146</td>
<td class="tg-0lax">0.0556</td>
<td class="tg-0lax">0.0670</td>
<td class="tg-0lax">0.0839</td>
<td class="tg-0lax">0.6312</td>
<td class="tg-0lax">0.0647</td>
<td class="tg-0lax">0.0420</td>
<td class="tg-0lax">0.2205</td>
<td class="tg-0lax">0.1113</td>
<td class="tg-0lax">0.0459</td>
<td class="tg-0lax">0.0456</td>
<td class="tg-0lax">0.0724</td>
<td class="tg-0lax">0.0831</td>
<td class="tg-0lax">0.0863</td>
<td class="tg-0lax">0.0423</td>
<td class="tg-0lax">0.0328</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1745</td>
<td class="tg-0lax">0.0625</td>
<td class="tg-0lax">0.0453</td>
<td class="tg-0lax">0.0908</td>
<td class="tg-0lax">0.0611</td>
<td class="tg-0lax">0.0931</td>
<td class="tg-0lax">0.0314</td>
</tr>
<tr>
<td class="tg-1wig">Rússia</td>
<td class="tg-0lax">0.1832</td>
<td class="tg-0lax">0.1564</td>
<td class="tg-0lax">0.0532</td>
<td class="tg-0lax">0.2046</td>
<td class="tg-0lax">0.8489</td>
<td class="tg-0lax">0.2226</td>
<td class="tg-0lax">0.2765</td>
<td class="tg-0lax">0.3063</td>
<td class="tg-0lax">0.2188</td>
<td class="tg-0lax">0.1446</td>
<td class="tg-0lax">0.2038</td>
<td class="tg-0lax">0.1237</td>
<td class="tg-0lax">0.0927</td>
<td class="tg-0lax">0.2317</td>
<td class="tg-0lax">0.0785</td>
<td class="tg-0lax">0.1594</td>
<td class="tg-0lax">0.1745</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0920</td>
<td class="tg-0lax">0.2830</td>
<td class="tg-0lax">0.0342</td>
<td class="tg-0lax">0.2555</td>
<td class="tg-0lax">0.1539</td>
<td class="tg-0lax">0.2438</td>
</tr>
<tr>
<td class="tg-1wig">Espanha</td>
<td class="tg-0lax">0.0362</td>
<td class="tg-0lax">0.0539</td>
<td class="tg-0lax">0.0693</td>
<td class="tg-0lax">0.1453</td>
<td class="tg-0lax">0.7006</td>
<td class="tg-0lax">0.0879</td>
<td class="tg-0lax">0.0858</td>
<td class="tg-0lax">0.3947</td>
<td class="tg-0lax">0.1537</td>
<td class="tg-0lax">0.0583</td>
<td class="tg-0lax">0.0847</td>
<td class="tg-0lax">0.1236</td>
<td class="tg-0lax">0.0679</td>
<td class="tg-0lax">0.1205</td>
<td class="tg-0lax">0.0317</td>
<td class="tg-0lax">0.0626</td>
<td class="tg-0lax">0.0625</td>
<td class="tg-0lax">0.0920</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.0725</td>
<td class="tg-0lax">0.0254</td>
<td class="tg-0lax">0.1403</td>
<td class="tg-0lax">0.1252</td>
<td class="tg-0lax">0.0915</td>
</tr>
<tr>
<td class="tg-1wig">Suécia</td>
<td class="tg-0lax">0.0214</td>
<td class="tg-0lax">0.0455</td>
<td class="tg-0lax">0.1201</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.7566</td>
<td class="tg-0lax">0.0524</td>
<td class="tg-0lax">0.0206</td>
<td class="tg-0lax">0.2911</td>
<td class="tg-0lax">0.1645</td>
<td class="tg-0lax">0.0663</td>
<td class="tg-0lax">0.0467</td>
<td class="tg-0lax">0.1072</td>
<td class="tg-0lax">0.1534</td>
<td class="tg-0lax">0.1145</td>
<td class="tg-0lax">0.0859</td>
<td class="tg-0lax">0.0530</td>
<td class="tg-0lax">0.0453</td>
<td class="tg-0lax">0.2830</td>
<td class="tg-0lax">0.0725</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1327</td>
<td class="tg-0lax">0.1115</td>
<td class="tg-0lax">0.1644</td>
<td class="tg-0lax">0.0723</td>
</tr>
<tr>
<td class="tg-1wig">Suíça</td>
<td class="tg-0lax">0.0812</td>
<td class="tg-0lax">0.0995</td>
<td class="tg-0lax">0.0533</td>
<td class="tg-0lax">0.1335</td>
<td class="tg-0lax">0.6211</td>
<td class="tg-0lax">0.1224</td>
<td class="tg-0lax">0.1607</td>
<td class="tg-0lax">0.3474</td>
<td class="tg-0lax">0.1445</td>
<td class="tg-0lax">0.0632</td>
<td class="tg-0lax">0.1104</td>
<td class="tg-0lax">0.1077</td>
<td class="tg-0lax">0.0386</td>
<td class="tg-0lax">0.1041</td>
<td class="tg-0lax">0.0276</td>
<td class="tg-0lax">0.0767</td>
<td class="tg-0lax">0.0908</td>
<td class="tg-0lax">0.0342</td>
<td class="tg-0lax">0.0254</td>
<td class="tg-0lax">0.1327</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1652</td>
<td class="tg-0lax">0.0918</td>
<td class="tg-0lax">0.1397</td>
</tr>
<tr>
<td class="tg-1wig">Turquia</td>
<td class="tg-0lax">0.0826</td>
<td class="tg-0lax">0.1418</td>
<td class="tg-0lax">0.1100</td>
<td class="tg-0lax">0.0830</td>
<td class="tg-0lax">0.6705</td>
<td class="tg-0lax">0.0256</td>
<td class="tg-0lax">0.1151</td>
<td class="tg-0lax">0.1517</td>
<td class="tg-0lax">0.0292</td>
<td class="tg-0lax">0.0446</td>
<td class="tg-0lax">0.0476</td>
<td class="tg-0lax">0.0759</td>
<td class="tg-0lax">0.1049</td>
<td class="tg-0lax">0.1254</td>
<td class="tg-0lax">0.1009</td>
<td class="tg-0lax">0.0290</td>
<td class="tg-0lax">0.0611</td>
<td class="tg-0lax">0.2555</td>
<td class="tg-0lax">0.1403</td>
<td class="tg-0lax">0.1115</td>
<td class="tg-0lax">0.1652</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1053</td>
<td class="tg-0lax">0.0319</td>
</tr>
<tr>
<td class="tg-1wig">Reino Unido</td>
<td class="tg-0lax">0.1109</td>
<td class="tg-0lax">0.1662</td>
<td class="tg-0lax">0.0990</td>
<td class="tg-0lax">0.0824</td>
<td class="tg-0lax">0.4789</td>
<td class="tg-0lax">0.1278</td>
<td class="tg-0lax">0.1935</td>
<td class="tg-0lax">0.2098</td>
<td class="tg-0lax">0.1040</td>
<td class="tg-0lax">0.0790</td>
<td class="tg-0lax">0.0952</td>
<td class="tg-0lax">0.0870</td>
<td class="tg-0lax">0.0596</td>
<td class="tg-0lax">0.0397</td>
<td class="tg-0lax">0.0683</td>
<td class="tg-0lax">0.0820</td>
<td class="tg-0lax">0.0931</td>
<td class="tg-0lax">0.1539</td>
<td class="tg-0lax">0.1252</td>
<td class="tg-0lax">0.1644</td>
<td class="tg-0lax">0.0918</td>
<td class="tg-0lax">0.1053</td>
<td class="tg-0lax">0.0000</td>
<td class="tg-0lax">0.1764</td>
</tr>
<tr>
<td class="tg-1wig">Estados Unidos</td>
<td class="tg-0lax">0.0410</td>
<td class="tg-0lax">0.1019</td>
<td class="tg-0lax">0.1111</td>
<td class="tg-0lax">0.1181</td>
<td class="tg-0lax">0.6572</td>
<td class="tg-0lax">0.0244</td>
<td class="tg-0lax">0.0691</td>
<td class="tg-0lax">0.2509</td>
<td class="tg-0lax">0.0680</td>
<td class="tg-0lax">0.0411</td>
<td class="tg-0lax">0.0578</td>
<td class="tg-0lax">0.1073</td>
<td class="tg-0lax">0.1089</td>
<td class="tg-0lax">0.1473</td>
<td class="tg-0lax">0.0821</td>
<td class="tg-0lax">0.0257</td>
<td class="tg-0lax">0.0314</td>
<td class="tg-0lax">0.2438</td>
<td class="tg-0lax">0.0915</td>
<td class="tg-0lax">0.0723</td>
<td class="tg-0lax">0.1397</td>
<td class="tg-0lax">0.0319</td>
<td class="tg-0lax">0.1764</td>
<td class="tg-0lax">0.0000</td>
</tr>
</table>
</center>
<p><em><strong>Tabela 4</strong>: Matriz de distâncias KL entre as distribuições do primeiro dígito do número de casos de COVID-19 dos países analisados, arredondado para quatro casas decimais</em></p>
<p>A matriz acima não tem uma interpretação prática muito imediata, então aplicamos um algoritmo de clusterização para definir quais são os países que se parecem mais entre si – pares de países com grande distância KL são menos parecidos entre si que pares de países com baixa distância KL. O algoritmo escolhido foi o DBSCAN, que cria <em>clusters</em> para cada ponto da amostra com base no número mínimo de pontos em cada <em>cluster</em> (\(mp\)) e na distância máxima que um ponto pode estar em relação a outro ponto do mesmo <em>cluster</em> (\(\varepsilon\)). <ins>Pontos que não possui pelo menos \(mp\) pontos dentro do raio de \(\varepsilon\) são classificados como <em>outliers</em> sem <em>cluster</em></ins>. Um bom material introdutório sobre o DBSCAN pode ser encontrado em <a href="https://medium.com/@elutins/dbscan-what-is-it-when-to-use-it-how-to-use-it-8bd506293818">aqui</a>.</p>
<p>Uma das vantagens do DBSCAN é o fato de o número de <em>cluster</em> ser definido automaticamente em vez de escolhido pelo usuário, tornando-o um bom instrumento para a detecção de anomalias. Para este exercício, utilizamos \(mp=3\) e \(\varepsilon\) como sendo a média das distâncias KL entre os países acrescida de três desvios-padrão amostrais. O resultado dessa clusterização é mais fácil de ser interpretada:</p>
<center>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-c3ow{border-color:inherit;text-align:center;vertical-align:top}
.tg .tg-7btt{font-weight:bold;border-color:inherit;text-align:center;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-7btt">País</th>
<th class="tg-7btt">Cluster</th>
</tr>
<tr>
<td class="tg-c3ow">Áustria</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Bélgica</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Brasil</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Canadá</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">China</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">França</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Alemanha</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Índia</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Irã</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Irlanda</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Israel</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Itália</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Japão</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Coreia do Sul</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Países Baixos</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Peru</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Portugal</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Rússia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Espanha</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Suécia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Suíça</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Turquia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Reino Unido</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Estados Unidos</td>
<td class="tg-c3ow">1</td>
</tr>
</table>
</center>
<p><em><strong>Tabela 5</strong>: Clusterização por DBSCAN das distâncias KL entre as distribuições do primeiro dígito do número de casos de COVID-19 dos países analisados</em></p>
<style type="text/css">
.tg {border-collapse:collapse;border-spacing:0;}
.tg td{font-family:Arial, sans-serif;font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg th{font-family:Arial, sans-serif;font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:black;}
.tg .tg-c3ow{border-color:inherit;text-align:center;vertical-align:top}
.tg .tg-7btt{font-weight:bold;border-color:inherit;text-align:center;vertical-align:top}
</style>
<table class="tg">
<tr>
<th class="tg-7btt">País</th>
<th class="tg-7btt">Cluster</th>
</tr>
<tr>
<td class="tg-c3ow">Áustria</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Bélgica</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Brasil</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Canadá</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">China</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">França</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Alemanha</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Índia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Irã</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Irlanda</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Israel</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Itália</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Japão</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Coreia do Sul</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Países Baixos</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Peru</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Portugal</td>
<td class="tg-7btt">Outlier</td>
</tr>
<tr>
<td class="tg-c3ow">Rússia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Espanha</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Suécia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Suíça</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Turquia</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Reino Unido</td>
<td class="tg-c3ow">1</td>
</tr>
<tr>
<td class="tg-c3ow">Estados Unidos</td>
<td class="tg-c3ow">1</td>
</tr>
</table>
<p><em><strong>Tabela 6</strong>: Clusterização por DBSCAN das distâncias KL entre as distribuições do primeiro dígito do número de óbitos por COVID-19 dos países analisados</em></p>
<p>Novamente, assim como sugerido pela inspeção visual e pelos testes de hipóteses supramencionados, os resultados indicam que os dados da China apresentam padrões distintos da grande parte dos outros países mais afetados pela pandemia, os quais mostraram padrões similares de infectividade e letalidade: o algoritmo retornou apenas um <em>cluster</em>, classificando China como “<em>outlier</em>” tanto para os dados de casos quanto para os dados de óbitos. De fato, os países categorizados como “<em>cluster</em> 1” parecem seguir melhor a distribuição da Lei de Benford.</p>
<p>Apesar de a China ser o local de origem da doença, dada a grande divergência entre seus dados e os dos demais locais, os dados chineses devem ser utilizados com especial cautela para análises como a estimação dos parâmetros médicos (<em>basic reproducing number</em>, <em>serial interval</em> e <em>case-fatality ratio</em>, por exemplo), a modelagem da dispersão geográfica do patógeno, diagnósticos da eficácia de cenários de intervenção, etc.</p>
<h2 id="considerações-finais">Considerações finais</h2>
<p>A medida que à pandemia atinge mais e mais pessoas e traz impactos cada vez mais profundos nas atividades econômicas e na vida social a nível global, discutir a subnotificação dos dados do COVID-19 se torna especialmente relevante, tanto para a avaliação da severidade do cenário quanto para a proposição de soluções e meios de enfrentamento da crise. Dado que acadêmicos, pesquisadores e formuladores de políticas públicas do mundo todo estão se dedicando a essa causa, ter em mãos dados precisos e confiáveis é de fundamental importância, pois a qualidade dos dados condiciona diretamente na qualidade de todas as análises que deles derivam. Como diz o ditado: <strong>“<em>Garbage in, garbage out!</em>“</strong></p>
<hr />
<p><strong>Às vezes, “coincidência” é apenas um jeito conveniente de alguém se esquivar dos fatos que ele não conseguiu explicar.</strong></p>
<p><img src="https://cdn.shopify.com/s/files/1/1218/4290/products/GOLD13391_46faec9e-ca27-48f7-997d-e152c18f4349_800x.JPG?v=1515022654" alt="tsuru" /></p>
O Método dos Mínimos Quadrados Ordinários e Regressão Linear Simples2020-02-07T23:59:07+00:00http://lamfo-unb.github.io/2020/02/07/O-Método-dos-Mínimos-Quadrados-Ordinários-e-Regressão-Linear-Simples<h1 id="o-método-dos-mínimos-quadrados-ordinários-e-regressão-linear-simples">O Método dos Mínimos Quadrados Ordinários e Regressão Linear Simples</h1>
<hr />
<h2 id="1-introdução-o-que-é-a-econometria">1. Introdução: o que é a Econometria?</h2>
<p>A econometria é um campo de estudo baseado no desenvolvimento de métodos e ferramentas estatísticos para aplicação em dados econômicos. Pode ser usada para testar teorias, avaliar planos e auxiliar na tomada de decisões.</p>
<p>Um modelo econométrico pode ser desenvolvido a partir de um modelo econômico formal, mas também pode ser baseado em raciocínios econômicos informais e na prórpria intuição.</p>
<p>Um exemplo de aplicação da econometria é o estudo dos determinantes do salário. Podemos deduzir que a função que determina o salário é composta de diversos argumentos, cada qual representante de um fator observável: nível de educação, experiência prévia, qualidade da educação, aptidão inata, entre outros. Ao montarmos um modelo econométrico de forma a estudar como estes fatores influenciam na determinação do salário, estimamos parâmetros \(\beta\) que descrevem as direções e as influências da relação entre a variável salário e os fatores usados para determiná-lo.</p>
\[salario=\beta_0\ + \beta_1 educ + \beta_2 exper + u\]
<p>Onde:</p>
<ul>
<li><strong>salário</strong> é o indicador medindo o nível salarial</li>
<li><strong>educ</strong> é a variável que mede o número de anos de educação formal</li>
<li><strong>exper</strong> é a variável que mede o número de anos de experiência de trabalho</li>
<li><strong>u</strong> é o termo contém todos os fatores não observados, como a aptidão; é denominado <strong><em>termo de erro</em></strong></li>
</ul>
<p>O objetivo da análise econométrica é estimar os parâmetros do modelo e testar hipóteses sobre esses parâmetros; os valores e os sinais dos parâmetros podem determinar a validade (ou não) de uma teoria econômica, assim como os efeitos de determinadas políticas e decisões.</p>
<p>Quando da realização de hipóteses nas ciências sociais, as noções de <em>ceteris paribus</em> e de inferência causal são de grande importância. A primeira se referere a que, ao se estudar a relação entre duas variáveis, todos os outros fatores relevantes devem permanecer fixos. Além disso, descobrir relações causais é uma difícil tarefa, em razão da natureza não experimental (isto é, não controlável) dos dados coletados.</p>
<h2 id="2-modelo-de-regressão-simples">2. Modelo de regressão simples</h2>
<h3 id="21-definição-de-um-modelo-de-regressão-simples">2.1 Definição de um modelo de regressão simples</h3>
<p>Um modelo de regressão simples estuda a relação entre duas variáveis quaisquer. Iremos chamar a variável <em>y</em> de <strong><em>variável dependente</em></strong>, e <em>x</em> de <strong><em>variável independente</em></strong>. Assim, estaremos estabelecendo que nosso intuito é observar como \(y\) varia a partir de variações em \(x\). Já um modelo de regressão múltipla constitui uma extensão do modelo simples na medida em que permite a inclusão de mais variáveis independentes no modelo de interesse; para este post, no entanto, estaremos nos limitando à análise de uma regressão linear simples.</p>
<p>Podemos escrever uma equação que relaciona y e x da seguinte forma:</p>
\[y=\beta_0\ + \beta_1 x + u \tag{1}\]
<p>Onde o termo de erro <em>u</em> agrega todos os fatores não observados na equação que podem influenciar o valor de \(y\). Temos ainda \(\beta_0\), que é o <em>parâmetro de intercepto</em> da equação (ou <em>uma constante</em>) e \(\beta_1\) que é o parâmetro de inclinação da relação entre \(y\) e \(x\), mantidos fixos os outros fatores em \(u\).</p>
<p>A equação (1) trata da relação entre \(y\) e \(x\). Se os fatores contidos em no termo de erro são mantidos fixos, de modo que \(\Delta u=0\), então \(x\) terá um efeito linear sobre \(y\), de modo que a variação em \(y\) é o coeficiente \(\beta_1\) multiplicado pela variação em \(x\):</p>
\[\Delta y= \beta_1 \Delta x\]
<h3 id="22-derivação-das-estimativas-de-mínimos-quadrados-ordinários">2.2 Derivação das estimativas de mínimos quadrados ordinários</h3>
<p>Agora iremos tratar da estimação dos parâmetros \(\beta_0\) e \(\beta_1\) da equação (1). Para tanto, faz-se necessário obter uma amostra da população; considere {(\(x_i\), \(y_i\)): i = 1, …, \(n\)} como sendo uma amostra aleatória de tamanho \(n\) da população. Podemos escrever \(y_i=\beta_0+\beta_1 x_i+u_i\), onde \(u_i\) é o termo de erro para cada observação i.</p>
<p>Faremos uso da seguinte hipótese: na população, <em>u</em> tem média zero e não é correlacionado a <em>x</em>. Assim, <em>u</em> tem média zero (equação 2) e a covariância entre <em>x</em> e <em>u</em> é zero (equação 3).</p>
\[E(u)=0 \tag{2}\]
<p>e</p>
\[Cov(x,u)=E(xu)=0 \tag{3}\]
<p>Reescrevnedo em termos das variáveis observáveis <em>y</em> e <em>x</em> e dos parâmetros desconhecidos \(\beta_0\) e \(\beta_1\):</p>
\[E(y-\beta_0-\beta_1 x)=0 \tag{4}\]
<p>e</p>
\[E[x(y-\beta_0-\beta_1 x)]=0 \tag{5}\]
<p>As equações (4) e (5) podem ser usadas para estimar os parâmetros desconhecidos de modo a obter bons estimadores \(\hat{\beta_0}\) e \(\hat{\beta_1}\). De fato, para uma dada amostra de dados, escolhemos as estimativas \(\hat{\beta_0}\) e \(\hat{\beta_1}\) para resolver as equivalências amostrais de (4) e (5):</p>
\[n^{-1}\sum_{i=1}^{n} (y_i-\hat{\beta_0}-\hat{\beta_1}x_i)=0 \tag{6}\]
<p>e</p>
\[n^{-1}\sum_{i=1}^{n} x_i(y_i-\hat{\beta_0}-\hat{\beta_1}x_i)=0 \tag{7}\]
<p>Podemos ainda reescrever a equação (6) como</p>
\[\overline{y}=\hat{\beta_0}+\hat{\beta_1}\overline{x} \tag{8}\]
<p>o que nos dá</p>
\[\hat{\beta_0}=\overline{y}-\hat{\beta_1}\overline{x} \tag{9}\]
<p>Ou seja, quando obtemos uma estimativa do parâmetro de inclinação \(\hat{\beta_1}\), obtemos também uma estimativa do intercepto, dados os valores médios \(\overline{y}\) e \(\overline{x}\).</p>
<p>Suprimindo \(n^{-1}\) de (7) e inserindo (9) na equação, obtemos: \(\sum_{i=1}^{n} x_i(y_i-(\overline{y}-\hat{\beta_1}\overline{x})-\hat{\beta_1}x_i)=0\)
a qual pode ser, por sua vez, reescrita como
\(\sum_{i=1}^{n} x_i(y_i-\overline{y})=\hat{\beta_1}\sum_{i=1}^{n}(x_i-\overline{x})\)</p>
<p>Das propriedades do operados somatório, observe que:
\(\sum_{i=1}^{n} x_i(x_i-\overline{x}) = \sum_{i=1}^{n} (x_i-\overline{x})^{2}\qquad e \qquad\sum_{i=1}^{n} x_i(y_i-\overline{y}) = \sum_{i=1}^{n} (x_i-\overline{x})(y_i-\overline{y})\)</p>
<p>O que nos informa que a inclinação estimada deve ser</p>
\[\hat{\beta_1}=\frac{\sum\limits_{i=1}^{n} (x_i -\overline{x})(y_i - \overline{y})}{\sum\limits_{i=1}^{n} (x_i -\overline{x})^{2}} \tag{10}\]
<p>A equação (10) nada mais é do que a covariância amostral entre \(x_i\) e \(y_i\) dividida pela variância amostral de \(x_i\). Assim, podemos escrever \(\hat{\beta_1}\) como:</p>
\[\hat{\beta_1}=\hat{\rho}_{x_y}\left(\frac{\hat{\sigma}_x}{\hat{\sigma}_y}\right) \tag{11}\]
<p>Em que \(\hat{\rho}_{x_y}\) é a correlação amostral entre \(x_i\) e \(y_i\), e \(\hat{\sigma}_x\) e \(\hat{\sigma}_y\) denotam os desvios padrão da amostra. Disto temos a implicação de que se \(x_i\) e \(y_i\) forem positivamente correlacionados na amostra, \(\hat{\beta_1}<0\) (o contrário também é válido).</p>
<p>As estimativas dadas por (9) e (10) são denominadas de <strong>estimativas de mínimos quadrados ordinários (MQO)</strong> de \(\beta_0\) e \(\beta_1\).</p>
<p>Seja \(\hat{y_i}\) um valor estimado de y quando \(x\) = \(x_i\), de tal forma que obtemos \(\hat{y_i}=\hat{\beta_0}+\hat{\beta_1}x_i\). O <strong>resíduo</strong> da observação i é a diferença entre o valor verdadeiro de \(y_i\) e seu valor estimado:</p>
\[\hat{u}_i=y_i - \hat{y}_i = y_i-\hat{\beta_0}-\hat{\beta_1}x_i \tag{12}\]
<p>É importante observar que os resíduos não são iguais ao termo de erro. Agora, suponha que escolhamos \(\hat{\beta_0}\) e \(\hat{\beta_1}\) com a finalidade de fazer a soma dos quadrados dos resíduos,</p>
\[\sum_{i=1}^{n} \hat{u}_i^{2}= \sum_{i=1}^{n} (y_i-\hat{\beta_0}-\hat{\beta_1}x_i)^{2} \tag{13}\]
<p>tão pequena quanto possível. O nome “mínimos quadrados ordinários” vem do fato de que as estimativas (9) e (10) minimizam essa soma dos quadrados dos resíduos dada em (13).</p>
<p>Há três propriedades dos estimadores de MQO muito importantes para análise econmétrica. A <strong>primeira</strong> delas é de a soma, e portanto a média amostral dos resíduos de MQO é zero:</p>
\[\sum_{i=1}^{n} \hat{u}_i=0 \tag{14}\]
<p>As estimativas de MQO \(\hat{\beta}_0\) e \(\hat{\beta}_1\) são escolhidas para que esse resultado seja válido. A <strong>segunda</strong> é de que a covariância amostral entre os regressores e os resíduos de MQO é zero. Já a <strong>terceira</strong> é de que o ponto (\(\overline{x}, \overline{y}\)) sempre está sobre a reta de regressão de MQO.</p>
<h3 id="23-minimizando-a-soma-dos-quadrados-dos-resíduos">2.3 Minimizando a soma dos quadrados dos resíduos</h3>
<p>Iremos agora expandir o resultado da última subseção, de modo a providenciar amparo à noção de que \(\hat{\beta}_0\) e \(\hat{\beta}_1\) são os estimadores que minimizam a soma dos quadrados dos resíduos. Formalmente, o problema é caracterizar as soluções \(\hat{\beta}_0\) e \(\hat{\beta}_1\) para o problema de minimização:</p>
\[Q(b_0,b_1)=min_{b_0,b_1} \sum_{i=1}^{n}(y_i-b_0-b_1x_i)^2 \tag{15}\]
<p>onde \(b_0\) e \(b_1\) são argumentos <em>dummy</em> para o problema de otimização.A condição necessária para \(\hat{\beta}_0\) e \(\hat{\beta}_1\) resolver o problema é que as derivadas parciais de Q(\(b_0\),\(b_1\)) em relação a \(b_0\) e \(b_1\) devem ser zero quando estimadas com \(\hat{\beta}_0\) e \(\hat{\beta}_1\):</p>
\[\partial \,Q(b_0,b_1)/\partial \,b_0=-2\sum_{i=1}^{n}(y_i-\hat{\beta}_0-\hat{\beta}_1x_i)=0\]
<p>e</p>
\[\partial \,Q(b_0,b_1)/\partial \,b_1=-2\sum_{i=1}^{n}x_i(y_i-\hat{\beta}_0-\hat{\beta}_1x_i)=0\]
<p>Repare que essas duas equações são exatamente iguais a (6) e (7) multiplicadas por \(-2n\) e, portanto, são solucionadas por \(\hat{\beta}_0\) e \(\hat{\beta}_1\).</p>
<p>Uma forma de verificar que minimizamos a soma dos quadrados dos resíduos é escrever, para qualquer \(b_0\) e \(b_1\),</p>
\[\begin{split}
Q(b_0,b_1) & =\sum_{i=1}^{n}\,[\,y_i-\hat{\beta}_0-\hat{\beta}_1x_i+(\hat{\beta}_0-b_0)+(\hat{\beta}_1-b_1)x_i\,]^2 \\
& =\sum_{i=1}^{n}\,[\hat{u}_i+(\hat{\beta}_0-b_0)+(\hat{\beta}_1-b_1)x_i\,]^2 \\
& =\sum_{i=1}^{n}\hat{u}_i \, +n(\hat{\beta}_0-b_0)^{2} \, +(\hat{\beta}_1-b_1)^{2}\sum_{i=1}^{n}x_i{^2} \,
+2(\hat{\beta}_0-b_0)(\hat{\beta}_1-b_1)\sum_{i=1}^{n}x_i
\end{split}\]
<p>Agora usamos as propriedades dos estimadores de MQO, a que chegamos a:</p>
\[\sum_{i=1}^{n} \, [(\hat{\beta}_0-b_0)+(\hat{\beta}_1-b_1)x_i]^{2} \tag{16}\]
<p>Visto que essa expressão é uma soma de termos quadráticos, o seu menor valor possível é zero. Logo, esse valor ocorre quando \(b_0\)=\(\hat{\beta}_0\) e \(b_1\)=\(\hat{\beta}_1\).</p>
<h3 id="24-características-de-mqo-em-uma-amostra-de-dados">2.4 Características de MQO em uma amostra de dados</h3>
<p>Da primeira propriedade de MQO introduzida na subção 2.2, tem-se que a média dos resíduos é zero; equivalentemente, a média amostral dos valores estimador, \(\hat{y}_i\), é a mesma da média amostral de \(y_i\), ou \(\overline{\hat{y}} = \overline{y}\). Além disso, as duas primeiras propriedades podem ser usadas para mostrar que a covariância amostral entre \(\hat{y}_i\) e \(\hat{y}_i\) é zero. Podemos ver o método dos quadrados ordinários como um processo que decompõe \(y_i\) em duas partes: um valor ajustado e um resíduo.</p>
<p>Defina a <strong>soma dos quadrados total (SQT)</strong>, a <strong>soma dos quadrados explicada (SQE)</strong> e a <strong>soma dos quadrados dos resíduos (SQR)</strong> como a seguir:</p>
\[SQT = \sum_{i=1}^{n} \, (y_i - \overline{y})^{2} \tag{17}\]
\[SQE = \sum_{i=1}^{n} \, (\hat{y}_i - \overline{y})^{2} \tag{18}\]
\[SQR = \sum_{i=1}^{n} \, \hat{u}_{i}^{2} \tag{19}\]
<p>As equações acima são medidas de variação amostral. A variação total em \(y_i\) pode ser expressa como a soma da variação explicada e da variação não explicada.</p>
\[SQT = SQE+SQR \tag{20}\]
<p>O R-quadrado da regressão é definido como</p>
\[R^{2} = SQE/SQT = 1 - SQR/SQT \tag{21}\]
<p>O \(R^{2}\) é a razão entre a variação explicada e a variação total; assim, ele é interpretado com a fração da variação amostra em \(y\) que é explicada por \(x\). É um número que mede quão bem a reta de regressão de MQO se ajusta aos dados.</p>
<p>O valor de \(R^{2}\) está sempre contido entre zero e um; um valor de \(R^{2}\) quase igual a zero indica um ajuste ruim da reta de MQO.</p>
<h3 id="25-valores-esperados-e-variâncias-dos-estimadores-de-mqo">2.5 Valores esperados e variâncias dos estimadores de MQO</h3>
<h4 id="251-inexistência-de-viés-em-mqo">2.5.1 Inexistência de viés em MQO</h4>
<p>Para estabelecer a inexistência de viés do método dos mínimos quadrados ordinários, faz-se necessário lançar mão de algumas hipóteses. Importante notar que as seguintes hipóteses, denotadas por RLS.#, são aplicadas ao caso da regressão linear simples.</p>
<p>A <strong>primeira</strong> hipótese (RLS.1) define o modelo populacional; nele, a variável dependente está relacionada à variàvel independente \(x\) e ao erro \(u\) da seguinte forma:</p>
\[y = \beta_0 + \beta_1x + u \tag{22}\]
<p>em que \(\beta_0\) e \(\beta_1\) são os parâmetros de intercepto e de inclinação populacionais, respectivamente.</p>
<p>A <strong>segunda</strong> hipótese (RLS.2) é de que podemos usar uma amostra aleatória de tamanho \(n\), {(\(x_i\), \(y_i\)): i = 1, 2, …, \(n\)}, proveniente de um modelo populacional. Estamos interessados em usar os dados de \(y\) e \(x\) para estimar os parâmetros beta.</p>
<p>Podemos escrever (22) em termos da amostra aleatória como</p>
\[y_i = \beta_0 + \beta_1x_i + u_i, \qquad i = 1, 2, ..., n \tag{23}\]
<p>A <strong>terceira</strong> hipótese (RLS.3) é de os resultados amostrais em \(x\), ou seja, (\(x_i\), i = 1, 2, …, \(n\)) não são todos de mesmo valor.</p>
<p>A <strong>quarta</strong> hipótese (RLS.4) é a de que o erro \(u\) tem um valor esperado igual a zero, dado qualquer valor da variável esxplicativa: \(E(u \vert x) = 0\).</p>
<p>Agora, da equação (10), temos</p>
\[\hat{\beta}_1 = \frac{\sum\limits_{i = 1}^{n} \, (x_i - \overline{x})y_i}{\sum\limits_{i = 1}^{n} \, (x_i - \overline{x})^{2}} \tag{24}\]
<p>Sendo a variação total em \(x_i\) igual a \(SQT_x\), e substituindo (23) em (24):</p>
\[\hat{\beta}_1 = \frac{\sum\limits_{i = 1}^{n} \, (x_i - \overline{x})(\beta_0 + \beta_1x_i + u_i)}{SQT_x} \tag{25}\]
<p>Por meio de álgebra, podemos escrever o numerador de \(\hat{\beta_1}\) como</p>
\[\sum_{i = 1}^{n} \, (x_i - \overline{x})\beta_0 + \sum_{i = 1}^{n} \, (x_i - \overline{x})\beta_1x_i + \sum_{i = 1}^{n} \, (x_i - \overline{x})u_i \tag{26}\]
\[=\beta_0\sum_{i = 1}^{n} \, (x_i - \overline{x}) + \beta_1\sum_{i = 1}^{n} \, (x_i - \overline{x})x_i + \sum_{i = 1}^{n} \, (x_i - \overline{x})u_i \tag{27}\]
<p>Sabendo que \(\sum_{i = 1}^{n} \, (x_i - \overline{x}) = 0\) e \(\sum_{i = 1}^{n} \, (x_i - \overline{x})x_i = \sum_{i = 1}^{n} \, (x_i - \overline{x})^{2} = SQT_x\), temos que a expressão resulta em</p>
\[\hat{\beta}_1 = \beta_1 + \frac{\sum\limits_{i = 1}^{n} \, (x_i - \overline{x})u_i}{SQT_x} \tag{28}\]
<p>Assim, o estimador \(\hat{\beta}_1\) é igual à inclinação populacional \(\beta_1\) somada a um termo que é a combinação linear dos erros. A diferença entre \(\hat{\beta}_1\) e \(\beta_1\) se dá pelo fato de que esses erros são, em geral, não-nulos.</p>
<p>Usando as hipóteses RLS.1 a RLS.4, podemos afirmar que</p>
\[E(\hat{\beta}_0) = \beta_0 \quad e \quad E(\hat{\beta}_1) = \beta_1\]
<p>em outras palavras, \(\hat{\beta}_0\) é não viesado para \(\beta_0\) e \(\hat{\beta}_1\) é não viesado para \(\beta_1\).</p>
<h4 id="252-variâncias-dos-estimadores-de-mqo">2.5.2 Variâncias dos estimadores de MQO</h4>
<p>A variância dos estimadores de MQO pode ser calculada sob as hipóteses RLS.1 a RLS.4. Em razão da complexidade da expressão dessas variâncias, vamos adicionar uma hipótese conhecida com a hipótese de <strong>homoscedasticidade</strong> (RLS.5): o erro <em>u</em> tem a mesma variância, dado qualquer valor da variável explicativa:</p>
\[Var(u|x) = \sigma^{2} \tag{29}\]
<p>É útil escrever RLS.4 e RLS.5 em termos de média condicional e da variância condicional de y:</p>
<p>\(E(y|x) = \beta_0 + \beta_1x \tag{30}\)
\(Var(y|x) = \sigma^{2} \tag{31}\)</p>
<p>Agora, sob as hipóteses RLS.1 a RLS.5,</p>
\[Var(\hat{\beta}_1) = \frac{\sigma^{2}}{SQT_x} \tag{32}\]
<p>e</p>
\[Var(\hat{\beta}_0) = \frac{\sigma^{2} \, n^{-1}\sum\limits_{i = 1}^{n} \, x_{i}^{2}}{SQT_x} \tag{33}\]
<p>De (33), atesta-se que quanto maior a variância do erro, maior é Var(\(\hat{\beta}_1\)), já que uma variação maior nos fatores não observáveis que afetam \(y\) faz com que seja mais difícil estimar com precisão o parâmetro. Por outro lado, uma maior variabilidade na variável independente é preferível, pois será mais fácil descrever a relação entre \(E(y \vert x)\) e \(x\).</p>
<h4 id="253-estimação-da-variância-do-erro">2.5.3 Estimação da variância do erro</h4>
<p>As fórmulas (32) e (33) permitem-nos isolar os fatores que contribuem para Var(\(\hat{\beta}_1\)) e Var(\(\hat{\beta}_0\)). No entanto, essas fórmulas são em geral desconhecidas. Podemos, contudo, usar os dados para estimar \(\sigma^{2}\).</p>
<p>Primeiro, \(\sigma^{2} = E(u^{2})\), de modo que um “estimador” não viesado de \(\sigma^{2}\) é \(n^{-1}\sum_{i = 1}^{n} \, u_{i}^{2}\). Entretanto esse “estimador” não atende às nossas necessidades, já que os erros não são observados. Temos, contudo, os resíduos \(\hat{u}_i\) de MQO. Se substituímos os erros pelos resíduos de MQO, obtemos \(SQR/n\).</p>
<p>Esse sim é um esimador verdadeiro, ainda que viesado, porque ele não explica a razão de duas restrições que devem ser satisfeitas pelos resíduos de MQO: \(\sum_{i = 1}^{n} \, \hat{u}_i = 0\) e \(\sum_{i = 1}^{n} \, x_i\hat{u}_i = 0\). De forma a observar essas restrições é assumir n-2 graus de liberdade nos resíduos de MQO. O estimador não viesado de \(\sigma^{2}\) que faz um ajustamento aos graus de liberdade é:</p>
\[\hat{\sigma}^{2} = SQR/(n - 2) \tag{34}\]
<p>O estimado dos desvios padrão de \(\hat{\beta}_1\) e \(\hat{\beta}_0\) é</p>
\[\hat{\sigma} = \sqrt{\hat{\sigma}^{2}} \tag{35}\]
<p>e é chamado <strong>erro padrão da regressão (EPR)</strong>.</p>
<p>Como dp(\(\hat{\beta}_1\)) = \(\sigma / \sqrt{SQT_x}\), o estimador natural de dp(\(\hat{\beta}_1\)) é:</p>
\[ep(\hat{\beta}_1) = \hat{\sigma} / \sqrt{SQT_x} \tag{36}\]
<p>que é chamado de <strong>erro padrão de $\hat{\beta}_1$</strong>. Semelhantemente, ep(\(\hat{\beta}_0\)) é obtido de dp(\(\hat{\beta}_0\)) ao substituir \(\sigma\) por \(\hat{\sigma}\). O erro padrão de qualquer estimativa nos dá uma ideia de quão preciso é o estimador.</p>
<h2 id="3-exemplo-de-regressão-linear">3. Exemplo de regressão linear</h2>
<p>Como exemplo de aplicação de regressão linear, queremos relacionar notas de testes com a proporção de estudantes por professor obtidos de uma base de dados referentes a escolas da Califórnia (EUA). A nota dos testes (<strong>TestScore</strong>) é a média das notas de leitura e matemática para classes do 5º ano; já o tamanho das salas é medido pela proporção de estudantes relativa à quantidade de professores (que a partir deste ponto será identificada como <strong>STR</strong>, ou <em>student-teacher ratio</em>). Os dados são provenientes do banco de dados <em>CASchools</em>, contido no pacote <em>AER</em> disponível para R.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>library(AER)
data(CASchools)
</code></pre></div></div>
<p>É importante notar que as duas variáveis de interesse não estão incluídas no pacote: faz-se necessário computá-las manualmente a partir dos dados contidos em <em>CASchools</em>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Compute STR e TestScore e junte-os a CASchools
CASchools$STR <- CASchools$students/CASchools$teachers
CASchools$score <- (CASchools$read + CASchools$math)/2
</code></pre></div></div>
<p>De modo a estimar o modelo por MQO, definindo <em>TestScore</em> como a variável dependente e <em>STR</em> como a variável independente, fazemos uso da função <em>lm()</em> do R para realizar uma regressão linear simples.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Estimando o modelo
linearmodel <- lm(score ~ STR, data = CASchools)
# Descobrimos os parametros beta estimados pelo modelo:
linearmodel
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>##Call:
##lm(formula = score ~ STR, data = CASchools)
##
##Coefficients:
##(Intercept) STR
## 698.93 -2.28
</code></pre></div></div>
<p>Agora, plotamos os dados e o modelo estimado em um gráfico.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Plotando os dados
plot(score ~ STR,
data = CASchools,
main = "Grafico de dispersao de TestScore e STR",
xlab = "STR (X)",
ylab = "Test Score (Y)",
xlim = c(10, 30),
ylim = c(600, 720))
# Adicionando a linha de regressao estimada
abline(linearmodel)
\end{lstlisting}
</code></pre></div></div>
<p><img src="/img/exemplo_regressao_linear.jpg" style="display: block; margin: auto;" /></p>
<p>A interpretação do modelo é simples: a relação entre <em>TestScore</em> e <em>STR</em> é negativa, ou seja, escolas onde se observa uma maior proporção de estudantes relativa à quantidade de professores apresentam notas menores em testes. Pelo modelo estimado, há uma queda de aproximadamente 2.3 pontos na nota dos testes para um aumento observado no STR de um aluno por professor.</p>
<p>Para identificar o \(R^{2}\) e o erro padrão da regressão (EPR), aplicamos o comando <em>summary()</em>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>summary(linearmodel)
##Call:
##lm(formula = score ~ STR, data = CASchools)
##Residuals:
## Min 1Q Median 3Q Max
##-47.727 -14.251 0.483 12.822 48.540
##Coefficients:
Estimate Std. Error t value Pr(>|t|)
##(Intercept) 698.9329 9.4675 73.825 < 2e-16 ***
##STR -2.2798 0.4798 -4.751 2.78e-06 ***
---
##Signif. codes:
##0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
##Residual standard error: 18.58 on 418 degrees of freedom
##Multiple R-squared: 0.05124, Adjusted R-squared: 0.04897
##F-statistic: 22.58 on 1 and 418 DF, p-value: 2.783e-06
</code></pre></div></div>
<p>O \(R^{2}\) deste modelo tem um valor de 0,051. Logo, 5,1% da variação da variável dependente <em>TestScore</em> é explicada pela variável independente <em>STR</em>, ou seja, a regressão explica pouco da variação nas notas, e muito dessa variação permanece inexplicada. O erro padrão da regressão, por sua vez, é de 18,58; isso indica que na média o desvio da nota realmente obtida em relação à reta de regressão é de 18,58 pontos.</p>
<h2 id="referências">Referências:</h2>
<p><strong>BUSAB</strong>, W. <strong>MORETTIN</strong>, P. <em>Estatística Básica: 9ª Edição</em>. São Paulo, SP: Saraivauni, 2017.</p>
<p><strong>HANCK</strong>, Cristoph. et al. <em>Introduction to Econometrics with R</em>. Disponível em: <a href="https://www.econometrics-with-r.org/">https://www.econometrics-with-r.org/</a>.</p>
<p><strong>KUTNER</strong>, Michael H. et al. <em>Applied linear statistical models: 5th ed.</em> McGraw-Hill/Irwin, 2004.</p>
<p><strong>PAULA</strong>, Gilberto A. <em>Modelos de regressão com apoio computacional</em>. São Paulo, SP: Instituto de Matemática e Estatística, Universidade de São Paulo. 2013.</p>
<p><strong>PINDYCK</strong>, R. <strong>RUBINFELD</strong>, D. <em>Econometric models and economic forecasts</em>. McGraw-Hill/Irwin, 1998.</p>
<p><strong>STOCK</strong>, J; <strong>WATSON</strong>, M. <em>Introduction to econometrics: 3rd ed</em>. Pearson, 2010.</p>
<p><strong>WOOLDRIDGE</strong>, Jeffrey M. <em>Introdução à econometria: uma abordagem moderna: tradução da 6ª edição norte-americana</em>. São Paulo, SP: Cengage Learning, 2016.</p>
Markowitz - Seleção de carteiras2020-01-22T23:59:07+00:00http://lamfo-unb.github.io/2020/01/22/Markowitz-selecao-carteiras<h3 id="definição-de-risco-e-retorno">Definição de risco e retorno</h3>
<p>Considere uma série de preços de uma ação em que cada preço de refere a uma observação em um determinado período de tempo:</p>
\[P = \{p_1, p_2, ..., p_n\}\]
<p>O <em>retorno efetivo</em> do ativo no período \(t=2\) é dado por \(R_{2} = p_{2} - p_{1}\). A ideia é que se um agente comprasse o ativo no período 1 ao preço \(p_1\) e o vendesse no período 2 ao \(p_2\), ele teria o ganho de \(R_2\) unidades monetárias. Entretanto, para que essa medida de ganho seja comparável entre ativos diferentes se usa frequentemente o retorno percentual como medida de retorno, isto é:</p>
\[R_2 = \frac{p_2 - p_1}{p_1}\]
<p>Os valores de retornos efetivos já observados são chamados também de retornos históricos.</p>
<p>Uma medida mais interessante para o investidor é qual será o retorno do ativo no futuro. Este tipo de retorno é chamado de <em>retorno esperado</em>. Enquanto o retorno efetivo diz respeito ao que ocorreu de fato, o retorno esperado desrespeita ao que ocorrerá no futuro, portanto, uma expectativa. Matematicamente, pode-se definir o retorno esperado como:</p>
\[\mu = E(R) = \sum_{i=1}^n{p_iR_i}\]
<p>Em outros termos, o retorno esperado é o somatório dos retornos do ativo ponderado pelo pelas respectivas probabilidades de ocorrência. Assim, para calcular o retorno esperado pela definição deve-se saber todos os retornos que o ativo pode ter e quais as probabilidades associados a eles. Isso significa dizer que se conhece todos os cenários que podem ocorrer, suas probabilidades e retornos associados a eles.</p>
<p>Na maioria dos casos, não se tem este tipo de conhecimento sobre os retornos de determinado ativo. Nesse caso, os retornos históricos podem serem usados para estimar o retorno esperado, mas não há nenhuma garantia de que o retorno futuro será o mesmo que o já observado no passado. Disto isto, neste <em>post</em> o retorno esperado de um ativo será estimado como sendo a média aritmética do retornos históricos. Essa abordagem será adotada em razão da sua simplicidade.</p>
<p>Além da medida de retorno, outra medida de grande importância para os investidores é o risco associado aos ativos. Tal métrica mede o quanto em média o valor do retorno efetivo irá divergir do retorno esperado. Isso significa que ativos com risco alto têm retornos efetivos que divergem bastante do retorno esperado, ao mesmo tempo que o ativos menos arriscados têm retornos efetivos que divergem pouco do retorno esperado.</p>
<p>O gráfico a seguir ilustra intuitivamente essa ideia. Considere dois ativos que têm o retorno esperado de 4%, entretanto o ativo <em>A</em> possui um risco menor que o ativo <em>B</em>:</p>
<p><img src="/img/makowitz-selecao-carteiras/main_files/figure-html/histogramas-risco-1.png" style="display: block; margin: auto;" /></p>
<p>Como consequência os retornos efetivos do ativo <em>A</em> são bem mais concentrados, ou próximos, ao retorno esperado do ativo. Ao mesmo tempo que os retornos efetivos de ativo <em>B</em> são bem mais dispersos. Formalmente, o risco de um ativo é definido como o desvio padrão dos retornos efetivos em relação ao retorno esperado:</p>
\[\sigma = (E[(R_i - \mu)^2])^{0,5}\]
<p>O desvio padrão não é a única medida para avaliar risco. A semi-variância ou <em>downside risk</em> é outro exemplo de medida de risco. Ela formula a ideia de que a variância oriunda de retornos efetivos acima do retorno esperado não deveria ser computado como risco. Pois, quando o retorno efetivo for maior que o retorno esperado isso é um risco “bom”, porém, o risco é em geral associado ao custo de manter determinado ativo.</p>
<p>Nesse <em>post</em> será usado o desvio padrão como medida de risco. Além disso, cabe considerar que a discussão sobre a viabilidade de calcular o retorno a partir da definição se aplica também para o cálculo do risco. Dessa forma, será usado o desvio padrão histórico como estimador para o risco.</p>
<h3 id="risco--e-retorno-para-carteiras">Risco e retorno para carteiras</h3>
<p>Até agora foi abordado o risco e retorno do ponto de vista de um ativo individual. Entretanto, seria interessante analisar vários ativos em conjunto. Essa é a ideia de carteira. De modo geral, uma carteira é um conjunto de ativos, a participação de cada ativo no valor total da carteira é chamado de peso do ativo na carteira. Assim, se um ativo alcança o valor $ 10 em uma carteira com o valor total de $ 100, então esse ativo tem peso de 10% na carteira.</p>
<p>Dito isso, o retorno esperado de uma carteira é dada por:</p>
\[R_c = \sum_{i=1}^{n}w_i R_i\]
<p>Em que \(n\) é a quantidade de ativos que compõe a carteira, \(w_i\) a participação de do ativo \(i\) na carteira e \(R_i\) o retorno esperado do ativo \(i\). Usando a notação matricial podemos descrever essa relação como um produto interno entre dois vetores:</p>
\[R_c = w'R\]
<p>Sendo \(w\) um vetor coluna com as participações dos ativos na carteira e \(w'\) a sua transporta e \(R\) outro vetor coluna que contém os retornos dos ativos da carteira:</p>
\[w = \begin{bmatrix}
w_{1} \\
w_{2} \\
\vdots \\
w_{n}
\end{bmatrix},
w' = \begin{bmatrix}
w_1 & w_2 & \dots & w_n
\end{bmatrix},
R = \begin{bmatrix}
R_{1} \\
R_{2} \\
\vdots \\
R_{n}
\end{bmatrix}\]
<p>De agora em diante, um vetor sempre será tratado como uma matriz com uma coluna.</p>
<p>Já o variância da carteira - quadrado do seu risco - é definida como:</p>
\[Var(R_p) = w_iw_j\sum_{i}\sum_{j} cov(R_i,R_j)\]
<p>Para o caso de uma carteira com dois ativo podemos reescrever a relação como:</p>
\[\begin{equation}
\begin{split}
Var(R_p) & = w_1w_1cov(R_1, R_1) + w_1w_2cov(R_1, R_2) + w_2w_1cov(R_2, R_1) + w_2w_2cov(R_2, R_2) \\
Var(R_p) & = w_1^2\sigma_{11} + w_1w_2\sigma_{12} + w_2w_1\sigma_{21} + w_2^2\sigma_{22}
\end{split}
\end{equation}\]
<p>Sendo \(cov(R_i,R_i) = var(R_i) = \sigma_{ii} = \sigma_{i}^2\) e \(cov(R_i, R_j) = cov(R_j, R_i)\) segue:</p>
\[Var(R_p) = w_1^2\sigma_1^2 + 2w_1w_2\sigma_{12} + w_2^2\sigma_{2}^2\]
<p>Diferente do caso do retorno, o risco de uma carteira não é igual à média ponderada dos riscos de cada ativo. A razão para isso é que em geral sempre há uma relação entre a evolução de um preço de ativo \(A\) e um ativo \(B\), por exemplo, há um relação entre a evolução dos preços das ações da Petrobras e da Vale dado que ambas exportam <em>commodities</em>. No caso da carteira com dois ativos, o relacionamentos entre os dois ativos é captado pela covariância entre eles, \(\sigma_{12}\).</p>
<p>O risco de uma carteira com <em>n</em> ativos pode ser definido como:</p>
<p>\(Var(R_p) = w'\Omega w\)
Novamente \(w\) é o vetor com a participação de cada ativo na carteira, já \(\Omega\) é a matriz do covariância dos retornos dos ativos:</p>
\[\Omega = \begin{bmatrix}
\sigma_{11} & \sigma_{12} & \dots & \sigma_{1n} \\
\sigma_{21} & \sigma_{22} & \dots & \sigma_{2n} \\
\vdots & \vdots & \ddots & \vdots \\
\sigma_{n1} & \sigma_{n2} & \dots & \sigma_{nn}
\end{bmatrix}\]
<p>Assim, cada célula \(\sigma_{ij}\) da matriz é a covariância entre os retornos do ativo \(i\) e dos retornos do ativo \(j\). Como \(\sigma_{ij} = \sigma_{ji}\), \(\Omega\) é uma matriz simétrica cuja diagonal é a variância dos ativos.</p>
<h3 id="tipos-de-risco">Tipos de Risco</h3>
<p>O risco, pode ser dividido em dois tipos: idiossincrático, também conhecido como risco não sistemático, e sistemático.</p>
<p>O risco idiossincrático está associado a variância específica do ativo mensurado, é uma característica única do ativo. No caso, por exemplo, de um seguro para casas, assaltos são riscos idiossincráticos, pois dependendo da vizinhança, segurança interna ou até mesmo da aparência, cada casa possui uma chance de ser assaltada ou não, e, não necessariamente, caso uma casa seja assaltada as outras serão também. Esse risco não será tão relevante para o modelo apresentado mais a frente, isso ficará mais claro a seguir.</p>
<p>Já o risco sistemático é aquele ao qual estão sujeitos todos os ativos negociados, isso pode incluir não só ativos que estão listados em bolsas, como também os negociados em mercados de balcão, moedas, etc. Voltando ao exemplo do seguro, o risco sistemático seria a chance de haver um desastre natural que atingisse todas as casas, independentemente de qualquer característica individual de cada casa.</p>
<h3 id="diversificação">Diversificação</h3>
<p>Para entender a diversificação é preciso que esteja clara a distinção entre os tipos de risco. O risco não sistemático então é aquele que afetará somente um ou alguns ativos. No caso das ações de uma empresa seu risco específico está relacionado às decisões de investimentos tomadas pelo gestor, investimentos com \(VPL\) positivo impactam positivamente o valor de uma ação, porém a ocorrência de greves ou fraudes terá impacto negativo.</p>
<p>Já como risco sistemático podemos citar eventos macroeconômicos como a inflação que afeta oferta e demanda de todo um país, é em diferentes níveis para cada tipo de bem, serviço ou setor, mas de maneira geral toda a economia é afetada.</p>
<p>Dadas tais diferenças é possível perceber que em uma carteira com vários ativos, apesar de todos estarem sujeitos ao risco sistemático, cada um deles terá também seu risco específico e enquanto alguns sofrem valorização outros terão queda no preço, e assim é feita a compensação de ganhos e perdas, por isso é importante que uma carteira possua um bom número de ativos e que estes sejam escolhidos de maneira que os riscos não sistemáticos tenham pouca relação entre si.</p>
<p>Podemos voltar então ao exemplo de uma companhia de seguros para exemplificar como funciona a diversificação. Digamos que existem apenas dois riscos envolvendo as casas asseguradas de uma cidade: desastres naturais e roubos. Não é possível a seguradora evitar que ocorram desastres ou que as casas não sejam atingidas por eles, esse risco também pode ser maior ou menor dependendo da época do ano. Porém, os roubos não atingem todas as casas ao mesmo tempo e as ocorrências podem ser maiores a depender de bairro, aparência das casas, etc. Nesse caso, seria prudente que a seguradora tivesse imóveis assegurados dos mais diferentes tipos e também em lugares diferentes. O risco de desastres não é eliminado por diversificação, porém o risco de perdas devido a assaltos diminui quanto maior for a diversificação.</p>
<p>Assim, o efeito diversificação consiste em na redução do risco de uma carteira numa proporção maior que a redução da média ponderada dos retornos quando se adiciona ativos na carteira.</p>
<p>A correlação é a medida da estatística utilizada para medir se dois ativos possuem flutuações muito ou pouco parecidas, é, no cálculo, o que fará o risco aumentar ou diminuir ao montar uma carteira de investimentos. Pode variar de -1, que é quando os ativos possuem correlação perfeitamente negativa, a 1, ativos com correlação perfeitamente positiva. Quanto mais próxima de 1, maior o risco da carteira, pois neste caso, os ativos se comportam de maneira muito parecida, e quanto mais próxima de -1, menor o desvio padrão da carteira. Entretanto, a correlação não capta relações não-lineares entre variáveis.</p>
<p>A correlação entre ativos pode contribuir para aumentar ou reduzir o efeito diversificação em uma carteira. Considere uma carteira com duas ações, o risco da carteira depende da correlação entre os ativos. No caso em que a correlação entre os ativos é \(-1\) o risco da carteira pode ser nulo dependendo dos pesos entre os ativos. Por outro lado, caso a correlação seja \(1\) não há efeito diversificação.</p>
<p>Isso é ilustrado no gráfico a seguir, em que cada ponto corresponde a um ativo:</p>
<p>
<img src="/img/makowitz-selecao-carteiras/img-sarah/efeito-correlacao.png" with="672" style="display: block; margin: auto;" />
<br />
<em>Fonte: Adaptado de BERK, 2014</em>
</p>
<p>Entretanto, em uma carteira com muito ativos o efeito ilustrado acima é difícil de acontecer, em razão das correlações entre os vários ativos. Nesta situação, no pior dos casos, diversificar torna o risco da carteira igual ao valor do risco sistemático dos ativos, eliminando o risco idiossincrático.</p>
<p>Considere um carteira com \(n\) ativos, tal que todos os ativos têm o mesmo peso na carteira. Como já mencionado, a variância de uma carteira \(p\) com \(n\) ativos é dada por:</p>
\[Var(R_p) = \sum_i^n\sum_j^nw_iw_jCov(R_i, R_j)\]
<p>Separando em variâncias e covariâncias segue:</p>
\[\begin{split}
Var(R_p) &= \sum_{\substack{ i, \ j \\i = j}}^{n}w_iw_jCov(R_i, R_j) + \sum_{\substack{ i, \ j \\i \neq j}}^{n}w_iw_jCov(R_i, R_j) \\
Var(R_p) &= \sum_i^{n}w_i^2Var(R_i) + \sum_{\substack{ i, \ j \\i \neq j}}^{n}w_iw_jCov(R_i, R_j)
\end{split}\]
<p>Considerando que \(w_i = w_j = \frac{1}{n}\), segue:</p>
\[Var(R_p) = \frac{1}{n^2} \sum_i^{n}Var(R_i) + \frac{1}{n^2}\sum_{\substack{ i, \ j \\i \neq j}}^{n}Cov(R_i, R_j)\]
<p>Note que na equação acima há \(n\) variâncias, uma para cada ativo, e \(n*n - n\) covariâncias, todas as covariâncias descontadas as variâncias. Assim, a equação acima pode ser reescrita como:</p>
\[\begin{split}
Var(R_p) &= \frac{1}{n^2}\frac{n}{n} \sum_i^{n}Var(R_i) + \frac{1}{n^2}\frac{n^2-n}{n^2-n}\sum_{\substack{ i, \ j \\i \neq j}}^{n}Cov(R_i, R_j) \\
Var(R_p) & = \frac{1}{n}\bar{\sigma_i}^2 + \left( 1 + \frac{1}{n}\right)\bar{\sigma_{ij}}
\end{split}\]
<p>Tal que:</p>
<ul>
<li>\(\bar{\sigma_i}^2 \equiv \frac{1}{n} \sum_i^{n}Var(R_i)\), que é a média das variâncias individuais dos ativos;</li>
<li>\(\bar{\sigma_{ij}} \equiv \frac{1}{n^2-n}\sum_{\substack{ i, \ j \\i \neq j}}^{n}Cov(R_i, R_j)\), que é a média das covariâncias entre os ativos.</li>
</ul>
<p>Assim, quando o número de ações na carteira tende ao infinito, segue:</p>
\[\lim_{n\to\infty}{Var(R_p)} = \bar{\sigma_{ij}}\]
<p>Isto é, quando o número de ativos cresce muito a variância da carteira se aproxima do valor da média da covariância entre os ativos. Assim, o risco remanescente corresponde ao risco de mercado, o que está ilustrado no gráfico a seguir.</p>
<p>
<img src="/img/makowitz-selecao-carteiras/img-sarah/efeito-diversificao.png" with="672" style="display: block; margin: auto;" />
<br />
<em>Fonte: BERK, 2014</em>
</p>
<h3 id="escolha-de-uma-carteira">Escolha de uma carteira</h3>
<p>Não existe uma carteira que seja a melhor para todos investidores. Isso ocorre por que investidor têm preferências diferentes de combinação de risco e retorno, e tais preferências variam de acordo com fatores como idade, renda, estado civil e perspectivas futuras. Isto é, esses fatores podem tornar o agente mais ou menos avesso ao risco. Nesse contexto, a seleção de carteira consiste encontrar a carteira que melhor satisfaça a preferência do investidor dentre N carteiras diferentes.</p>
<h4 id="princípio-da-dominância">Princípio da dominância</h4>
<p>A diversificação permite a criação de diversas combinações de risco e retorno, e nem todas as carteiras diversificadas são eficientes. É possível realizar a comparação entre carteiras ou ativos que apresentem o mesmo risco ou o mesmo retorno. Essa comparação pode mostrar aquele ativo ou carteira que é mais eficiente, comparativamente, que os demais.</p>
<p>Supondo que no mercado existam as ações \(X\) e \(Y\), essas ações possuem o mesmo retorno, mas riscos distintos - o risco da ação \(Y\) é quatro vezes maior que o risco da ação \(X\). Se o investidor avaliar somente o retorno esperado, será indiferente entre os dois ativos. Entretanto, se esse investidor for racional e analisar tanto o retorno como o risco, optará pela ação \(X\), que está de acordo com o princípio da dominância. Esse princípio diz que: “um agente racional optará pelo investimento que lhe fornece o maior retorno esperado dado um nível de risco, ou o menor risco dado um nível de retorno”. Com isso é nítido que o ativo \(X\) domina o ativo \(Y\).</p>
<p>No gráfico abaixo, note que a ação da Coca-Cola apresenta um risco de 25%, assim como a ação da Bore. Todavia, o retorno apresentado pela Coca-Cola é maior. Logo, um investidor racional, ao se deparar com as duas ações no mercado, irá optar por aquela com maior retorno. Apesar de ser dominante, nenhuma dessas duas ações está sobre a fronteira de eficiência, portanto existe uma combinação que pode trazer um maior retorno, com o mesmo risco.</p>
<p>
<img src="/img/makowitz-selecao-carteiras/img-alicia/fronteira01.png" with="672" style="display: block; margin: auto;" />
<br />
<em>Fonte: BERK, 2014</em>
</p>
<h4 id="carteiras-eficientes">Carteiras Eficientes</h4>
<p>No exemplo anterior, o investidor escolheu a carteira composta com a ação da Coca Cola, uma vez que esta era dominante, dentre as opções que ele possui. Agora suponha que existe a carteira \(A\), que assim como as ações apresentadas, possui uma volatilidade de 25%, mas a carteira \(A\) representa a combinação de ativos com o maior retorno. Essa carteira será a carteira eficiente, uma vez que o investidor pode ficar numa melhor posição ao escolher \(A\), invés das demais carteiras.</p>
<p>
<img src="/img/makowitz-selecao-carteiras/img-alicia/fronteira02.png" with="672" style="display: block; margin: auto;" />
<br />
<em>Fonte: BERK, 2014</em>
</p>
<p>Note que na combinação \((0,1)\), em que a carteira é composta apenas por ativos da Coca-Cola, o risco é o mesmo que no ponto \((0.4, 0.6)\), em que 40% da carteira é composta por ações da Intel e 60% por ações da Coca-Cola, essa carteira apresenta o mesmo risco, entretanto o retorno é maior e ela está posicionada na fronteira de eficiência, isso significa que um investidor racional que está disposto a aceitar 25% de volatilidade, irá optar pela combinação \((0.4, 0.6)\).</p>
<p>Uma carteira eficiente, portanto, pode ser definida como aquela que apresenta o maior retorno esperado dado um nível de risco. Ou, alternativamente, a carteira de menor risco dado um nível de retorno, isto é, a carteira de variância mínima. Essa é a carteira que um investidor racional irá escolher dentre as opções que foram apresentadas para ele.</p>
<p>Partindo da uma visão de carteira de variância mínima, o problema de selecionar uma carteira pode ser definido como um problema de otimização. Isto é, como encontrar a carteira de menor risco dado um retorno desejado. Matematicamente:</p>
\[\begin{equation}
\begin{split}
\underset{w}{min} &\quad w'M w\\
s.a &\\
& wR = R_d \\
& w\textbf{1} = 1
\end{split}
\end{equation}\]
<p>Sendo \(w\) o vetor de pesos da carteira a ser encontrada, \(M\) a matriz de covariância dos retornos, \(R\) o vetor com dos retornos de cada ativo, \(R_d\) o retorno desejado para a carteira ótima e \(\textbf1\) um vetor de cuja todas as coordenadas são 1. O problema de otimização tem duas restrições: \(wR=R_d\) e \(w\textbf{1}=1\). A primeira restrição afirma que a carteira ótima deve ter o retorno igual ao retorno desejado, já segunda afirma que a soma das participações de cada ativo deve somar 1.</p>
<p>Resolver tal problema de minimização significa encontrar a participação de cada ativo na carteira, os pesos, tal que a carteira tenha o menor risco entre todas as carteiras com os mesmos ativos e retorno igual \(R_d\).</p>
<p>Através dessa solução, variando os valores \(R_d\), pode-se representar em um espaço bidimensional de Variância x Retorno Esperado, todas as carteiras geradas essa representação apresenta a forma de uma hipérbole. Ademais, o problema de otimização de Markowitz é quadrático e convexo, o que garante que de fato o problema é solucionado de maneira eficiente.</p>
<p>O modelo de otimização de Markowitz também pode ser resolvido através da maximização do retorno dado um nível de risco. Assim, uma formulação equivalente ao problema de minimização é:</p>
\[\begin{equation}
\begin{split}
\underset{w}{max} &\quad wR\\
s.a &\\
& w'M w = \sigma^2_d\\
& w\textbf{1} = 1
\end{split}
\end{equation}\]
<p>Usando termos de pesquisa operacional, diz-se que o problema de minimização de variância dado um nível de retorno desejado é o problema primal e o de maximização do retorno dado um nível de variância desejada, o seu dual.</p>
<h3 id="fronteira-eficiente">Fronteira eficiente</h3>
<p>Colocando todas as combinações de retorno e risco das possíveis carteiras de conjunto de ativos obtém-se o seguinte gráfico. Abaixo pode-se observar duas fronteiras eficientes, a fronteira eficiente de uma carteira contendo as 10 ativos, representada pela linha continua, a fronteira eficiente contendo 3 ativos, representada pela linha pontilhada. O eixo \(Y\) apresenta todos os retornos para cada combinação e o eixo \(X\) apresenta o risco para cada combinação de ativos.</p>
<p>
<img src="/img/makowitz-selecao-carteiras/img-alicia/fronteira03.png" with="672" style="display: block; margin: auto;" />
<br />
<em>Fonte: BERK, 2014</em>
</p>
<p>Cada ponto no acima abaixo representa uma carteira. Dado um nível de risco desejado, o agente escolheria a carteira mais alta no gráfico e, dado um nível de retorno, o agente escolheria a carteira mais à esquerda no gráfico segundo o princípio da dominância. Essas escolhas são as carteiras eficientes e conjunto dessas carteiras é chamada de fronteira eficiente. No gráfico acima, as fronteiras eficientes são representadas pela cor vermelha.</p>
<p>Ademais, a fronteira eficiente tende a expandir à medida que se se aumenta a quantidade de ativos na carteira. Abaixo, na linha pontilhada, observa-se que uma fronteira formada apenas por três ativos é menor que a fronteira composta pelos 10 ativos, representada pela linha contínua. Essa expansão mostra que a diversificação pode ser benéfica.</p>
<h3 id="usando-o-r">Usando o R</h3>
<p>Para ilustrar a discussão teórica feita até aqui, será usado o R para calcular uma fronteira eficiente para um conjunto de ativos.</p>
<h4 id="obtendo-dados">Obtendo dados</h4>
<p>Será necessário carregar os seguintes pacotes:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>library(ggplot2)
library(magrittr)
library(quantmod)
library(xts)
library(tseries)
library(ggplot2)
</code></pre></div></div>
<p>Caso não possua esses pacotes instalados você pode usar <code class="language-plaintext highlighter-rouge">install.packages('nome_pacote')</code> para instalá-los e depois carregue eles usando os comandos acima. Além dos listados acima, será necessário que os pacotes <code class="language-plaintext highlighter-rouge">tidyr</code> e <code class="language-plaintext highlighter-rouge">dplyr</code> estejam instalados, entretanto, não é necessário carrega-los.</p>
<p>Usaremos os pacotes <code class="language-plaintext highlighter-rouge">quantmod</code> e <code class="language-plaintext highlighter-rouge">xts</code> para obter os dados de interesse e tratar-los para o objetivo que desejamos. Assim, para o exercício, vamos obter o dados para as seguintes ativos:</p>
<ul>
<li>ITSA4 - Itaú SA Investimentos;</li>
<li>NATU3 - Natura;</li>
<li>PETR4 - Petrobras;</li>
<li>ABEV3 - Ambev SA.</li>
</ul>
<p>Usaremos as funções do pacote <code class="language-plaintext highlighter-rouge">quantmod</code> para obter os preços diárias das ações entre outubro de 2016 e dezembro de 2019. Antes desse período, os dados do índice Bovespa apresenta muitos valores perdidos.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Definindo parâmetros
simbolos <- c("ITSA4.SA", "VVAR3.SA", "FNOR11.SA", "PETR4.SA", "BOVV11.SA")
startdate <- '2016-10-27' # Sys.Date() - 730
enddate <- '2019-12-15' # Sys.Date()
# Fazendo download
ativos <- new.env()
getSymbols(Symbols = simbolos, env = ativos, src = 'yahoo',
from = startdate, to = enddate, auto.assign = TRUE)
ativos <- as.list(ativos)
</code></pre></div></div>
<p>Se tudo tiver corrido corretamente os dados das ações foram baixados em carregados no <em>environment</em> <code class="language-plaintext highlighter-rouge">ativos</code> que posteriormente foi transformando em uma lista. Usaremos lista frequentemente nesse exercício, elas simplificam bastante a transformação de dados ao permitir que uma operação seja realizada sobre todos os seu elementos usando a função <code class="language-plaintext highlighter-rouge">lappy()</code>.</p>
<h4 id="processando-os-dados">Processando os dados</h4>
<p>Agora que temos os dados, vamos realizar um processamento de modo a obter o retorno mensais dessas séries, mas antes disso vamos que criar algumas funções para nos auxiliar nisso:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>get_preco_fechamento <- function(x){
## Obtem preço de fechamento
x[, base::grepl(pattern = '\\.Close$$', x = dimnames(x)[[2]])]
}
list_to_xts <- function(list_xts){
## Transforma uma lista de objetos xts em um objeto xts
nomes <- names(list_xts)
res <- do.call(cbind.xts, list_xts)
dimnames(res)[[2]] <- nomes
return(res)
}
xts_to_data.frame <- function(x){
## Transforma objeto xts em data.frame
df <- as.data.frame(x)
df <- data.frame(
periodo = row.names(df),
df
)
row.names(df) <- NULL
return(df)
}
</code></pre></div></div>
<p>Na lista <code class="language-plaintext highlighter-rouge">ativos</code> estão os dados de transações de cada ativo na bolsa em objetos <code class="language-plaintext highlighter-rouge">xts</code>. Em cada objeto <code class="language-plaintext highlighter-rouge">xts</code> estão guardados informações como o menor preço alcançado pela ação no dia, o maior preço alcançado, o preço do ativo na abertura do pregão, o preço de fechamento e outras informações. Para nosso exercício, usaremos o preços de fechamento dos ativos e partir deles calcularemos os retornos mensais, por isso, precisamos da função <code class="language-plaintext highlighter-rouge">get_preco_fechamento()</code>.</p>
<p>Já a função <code class="language-plaintext highlighter-rouge">list_to_xts()</code> recebe uma lista de objetos <code class="language-plaintext highlighter-rouge">xts</code> e a transforma em apenas um objeto <code class="language-plaintext highlighter-rouge">xts</code> e, por fim, a função <code class="language-plaintext highlighter-rouge">xts_to_data.frame</code> transforma um objeto <code class="language-plaintext highlighter-rouge">xts</code> em um <code class="language-plaintext highlighter-rouge">data.frame</code> mantendo o período dos dados como uma coluna do <code class="language-plaintext highlighter-rouge">data.frame</code> resultante. A seguir, vamos calcular os retornos mensais dos ativos:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#Obtendo apenas os preços de fechamento
ativos <- lapply(X = ativos, FUN = get_preco_fechamento)
# calculando retornos mensais
retornos_men <- lapply(ativos, quantmod::monthlyReturn)
# Juntando ativos em um objeto xts
carteira <- list_to_xts(retornos_men)
# Transformando objeto xts em uma matriz e retirando dados perdidos
carteira <- as.matrix(carteira)
carteira <- na.omit(carteira)
</code></pre></div></div>
<p>Aplicando a função <code class="language-plaintext highlighter-rouge">get_preco_fechamento()</code> por meio da função <code class="language-plaintext highlighter-rouge">lapply()</code> obtemos uma lista com o preço de fechamento de cada ativo, procedimento semelhante foi feito para calcular o retorno mensal de cada ativo. Ao final, a matriz <code class="language-plaintext highlighter-rouge">carteira</code> representa a carteira contendo os retornos dos ativos.</p>
<h4 id="explorando-dados">Explorando dados</h4>
<p>Antes de prosseguirmos, vamos dar uma olhada na evolução dos preços de fechamento dos ativos. Para isso, usaremos as seguintes funções:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>precos_tidy <- function(data, periodo){
## Transforma os precos para o formato long
cols <- base::setdiff(names(data), periodo)
res <- tidyr::gather(data, key = 'ativo', value = 'precos', cols)
res[, periodo] <- as.Date(as.character(res[[periodo]]))
class(res) <- c('carteira', class(res))
return(res)
}
plot_precos <- function(data, periodo, filter = NULL){
## Plota a evolução dos preços
# Validação
stopifnot('carteira' %in% class(data))
# Quotando variável
periodo <- dplyr::sym(periodo)
# Filtrando ativos
if(!is.null(filter)){
data <- dplyr::filter(data, ativo %in% filter)
}
ggplot(data, aes(x = !!periodo, y = precos, color = ativo))+
geom_line()+
labs(
x = '',
y = 'Preço de fechamento',
color = 'Ativo',
title = 'Evolução dos ativos'
)
}
</code></pre></div></div>
<p>Os dados dos ativos estão organizados de forma que cada coluna representa uma ativo diferente, nesse caso, diz-se que os dados estão num formato <code class="language-plaintext highlighter-rouge">wide</code>. Entretanto, o <code class="language-plaintext highlighter-rouge">ggplot2</code> foi construído para seguir uma lógica em que os dados estão no formato <code class="language-plaintext highlighter-rouge">long</code>, também chamado de <code class="language-plaintext highlighter-rouge">tidy</code>. Nesse caso, os dados sobre os ativos são organizados em duas colunas: uma conterá o nome do ativo e outra o preço da ação correspondente respeitando o período da observação. A função <code class="language-plaintext highlighter-rouge">precos_tidy()</code> faz justamente essa transformação.</p>
<p>A função <code class="language-plaintext highlighter-rouge">plot_precos()</code> toma o preços no formato <code class="language-plaintext highlighter-rouge">long</code> e cria um gráfico usando as funções do <code class="language-plaintext highlighter-rouge">ggplot2</code>. A seguir, plotamos a evolução dos preços de fechamento das ações e calcular as correlações entres o preços.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>precos_ <- precos_tidy(precos, 'periodo')
plot_precos(precos_, 'periodo')
</code></pre></div></div>
<p><img src="/img/makowitz-selecao-carteiras/main_files/figure-html/explorando_precos-1.png" style="display: block; margin: auto;" /></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># calculando correlação entre os preços
m <- as.matrix(precos[, -1])
m <- na.omit(m)
cor(m)
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## ABEV3 NATU3 PETR4 ITSA4
## ABEV3 1.0000000 -0.3243479 -0.2361517 0.4825303
## NATU3 -0.3243479 1.0000000 0.7464562 0.2422055
## PETR4 -0.2361517 0.7464562 1.0000000 0.5854143
## ITSA4 0.4825303 0.2422055 0.5854143 1.0000000
</code></pre></div></div>
<p>Na tabela acima, cada célula representa a correlação entre os preços do ativo da linha com o ativo da coluna. Chama a atenção a alta correlação existente entre preços das ações da Petrobras, <em>PETR4</em>, e da Natura <em>NATU3</em>, que alcança o valor de 74,65%. Isso é um pouco curioso, já que essas empresas são de setores diferentes. Tal relação fica mais clara no gráfico a seguir:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>plot_precos(precos_, 'periodo', filter = c('PETR4', 'NATU3'))
</code></pre></div></div>
<p><img src="/img/makowitz-selecao-carteiras/main_files/figure-html/grafico_petr4_natu3-1.png" style="display: block; margin: auto;" /></p>
<p>Os dois ativos apresentam a tendência de queda entre 2013 e meados de 2016, após esse período passa a ter uma tendência ascendente. Talvez a mudança de governo ocorrido em 2016 tenha sido um motivo relevante para esse comportamento. A apesar de tudo isso, a mesma relação não se mantém quando calculamos a correlação entre os retornos. Quando fazemos esse cálculo, percebemos que a maior correlação ocorre entre <em>PETR4</em> e <em>ITSA4</em> como pode ser visto abaixo:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Correlação entre os retornos
cor(carteira)
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## ABEV3 NATU3 PETR4 ITSA4
## ABEV3 1.00000000 0.1066042 0.06589754 0.3241655
## NATU3 0.10660416 1.0000000 0.30124177 0.2985749
## PETR4 0.06589754 0.3012418 1.00000000 0.6686894
## ITSA4 0.32416546 0.2985749 0.66868936 1.0000000
</code></pre></div></div>
<h4 id="calculando-fronteira-eficiente">Calculando fronteira eficiente</h4>
<p>O pacote <code class="language-plaintext highlighter-rouge">tseries</code> possui uma função chamada <code class="language-plaintext highlighter-rouge">portfolio.optim()</code>. Dado um conjunto de ativos e um retorno esperado para a carteira, ela calcula a carteira de menor variância e retorna uma lista com os pesos de cada ativo na carteira ótima, o risco e o retorno esperado.</p>
<p>Usaremos essa função para calcular a fronteira eficiente para o 4 ativos escolhidos. Para o nosso objetivo, três argumentos será de particular interesse: <code class="language-plaintext highlighter-rouge">x</code>, <code class="language-plaintext highlighter-rouge">pm</code> e <code class="language-plaintext highlighter-rouge">shorts</code>. O argumento <code class="language-plaintext highlighter-rouge">x</code> recebe uma matriz com os retornos históricos dos ativos em cada coluna é uma ativo diferente; <code class="language-plaintext highlighter-rouge">pm</code> recebe o retorno desejado para carteira ótima escolhida e <code class="language-plaintext highlighter-rouge">shorts</code> recebe <code class="language-plaintext highlighter-rouge">TRUE</code> ou <code class="language-plaintext highlighter-rouge">FALSE</code>, <code class="language-plaintext highlighter-rouge">TRUE</code> quando é permitido a venda a descoberto de ativos e <code class="language-plaintext highlighter-rouge">FALSE</code> quando não.</p>
<p>A venda a descoberta consiste na venda de uma ação que o investidor não possui na sua carteira. Neste caso o peso correspondente à essa ação na carteira será negativa. Operar com venda a descoberta é útil quando se deseja alcançar um retorno que é maior (menor) que o maior (menor) retorno do ativo de maior (menor) retorno na carteira.</p>
<p>Para facilitar esse trabalho, vamos criar algumas funções:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>carteira_otima <- function(ativos, retorno_desejado, shorts = FALSE){
## Calcula carteira ótima
s <- tseries::portfolio.optim(
x = ativos,
pm = retorno_desejado,
shorts = shorts
)
pesos <- s[['pw']]
names(pesos) <- colnames(ativos)
res <- list(
pesos = pesos,
retorno = s[['pm']],
risco = s[['ps']]
)
return(res)
}
get_retorno <- function(res){
## Obtém o retorno da carteira ótima
## res: list
sapply(res, `[[`, i = 'retorno')
}
get_risco <- function(res){
## Obtém o risco da carteira ótima
## res: list
sapply(res, `[[`, i = 'risco')
}
</code></pre></div></div>
<p>Assim, a carteira ótima que tem o retorno mensal esperado de \(1\%\) seria dada por:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>carteira_otima(ativos = carteira, retorno_desejado = .01, shorts = FALSE)
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## $pesos
## ABEV3 NATU3 PETR4 ITSA4
## 0.5035733 0.2429710 0.0000000 0.2534557
##
## $retorno
## [1] 0.01
##
## $risco
## [1] 0.04844689
</code></pre></div></div>
<p>Sendo <code class="language-plaintext highlighter-rouge">pesos</code> a participação de cada ativo na carteira ótima, <code class="language-plaintext highlighter-rouge">retorno</code> o retorno esperado e <code class="language-plaintext highlighter-rouge">risco</code> o desvio padrão esperado.</p>
<p>Vamos calcular o retorno esperados para o ativos e seus respectivos riscos e guardar tais informações em um <code class="language-plaintext highlighter-rouge">data.frame</code>. Após isso, vamos gerar um vetor de retornos desejados para as carteira ótimas a fim de gerar a fronteira eficiente.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>retornos_esperados <- apply(carteira, MARGIN = 2, mean)
riscos <- apply(carteira, MARGIN = 2, sd)
ativos <- data.frame(
acao = names(retornos_esperados),
risco = riscos,
retorno = retornos_esperados,
row.names = NULL
)
ativos
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>## acao risco retorno
## 1 ABEV3 0.05395006 0.00815532
## 2 NATU3 0.09332690 0.01254119
## 3 PETR4 0.13895500 0.01134941
## 4 ITSA4 0.07556379 0.01122900
</code></pre></div></div>
<p>Note que estamos estimando o retorno esperado dos ativos como sendo o média do retorno histórico, entretanto, essa é uma abordagem ingênua que implica em uma série de problemas como: não há garantias do que o que ocorreu no passado ocorrerá no futuro; dependendo do períodos observado, a média do retorno histórico é diferente.</p>
<p>As ações da <em>ABEV3</em> a presentaram o menor retorno esperado, 0,8%, e o menor risco 5,4%. Já <em>NATU3</em> apresenta o maior retorno esperado, 1,25%, entretanto, não apresenta o maior risco. Nesse caso, a máxima de que um maior risco implica em uma maior retorno nem sempre é válida quando estamos avaliando ativos individuais. Esse fato pode ser explicado pela distinção entre risco diversificável - idiossincrático - e não diversificável - risco sistêmico.</p>
<p>Para calcular a fronteira usaremos a função <code class="language-plaintext highlighter-rouge">carteira_otima()</code>. Ela toma como argumentos um conjunto de ativos e um retorno desejado e retorna a carteira com menor risco que possui o retorno igual ao retorno desejado. A fronteira eficiente é justamente o conjunto de carteiras com menor risco possível ao valor de retorno dado.</p>
<p>Portanto, para gerar a fronteira eficiente será necessário gerar esse conjunto de carteira ótimas. Para tanto, é necessário gerar um retorno desejado para cada carteira ótima. A seguir serão gerando 50 retornos desejados para gerar 50 carteiras ótimas e construir a fronteira eficiente.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>retorno_min <- 0.5*min(retornos_esperados)
retorno_max <- 1.5*max(retornos_esperados)
retornos_seq <- seq(retorno_min, retorno_max, length.out = 50)
</code></pre></div></div>
<p>O menor retorno esperado tem a metade do retorno do ativo com menor retorno e o maior tem a metade a mais que do retorno esperado do ativo de maior rendimento. Assim, foram gerados 50 retornos desejados igualmente espaçados.</p>
<p>A seguir calcularemos as carteiras da fronteira. Como há retornos desejados abaixo e acima dos retornos mínimo e máximo dos ativos na carteira usaremos <code class="language-plaintext highlighter-rouge">short = TRUE</code>.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Primeira com todos os ativos
fronteira <- lapply(
X = retornos_seq,
FUN = carteira_otima,
ativos = carteira,
shorts = TRUE
)
# Fronteira sem NATU3
nomes_ativ <- c("ABEV3", "PETR4", "ITSA4")
fronteira2 <- lapply(
X = retornos_seq,
FUN = carteira_otima,
ativos = carteira[, nomes_ativ],
shorts = TRUE
)
# Criando data frame
dados_plot <- data.frame(
retorno = get_retorno(fronteira),
risco = get_risco(fronteira),
retorno2 = get_retorno(fronteira2),
risco2 = get_risco(fronteira2)
)
</code></pre></div></div>
<p>O <code class="language-plaintext highlighter-rouge">data.frame</code> <code class="language-plaintext highlighter-rouge">dados_plot</code> contêm o dados de risco e retorno das carteiras ótimas. Com eles é possível plotar a fronteira eficiente, como poder ser visto no gráfico a seguir:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Plotando fronteira eficiente
dados_plot %>%
ggplot(aes(x = retorno, y = risco, color = '#E7B800'))+
geom_line(size = 1)+
geom_line(size = 1, aes(y = risco2), color = '#5F9EA0')+
geom_point(data = ativos, aes(x = retorno, y = risco, color = acao))+
geom_text(data = ativos, aes(x = retorno, y = risco, label = acao, color = acao))+
coord_flip()+
labs(
x = 'Retorno',
y = 'Risco',
title = 'Fronteira Eficiente',
color = ''
)+
theme(legend.position = 'none')
</code></pre></div></div>
<p><img src="/img/makowitz-selecao-carteiras/main_files/figure-html/fronteira_plot-1.png" style="display: block; margin: auto;" /></p>
<p>A fronteira mais escura foi construída a partir dos ativos <em>ABEV3</em>, <em>PETR4</em> e <em>ITSA4</em>, já a fronteira laranja foi construída com os mesmo ativos mais o ativo <em>NATU3</em>. A nova fronteira ficou mais à esquerda que a anterior, portanto, é possível obter o mesmo retorno com uma risco menor por meio dessa nova nova fronteira eficiente. Tais resultados são possíveis devido aos efeitos da diversificação: ao aumentar a quantidade de ativos na carteira, o risco cai mais que os retornos ponderados dos ativos.</p>
<p>Os scripts usados ao longo do <em>post</em> estão disponíveis no <a href="https://github.com/lamfo-unb/media-variancia-markowitz">GitHub</a></p>
<h3 id="fontes-consultadas">Fontes consultadas</h3>
<hr />
<p>BERK, Jonathan B.;DEMARZO, Peter. Corporate finance. 3rd ed. Peason, 2014.</p>
<p>ROSS, Stephen A. et al.Fundamentos de administração financeira. 9 ed. Porto Alegre: AMGH, 2013.</p>
<p>BREALEY, Richard A.; MYERS, Stewart C.; ALLEN, Franklin. Princípios de finanças corporativas. 10 ed. Porto Alegre: AMGH, 2013.</p>
Estatística Espacial2019-12-04T23:59:07+00:00http://lamfo-unb.github.io/2019/12/04/Estatística-Espacial<h1 id="estatística-espacial">Estatística Espacial</h1>
<p>Estatística Espacial consiste no estudo, caracterização e modelagem de variáveis aleatórias que apresentam uma estrutura espacial ou espaço-temporal. O estudo tem por objetivo determinar um fenômeno em determinado espaço geográfico que pode ocorrer ou não ao longo do tempo.</p>
<p>Para fazer uma avaliação completamente precisa seriam necessários coletar todos os casos desse evento; o que é proposto é que sejam coletadas amostras em locais diferentes (em períodos diferentes se for o caso) e, a partir delas, sejam criadas previsões para as áreas sem coleta de amostra. Um exemplo de previsão para tomada de decisão será elucidado ao fim desse post.</p>
<p>Exemplo de dados que utilizam Estatística Espacial são estudos de criminalidade, para avaliar concentração de crimes por bairros, por exemplo, ou estudos de clima, para estudar precipitação de chuva em uma região.</p>
<h1 id="dados">Dados</h1>
<p>Os dados utilizados na Geoestatística são aqueles que as principais características deles estão relacionados às coordenadas espaciais e ao tempo.</p>
<p>Eventos pontuais: Tais eventos são marcados pela localização ou momento no tempo. Assim, podemos estimar o número esperado de eventos em uma área, ou seja, estima a intensidade deles.</p>
<p>Dados de superfícies: Nesse caso, os eventos não tem uma precisão (latitude e longitude), mas estão definidos em um aglomerado de dados em um espaço (bairro, distrito, município) ou tempo. É comum termos a visualização desses dados nos chamados mapas climáticos.</p>
<h2 id="tipos-de-dados">Tipos de Dados</h2>
<p>Abaixo, é possível observar os tipos de dados analisados em Estatística Espacial.</p>
<table>
<thead>
<tr>
<th> </th>
<th>Tipos de Dados</th>
<th>Exemplo</th>
<th>Problemas Típicos</th>
</tr>
</thead>
<tbody>
<tr>
<td>Análise de Eventos Pontuais</td>
<td>Eventos Localizados</td>
<td>Ocorrência de Doenças</td>
<td>Determinação de Padrões</td>
</tr>
<tr>
<td>Análise de Superfícies</td>
<td>Amostra de campo e matrizes</td>
<td>Depósitos Minerais</td>
<td>Interpolação e medidas de Incerteza</td>
</tr>
<tr>
<td>Análise de Áreas</td>
<td>Polígonos e Atributos</td>
<td>Dados Censitários</td>
<td>Regressão e Distribuições Conjuntas</td>
</tr>
</tbody>
</table>
<h1 id="workflow">Workflow</h1>
<p>O tratamento e análise dos dados consistem em aplicar um método de interpolação para o melhor entendimento do fenômeno estudado. A interpolação é uma técnica de transformação de eventos pontuais para dados de superfície.</p>
<p><img src="https://i.imgur.com/HmBXe1T.png" alt="" /></p>
<p>Tal análise segue o fluxo acima, no qual passamos por oito passos.</p>
<ol>
<li>Coleta dos dados: Seja por meio de extração de materiais ou por uma pesquisa de campo.</li>
<li>Pre-processamento dos dados: uma etapa não obrigatória, que avalia se os dados utilizados não apresentam alguma inconsistência.</li>
<li>Modelagem da estrutura espacial: alguns métodos requerem que as amostras sejam modeladas usando um semivariograma ou uma função de covariância para definir se a amostra tem mais similaridade com os elementos próximos ou com o grupo todo.</li>
<li>Definição da estratégia de busca: nessa etapa são definido quantas amostras serão utilizadas na interpolação.</li>
<li>Previsão de valores: com o modelo pronto, faremos a efetivamente a interpolação tendo geralmente por resultado um mapa com as previsões para as localizações sem amostra.</li>
<li>Quantificação da incerteza das previsões: ao mesmo tempo que são geradas previsões sobre valores sem amostras, avaliamos os erros na previsão. Isso ocorre, pois certos métodos de interpolação não são determinísticos e assim possibilitam a avaliação de erros em seus cálculos.</li>
<li>Verificação: etapa na qual é verificado com amostras não utilizadas se os valores das previsões condizem com elas. Caso estejam destoantes, será necessário reavaliar os passos um a três.</li>
<li>Uso dos dados de superfície para tomada de decisão.</li>
</ol>
<h1 id="métodos-de-interpolação">Métodos de interpolação</h1>
<p>Existem duas categorias de métodos de interpolação: determinísticos e geoestatísticos. Os métodos deterministicos calculam os valores de cada ponto baseados diretamente nas amostras próximas. Já os métodos geoestatísticos utilizam a relação estatística entre as amostras levantadas.</p>
<h2 id="métodos-determinísticos">Métodos determinísticos</h2>
<p>Tais métodos levam em conta que todo o conjunto da amostra se comporta de forma regular e por isso não contabilizam por erros. Um exemplo é o método da média móvel que avalia a média das amostras dentro de certo raio para determinar o valor do ponto sem amostra. Outro exemplo é o Inverse Distance Weighted (IDW) que também avalia as amostras mais próximas, porém atribui pesos para o valor de cada amostra a fim de determinar o ponto sem amostra.</p>
<h2 id="métodos-geoestatísticos">Métodos geoestatísticos</h2>
<p>Tais métodos levam em conta a autocorrelação dos dados - as relações estatísticas entre o pontos. Por isso que além de produzir uma previsão, eles também produzem um nível de certeza do resultado.</p>
<p>O Kriging é um dos métodos de interpolação geoestatístico que assume que a distância ou direção dos pontos reflete uma correlação espacial que pode ser usada para explicar a variação da superfície. A fórmula do Simple Kriging é semelhante a do IDW:</p>
\[\hat{Z}(s_0) = \sum_{i=1}^{N}\lambda_iZ(s_i)\]
<p>Sendo:
(s_0) a previsão para um local
(λ_i) o peso para alocalização (i)
(Z(s_i)) o valor da amosta na localização (i)
(N) o número de amostras</p>
<p>A diferença entre o Simple Kriging e o IDW é que o peso do IDW depende somente da distância para as amostras. Enquanto que o Simple Kriging considera a relação espacial com as amostras por meio de um varioagrama.</p>
<p>Os métodos Kriging são usados quando há uma correlação espacial nas amostras. O Kringing é um método de multi-etapas que serão discutidas a seguir.</p>
<h3 id="etapa-1-análise-dos-dados-de-entrada">Etapa 1: Análise dos dados de entrada</h3>
<p>Para isso iremos avaliar se os dados são distribuídos aleatoriamente ou se eles parecem agrupados com uma análise de padrões. Além disso eliminaremos os pontos que:</p>
<ul>
<li>as coordenadas são inválidas</li>
<li>os valores do fenômeno são indefinidos</li>
<li>são duplicados
Para o caso de uma amostra muito grande, o recomendado é dividir o conjunto de dados em duas partes: uma para interpolação e outra para verificação.</li>
</ul>
<h3 id="etapa-2-cálculo-da-variação-do-conjunto-de-dados">Etapa 2: Cálculo da variação do conjunto de dados</h3>
<p>Nesta etapa, são determinados os pontos de entrada que vão contribuir para o valor de saída, limitados pela distância limite previamente especificada e dependendo também do número mínimo e máximo de pontos. Neste caso, são ignorados os pontos de entrega que estão acima da distância limite e são calculadas as distâncias de cada amostra com o ponto a ser buscado.</p>
<h3 id="etapa-3-variação-e-variogramas">Etapa 3: Variação e variogramas</h3>
<p>Como a primeira lei da geografia de Tobler diz:</p>
<blockquote>
<p>“Everything is related to everything else, but near things are more related than distant things”</p>
</blockquote>
<p>Assim, para determinar a concentração de um fenômeno em um ponto, temos de modelar um variograma que leva em consideração essa lei. O primeiro passo para criar o variagrama é avaliar a distância entre todos os possíveis pares de amostras.</p>
<p><img src="https://gisgeography.com/wp-content/uploads/2016/10/semi-variogram-feature-2-678x322.png" alt="" /></p>
<p>A imagem acima exemplifica a distância ((h)) entre todas as amostras e uma amostra em específico. Tal passo deve ser repetido para cada uma das outras amostras, levantando a distância entre todos dois pontos possíveis.</p>
<p>Ao mesmo tempo, para cada dois pontos iremos calcular a variância desses dois pontos pela seguinte fórmula:</p>
\[Semivariância(h) = \sqrt{\sum_{i=0}^{N}(Z(s_i)-\overline{Z(s)})^{2}}\]
<p>Uma vez feito isso, plotamos então em um gráfico. Utilizamos o valor da semivariância calculado anteriormente como o eixo $X$ e a distância até o local que queremos determinar a amostra como o eixo $Y$. Tal gráfico é o variograma empírico:</p>
<p><img src="https://i.imgur.com/qlfvcRb.png" alt="" />
\(Semivariância(h) x Distância\)</p>
<h3 id="etapa-4-avaliação-de-tendência">Etapa 4: Avaliação de tendência</h3>
<p>Precisamos transformar nossos pontos em uma função. Muitas vezes, os pontos se encontram em uma distância única além disso a combinação de possibilidades pode ser muito grande. Nesses casos podemos considerar agrupar por grupos de distância, chamados de lag bins. Nessa situação, tiramos uma média de cada lag bin, indicado pelo símbolo de adição no gráfico abaixo. Então criamos um gráfico a partir dessas médias (indicado pela linha azul no gráfico abaixo). Esse é o semivariograma.</p>
<p><img src="https://i.imgur.com/iLndLwO.png" alt="" /></p>
<h3 id="etapa-5-modelar-variograma">Etapa 5: Modelar variograma</h3>
<p>Tendo o variograma empírico, temos que avaliar com qual modelo ele mais se assemelha. Esse processo é chamado de fitting. Fazemos isso para poder avaliar os pontos que as nossas amostras não contemplam. Nele analisaremos nosso variograma com cinco modelos que o Kringing provê:</p>
<ul>
<li>Circular</li>
<li>Spherical</li>
<li>Exponential</li>
<li>Gaussian</li>
<li>Linear</li>
</ul>
<p><img src="https://i.imgur.com/IoHwnFn.png" alt="" /></p>
<p><img src="https://i.imgur.com/uHAldUv.png" alt="" /></p>
<p>Ao encontrar qual modelo nossos dados se adequam melhor, utilizamos a fórmula que esse modelo provê para chegar até os pesos das amostras. Ao utilizar um desses modelos, levamos em consideração que nem todas as amostras de proximidades semelhantes tem o mesmo impacto no ponto que buscamos. Outro método da geoestatística, o IDW (Inverse Distance Weighing), assume que todos os pontos tem a mesma influência e essa seria a diferença entre os dois.</p>
<p>Cada fórmula possui três elementos principais: o Range, o Sill e o Nugget.O Range é a distância até que as amostras se tornam irrelevantes para o ponto estudado; no gráfico isso é representado como o momento em que o modelo não varia mais. O Sill é o valor da semivariância máxima que é atingida no momento em que o modelo não varia mais. O Nugget é o valor em que o modelo corta o eixo Y. Abaixo temos uma representação de cada um destes três elementos.</p>
<p><img src="https://gisgeography.com/wp-content/uploads/2016/10/Variogram-Nugget-Range-Sill.png" alt="" /></p>
<p>Tendo feito o fitting, utilizamos os valores do Range ((r)), do Sill ((\alpha)) e do Nugget ((C_0)) obtidos do modelos na fórmula. Agora resta apenas a distância ((h)) na fórmula. Faremos uma matriz de todas as possibilidades de relações de amostras e para cada distância, calcularemos o valor da semivariância. Resultando em uma matriz de semivariâncias, por exemplo:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">C11</span> <span class="n">C12</span> <span class="n">C13</span><span class="p">]</span> <span class="p">[</span><span class="mi">4</span> <span class="mf">1.1</span> <span class="mf">0.62</span><span class="p">]</span>
<span class="o">|</span><span class="n">C21</span> <span class="n">C22</span> <span class="n">C23</span><span class="o">|</span> <span class="o">=</span> <span class="o">|</span><span class="mf">1.1</span> <span class="mi">4</span> <span class="mf">0.62</span><span class="o">|</span>
<span class="p">[</span><span class="n">C31</span> <span class="n">C32</span> <span class="n">C33</span><span class="p">]</span> <span class="p">[</span><span class="mf">0.62</span> <span class="mf">0.62</span> <span class="mi">4</span> <span class="p">]</span>
</code></pre></div></div>
<p>Também é necessário criar uma matriz de semivariâncias de todas as amostras em relação ao ponto a ser obtido. Nesse caso, o valor da distância ((h)) na fórmula será a distância entre a amostra e o ponto a ser observado ((Z(0))), por exemplo:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">C10</span><span class="p">]</span> <span class="p">[</span><span class="mf">1.48</span><span class="p">]</span>
<span class="o">|</span><span class="n">C20</span><span class="o">|</span> <span class="o">=</span> <span class="o">|</span><span class="mf">1.48</span><span class="o">|</span>
<span class="p">[</span><span class="n">C30</span><span class="p">]</span> <span class="p">[</span><span class="mf">1.1</span> <span class="p">]</span>
</code></pre></div></div>
<p>Com essas matrizes, adicionamos mais uma linha e uma coluna na matriz entre as amostras para ser contabilizado como o erro e a invertemos. Em seguida, multiplicamos o resultado pela matriz de distâncias até o ponto a ser obtido ((Z(0))):</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">w1</span><span class="p">]</span> <span class="p">[</span><span class="mi">4</span> <span class="mf">1.1</span> <span class="mf">0.62</span> <span class="mi">1</span><span class="p">]</span><span class="o">-</span><span class="mi">1</span> <span class="p">[</span><span class="mf">1.48</span><span class="p">]</span> <span class="p">[</span> <span class="mf">0.353</span><span class="p">]</span>
<span class="o">|</span><span class="n">w2</span><span class="o">|</span> <span class="o">=</span> <span class="o">|</span><span class="mf">1.1</span> <span class="mi">4</span> <span class="mf">0.62</span> <span class="mi">1</span><span class="o">|</span> <span class="o">|</span><span class="mf">1.48</span><span class="o">|</span> <span class="o">=</span> <span class="o">|</span> <span class="mf">0.353</span><span class="o">|</span>
<span class="o">|</span><span class="n">w3</span><span class="o">|</span> <span class="o">|</span><span class="mf">0.62</span> <span class="mf">0.62</span> <span class="mi">4</span> <span class="mi">1</span><span class="o">|</span> <span class="o">|</span><span class="mf">1.1</span> <span class="o">|</span> <span class="o">|</span> <span class="mf">0.293</span><span class="o">|</span>
<span class="p">[</span><span class="n">λ</span> <span class="p">]</span> <span class="p">[</span><span class="mi">1</span> <span class="mi">1</span> <span class="mi">1</span> <span class="mi">0</span><span class="p">]</span> <span class="p">[</span><span class="mi">1</span> <span class="p">]</span> <span class="p">[</span><span class="o">-</span><span class="mf">0.505</span><span class="p">]</span>
</code></pre></div></div>
<p>O resultado são os pesos das amostras em relação ao ponto a ser obtido ((Z(0))). Com os pesos, utilizamos a fórmula do kriging, somamos a multiplicação dos peso pela concentração da amostra:</p>
\[\hat{Z}(s_0) = \sum_{i=1}^{N}\lambda_iZ(s_i)\]
<p>Ao fazer o somatório dos valores da multiplicação do peso com o valor da amostra em questão, obtemos o valor do local sem amostras. Após obter o resultado de um local, esse processo deve ser repetido para todo os pontos do mapa.</p>
<h3 id="exemplo">Exemplo</h3>
<p>Digamos que temos uma propriedade, que se extende por 5.5km de largura e comprimento, na qual queremos saber a melhor localidade para extração de ouro. Para tal, extraímos amostras de alguns lugares de nossa propriedade. Abaixo são indicadas as latitudes (x(i)), longitudes (y(i)) e a concentrações (Z(s_i)) encontradas:</p>
<table>
<thead>
<tr>
<th>Amostra $i$</th>
<th>$x(i)$</th>
<th>$y(i)$</th>
<th>$Z(s_i)$</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td>0.3</td>
<td>1.2</td>
<td>0.47</td>
</tr>
<tr>
<td>1</td>
<td>1.9</td>
<td>0.6</td>
<td>0.56</td>
</tr>
<tr>
<td>2</td>
<td>1.1</td>
<td>3.2</td>
<td>0.74</td>
</tr>
<tr>
<td>3</td>
<td>3.3</td>
<td>4.4</td>
<td>1.47</td>
</tr>
<tr>
<td>4</td>
<td>4.7</td>
<td>3.8</td>
<td>1.74</td>
</tr>
</tbody>
</table>
<p>Para determinar a maior concentração, utilizaremos a biblioteca PyKrige que realiza os cálculos do Kriging. Ela pode ser instalado no anaconda com o comando:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">pykrige</span>
</code></pre></div></div>
<p>Abaixo um simples exemplo de Ordinary Kringing.
Ele se inica com a criação de um array de amostras com a posição (X, Y) e o valor de concentração do fenômeno.</p>
<p>Logo em seguida é criado o grid em que serão exibidos os resultados. Tal grid é composto pelo eixo (X) e (Y) em que cada um possui um valor inicial, um final e um espaçamento entre cada ponto.</p>
<p>Na criação do Ordinary Kringing são passados todos os valores do eixo (X) das amostras, em seguida do eixo (Y) e por fim a concentração do fenômeno. Além desses parâmetros também é passado o tipo de modelo de variograma. Caso nenhum modelo seja passado, a biblioteca irá automaticamente tentar fazer o fitting dos dados em um modelo.</p>
<p>Após criado a variável Ordinary Kringing, executamos ele. O resultado é o grid de valores e a variância do grid.</p>
<p>Essa biblioteca também permite a execução de outros tipos de Kringing.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">pykrige.kriging_tools</span> <span class="k">as</span> <span class="n">kt</span>
<span class="kn">from</span> <span class="nn">pykrige.ok</span> <span class="kn">import</span> <span class="n">OrdinaryKriging</span>
<span class="c1"># array de amostras
</span><span class="n">amostras</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([[</span><span class="mf">0.3</span><span class="p">,</span> <span class="mf">1.2</span><span class="p">,</span> <span class="mf">0.47</span><span class="p">],</span>
<span class="p">[</span><span class="mf">1.9</span><span class="p">,</span> <span class="mf">0.6</span><span class="p">,</span> <span class="mf">0.56</span><span class="p">],</span>
<span class="p">[</span><span class="mf">1.1</span><span class="p">,</span> <span class="mf">3.2</span><span class="p">,</span> <span class="mf">0.74</span><span class="p">],</span>
<span class="p">[</span><span class="mf">3.3</span><span class="p">,</span> <span class="mf">4.4</span><span class="p">,</span> <span class="mf">1.47</span><span class="p">],</span>
<span class="p">[</span><span class="mf">4.7</span><span class="p">,</span> <span class="mf">3.8</span><span class="p">,</span> <span class="mf">1.74</span><span class="p">]])</span>
<span class="c1"># eixos grid com inicio, fim e espacamento
</span><span class="n">gridx</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">5.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">)</span>
<span class="n">gridy</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mf">0.0</span><span class="p">,</span> <span class="mf">5.5</span><span class="p">,</span> <span class="mf">0.5</span><span class="p">)</span>
<span class="c1"># Criação do Ordinary Kringing
</span><span class="n">OKringing</span> <span class="o">=</span> <span class="n">OrdinaryKriging</span><span class="p">(</span><span class="n">amostras</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">amostras</span><span class="p">[:,</span> <span class="mi">1</span><span class="p">],</span> <span class="n">amostras</span><span class="p">[:,</span> <span class="mi">2</span><span class="p">],</span> <span class="n">variogram_model</span><span class="o">=</span><span class="s">'linear'</span><span class="p">,</span>
<span class="n">verbose</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">enable_plotting</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="c1"># Executa o Kringing
</span><span class="n">z</span><span class="p">,</span> <span class="n">ss</span> <span class="o">=</span> <span class="n">OKringing</span><span class="p">.</span><span class="n">execute</span><span class="p">(</span><span class="s">'grid'</span><span class="p">,</span> <span class="n">gridx</span><span class="p">,</span> <span class="n">gridy</span><span class="p">)</span>
<span class="c1"># escreve o resultado em um arquivo
</span><span class="n">kt</span><span class="p">.</span><span class="n">write_asc_grid</span><span class="p">(</span><span class="n">gridx</span><span class="p">,</span> <span class="n">gridy</span><span class="p">,</span> <span class="n">z</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="s">"output.asc"</span><span class="p">)</span>
</code></pre></div></div>
<h3 id="resultado">Resultado</h3>
<p>Como observamos no resultado abaixo, a maior concentração de ouro na propriedade encontra-se no canto superior esquerdo:</p>
<p>latitude: 5.5 <br />
longitude: 4.5 <br />
concentração: 1.74</p>
<p>Os valores ao redor desse ponto também são os mais altos, sendo assim o melhor ponto para extração.</p>
<p><img src="https://i.imgur.com/YennQMk.png" alt="" /></p>
<h3 id="referências">Referências</h3>
<p>Bailey and Gatrell. Ordinary Kriging, Ch. 5.5. Michigan State University. pdf.</p>
<p>Monteiro, A. M. V., Câmara, G., Carvalho, M. S., & Druck, S. (2004). Análise espacial de dados geográficos. Brasília: Embrapa.</p>
<p>Royle, A. G., F. L. Clausen, and P. Frederiksen. “Practical Universal Kriging and Automatic Contouring.” Geoprocessing 1: 377–394. 1981</p>
<p>Tobler W., (1970) “A computer movie simulating urban growth in the Detroit region”. Economic Geography, 46(Supplement): 234–240.</p>
<p>http://desktop.arcgis.com/en/arcmap/10.3/tools/3d-analyst-toolbox/how-kriging-works.htm</p>
<p>https://gisgeography.com/semi-variogram-nugget-range-sill/</p>
<p>http://www.dpi.inpe.br/gilberto/tutorials/software/geoda/tutorials/w12_kriging_slides.pdf</p>
Cálculo Estocástico2019-10-05T11:15:00+00:00http://lamfo-unb.github.io/2019/10/05/Calculo-Estocastico<h2 id="cálculo-estocástico">Cálculo Estocástico</h2>
<p>O cálculo estocástico fornece uma teoria de integração a ser definida para integrais de processos estocásticos em relação a processos estocásticos. É a parte de cálculo dos processos estocásticos que consiste em um evento de interesse que se desenvolve no tempo de uma maneira que (pelo menos) uma componente do processo é aleatória. Portanto, trata-se de uma coleção de variáveis aleatórias indexadas pelo tempo. É usado para modelar sistemas e processos que se comportam aleatoriamente ao longo do tempo.</p>
<p>A maioria dos problemas reais são modelados utilizando processos estocásticos de tempo contínuo (a variável pode mudar o seu valor em qualquer momento de tempo) com variável contínua. Esse tipo de processo exige o uso do cálculo para a resolução de equações diferenciais estocásticas que modelam tais processos. Além disso, eles podem ser aproximados através de processos discretos, cuja modelagem é mais simples.</p>
<p>Existem diversos processos e vamos explorar os mais conhecidos e utilizados que irá desde o random walk até a aplicação de Itô na fórmula de Black and Scholes amplamente utilizada e conhecida em finanças. O post segue com a seguinte estrutura.</p>
<ul>
<li>
<p>Processo de markov;</p>
</li>
<li>
<p>Random walk;</p>
</li>
<li>
<p>Processo de Wiener;</p>
</li>
<li>
<p>Processo de Wiener Generalizado;</p>
</li>
<li>
<p>Lema e Cálculo de Itô;</p>
</li>
<li>
<p>Black and Scholes;</p>
</li>
<li>
<p>Aplicação e simulação dos Processos.</p>
</li>
</ul>
<h2 id="processo-de-markov">Processo de markov</h2>
<p>O Processo de Markov é um processo estocástico onde somente o valor atual da variável é relevante para predizer a evolução futura do processo (depende apenas de 1 momento já realizado). Valores históricos (caminho realizado) através do qual a variável atingiu o seu valor atual são irrelevantes para a determinação do seu valor futuro. Nesse modelo, assumimos que o preço atual de uma ação reflete todas as informações históricas bem como as expectativas a respeito do preço futuro desta ação.</p>
<p><strong>Definição:</strong> Um processo estocástico discreto é um processo de Markov se</p>
\[P(X_{t+1} = S / X_0, X_1, \cdots, X_t) = P(X_{t+1} = S /X_t)\]
<p>para todo \(t ≥ 0\) e \(S\).</p>
<p>Geralmente, o processo é totalmente descrito pela matriz de probabilidade de transição <strong>A</strong> que indica todas as probabilidades de sair de um estado i para j, em 1 passo. A partir da matriz <strong>A</strong> é possível calcular as probabilidades de transição em mais passos até a sua convergência no limite.</p>
<h2 id="random-walk">Random walk</h2>
<p>Random Walk é um processo de Markov em tempo discreto que tem incrementos independentes e estacionários na forma de:</p>
\[S_{t+1} = S_{t} + \epsilon_t\]
<p>no qual \(S_0= 0\), \(S_t\) é o valor da variável no tempo t e \(\epsilon_t\) é uma variável aleatória com probabilidade P(\(\epsilon_t\)= 1) = P(\(\epsilon_t\)= -1) = 0.5.</p>
<p>O Random Walk pode incluir um termo de crescimento/decrescimento, ou “drift”, que representa um crescimento/decrescimento de longo prazo. Sem o termo de drift, a melhor estimativa do próximo valor da variável \(S_{t+1}\) é o seu valor atual (markov), uma vez que o termo de erro é normalmente distribuído com média zero. Com o termo de drift os valores futuros da variável tendem a crescer de maneira proporcional a taxa de crescimento.</p>
<h2 id="processo-de-wiener-movimento-browniano">Processo de Wiener (Movimento Browniano)</h2>
<p>O processo de Wiener é um processo estocástico de tempo contínuo, chamado também de movimento browniano pela a sua relação com o processo físico observado por Robert Brown. É um processo de Lévy que ocorre frequentemente em matemática pura e aplicada, economia, finanças (Black and Scholes é baseado nesse conceito) e física.</p>
<p>Esse processo é um caso particular do processo markoviano no qual considera que a única informação necessária para determinar o estado futuro é o estado atual (não é necessário a memória do restante do processo), em que a distribuição é normal com média 0 e variância 1.</p>
<p>Além disso, um movimento browniano x é caracterizado pelas seguintes propriedades:</p>
<ul>
<li>\(P(x(0) = 0) = 1\);</li>
<li><strong>Estacionário</strong> Para todo \(0 \le s \le t, x(t) - x(s) \sim N(0, t-s)\);</li>
<li><strong>Incremento independente</strong> Se o intervalo \((S_i, t_i)\) não são sobrepostos, então \(x(t_i) - x(S_i)\) são independentes;</li>
<li>É um processo contínuo. Pode-se dizer que é um Random Walk com amostras infinitesimais;</li>
<li>Não é diferenciável (a prova pode ser encontrada em Choongbum Lee, MIT open course ware).</li>
</ul>
<h2 id="processo-de-wiener-generalizado">Processo de Wiener Generalizado</h2>
<p>A generalização do processo de Wiener ocorre quando se considera que a variação não é constante em delta z. No caso do processo simples, a taxa de variância é 1 e significa que a variância da mudança em z em um intervalo de tempo delta t é igual a delta t (constante para todas as diferenças). Portanto, para incorporar no processo, denotado agora por \(dz\), essa variabilidade é definida pela seguinte equação:</p>
\[dx = adt + bdz\]
<p>no qual \(a\) e \(b\) são constantes.</p>
<p>Para entender a equação é útil considerar os dois componentes no lado direito separadamente. O termo adt implica que \(x\) tem uma taxa de derivação esperada de a por unidade de tempo. Sem o termo \(bdz\) a equação é \(dx=adt\) que implica que \(\frac{dx}{dt}=a\). Integrando com relação ao tempo, obtemos: \(x=x_0+at\), onde \(x_0\) é o valor de \(x\) no tempo 0. Em um período de tempo de duração \(T\), a variável \(x\) aumenta na quantidade \(aT\). O termo \(bdz\) no lado direito da equação pode ser considerado como um ruído ou variabilidade no caminho seguido por \(x\). O nível desse ruído ou variabilidade é \(b\) vezes um processo de Wiener. Um processo de Wiener, por sua vez, tem uma taxa de variância por unidade de tempo 1. Logo, \(b\) vezes um processo de Wiener tem uma taxa de variância por unidade de tempo de \(b^2\).</p>
<p><img src="/img/mlg/processo_wiener.jpg" height="450" width="450" /></p>
<h2 id="lema-e-cálculo-de-itô">Lema e Cálculo de Itô</h2>
<p>O processo de Itô acontece quando a generalização do processo de Winer assume que os termos \(a\) e \(b\) da equação são funções do valor do ativo (x) e do tempo (t), fornecendo a seguinte fórmula:</p>
\[dx = a(x,t)dt + b(x,t)dz\]
<p>A taxa de derivação e a taxa de variância esperadas de um processo de Itô podem mudar com o tempo. Em um pequeno intervalo entre t e \(t + \Delta t\), a variável muda de \(x\) para \(x + \Delta x\), onde, \(\Delta x = a(x,t)\Delta t + b(x,t)\epsilon\sqrt{\Delta t}\).</p>
<p>Essa equação envolve uma pequena aproximação. Ela pressupõe que a taxa de derivação e de variância de \(x\) permanecem constantes, iguais a seus valores no tempo t, durante o intervalo de tempo entre \(t\) e \(t + \Delta t\).</p>
<p>O lema de Itô parte de uma expansão de Taylor para resolver o problema da não diferenciação (variação quadrática \(dx^2 = dt\)) do movimento Browniano para chegar em uma fórmula analítica. O lema de Itô para uma função qualquer G de x e t segue o processo:</p>
<p>\(dG = (\frac{dG}{dx}+\frac{dG}{dt}+\frac{1}{2}\frac{d^2G}{dx^2}b^2)dt + \frac{dG}{dx}bdz\),</p>
<p>No qual \(dz\) é o mesmo processo de Wiener que na equação. Assim, G também segue um processo de Itô, com taxa de derivação de: \(\frac{dG}{dx}a+\frac{dG}{dt}+\frac{1}{2}\frac{d^2G}{dx^2}b^2)dt\). E a taxa de variância de: \({\frac{dG}{dx}}^2 b^2\).</p>
<p>A partir desse lema de Itô que o modelo Black and Scholes é elaborado, mostrando a relação entre preço do ativo, taxa livre de risco, volatilidade e suas gregas.</p>
<h2 id="black-and-scholes">Black and Scholes</h2>
<p>O modelo de Black and Scholes surgiu na década de 70 e até hoje é utilizado como modelo padrão para precificação de opções. Ele foi feito para opções europeias seja compra (call) europeias com tempo contratado definido (fixo) e considera que a taxa de juros livre de risco (Taxa Selic) seja constante e conhecida e o preço segue um movimento Browniano geométrico com tendência e volatilidade constantes, sua fórmula é dada por:</p>
\[dS(t) = \mu Sdt + \sigma SdW(t)\]
<p>No qual \(S(t)\) é valor do ativo subjacente no tempo \(t, \mu\) é a tendência, \(\sigma\) é a volatilidade (constante) de \(S\) e \(dW(t)\) é processo estocástico em relação ao ativo \(S\).</p>
<p>Portanto, é uma aplicação que possui as características de um processo de Itô.</p>
<p>A partir da fórmula de black and Scholes é possível chegar nas seguintes fórmulas de Call e Put para as opções:</p>
<p>\(C(S,t) = SN(d_1) - K e^{-r(T-1)} N(d_2)\)
\(P(S,t) = X e^{-r(T-1)}N(-d_2) - SN(-d_1)\)
\(d_1 = \frac{ln(\frac{S}{K})+(r+\frac{\sigma^2}{2})(T-t)}{\sigma\sqrt{(T-t)}}\)
\(d_2 = d_1 - \sigma\sqrt{(T-t)}\)</p>
<p>No qual \(K\) é o preço de exercício da opção (Strike) e N(.) é a distribuição normal acumulada padronizada.</p>
<p>A partir da equação de Black and Scholes é possível calcular as gregas, que são as derivadas parciais em relação ao preço, volatilidade, tempo e a taxa livre de risco. A interpretabilidade de cada grega é:</p>
<ul>
<li>Delta (derivada no preço): o quanto o preço da opção irá se alterar conforme o preço do ativo subjacente altera;</li>
<li>Gamma (segunda derivada no preço, aceleração): a velocidade de mudança do Delta;</li>
<li>Theta (derivada no tempo): sensibilidade do preço da opção conforme o tempo passa ao longo dos dias;</li>
<li>Vega (derivada na volatilidade): como o preço da opção se move dado o tamanho da volatilidade do ativo;</li>
<li>Rho (derivada na taxa livre de risco): mudanças na taxa de juros livre de risco.</li>
</ul>
<p><img src="/img/mlg/estrutura_processos.png" height="350" width="850" /></p>
<h2 id="análise-e-simulação-de-dados">Análise e simulação de dados</h2>
<p>Para a análise foi utilizado apenas simulações de dados, uma vez que estamos estudando os processos teóricos é pertinente observar as caracteristicas mencionadas de cada um. Para estimar o valor da opção e das gregas pelo Black and Scholes foram utilizados valores arbitrários mas que representam a realidade, para expandir o uso para determinado ativo real basta substituir os valores pelos valores do próprio ativo de interesse.</p>
<p>O software R de computação estatística foi utilizado.</p>
<p>O primeiro processo simulado é a cadeia de markov. Foi criado uma matriz com 3 estados, chamados de estados 1, 2 e 3. São colocados os valores de transição entre cada zona de forma que a matriz mc_zona indica na linha os estados iniciais e as colunas os estados finais com as probabilidades de transição de um passo ao longo da matriz.</p>
<p>Para calcular a transição a nível de 2 passos, basta elevar a matriz ao quadrado, ou seja, sair de determinado estado e ir para outro estado em 2 movimentos. Para os demais passos basta repetir o processo.</p>
<p>A última matriz gerada são os valores de convergência dos estados, ou seja, no limite (depois de muito tempo) qual a probabilidade de estar em cada estado independente do estado de partida. Assim, pelo exemplo o primeiro estado é o mais provável com 38,8% e o terceiro o menos provável com 27,7%.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># cadeias de markov
library(markovchain)
zona <- c("1","2","3")
zona_transicao <- matrix(c(0.3,0.3,0.4,0.4,0.4,0.2,0.5,0.3,0.2),nrow = 3, byrow = T)
dimnames(zona_transicao) <- list(zona,zona)
zona_transicao
mc_zona <- new('markovchain',
transitionMatrix = zona_transicao, # These are the transition probabilities of a random industry
states = zona, byrow=T)
# Matriz de transição em 1 passo
mc_zona
# 2 passos
mc_zona^2
# Convergência dos estados, estado inicial não interessa mais
steadyStates(mc_zona)
</code></pre></div></div>
<p><img src="/img/mlg/matriz1.JPG" height="150" width="150" /></p>
<p><img src="/img/mlg/matriz2.JPG" height="250" width="450" /></p>
<p><img src="/img/mlg/matriz3.JPG" height="250" width="450" /></p>
<p><img src="/img/mlg/matriz4.JPG" height="100" width="250" /></p>
<p>Para simular o random walk, foi gerado a partir da simulação do modelo ARIMA (um modelo famoso que possui componentes autorregressivas e de médias moveis) com 0 componentes autorregressivas e 0 componentes de médias móveis (parâmetros no order), ou seja, é um ARIMA apenas com o termo aleatório. Ao simular o processo, verificamos o caminhar aleatório do processo para valores negativos mas sempre com movimentos de alta para se aproximar de zero, cada observação é um novo ruído branco. Além disso, ao observarmos a primeira observação parte do valor 0, indicando que está centralizado o processo. Portanto, é um passeio aleatório.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Passeio aleátorio
# sem média e variância especificados
# forte dependência no tempo
# incrementos são ruído branco
set.seed(10)
rw <- arima.sim(model=list(order=c(0,1,0)),n=500)
head(rw)
ts.plot(rw, main="Random Walk (Passeio aleatório)")
</code></pre></div></div>
<p><img src="/img/mlg/rw1.JPG" height="50" width="500" /></p>
<p><img src="/img/mlg/rw2.JPG" height="450" width="450" /></p>
<p>Para simular o movimento browniano foi gerado a partir da distribuição normal padrão (N(0,1)) 10.000 observações e somado seus valores ao longo do processo.</p>
<p>Novamente é observado o caminho aleatório do processo alternando entre valores positivos e negativos. Portanto, pelo gráfico verifica-se que é estacionário e como cada observação foi gerado de uma normal de forma independente, seus incrementos são independentes. Pelo gráfico, verificasse maior granularidade do que Random Walk (amostras infinitesimais).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Movimento Browniano
set.seed(10)
dis = rnorm(10000, 0, 1); # Normal!
dis = cumsum(dis);
plot(dis, type= "l",main= "Movimento Browniano", xlab="Tempo", ylab="Valor")
</code></pre></div></div>
<p><img src="/img/mlg/mb.JPG" height="450" width="450" /></p>
<p>É possível fazer o mesmo processo utilizando o comando rwiener que gera valores aleatórios do processo. Dessa forma, segue novamente o processo mas com um código alternativo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Movimento Wiener
library(e1071)
set.seed(10)
wiener <- rwiener(end = 1, frequency = 1000)
# end = tempo da última observação
# frequency = número de observações por unidade de tempo.
# Exatamente por ser tempo contínuo é declarado o intervalo final
plot(wiener,type="l",main= "Movimento Wiener", xlab="Tempo", ylab="Valor")
</code></pre></div></div>
<p><img src="/img/mlg/mw.JPG" height="450" width="450" /></p>
<p>Para finalizar, será calculado o preço de uma opção e de sua grega pelo Black and Scholes que resume tudo o que foi abordado nesse post, o uso desses processos em finanças é muito grande mas não se resume a essa área.</p>
<p>Para calcular o preço de determinada opção de um ativo qualquer, pode ser usado o comando GBSOption, no qual é necessário informar se é uma opção de compra (‘c’) ou venda (‘p’), o valor do ativo no momento (S), o valor do strike (‘X’), o tempo para expirar em anos a opção (‘Time’), a taxa livre de risco (‘r’), a taxa de dividendos paga (‘b’) e a volatilidade do ativo (‘sigma’).</p>
<p>Nesse exemplo, foram passados valores próximos aos de mercado mas sem nenhum ativo em particular, para utilizar a mesma função para um ativo como PETR4 basta mudar os valores para os valores do ativo.</p>
<p>Dessa forma, a função retorna o valor de compra segundo Black and Scholes, para esses valores de input o valor é R$0,11, ou seja, a partir disso pode-se verificar se o mercado está precificando a opção conforme Black and Scholes ou se está sobreprecificando ou subprecificando, podendo ser o início de uma estratégia.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Black and Scholes
library(fOptions)
GBSOption(TypeFlag = "c", S = 100, X = 110,
Time = 10/252, r = 6.5,
b = 0, sigma = 0.3)
</code></pre></div></div>
<p><img src="/img/mlg/bs1.JPG" height="450" width="550" /></p>
<p>Da mesma forma que a função anterior calculava o preço da opção, a função GBSGreeks calcula as gregas de Black and Scholes. Além dos parâmetros já informados anteriormente, é necessário dizer qual grega é de interesse podendo ser o “delta”, “gamma”, “vega”, “theta” ou “rho”.</p>
<p>Nesse exemplo, ao calcularmos a grega delta obtemos o valor de 0,04, ou seja, a probabilidade de exercício dessa opção com essas características é de apenas 4%.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GBSGreeks(Selection = "delta", TypeFlag = "c", S = 100,
X = 110,
Time = 10/252, r = 6.5, b = 0,
sigma = 0.3)
</code></pre></div></div>
<p><img src="/img/mlg/bs2.JPG" height="50" width="150" /></p>
<h2 id="referências">Referências</h2>
<p>Elementary Stochastic Calculus with Finance in View. Mikosch, Thomas. University of Copenhagen. World Scientific Publishing.</p>
<p>John C Hull.Opções, futuros e outros derivativos. Bookman, 9oedition, 2016.Tradução: Francisco Araújo da Costa ; revisão técnica: Guilherme Ribeiro de Macêdo.</p>
<p>Apresentação Opções reais. Prof. Luiz Brandão, IAG PUC-Rio, brandao@iag.puc-rio.br</p>
<p>MIT open course ware. Choongbum Lee. Lectures 5,17,18. https://ocw.mit.edu/courses/mathematics/18-s096-topics-in-mathematics-with-applications-in-finance-fall-2013/video-lectures/</p>
Dados em Painel2019-09-11T21:12:39+00:00http://lamfo-unb.github.io/2019/09/11/Dados em painel<h1 id="dados-em-painel">Dados em Painel</h1>
<p>Nada é por acaso. As coisas acontecem em seu próprio contexto e por algum motivo em seu próprio tempo-espaço. A inferência estatística e a econometria são humildes ferramentas que buscam descobrir causalidade. Por exemplo, A causa B? B causa A? Os dois? Ou será que não são correlacionados? Ou será que foi uma coincidência engraçada? Para descobrir a veracidade de uma hipótese (no caso A causa B), precisamos de dados. Falaremos de um tipo específico de dados que são os dados em painel.</p>
<p><strong>O que são?</strong></p>
<p>Dados em painel são úteis e sua aplicabilidade é ubíqua. Possuem funcionalidade em diferentes áreas desde as ciências políticas, economia, finanças, políticas públicas, até casos como as relações internacionais, em campos como de ajuda humanitária. No entanto, é importante frisar que o seu uso é algo simples. Dados em painel são dados nos quais temos <em>algumas</em> observações de indivíduos $i$ e os acompanhamos <em>por um período de tempo</em> $t$.</p>
<p><strong>O que não são?</strong></p>
<p>Isso os diferencia dos dados <em>cross-section</em>, pois esse coleta as observações de um único período de tempo. Com base nisso, podemos dizer que um dado <em>cross-section</em> é um dado em painel com $t = 1$. Por sua vez, diferem também das séries de tempo, os quais se coleta variáveis para apenas um indivíduo (ou país, ou entidade, ou empresa…). Podemos dizer que séries de tempo são dados em painel com a $quantidade \quad de \quad indivíduos = $1$.</p>
<p><strong>Vantagens dos Dados em Painel</strong></p>
<p>As vantagens dos dados em painel são de acordo com Hsiao (2005), as seguintes:</p>
<ol>
<li>
<p>Melhor acurácia para inferência de parâmetros. Uma vez que dados em painel tendem a ter mais graus de liberdade e menos multi-colinearidade que as suas contrapartidas cross-section.</p>
</li>
<li>
<p>Maior capacidade em capturar a complexidade do comportamento humano que uma série de tempo ou um cross-section:</p>
</li>
</ol>
<ul>
<li>
<p>Permite modelar aspectos comportamentais mais complexos. Por exemplo, investigando os efeitos de políticas públicas quanto ao antes e depois.</p>
</li>
<li>
<p>Controlar o efeito das variáveis omitidas. O que discutiremos posteiormente.</p>
</li>
<li>
<p>Desvelar relações dinâmicas entre as variáveis. Assim, podemos analisar como causas passadas podem influenciar o presente por meio de defasagens.</p>
</li>
<li>
<p>Gerar maior acurácia, uma vez que podemos comparar os comportamentos dos agentes com de outros ao longo do tempo, dado circunstâncias semelhantes.</p>
</li>
<li>
<p>Permite estimar agentes heterogêneos. Dessa forma, no lugar de invocarmos a hipótese do “agente representativo”, podemos realizar análises levando em conta a individualidade e heterogeneidade das observações.</p>
</li>
</ul>
<ol>
<li>Simplifica a computação e a inferência estatística:</li>
</ol>
<ul>
<li>
<p>Análise de séries não estacionárias. Não estacionariedade implica que a série não converge para uma média, mas que ela varia ao longo do tempo, assim a distribuição não se mantém normal. O que pode ser tratado se temos dados em painel.</p>
</li>
<li>
<p>Erros de medida. Dados de múltiplos indivíduos ou tempos diferentes permitem identificação de modelos mais precisa.</p>
</li>
</ul>
<p><strong>Motivação no uso de Dados em Painel</strong></p>
<p>Analisemos os dados em painel e coloquemos em prática os modelos utilizados para tomar proveito desse formato de dado.</p>
<p>Imagine-se em uma posição de autoridade, decidindo o futuro do país e preocupado com a segurança da população. Criminalidade é o seu inimigo declarado e você quer controlá-lo. Como as pessoas reagem a incentivos (Mankiw, 2014), supõe-se que mudando as regras do jogo, seja reduzido as taxas de criminalidade. Todavia, cada passo dado pelas autoridades geram grandes impactos. O líder deverá proceder com cautela em suas declarações e formulações de políticas públicas, estudando vigorosamente o passado e antevendo o futuro o máximo possível.</p>
<p>Para atacar esse problema, usaremos como base os dados provenientes de Cornwell e Trumbull (1994) e também de Wooldridge (2016), com a intenção de descobrir o que afeta a criminalidade de uma região.</p>
<p>Em termos de pacotes dentro da linguagem Python e R, os principais seriam o linear models e o plm (panel linear models), respectivamente. No primeiro, pode-se criar uma análise em painel de dados a partir do pacote mencionado em associação ao numpy e ao pandas.</p>
<p>O pacote plm é o mais comumente usado para atividades de dados em painel na linguagem R. No exemplo desse trabalho, associar-se-á o plm ao readr e ao stargazer. O último é empregado para ter uma característica de maior adequação dos resultados das regressões (Hlavac, 2018).</p>
<p>```{r include = FALSE}
#Primeiramente abrimos algumas bibliotecas que serão úteis
library(plm) #biblioteca de dados em painel
library(readxl) #biblioteca de leitura de xls
library(stargazer) #biblioteca de visualização de tabelas</p>
<p>setwd(“~/LAMFO/Crime”) #Escolhemos o diretório onde colocamos os dados
crime4 <- read_excel(“crime4.xls”)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>```{r include = FALSE, echo = FALSE, message = FALSE, warning = FALSE}
#nomeamos as variáveis
names(crime4) <- c("county", "year", "crmrte", "prbarr", "prbconv", "prbpris", "avgsen", "polpc", "density", "taxpc", "west", "central", "urban", "pctmin80", "wcon", "wtuc",
"wtrd", "wfir", "wser", "wmfg", "wfed", "wsta", "wloc", "mix", "pctymle", "d82", "d83", "d84", "d85", "d86", "d87", "lcrmrte", "lprbarr", "lprbconv", "lprbpris", "lavgsen", "lpolpc", "ldensity", "ltaxpc", "lwcon",
"lwtuc", "lwtrd", "lwfir", "lwser", "lwmfg", "lwfed", "lwsta", "lwloc", "lmix", "lpctymle", "lpctmin", "clcrmrte", "clprbarr", "clprbcon", "clprbpri", "clavgsen", "clpolpc", "cltaxpc", "clmix" )
</code></pre></div></div>
<p>Exploraremos as mesmas variáveis usadas pelos autores. No caso, seria: <strong>lcrmrte</strong> = log do crimes por pessoa, <strong>lprbarr</strong>= log da probabilidade de ser preso, <strong>lprbcon</strong>= log da probabilidade de condenação, <strong>lprbpri</strong>= log da probabilidade de prisão, <strong>lavgsen</strong>= log da duração da sentença média em dias, <strong>lpolpc</strong>= log de policiais per capita, <strong>county</strong> = município, <strong>year</strong> = ano. Usamos as variáveis em log para estimar efeitos em percentuais</p>
<p>Dessa forma, nosso objetivo é explicar a criminalidade (na verdade, estaremos estimando o log do clcrmrte, que é lclcrmrte) de diferentes formas. A variável a ser explicada é a dependente ($Y$) e as independentes a serem usadas para explicar, ou seja, que supomos ser correlacionadas se chamam variáves explicativas ($X_1$, …,$X_k$).</p>
<h1 id="regressão-agrupoada-pooling-regression">Regressão Agrupoada (Pooling Regression)</h1>
<p>O modelo mais simples que se pode usar em dados em painel é a regressão <em>pooling</em>. Basicamente, consiste no empilhamento dos dados e a estimação do MQO. Ademais, essa é a regressão que ignora a colinearidade temporal e considera cada observação de tempo e país como independentes para derivar uma relação linear entre as variáveis explicativas $X_1, \dots, X_k$ e a variável dependente $Y$. Como temos as observações para tempos diferentes ($t$) e indivíduos diferentes ($i$), adicionamos os respectivos subscriptos nas variáveis explicativas e na variável dependente.</p>
<p>\(Y_{it} = \beta_0 + \beta_1X_{1it} + ... \beta_kX_{kit} + u_i\)
O objetivo é estimar os valores dos $\beta_1, …,\beta_k$, os quais representam o efeito das variáveis $X_1,…,X_k$. Como esperamos uma aleatoriedade dessa relação, colocamos um termo de erro $u_i$ que indica o desvio da nossa observação para o nosso modelo predito pelos betas estimados e as variáveis dependentes.</p>
<p>Então, de forma simples, o modelo pooled consiste em empilhar os dados e estimá-los por meio de Mínimos Quadrados Ordinários. A suposição chave é a de que não existem atributos únicos a cada indivíduo (ou, pra nós, para cada município) e nem efeitos que mudam ao longo do tempo. O método dos mínimos quadrados ordinários é uma forma de estimar os parâmetros de cada $\beta$ de forma que o erro seja o mínimo possível de acordo com algum critério. Nesse caso, o erro quadrado seja o mínimo.</p>
<p>Em suma, é computacionalmente estimado da seguinte forma.</p>
<p>```{r results = ‘asis’}
library(plm) #Library para regressão em dados de painel</p>
<p>p1 <- plm(lcrmrte ~ lprbarr + lprbconv + lprbpris + lavgsen + lpolpc, model = “pooling”, index = c(“county”, “year”), data = crime4) #Função para especificar a regressão
#Note que é necessário indicar no index um vetor de variáveis de identidade e de tempo.</p>
<p>stargazer::stargazer(p1, header=FALSE, type=’html’) #Comando para revelar a tabela</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
A interpretação é a seguinte: o aumento de 1% na probabilidade de ser pego (lprbarr) diminui 0.721% a criminalidade (lcrmrte), mantendo todos os outros fatores constantes. O argumento é análogo para as outras variáveis que são por exemplo, um aumento de 1% na probabilidade de sentença de prisão (lprbpris) aumenta a criminalidade em 0.389%.
Costumamos dar crédito ao efeito dessas variáveis se seu p-valor é menor que 0.05, ou equivalentemente, se há 2 asteriscos no número. Quanto mais asteriscos, maior significância, no caso do efeito da probabilidade de prisão (lpolpc) há 3 asteríscos, então seu p-valor é menor que 0.01. Isso quer dizer que em no máximo 1\% das vezes nós estaríamos errado em dizer que *mais policiais implicam em mais criminalidade*.
Cremos ter uma anomalia na análise.
Como pode ser que maior chance de cadeia induz as pessoas a cometer mais crimes? É nesse momento que percebemos que em econometria, não podemos só contar com os números e as técnicas, mas precisamos conhecer o caso que estamos analizando.
Uma hipótese é de que municípios que sofrem com mais criminalidade podem ter equipes mais bem preparadas para prender os criminosos. Veja que a causalidade está do lado contrário!
Voltando a sua posição de realizador de políticas públicas. No que acreditar? Nos números ou na sua intuição? Você deve decidir se devemos melhorar os nossos mecanismos de aprisionamento ou não. Vemos que é necessário conhecer várias técnicas e discernir a adequada para cada momento.
# Efeitos Fixos (Modelo Within)
Uma preocupação que existe nesse modelo é o viés de variável omitida. Quiçá exista variáveis que são necessárias para explicar o modelo, mas não especificamos na equação. Caso tais variáveis sejam únicas a cada indivíduo/município e não mudem ao longo do tempo, podemos eliminá-lo com a seguinte técnica.
No nosso caso, podemos estar preocupados com o fato de características geográficas, culturais,como proximidade de áreas metropolitanas, poder local de organizações criminosas, câmeras de segurança. No final, você só quer não quer se preocupar com essas coisas e só quer responder uma pergunta: devo ou não melhorar o nosso sistema?
A boa notícia é que podemos isolar esses efeitos de nossa equação usando o modelo de efeitos fixos ou também conhecido como *within estimator*. Comecemos adicionando ao modelo variáveis que explicam o valor de $Y$ variáveis dummies que identificam cada indivíduo. Nós o chamaremos de $\alpha_i$. Cada um dos nossos $\alpha_i$ funciona como um intercepto para cada observação, então não é necessário incluí-lo.
$$ Y_{i t}= \beta_{1} X_{1i t} + ... + \beta_kX_{kit} +\alpha_{i}+u_{i t} $$
O segundo passo é formar uma regressão com base na média da relação entre as variáveis explicativas e a variável dependente ao longo do tempo. Veja que obviamente as dummies de identificação $\alpha_i$ permanecem inalteradas (o qual justifica chamá-lo de efeito fixo).
$$ \overline{Y}_i = \beta_1\overline{X}_{1i} + ... + \beta_k\overline{X}_{ki} + \alpha_i + \overline{u}_i $$
Então a mágica acontece. Subtraímos a média da variável explicativa ($\overline{Y}_i$) para cada observação. Faremos o mesmo nas variáveis dependentes.
$$ Y_{i} - \overline{Y}_{i} = \beta_1(X_{1it}-\overline{X}_{1i}) + ... + \beta_k(X_{kit} - \overline{X}_{ki}) + (u_{it}-\overline{u_i}) $$
Como os efeitos fixos sumiram, nós rearranjamos a equação acima para uma notação mais concisa:
$$ \tilde{Y}_i = \beta_1\tilde{X}_{1i} + ... + \beta_k\tilde{X}_{ki} + \tilde{u}_i $$
Na prática, a biblioteca faz isso diretamente para nós, bastando especificar o índice de identidade (county) e de tempo (year) na especificação. No nosso caso, queremos estimar os seguintes betas:
$$ \tilde{lcrmrte}_i = \beta_1\tilde{lprbarr}_{i} + \beta_2\tilde{lprbconv}_{i} +\beta_3\tilde{lprbpri}_{i} +\beta_4\tilde{lavgsen}_{i} +\beta_5\tilde{lpolpc}_{i} + \tilde{u}_i $$
Computacionalmente, o pacote plm faz isso para nós.
```{r p2, results='asis'}
library(plm)
p2 <- plm(lcrmrte ~ lprbarr + lprbconv + lprbpris + lavgsen + lpolpc, model = "within", index = c("county", "year"),data = crime4) # Especificação do modelo de efeito fixo
stargazer::stargazer(p2, header=FALSE, type='html') # Gerar a tabela
</code></pre></div></div>
<p>A interpretação é análoga. Variação percentual na variável explicativa afeta a variável dependente em tal grau positivamente ou negativamente. Todavia, podemos afirmar menos ruído devido às características peculiares dos municípios e, assim, concentrarmos apenas naquelas que estamos nos preocupando e mudam ao longo do tempo.</p>
<h1 id="efeitos-aleatórios">Efeitos Aleatórios</h1>
<p>As vantagens desse próximo modelo são que os betas estimados mostram-se mais eficientes, ou seja, que há menor variância e portanto, mais certeza de que o estimador está próximo do valor real (dado que não é viesado). Todavia, temos que supor que os as covariâncias entre as dummies de identidade e as variáveis explicativas deve ser zero. Ou seja, $Cov(X_{itj}, \alpha_i) = 0, t=1,2, …, T; j = 1,2, …, k.$ Caso contrário, existe grande endogeneidade nas nossas variáveis e, nesse caso, devemos usar os efeitos fixos.</p>
<p>Quanto a forma funcional supomos a mesma que os efeitos fixos, mas com o intercepto $\beta_0$.</p>
\[Y_{i t}= \beta_0 + \beta_{1} X_{it1} + ... + \beta_kX_{itk} +\alpha_{i}+u_{i t}\]
<p>Em seguida, vamos colocar os efeitos fixos $\alpha_i$ no termo de erro. O novo termo tornando-se $v_{it}$ = $\alpha_i$ + $u_{it}$.</p>
\[Y_{i t}=\beta_{0}+\beta_{1} X_{i t 1}+\ldots+\beta_{k} X_{i t k}+v_{i t}\]
<p>Pela suposição acima, temos que $v_{it}$ é correlacionado com $v_{is}$ pra quaisquer períodos de tempo $t$ e $s$, ou seja, existe uma dependência temporal do valor do erro no passado e o erro atual por meio dessa expressão, o qual $\sigma_{a}^{2}$ é a variância dos efeitos fixos $a_i$ e $\sigma_{u}^{2}$ é a variância do erro $u_{it}$.</p>
\[\operatorname{Corr}\left(v_{i t}, v_{i s}\right)=\sigma_{a}^{2} /\left(\sigma_{a}^{2}+\sigma_{u}^{2}\right), \quad t \neq s\]
<p>O que é um problema, pois necessitamos que os erros do momento sejam não correlacionados com o de tempos diferentes. Para eliminarmos essa correlação, definimos um coeficiente teta tal que está entre [0,1]:</p>
\[\theta=1-\left[\sigma_{u}^{2} /\left(\sigma_{u}^{2}+T \sigma_{a}^{2}\right)\right]^{1 / 2}\]
<p>Multiplicando esse por todos os termos da equação
\(\begin{aligned}\theta \bar{Y}_{i}=& \beta_{0}\theta+\beta_{1}\theta \bar{X}_{i 1}+\ldots+\beta_{k}\theta \bar{x}_{i k}+\theta \bar{v}_{i}\end{aligned}\)</p>
<p>E então fazemos um procedimento semelhante ao dos efeitos fixos, mas subtraindo a média penalizada pela constante teta. Finalmente temos o modelo de efeitos aleatórios o qual é denotado abaixo.</p>
\[\begin{aligned} Y_{i t}-\theta \bar{Y}_{i}=& \beta_{0}(1-\theta)+\beta_{1}\left(X_{i t 1}-\theta \bar{X}_{i 1}\right)+\ldots \\ &+\beta_{k}\left(X_{i k}-\theta \bar{X}_{i k}\right)+\left(v_{i t}-\theta \bar{v}_{i}\right) \end{aligned}\]
<p>Interessante notar que nos casos extremos que $\theta = 0$, a equação torna-se uma regressão pooled (erros de anos diferentes estão totalmente correlacionados) e torna-se um modelo de efeitos fixos quando $\theta = 1$ (erros de anos diferentes não são correlacionados). Vamos reescrever a situação acima usando o suscrito.</p>
<p>\(\begin{aligned}\ddot{Y}_{i}=& \beta_{0}+\beta_{1} \ddot{X}_{i 1}+\ldots+\beta_{k} \ddot{X}_{i k}+ \ddot{v}_{i}\end{aligned}\)
E assim a equação que queremos estimar se torna</p>
\[\ddot{lcrmrte}_i = \beta_1\ddot{lprbarr}_{i} + \beta_2\ddot{lprbconv}_{i} +\beta_3\ddot{lprbpri}_{i} +\beta_4\ddot{lavgsen}_{i} +\beta_5\ddot{lpolpc}_{i} + \ddot{v}_i\]
<p>Estimamos o modelo computacionalmente:</p>
<p>```{r p3, results=’asis’}
library(plm)</p>
<p>p3 <- plm(lcrmrte ~ lprbarr + lprbconv + lprbpris + lavgsen + lpolpc, index = c(“county”, “year”), model = “random”,
data = crime4)</p>
<p>stargazer::stargazer(p3, header=FALSE, type=’html’)</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
As interpretações dos interceptos é idêntica.
# Pooled VS Fixed VS Random
Podemos comparar o resultado das 3 estimações abaixo. Neste caso, muitas estimações tiveram magnitudes semelhantes, mas modelos usados equivocadamente podem nos dar conclusões errôneas. Vale lembrar que uma forma de ver a robustez de algum coeficiente é ver se sua significância, magnitude e sinal são parecidos em modelos diferentes, mas não é uma condição *sine qua non*. Muitas vezes certos modelos não são apropriados para dada situação.
```{r results='asis'}
library(plm)
p1 <- plm(lcrmrte ~ lprbarr + lprbconv + lprbpris + lavgsen + lpolpc, model = "pooling", index = c("county", "year"), data = crime4) #
p2 <- plm(lcrmrte ~ lprbarr + lprbconv + lprbpris + lavgsen + lpolpc, model = "within", index = c("county", "year"),data = crime4)
p3 <- plm(lcrmrte ~ lprbarr + lprbconv + lprbpris + lavgsen + lpolpc, index = c("county", "year"), model = "random",
data = crime4)
stargazer::stargazer(p1, p2, p3, header = FALSE, type = 'html')
</code></pre></div></div>
<p>Em suma, cada um dos modelos é adequado para alguma situação diferente. A grande questão é a forma como pensamos nossos dados. Devemos explorar o jogo de causalidades tendo em vista as limitações de cada modelo.</p>
<p>Caso nossa teoria não tenha nenhuma objeção em acreditar que há variável omitida, podemos usar a regressão agrupada sem problemas. Caso acreditemos que há variável omitida, existe um teste que nos auxilia para a escolha entre efeitos fixos e efeitos aleatórios que é o teste de Hausman.</p>
<p>Em essência, o teste de (especificação de) Hausman testa se a covariância entre as dummies de identificação e as variáveis explicativas são correlacionadas ou não. $Cov(\alpha_i, X_{it}) = 0$ ou não.</p>
<p>Em caso de covariância zero, que é a nossa hipótese nula, os betas de efeitos fixos e efeitos aleatórios são consistentes, ou seja, quando as observações são suficientemente numerosas, os estimadores são suficientemente próximos dos valores reais e os betas de efeitos aleatórios são mais eficientes que os de efeitos fixos. Em caso de covariância diferente de zero, somente os coeficientes dos efeitos fixos são consistentes.</p>
<p>Resumidamente, se o teste de Hausman nos der $Cov(\alpha_i, X_{it}) = 0$, efeitos aleatórios. Caso contrário, efeitos fixos.</p>
<p>Computacionalmente:</p>
<pre><code class="language-{r}">phtest(p2,p3)
</code></pre>
<p>Como o p-valor é menor do que 0.05, nós rejeitamos a hipótese nula. Dessa forma, dizemos que o modelo de efeitos fixos é o adequado para o modelo.</p>
<p>Sua conclusão é que nós devemos sim aumentar o policiamento do nosso município, que técnicas tem que ser combinadas com o conhecimento da situação e que causalidade é muito mais difícil e muito mais divertido do que você imaginou. Mais uma vez, o dia foi salvo graças à você.</p>
<h1 id="bibliografia">Bibliografia</h1>
<ul>
<li>
<p>Hlavac, Marek. Stargazer:
beautiful LATEX, HTML and ASCII tables from R statistical output.(2018). Available in: https://cran.r-project.org/web/packages/stargazer/vignettes/stargazer.pdf.</p>
</li>
<li>
<p>Hsiao, C. (2005). Why Panel Data ? (September).</p>
</li>
<li>
<p>Cornwell, C., & Trumbull, W. N. (1994). Estimating the economic model of crime with panel data. The Review of economics and Statistics, 360-366.</p>
</li>
<li>
<p>Mankiw, N. G. (2014). Principles of economics. Cengage Learning.</p>
</li>
<li>
<p>Wooldridge, J. M. (2016). Introductory econometrics: A modern approach. Nelson Education.</p>
</li>
</ul>
Clusterização de texto de reclamação não supervisionada usando K-means com python2019-09-02T23:59:07+00:00http://lamfo-unb.github.io/2019/09/02/cluster_texto<h1 id="clusterização-de-texto-de-reclamação-não-supervisionada-usando-k-means-com-python">Clusterização de texto de reclamação não supervisionada usando K-means com python</h1>
<p><img src="https://www.zugspitzakademie.de/wp-content/uploads/2019/02/kreatives-denken-steigern-nlp-muenchen.jpg" alt="" /></p>
<p><a href="https://www.zugspitzakademie.de/kreatives-denken-steigern-nlp-muenchen/]">fonte: Kreatives Denken steigern mit NLP München</a></p>
<p>Antes de começarmos, é importante deixar clara a diferença entre classificar um texto e clusterizar um texto.
A classificação de texto envolve atrelar categorias já conhecidas aos textos em análise. Já a clusterização envolve agrupar textos em grupos que mais façam sentido, em um número k de grupos.
O número k de grupos pode ser conhecido previamente, ou não. Mas como veremos, quando não sabemos o número de k e estamos trabalhando com texto, quase sempre caímos na <a href="https://towardsdatascience.com/the-curse-of-dimensionality-50dc6e49aa1e">maldição da dimensionalidade</a> e necessitamos de correção humana para validar o melhor k.</p>
<p>Como nosso objetivo aqui será agrupar textos de reclamação em k categorias, usaremos o recurso de <a href="https://lamfo-unb.github.io/2017/10/05/Introducao_basica_a_clusterizacao/">clusterização com k-means</a>.</p>
<h2 id="os-dados-e-bibliotecas-usadas">Os dados e bibliotecas usadas</h2>
<p>Os dados usados nessa análise estão em formato .csv e utilizaremos apenas uma coluna chamada “Reclamacao”.
Como estamos usando python, nada mais natural que usarmos um <a href="https://www.datacamp.com/community/tutorials/pandas-tutorial-dataframe-python">DataFrame do Pandas</a> para lidar com nossos dados.</p>
<p>As bibliotecas usadas ao longo de toda a análise são dispostas abaixo:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">from</span> <span class="nn">sklearn.cluster</span> <span class="kn">import</span> <span class="n">MiniBatchKMeans</span>
<span class="kn">from</span> <span class="nn">sklearn.feature_extraction.text</span> <span class="kn">import</span> <span class="n">TfidfVectorizer</span>
<span class="kn">from</span> <span class="nn">sklearn.decomposition</span> <span class="kn">import</span> <span class="n">PCA</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="kn">import</span> <span class="nn">nltk</span>
<span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">silhouette_samples</span><span class="p">,</span> <span class="n">silhouette_score</span><span class="p">,</span> <span class="n">v_measure_score</span>
<span class="kn">from</span> <span class="nn">sklearn.datasets</span> <span class="kn">import</span> <span class="n">load_files</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">from</span> <span class="nn">unidecode</span> <span class="kn">import</span> <span class="n">unidecode</span>
<span class="kn">from</span> <span class="nn">mpl_toolkits</span> <span class="kn">import</span> <span class="n">mplot3d</span>
</code></pre></div></div>
<h2 id="preparando-os-dados">Preparando os dados</h2>
<p>Antes de iniciarmos o processo de clusterização dos textos, é importante prepararmos os dados adequadamente.
Isso nos ajudará a reduzir nossa <a href="http://btechsmartclass.com/data_structures/sparse-matrix.html">Matriz Esparsa</a>, eliminando palavras desnecessárias e aglomerando aquelas de mesmo significado.
Primeiro, iremos transformar todas as letras do texto para minúsculo. Assim, palavras como “Carro”, “carro” e “CARRO” ficam todas como “carro”.</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#converte todas as letras para minúsculo
</span><span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">].</span><span class="nb">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">x</span><span class="p">.</span><span class="n">lower</span><span class="p">())</span>
</code></pre></div></div>
<p>Em seguida removemos quaisquer caracteres que não sejam letras e acentos da língua portuguesa, convertendo as strings para unicode.</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#remove números e caracteres especiais
</span><span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">].</span><span class="nb">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">re</span><span class="p">.</span><span class="n">sub</span><span class="p">(</span><span class="s">'[0-9]|,|\.|/|$|\(|\)|-|\+|:|•'</span><span class="p">,</span> <span class="s">' '</span><span class="p">,</span> <span class="n">x</span><span class="p">))</span>
<span class="c1">#remove acentos
</span><span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">].</span><span class="nb">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">unidecode</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
</code></pre></div></div>
<p>Por último, aplicamos o método chamado <a href="http://blog.chapagain.com.np/python-nltk-stemming-lemmatization-natural-language-processing-nlp/">Stemming</a>, o qual reduz as palavras ao seu radical (e.g. enviar, enviado, envio .. viram envi).</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#converte as palavras para seu radical
</span><span class="n">stemmer</span> <span class="o">=</span> <span class="n">nltk</span><span class="p">.</span><span class="n">stem</span><span class="p">.</span><span class="n">RSLPStemmer</span><span class="p">()</span>
<span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">]</span> <span class="o">=</span> <span class="n">data</span><span class="p">[</span><span class="s">"Reclamacao"</span><span class="p">].</span><span class="nb">apply</span><span class="p">(</span><span class="k">lambda</span> <span class="n">x</span><span class="p">:</span> <span class="n">stemmer</span><span class="p">.</span><span class="n">stem</span><span class="p">(</span><span class="n">x</span><span class="p">))</span>
</code></pre></div></div>
<p>Por fim, nossos dados devem estar semelhantes a esse exemplo:</p>
<p><img src="https://www.oreilly.com/library/view/applied-text-analysis/9781491963036/assets/atap_0401.png" alt="" /></p>
<p><a href="https://www.oreilly.com/library/view/applied-text-analysis/9781491963036/ch04.html">fonte: Chapter 4. Text Vectorization and Transformation Pipelines</a></p>
<p>Esse tipo de representação de texto é chamado de bolsa de palavras, ou Bag-of-words.</p>
<h2 id="bag-of-words">Bag-of-words</h2>
<p>Para convertermos o texto analisado em uma linguagem que o computador seja capaz de interpretar, precisamos criar nossa <a href="https://medium.com/greyatom/an-introduction-to-bag-of-words-in-nlp-ac967d43b428">Bag-of-Words</a>. Nessa Bag-of-words, separamos cada palavra em uma coluna, a qual passa a contar o número de aparições daquele termo.</p>
<p>Podemos usar uma frase como exemplo: “The book is on the table” fica:</p>
<table>
<thead>
<tr>
<th>The</th>
<th>book</th>
<th>is</th>
<th>on</th>
<th>the</th>
<th>Table</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>e “The key is not on the table” fica:</p>
<table>
<thead>
<tr>
<th>The</th>
<th>key</th>
<th>is</th>
<th>not</th>
<th>on</th>
<th>the</th>
<th>Table</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
</tbody>
</table>
<p>Juntando os dois casos temos:</p>
<table>
<thead>
<tr>
<th>The</th>
<th>key</th>
<th>book</th>
<th>is</th>
<th>not</th>
<th>on</th>
<th>the</th>
<th>Table</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>1</td>
</tr>
<tr>
<td>1</td>
<td>1</td>
<td>0</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>0</td>
</tr>
</tbody>
</table>
<p>Assim, podemos considerar que cada palavra se transforma em uma dimensão representada por um vetor.
Esse vetor, embora por um lado tenha eficiência computacional elevada, pode crescer em tamanho muito rapidamente e se tornar um obstáculo. Isso é, porém, facilmente contornado com as configurações adequadas do modelo.</p>
<p>Essa representação geralmente leva em conta alguma forma de significância. Aqui, analisa-se a frequência simples dos termos (apenas para a frase em destaque):</p>
<p><img src="https://www.oreilly.com/library/view/applied-text-analysis/9781491963036/assets/atap_0402.png" alt="" /></p>
<p><a href="https://www.oreilly.com/library/view/applied-text-analysis/9781491963036/ch04.html">fonte: Chapter 4. Text Vectorization and Transformation Pipelines</a></p>
<p>Podemos perceber uma fragilidade nessa abordagem, já que algumas palavras como “the” e “can” provavelmente não são tão importantes para compreender o sentido da frase, embora a frequência dela seja a mesma de “echolocation” (para a frase em questão).
Esses e outros termos precisam ser considerados, e a simples análise de frequência não é suficiente.</p>
<h2 id="tf-idf---importância-relativa-das-palavras">TF-IDF - Importância relativa das palavras.</h2>
<p>É importante fazermos uma análise de importância das palavras para identificar aquelas que realmente podem agregar significado à uma sentença.
Para isso, é usual empregarmos a <a href="https://www.tidytextmining.com/tfidf.html">técnica da frequência inversa</a>.
Com o TF-IDF (term frequency — inverse document frequency), consideramos a frequência de uma palavra na sentença, dividido pelo número de documentos em que ela aparece.</p>
<p><img src="https://miro.medium.com/max/702/1*mu6G-cBmWlENS4pWHEnGcg@2x.jpeg" alt="" /></p>
<p><a href="https://www.visiondummy.com/2014/04/curse-dimensionality-affect-classification/">fonte: Can TFIDF be applied to Scene Interpretation?</a></p>
<p>Assim, uma palavra que aparece muito em uma frase poderia parecer importante, mas se aparecer em 100% dos textos analisados, se tornando uma informação irrelevante.</p>
<p>Alguma palavras, como conectores, podem ter alta correlação com certos assuntos, não representando porém significância, como é o caso das Stopwords. <a href="https://pythonspot.com/nltk-stop-words/">Stopwords</a> são conectores textuais, como “mas”, “porem”, “assim”, os quais podem dificultar nossa análise (já que podem deslocar a média, e nosso modelo é sensível a isso).</p>
<p>Para criarmos nossa bag-of-words, considerando os stopwords, e analisando a frequência inversa dos documentos, usamos os seguintes comandos:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># nltk.download('stopwords')
</span><span class="n">stopwords</span> <span class="o">=</span> <span class="n">nltk</span><span class="p">.</span><span class="n">corpus</span><span class="p">.</span><span class="n">stopwords</span><span class="p">.</span><span class="n">words</span><span class="p">(</span><span class="s">'portuguese'</span><span class="p">)</span>
<span class="n">stopwords</span><span class="p">.</span><span class="n">extend</span><span class="p">([</span><span class="s">"nao"</span><span class="p">])</span>
<span class="n">vec</span> <span class="o">=</span> <span class="n">TfidfVectorizer</span><span class="p">(</span><span class="n">stop_words</span><span class="o">=</span><span class="n">stopwords</span><span class="p">)</span>
<span class="n">vec</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">Reclamacao</span><span class="p">.</span><span class="n">values</span><span class="p">)</span>
<span class="n">features</span> <span class="o">=</span> <span class="n">vec</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">Reclamacao</span><span class="p">.</span><span class="n">values</span><span class="p">)</span>
</code></pre></div></div>
<p>Assim, um exemplo do resultado final dessa análise seria:</p>
<p><img src="https://www.oreilly.com/library/view/applied-text-analysis/9781491963036/assets/atap_0404.png" alt="" /></p>
<p><a href="https://www.oreilly.com/library/view/applied-text-analysis/9781491963036/ch04.html">fonte: Chapter 4. Text Vectorization and Transformation Pipelines</a></p>
<p>Podemos perceber que a palavra “the”, apesar de aparecer na frase em análise, não tem importância para a terceira frase já que aparece em todos os documentos.</p>
<h2 id="o-modelo-k-means-e-os-desafios-da-dimensionalidade">O modelo k-means e os desafios da dimensionalidade</h2>
<p>O modelo k-means funciona de maneira razoavelmente simples.</p>
<p>Para exemplificar esse funcionamento, usaremos o exemplo da classificação de cães e gatos postado pela computer vision for dummies:</p>
<p>Se tivermos cães e gatos separados em uma dimensão, talvez aconteça de não sermos capazes de perceber nenhuma padrão. Matematicamente (e computacionalmente), isso se traduz em uma dificuldade de se traçar uma reta (ou plano, hiperplano…) que separe os animaizinhos domésticos em questão.</p>
<p><img src="https://www.visiondummy.com/wp-content/uploads/2014/04/1Dproblem.png" alt="" /></p>
<p><a href="https://www.visiondummy.com/2014/04/curse-dimensionality-affect-classification/">fonte: Computer vision for dummies</a></p>
<p>Se adicionarmos mais uma dimensão, porém, podemos começar a ter uma visão mais claro do que está acontecendo.</p>
<p><img src="https://www.visiondummy.com/wp-content/uploads/2014/04/2Dproblem.png" alt="" /></p>
<p><a href="https://www.visiondummy.com/2014/04/curse-dimensionality-affect-classification/">fonte: Computer vision for dummies</a></p>
<p>Continuando o processo, chegará um momento no qual atingiremos o estado ótimo (significando apenas que não há melhoria possível) e teremos algo como o abaixo:</p>
<p><img src="https://www.visiondummy.com/wp-content/uploads/2014/04/3Dproblem.png" alt="fonte: The Curse of Dimensionality in classification" /> <img src="https://www.visiondummy.com/wp-content/uploads/2014/04/3Dproblem_separated.png" alt="" /></p>
<p><a href="https://www.visiondummy.com/2014/04/curse-dimensionality-affect-classification/">fonte: Computer vision for dummies</a></p>
<p>Analisamos os resultados para 1, 2 e 3 dimensões para separar os gatinhos dos cachorros. E se continuarmos acrescentando dimensões? Nosso resultado continuará melhorando? A resposta curta é não, devido a dimensionalidade. Mas voltaremos nesse assunto (e pets) mais abaixo.</p>
<p>Assim, utilizando-se as dimensões geradas na vetorização das sentenças (lembrando que cada palavra é uma dimensão) e sua relativa frequência (TFIDF), tenta-se separar os clusters maximizando as distâncias entre a média da distância dos pontos (reclamações, no caso).
Matematicamente, essa expressão fica:</p>
<p><img src="https://www.saedsayad.com/images/Clustering_kmeans_c.png" alt="fonte: Computer vision for dummies" /></p>
<p><a href="https://www.saedsayad.com/clustering_kmeans.htm">fonte: K-Means Clustering</a></p>
<p>Como não sabemos o número de clusters que iremos usar, iremos testar algumas opções. Aqui, começaremos a testar k variando entre 2 e 29.
Para começar criamos um loop que roda uma vez para cada opção, classificando todos os textos em clusters: 1, 2, …:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">cluster</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span><span class="mi">30</span><span class="p">):</span>
<span class="n">cls</span> <span class="o">=</span> <span class="n">MiniBatchKMeans</span><span class="p">(</span><span class="n">n_clusters</span><span class="o">=</span><span class="n">cluster</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="n">random_state</span><span class="p">)</span>
<span class="n">cls</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
<span class="c1"># predict cluster labels for new dataset
</span> <span class="n">cls</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">features</span><span class="p">)</span>
<span class="c1"># to get cluster labels for the dataset used while
</span> <span class="c1"># training the model (used for models that does not
</span> <span class="c1"># support prediction on new dataset).
</span> <span class="n">cls</span><span class="p">.</span><span class="n">labels_</span>
</code></pre></div></div>
<p>Em seguida, analisamos uma métrica estatística que avalia a distância de cada grupo. Em regra, quanto maior a distância entre os grupos, melhor é o resultado.
Para isso, usamos o indicador Silhouete. O valor -1 significa classificação totalmente imperfeita, 1 totalmente perfeita, e valores no meio representam sobreposições.</p>
<p>O código para isso fica:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">silhouette_avg</span> <span class="o">=</span> <span class="n">v_measure_score</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">cluster_labels</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"For n_clusters ="</span><span class="p">,</span> <span class="n">w</span><span class="p">,</span>
<span class="s">"The average silhouette_score is :"</span><span class="p">,</span> <span class="n">silhouette_avg</span><span class="p">)</span>
</code></pre></div></div>
<p>E o resultado para os primeiros clusters:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Para número de clusters = 2 o valor médio do silhouette_score foi : 0.02266700210191528
Para número de clusters = 3 o valor médio do silhouette_score foi : 0.005991902728057088
Para número de clusters = 4 o valor médio do silhouette_score foi : 0.005276593705042646
Para número de clusters = 5 o valor médio do silhouette_score foi : 0.005690178439257757
Para número de clusters = 6 o valor médio do silhouette_score foi : 0.004483731771877256
Para número de clusters = 7 o valor médio do silhouette_score foi : 0.004786106699286532
Para número de clusters = 8 o valor médio do silhouette_score foi : 0.005219537391930194
Para número de clusters = 9 o valor médio do silhouette_score foi : 0.005530513106476973
Para número de clusters = 10 o valor médio do silhouette_score foi : 0.005672599203188975
</code></pre></div></div>
<p>Os valores, como observados, estão longe do ideal (1). Isso, porém, se deve a <a href="https://towardsdatascience.com/the-curse-of-dimensionality-50dc6e49aa1e">maldição da dimensionalidade</a>, que implica que se utilizarmos dimensões além do necessário, estaremos causando <a href="https://elitedatascience.com/overfitting-in-machine-learning">overfitting</a> em nossos dados, criando um caso artificialmente positivo, capaz apenas de funcionar para o cenário de treinamento.</p>
<p>Além disso, podemos citar a dificuldade inerente desse processo, já que as variáveis (então tratadas como independentes) são influenciadas por muitas outras variáveis, mas nenhuma em especial.</p>
<p>Como referencial dos nossos dados, eles já contam com duas labels que os dividem em 12 grupos e 120 subgrupos. Isso poderia nos indicar que existe uma divisão lógica nesses pontos. Analisamos, então, os clusters até 150.</p>
<p><img src="/img/text/elbow.png" alt="" /></p>
<p>Uma forma de se julgar esses números, é analisar a <a href="https://pythonprogramminglanguage.com/kmeans-elbow-method/">técnica do cotovelo</a>.
Nela, procura-se o número de clusters que faz com que o ganho se torne marginal.
Como nossa curva se aproxima de uma reta, não é possível visualmente escolher qualquer número de clusters (para o nossa caso, tratando de textos).</p>
<p>Dessa forma, considerando que processamentos de texto lidam com milhares de dimensões em uma mesma análise, já era esperado que os resultados sofressem dessa maldição.</p>
<p>Isso, porém, não significa que os clusters não sejam relevantes ou tenham qualquer prejuízo interpretativo. Na prática, a maldição da dimensionalidade implica apenas que é necessário input humano para decidir o melhor número de clusters.</p>
<h2 id="resultados-gráficos">Resultados gráficos</h2>
<p>Embora os resultados anteriores já sejam suficientes para compreendermos o que está acontecendo, podemos plotar os resultados em duas e três dimensões para podermos visualizar o que está acontecendo.
Precisamos, então, plotar os pontos individuais (cada reclamação), de acordo com a cor de cada grupo, e identificarmos o centro desses grupos numericamente.</p>
<p>Para isso precisamos, antes de mais nada, converter nossas informações de cluster para 2 e 3 dimensões para sermos capazes de visualizar esses dados:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">fig</span> <span class="o">=</span> <span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="n">plt</span><span class="p">.</span><span class="n">figaspect</span><span class="p">(</span><span class="mf">0.5</span><span class="p">))</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="c1">#Visualização gráfica 2D
</span> <span class="c1"># Converte as features para 2D
</span> <span class="n">pca</span> <span class="o">=</span> <span class="n">PCA</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span> <span class="mi">0</span><span class="p">)</span>
<span class="n">reduced_features</span> <span class="o">=</span> <span class="n">pca</span><span class="p">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">features</span><span class="p">.</span><span class="n">toarray</span><span class="p">())</span>
<span class="c1"># Converte os centros dos clusters para 2D
</span> <span class="n">reduced_cluster_centers</span> <span class="o">=</span> <span class="n">pca</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">cls</span><span class="p">.</span><span class="n">cluster_centers_</span><span class="p">)</span>
<span class="c1">#Plota gráfico 2D
</span> <span class="n">ax</span><span class="p">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">reduced_features</span><span class="p">[:,</span><span class="mi">0</span><span class="p">],</span> <span class="n">reduced_features</span><span class="p">[:,</span><span class="mi">1</span><span class="p">],</span> <span class="n">c</span><span class="o">=</span><span class="n">cls</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">features</span><span class="p">))</span>
<span class="n">ax</span><span class="p">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">reduced_cluster_centers</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">],</span> <span class="n">reduced_cluster_centers</span><span class="p">[:,</span><span class="mi">1</span><span class="p">],</span> <span class="n">marker</span><span class="o">=</span><span class="s">'o'</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="mi">150</span><span class="p">,</span> <span class="n">edgecolor</span><span class="o">=</span><span class="s">'k'</span><span class="p">)</span>
<span class="c1">#Plota números nos clusters
</span> <span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">c</span> <span class="ow">in</span> <span class="nb">enumerate</span><span class="p">(</span><span class="n">reduced_cluster_centers</span><span class="p">):</span>
<span class="n">ax</span><span class="p">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">c</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">c</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="n">marker</span><span class="o">=</span><span class="s">'$%d$'</span> <span class="o">%</span> <span class="n">i</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
<span class="n">s</span><span class="o">=</span><span class="mi">50</span><span class="p">,</span> <span class="n">edgecolor</span><span class="o">=</span><span class="s">'k'</span><span class="p">)</span>
<span class="c1">#Adiciona informações no gráfico
</span> <span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">"Análise de cluster k = %d"</span> <span class="o">%</span> <span class="n">cluster</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">'Dispersão em X'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">'Dispersão em Y'</span><span class="p">)</span>
<span class="c1">#Visualização gráfica 3D
</span>
<span class="n">ax</span> <span class="o">=</span> <span class="n">fig</span><span class="p">.</span><span class="n">add_subplot</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span><span class="n">projection</span><span class="o">=</span><span class="s">"3d"</span><span class="p">)</span>
<span class="c1"># ax = plt.axes(projection="3d")
</span>
<span class="c1"># Adiciona informações no gráfico
</span> <span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">"Análise de cluster k = %d"</span> <span class="o">%</span> <span class="n">cluster</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">'Dispersão em X'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">'Dispersão em Y'</span><span class="p">)</span>
<span class="c1">#converte dados para 3D
</span> <span class="n">pca</span> <span class="o">=</span> <span class="n">PCA</span><span class="p">(</span><span class="n">n_components</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
<span class="n">reduced_features</span> <span class="o">=</span> <span class="n">pca</span><span class="p">.</span><span class="n">fit_transform</span><span class="p">(</span><span class="n">features</span><span class="p">.</span><span class="n">toarray</span><span class="p">())</span>
<span class="c1">#Plota dados em 3D
</span> <span class="n">ax</span><span class="p">.</span><span class="n">scatter3D</span><span class="p">(</span><span class="n">reduced_features</span><span class="p">[:,</span><span class="mi">0</span><span class="p">],</span> <span class="n">reduced_features</span><span class="p">[:,</span><span class="mi">1</span><span class="p">],</span> <span class="n">reduced_features</span><span class="p">[:,</span><span class="mi">2</span><span class="p">],</span> <span class="n">marker</span><span class="o">=</span><span class="s">'o'</span><span class="p">,</span> <span class="n">s</span><span class="o">=</span><span class="mi">150</span><span class="p">,</span> <span class="n">edgecolor</span><span class="o">=</span><span class="s">'k'</span><span class="p">,</span> <span class="n">c</span><span class="o">=</span><span class="n">cls</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">features</span><span class="p">))</span>
<span class="c1"># Converte os centros dos clusters para 3D
</span> <span class="n">reduced_cluster_centers</span> <span class="o">=</span> <span class="n">pca</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="n">cls</span><span class="p">.</span><span class="n">cluster_centers_</span><span class="p">)</span>
<span class="c1">#Salva arquivo de imagem 3D
</span> <span class="n">plt</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="s">"imagens/grafico_cluster_k=%d"</span> <span class="o">%</span> <span class="n">cluster</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<p>E os resultados para os primeiros cluster podem ser vistos abaixo:</p>
<p><img src="/img/text/grafico_cluster_k=2.png" alt="" />
<img src="/img/text/grafico_cluster_k=3.png" alt="" />
<img src="/img/text/grafico_cluster_k=4.png" alt="" /></p>
<p>Podemos perceber, então, que os clusters se formam de maneira clara, com fronteira razoavelmente bem definida.
Contudo, devido a dimensionalidade, não podemos definir qual número de clusters faz mais sentido apenas pelos resultados (as fronteiras estão se sobrepondo).</p>
<p>Precisamos, então, de uma verificação humana.</p>
<h2 id="validando-os-resultados">Validando os resultados</h2>
<p>Com os resultados acima identificados, podemos perceber que o silhouete não pode nos dar pistas sobre o melhor número de clusters, mas isso não tem relação alguma com a qualidade dos grupos que estão sendo formados, como mostram os gráficos de clusters.
Resta, assim, que seja feita uma validação humana para decidir quais clusters fazem mais sentidos, dependendo da intenção que exista com essa classificação.</p>
<p>O código a seguir exporta as palavras mais importantes de cada cluster, para cada opção de número de cluster.</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">writer</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">ExcelWriter</span><span class="p">(</span><span class="s">'Output/resultados_classificacao.xlsx'</span><span class="p">,</span> <span class="n">engine</span><span class="o">=</span><span class="s">'xlsxwriter'</span><span class="p">)</span>
<span class="c1">#Estrutura os dados em uma lista por cluster para exportar ao excel
</span> <span class="n">resultado</span> <span class="o">=</span> <span class="nb">list</span><span class="p">()</span>
<span class="n">header</span> <span class="o">=</span> <span class="nb">list</span><span class="p">()</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">true_k</span><span class="p">):</span>
<span class="n">header</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="s">"Cluster "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="c1"># Nome das colunas
</span> <span class="n">principais_palavras_cluster</span> <span class="o">=</span> <span class="p">[</span><span class="n">terms</span><span class="p">[</span><span class="n">x</span><span class="p">]</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="n">order_centroids</span><span class="p">[</span><span class="n">i</span><span class="p">,</span> <span class="p">:</span> <span class="mi">21</span><span class="p">]]</span> <span class="c1"># listas com palavras ordenadas
</span> <span class="n">resultado</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">principais_palavras_cluster</span><span class="p">)</span> <span class="c1"># exporta resultados para uma lista de listas
</span>
<span class="c1">#Junta os resultados em um DataFrame
</span> <span class="n">resultados</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">resultado</span><span class="p">,</span> <span class="n">index</span> <span class="o">=</span> <span class="n">header</span><span class="p">)</span>
<span class="n">resultados</span> <span class="o">=</span> <span class="n">resultados</span><span class="p">.</span><span class="n">T</span>
<span class="c1"># print(resultados)
</span>
<span class="c1">#salva cada analise em uma aba do excel
</span> <span class="n">resultados</span><span class="p">.</span><span class="n">to_excel</span><span class="p">(</span><span class="n">writer</span><span class="p">,</span> <span class="n">sheet_name</span><span class="o">=</span> <span class="s">"K = "</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">true_k</span><span class="p">))</span>
<span class="n">wcss</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="n">inertia_</span><span class="p">)</span>
<span class="c1"># Salva os resultados no Excel
</span><span class="n">writer</span><span class="p">.</span><span class="n">save</span><span class="p">()</span>
</code></pre></div></div>
<p>A primeira aba da planilha deverá se parecer com a seguir:</p>
<table>
<thead>
<tr>
<th>Cluster 1</th>
<th>Cluster 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Palavra 1</td>
<td>Palavra 1</td>
</tr>
<tr>
<td>Palavra 2</td>
<td>Palavra 2</td>
</tr>
<tr>
<td>…</td>
<td>…</td>
</tr>
<tr>
<td>Palavra n</td>
<td>Palavra n</td>
</tr>
</tbody>
</table>
<p>Com essas informações em mãos, é possível usar input humano para decidir as categorias que mais fazem sentido, para em seguida etiquetar automaticamente cada reclamação como sendo pertencente de um grupo, ou outro.</p>
<p>Após decidirmos o número k de clusters, podemos definir a seguinte função:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">categoriza</span><span class="p">(</span><span class="nb">input</span><span class="p">):</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">vec</span><span class="p">.</span><span class="n">transform</span><span class="p">(</span><span class="nb">input</span><span class="p">)</span>
<span class="n">predicted</span> <span class="o">=</span> <span class="n">cls</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="k">return</span> <span class="n">predicted</span>
</code></pre></div></div>
<p>Input:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">clusteriza</span><span class="p">([</span><span class="s">"qual o grupo dessa frase?"</span><span class="p">])</span>
</code></pre></div></div>
<p>Output:</p>
<div class="language-py highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cluster</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">]</span>
</code></pre></div></div>
<h2 id="conclusão">Conclusão</h2>
<p>Com o uso da planilha gerada no passo anterior, podemos coletar input humano que nos auxilie a definir o k que mais gere valor para nossa análise.
Embora o uso de k-means seja uma técnica considerada não-supervisionada, o uso com NLP nos força a usar de recursos que exigem uma forma de supervisionamento.</p>
<p>Treinamos a máquina a aprender os critérios que fariam mais sentido servirem como separador dos grupos, preparamos os dados para análise, convertemos esses dados em uma linguagem que o computador possa interpretar, e criamos um classificador que recebe qualquer texto e o classifica como pertencendo a algum dos grupos.</p>
Simulação baseada em Agentes com Gama Platform para simulação de trânsito em rodovias de Brasília e do Distrito Federal2019-06-05T23:59:07+00:00http://lamfo-unb.github.io/2019/06/05/Simulação-baseada-em-Agentes-com-Gama-Platform-para-simulação -de-trânsito-em-rodovias-de-Brasília-e-do-Distrito-Federal<hr />
<h2 id="simulação-baseada-em-agentes-para-análise-de-trânsito">Simulação Baseada em Agentes para análise de Trânsito</h2>
<p><img src="https://i.ytimg.com/vi/ycbeYxV2B7M/maxresdefault.jpg" alt="m'ladyy" /></p>
<p>Simular o trânsito de grandes cidades é um grande desafio por vários motivos, os quais vão desde a complexidade de se formular matematicamente a complexidade da movimentação dos carros em horários e situações específicas do dia a dia, até um acidente ou um buraco na pista. Entretanto, uma coisa é certa: o problema da mobilidade em grandes centros urbanos é custosa e diretamente ligado à qualidade de vida.</p>
<p>Em megalópoles, como Nova Iorque, soluções igualmente complexas ao problema do trânsito foram desenvolvidas e implementadas, com semáforos sincronizados de maneira a tentar minimizar o congestionamento. No entanto, essas soluções não são facilmente replicáveis a outros cenários, especialmente quando a extensão da área analisada se torna muito grande.</p>
<p>É nesse cenário de complexidade que a simulação baseada em agentes se faz útil. Não é simples analisar o movimento complexo de um conjunto de carros ao longo do dia, porém é mais simples imaginar o padrão de comportamento de um único indivíduo. Por exemplo: não é exagero inferir com certa confiança que uma pessoa, em geral, sai para o trabalho 8:30 da manhã e volta às 18h para casa, com uma variação média de 30 minutos. Suposições como essas, simples, quando simuladas em grande escala, são capazes de gerar um padrão de comportamento complexo, que não seria facilmente possível por outras técnicas.</p>
<h2 id="simulação-baseada-em-agentes">Simulação baseada em Agentes</h2>
<p>Mas o que é simulação baseada em agentes? A simulação baseada em agentes nada mais é que a simulação individual de agentes (indivíduos, por exemplo), do nível mais baixo da interpretação de um fenômeno, para a compreensão de algo mais complexo, advindo do conjunto das ações individuais.</p>
<p>Por exemplo, o movimento de pássaros voando em conjunto, é algo matematicamente (e biologicamente) bastante complexo. Por trás da complexidade desses movimentos, porém, se esconde um padrão de pura simplicidade.</p>
<p><img src="https://i.giphy.com/media/gtqM4xScIm1Tq/giphy-downsized-large.gif" alt="m'ladyy" />
<em>https://www.slideshare.net/premsankarchakkingal/introduction-to-agent-based-modeling-using-netlogo</em></p>
<p>Se simularmos um simples pássaro, podemos com poucos parâmetros compreender o resultado do conjunto de interações. <a href="https://ccl.northwestern.edu/netlogo/models/Flocking">Em código disponível no NetLogo</a> (software consagrado para análises de ABM), são usados 3 simples principais parâmetros para analisar esse caso: alinhamento, separação e coesão.</p>
<h2 id="gama-platform">GAMA Platform</h2>
<p>Apesar de softwares como o NetLogo serem mais famosos para se trabalhar com a simulação baseada em agentes, é importante compreender que cada aplicação irá exigir algumas especificidades que podem favorecer um ou outro software. O artigo <a href="https://www.researchgate.net/publication/316002244_Agent_Based_Modelling_and_Simulation_tools_A_review_of_the_state-of-art_software">Agent Based Modelling and Simulation tools: A review of the state-of-art software</a> faz uma análise comparative dos softwares disponíveis. Aqui usaremos o GAMA Platform, devido à sua boa integração com dados georreferenciados.</p>
<p>A plataforma GAMA é um software de simulação utilizado para reproduzir n-agentes simultaneamente, e os visualizar de maneira gráfica atualizada em tempo real. O diferencial da plataforma, que possui linguagem própria (GAML), é a integração simples com arquivos de informação espacial GIS. Outras opções são usadas para a mesma finalidade.</p>
<h2 id="importando-os-arquivos-de-rodovias-para-análise">Importando os arquivos de rodovias para análise</h2>
<p>Para representar as ruas que serão usadas na análise, precisamos que estas estejam em formato compatível, com arquivos de shapefile. Assim, utilizaremos o arquivo Transporte_v2017.zip, disponível <a href="http://forest-gis.com/2009/04/base-de-dados-shapefile-do-brasil-todo.html/">neste link</a>.</p>
<p>Uma vez com os arquivos, devemos extrair o arquivo zip e com algum software de visualização de arquivos GIS editarmos o que precisamos. Aqui, utilizaremos o software QGIS, de código livre.</p>
<p>Na tela principal do QGIS, clique em Add Vector Layer
<img src="/img/ABM/2.png" alt="m'ladyy" /></p>
<p>Em seguida, escolha o arquivo “tra_trecho_rodoviario_I.shp”. Após carregar o arquivo, devemos ter a visão das rodovias de todo o Brasil.
<img src="/img/ABM/3.png" alt="m'ladyy" /></p>
<p>Podemos então refinar nossos dados para apenas a área desejada, para então reduzirmos nosso espaço de análise e tornarmos a simulação factível e interpretável. Com o uso do plugin OpenLayers, é possível ter uma visão cartográfica, para auxiliar no processo de escolha da região desejada. Com essa camada ativada no lado esquerdo inferior, podemos dar zoom na região do Distrito Federal, em seguida desselecionar a camada cartográfica e visualizar apenas as rodovias do local.</p>
<p><img src="/img/ABM/4.png" alt="m'ladyy" />
<img src="/img/ABM/5.png" alt="m'ladyy" /></p>
<p>Com a camada selecionada no lado inferior esquerdo, podemos usar a ferramenta select feature by area (botão amarelo) e escolher a região desejada, arrastando o mouse sobre a área desejada.</p>
<p>Com a área selecionada em destaque, podemos clicar com o lado direito sobre a camada tra_trecho_rodoviario_I e escolher a opção save selected features as, e então salvar o arquivo em formato shapefile (.shp).</p>
<p><img src="/img/ABM/6.png" alt="m'ladyy" /></p>
<p>Pronto, agora já temos os arquivos base para as rodovias que iremos usar em nossa simulação.</p>
<h2 id="gama-language--gaml">GAMA Language – GAML</h2>
<p>A simulação baseada em agentes se parece com a programação orientada a objetos. Temos variáveis e propriedades globais, bem como agentes, que são definidos com propriedades gerais e específicas. Assim, podemos herdar valores e funções em diferentes níveis para formar o agente com as características que precisarmos.</p>
<p>A simulação funciona em ticks, que funcionam como passagens do tempo. Quando se inicia uma simulação no GAMA, apenas o tick inicial é executado, sendo todos os demais executados de acordo com a passagem do tempo simulado ou critérios específicos.</p>
<p>Para iniciarmos nossa simulação, devemos primeiro criar um projeto e um arquivo .gaml.
<img src="/img/ABM/7.png" alt="m'ladyy" /></p>
<p>De início são criados dois principais diretórios, includes (onde irão todos os arquivos que servirão de input para nosso modelo) e models (onde ficará nosso código).</p>
<p><img src="/img/ABM/8.png" alt="m'ladyy" /></p>
<p>Com os arquivos gerados na etapa anterior, devemos colocá-los na pasta includes, e importá-los dentro da definição Global com o seguinte comando:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
}
</code></pre></div></div>
<p>Aproveitamos para definir a geometria das ruas.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
}
</code></pre></div></div>
<p>Em seguida, precisamos definir como o agente rodovia será. Aqui, vamos apenas dizer que a rua se parecerá com a geometria que o próprio arquivo traz consigo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>species rodovia {
aspect base {
draw shape color: #gray;
}
}
</code></pre></div></div>
<p>Em seguida, precisamos criar uma janela que será capaz de plotar as ruas, com as características que definimos como base.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>experiment plota_a_rodovia type:gui{
output {
display visao_superior type: opengl {
species rodovia aspect: base refresh: false;
}}}
</code></pre></div></div>
<p>Se rodarmos o experimento plota_a_rodovia (um botão verde deve aparecer automaticamente com esse nome, caso não haja erro de compilação), veremos que nada acontece. Isso porque não dissemos quem deve ser criado, nem quantos agentes devem ser criados e nem quais serão as ações de cada um. No nosso caso, devemos criar todas as rodovias desejadas, as quais serão um tipo de agente. Assim, precisamos utilizar o comando create dentro de init.</p>
<p>Init representa um conjunto de ações que ocorrem somente uma vez, quando a simulação é criada. O init, por não se tratar de um comando específico de nenhum agente, mas sim do universo, fica dentro de global.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
create rodovia from: shape_file_roads;
}
}
</code></pre></div></div>
<p><img src="/img/ABM/9.png" alt="m'ladyy" /></p>
<h2 id="limpando-os-dados-para-as-ruas">Limpando os dados para as ruas</h2>
<p>As ruas não podem apenas estar plotadas no nosso mapa para que possam servir de ruas navegáveis. Precisamos, portanto, transformar as ruas em grafos com suas conexões funcionando como nós. Para isso, precisamos realizar alguns passos para garantir que teremos um grafo que conecta todos os pontos, evitando erros de roteirização impossível (não existe caminho entre dois pontos), ruas soltas (não se conectam de nenhuma forma ao grafo) ou simplesmente defeitos no arquivo (ruas com 2 metros de distância da realidade, criando um espaçamento não existente).</p>
<p>Assim, antes de criar as ruas do arquivo importado, precisamos usar uma função especificamente desenvolvida para limpar esses dados, antes de criar o agente rodovia: clean_network(rua, tolerância, une sobreposições, mantém um só grafo).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0;
}
}
</code></pre></div></div>
<p>Assim, criamos uma lista de geometrias temporárias, as quais usamos para criar as ruas em seguida.</p>
<p>Entretanto, estamos deixando algumas informações de fora quando não analisamos o número de faixas e vias. Para isso, podemos simplesmente usar as informações que já vêm nos arquivos GIS e criar uma variável para cada rua com esse atributo usando o comando: with: [variável::formato(procura(nome_da_coluna)),…].</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))];
}
}
species rodovia {
int vias;
int lanes;
aspect base {
draw shape color: #gray;
}
}
</code></pre></div></div>
<p>Em seguida precisamos garantir que exista uma via para cada sentido da pista, já que as pistas devem ser direcionais. Assim, para cada pista, deverá haver uma outra de iguais propriedades, e geometria invertida. Além disso, precisamos explicitamente garantir que as ruas estejam conectadas umas às outras. Quando chamamos um agente dentro da função de outro agente, nos referimos ao mais recente como self, e ao mais antigo como myself (o que chamou a função primeiro).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))]{
create rodovia {
lanes <- myself.lanes;
shape <- polyline(reverse(myself.shape.points));
linked_road <-myself;
myself.linked_road <- self;
}}}}
species rodovia skills: [skill_road]{
int vias;
int lanes;
aspect base {
draw shape color: #gray;
}
}
</code></pre></div></div>
<p>Agora temos os links do nosso grafo, precisamos apenas dos nós. Para criar os nós, criamos um grafo de linhas temporárias, em seguida passamos em cada vértice e criamos um agente nó naquela localização.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))]{
create rodovia {
lanes <- myself.lanes;
shape <- polyline(reverse(myself.shape.points));
linked_road <-myself;
myself.linked_road <- self;
}}
graph tenp_graph <- as_edge_graph(rodovia);
loop v over: temp_graph.vertices {
create no with: [location::point(v)];
}
}}
species no skills: [skill_road_node];
.
.
.
</code></pre></div></div>
<p>Para juntar os links e nós em um grafo que se possa dirigir, declaramos um grafo em global (já que será usado fora de init) e usamos a função as_driving_graph() para retornar o grafo unindo linhas e nós.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))]{
create rodovia {
lanes <- myself.lanes;
shape <- polyline(reverse(myself.shape.points));
linked_road <-myself;
myself.linked_road <- self;
}}
graph tenp_graph <- as_edge_graph(rodovia);
loop v over: temp_graph.vertices {
create no with: [location::point(v)];
}
the_graph <- as_driving_graph(rodovia, no);
}}
.
.
.
</code></pre></div></div>
<p>Para criar os carros, precisamos definir alguns elementos básicos como quantidade de carros, localização e velocidade máxima. Aqui, a localização inicial será dada por um nó aleatório, e a velocidade e número de carros serão números inteiros fixos, por questões de simplificação. Para garantir que o carro seja iniciado corretamente em nosso sistema, devemos criar um alvo aleatório e calcular o caminho dele com a função compute_path().</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>create carro number:10{
location <- one_of(no).location;
max_speed <- 80.km/.h;
no the_target <- one_of(no);
try(do compute_path(graph: the_graph, target:the_target);
}
</code></pre></div></div>
<p>Lembrando que devemos também definir o agente, explicitando que desejamos usar o atributo advanced_driving. Para definir uma função que será chamada a cada tick, usamos o termo reflex. Aqui, faremos com que os carros andem de maneira aleatória em cada tick.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>species carro skills: [advanced_driving]{
reflex andar_aleatorio {
do drive random;
}
aspect base {
draw sphere(50) color: #yellow;
}
}
</code></pre></div></div>
<p>O resultado visual desse modelo é esse:</p>
<p><img src="/img/ABM/10.png" alt="m'ladyy" /></p>
<p>Analisando o equivalente à descida do Colorado (DF150), percebemos uma densidade de veículos maior nessa área.</p>
<p><img src="/img/ABM/11.png" alt="m'ladyy" /></p>
<p>De fato, a região é uma das de maior trânsito na cidade, estando inclusive passando por uma obra de ampliação prevista para acabar em 2019.</p>
<p><img src="/img/ABM/12.png" alt="m'ladyy" />
<em>http://www.jornalregional.com.br/noticia/7099/EPIA-NORTE:-Ponto-de-entrada-e-sa%C3%ADda-da-faixa-reversa-do-Colorado-será-deslocado-a-partir-desta-quarta-(6).html</em></p>
<p>Simulações como essa poderiam ser usadas para diversas finalidades. Seguindo o exemplo analisado, poderíamos usar essa simulação para analisar o trânsito caso adicionássemos mais uma via em outro local, ou caso quiséssemos observar o efeito de se ampliar as vias já existentes.</p>
<h2 id="extensão-do-modelo">Extensão do modelo</h2>
<p>Esta foi a base do modelo para simulação de trânsito em casos do mundo real. Vale ressaltar que, apesar de ser relativamente complexa a modelagem utilizando o pacote de habilidades advanced driving skill, os resultados são muito mais fidedignos devido à dezenas de atributos que são herdados automaticamente, como inercia para frear, probabilidade de quebrar o carro (como decorrente de um acidente), distância do veículo da frente, velocidade máxima entre muitas outras. Para conferir o artigo que trata do advanced driving skill, leia <a href="https://hal.archives-ouvertes.fr/hal-01055567/document">Traffic simulation with the GAMA platform </a>.</p>
<p>Entretanto, vale ressaltar que modelos usando pacotes mais simples podem ter resultado tão positivo quanto o aqui apresentado. No site da plataforma, um <a href="https://gama-platform.github.io/wiki/RoadTrafficModel">tutorial rápido ensina a montar um modelo de análise de trânsito em uma cidade onde os moradores tem um endereço residencial, e um local de trabalho</a>. O modelo, por usar um pacote de habilidade mais simples (moving skill) é capaz de gerar esse cenário com uma substancial simplicidade.</p>
Agent-based simulation with Gamma Platform for highway traffic simulation in Brasília - Federal District.2019-06-05T23:59:07+00:00http://lamfo-unb.github.io/2019/06/05/Simulação baseada em Agentes com Gama Platform para simulação de trânsito em rodovias de Brasília e do Distrito Federal - EN<hr />
<h2 id="agent-based-simulation-for-traffic-analysis">Agent Based Simulation for Traffic Analysis</h2>
<p><img src="https://i.ytimg.com/vi/ycbeYxV2B7M/maxresdefault.jpg" alt="m'ladyy" /></p>
<p>Simulating the traffic of big cities is a big challenge for several reasons, ranging from the difficulties of mathematically formulating the complexity of cars movements at specific times and in everyday situations, to such as an accident or a pothole. At the same time one thing can be taken as a fact: the problem of mobility in large urban centers is costly and directly linked to quality of life.</p>
<p>In megalopolises such as New York, equally complex traffic solutions have been developed and implemented, with synchronized traffic lights trying to minimize congestion. However, these solutions are not easily replicable to other scenarios, especially when the length of the analyzed area becomes too large.</p>
<p>It is (as an example) in this complexity scenario that agent-based simulation is useful. It is not simple to analyze the complex movement of a set of cars throughout the day, but it is (simpler) to imagine the pattern of behavior of a single individual. For example, it is no exaggeration to confidently infer that a person usually leaves for work at 8:30 am and returns home at 6 pm, with an average 30-minute variation. Simple assumptions, when simulated on a large scale, are capable of generating a complex pattern of behavior that would not be easily possible by other techniques.</p>
<h2 id="agent-based-simulation">Agent based simulation</h2>
<p>But what is agent-based simulation? Agent-based simulation is nothing more than individual agent simulation (individuals, for example), from the lowest level of interpretation of a phenomenon, used to the develop the understanding of something more complex, arising from the set of individual actions.</p>
<p>For example, the movement of birds flying together is mathematically (and biologically) quite complex. Behind the complexity of these movements, however, lies a pattern of pure simplicity.</p>
<p><img src="https://i.giphy.com/media/gtqM4xScIm1Tq/giphy-downsized-large.gif" alt="m'ladyy" />
<em>https://www.slideshare.net/premsankarchakkingal/introduction-to-agent-based-modeling-using-netlogo</em></p>
<p>If we simulate a simple bird flying we can with just a few parameters, understand the result of the set of interactions. <a href="https://ccl.northwestern.edu/netlogo/models/Flocking">In this code available from NetLogo</a> (established ABM analysis software), 3 simple main parameters are used to analyze this case: alignment, separation and cohesion.</p>
<h2 id="gama-platform">GAMA Platform</h2>
<p>Although softwares such as NetLogo are most famous for working with agent-based simulation, it is important to understand that each application will require some specificities that may favor either software. The article <a href="https://www.researchgate.net/publication/316002244_Agent_Based_Modelling_and_Simulation_tools_A_review_of_the_state-of-art_software">Agent Based Modeling and Simulation tools: A review of the state-of-the-art software</a> compares the available software. Here we will use the GAMA Platform, due to its good integration with georeferenced data.</p>
<p>The GAMA platform is a simulation software used to simultaneously reproduce n-agents and view them in a graphically updated manner in real time. The platform differential, which has its own language (GAML), is the simple integration with GIS spatial information files. Other software options can be used for the same purpose.</p>
<h2 id="importing-the-road-files-for-analysis">Importing the road files for analysis</h2>
<p>To represent the streets that will be used in this analysis, we need them to be in compatible format with shapefile files. Thus, we will use the Transport_v2017.zip file, available at <a href="http://forest-gis.com/2009/04/data-shapefile-do-todo.html/">this link</a>.</p>
<p>Once with the files, we should extract the zip file and with some GIS file viewer software of preference, edit what we need. Here we will use the open source QGIS software.</p>
<p>On the QGIS main screen, click Add Vector Layer.
<img src="/img/ABM/2.png" alt="m'ladyy" /></p>
<p>Then choose the file “tra_trecho_rodoviario_I.shp”. After uploading the file, we should have a view of the highways throughout Brazil.
<img src="/img/ABM/3.png" alt="m'ladyy" /></p>
<p>We can then refine our data to have just the desired area, then reduce our analysis space and make the simulation feasible and interpretable. Using the OpenLayers plugin, you can have a cartographic view to assist in the process of choosing the desired region. With this layer activated on the lower left side, we can zoom in on the Federal District region, then deselect the map layer and view only the highways there.</p>
<p><img src="/img/ABM/4.png" alt="m'ladyy" />
<img src="/img/ABM/5.png" alt="m'ladyy" /></p>
<p>With the layer selected on the lower left side, we can use the select feature by area tool (yellow button) and choose the desired region by dragging the mouse over the desired area.</p>
<p>With the selected area highlighted, we can right-click on the tra_trecho_rodoviario_I layer and choose save selected features as, and choose to save the file in shapefile (.shp) format.
<img src="/img/ABM/6.png" alt="m'ladyy" /></p>
<p>Okay, now we have the base files for the highways that we will use in our simulation.</p>
<h2 id="gama-language--gaml">GAMA Language – GAML</h2>
<p>Agent-based simulation are quite similar to object-oriented programming. We have global variables and properties, as well as agents, which are defined with general and specific properties. Thus we can inherit values and functions at different levels to form the agent with the characteristics we need.</p>
<p>The simulation works on ticks, which act as passages of time. When starting a simulation in GAMA, only the initial tick is executed, and all others are then executed accordingly to the simulated time passage or specific criteria, which need to be predetermined.</p>
<p>To start our simulation, we must first create a project and a .gaml file.
<img src="/img/ABM/7.png" alt="m'ladyy" /></p>
<p>Initially two main directories are created, includes (where will all files that will serve as input to our model be) and models (where our code will be).</p>
<p><img src="/img/ABM/8.png" alt="m'ladyy" /></p>
<p>With the files generated in the previous step, we must place them in the includes folder, and import them into the Global definition with the following command:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
}
</code></pre></div></div>
<p>We take the opportunity to define the geometry of the streets.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
}
</code></pre></div></div>
<p>Next we need to define what the highway agent will be like. Here, let’s just say that the street will look like the geometry that the file itself brings with it.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>species rodovia {
aspect base {
draw shape color: #gray;
}
}
</code></pre></div></div>
<p>Next we need to create a window that will be able to plot the streets, with the features we set as the basis.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>experiment plota_a_rodovia type:gui{
output {
display visao_superior type: opengl {
species rodovia aspect: base refresh: false;
}}}
</code></pre></div></div>
<p>If we run the plota_a_rodovia experiment (a green button should automatically appear with this name if there is no compilation error), we will see that nothing happens. This is because we did not say who should be created nor how many agents should be created. In our case, we must create all the desired highways, which will be an agent type. So we need to use the create command within init.</p>
<p>Init represents a set of actions that occur only once when the simulation is created. Init, because it is not a specific command of any agent, but of the universe, is inside global.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
create rodovia from: shape_file_roads;
}
}
</code></pre></div></div>
<p><img src="/img/ABM/9.png" alt="m'ladyy" /></p>
<h2 id="clearing-data-for-the-streets">Clearing data for the streets</h2>
<p>Streets cannot just be plotted on our map so that they can be navigable streets. We therefore need to turn the streets into graphs with their connections working like us. To do this, we need to take a few steps to ensure that we have a graph that connects all points, avoiding impossible scripting errors (no path between two points), loose streets (not at all connected to the graph) or simply file defects (streets 2 meters away from reality, creating a non-existent spacing).</p>
<p>Thus, before creating the streets of the imported file, we need to use a function specifically designed to clear this data before creating the highway agent: clean_network (street, tolerance, joins overlaps, maintains a single graph).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0;
}
}
</code></pre></div></div>
<p>So we created a list of temporary geometries, which we use to then create the streets.</p>
<p>However, we are leaving some information out when we do not analyze the number of lanes and lanes. To do this, we can simply use the information that is already in the GIS files and create a variable for each street with this attribute using the command: with: [variable :: format (search (column_name)), …].</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))];
}
}
species rodovia {
int vias;
int lanes;
aspect base {
draw shape color: #gray;
}
}
</code></pre></div></div>
<p>Next we need to ensure that there is a pathway for each direction of the track, as the tracks must be directional. Thus, for each track, there must be another one of equal properties and inverted geometry. In addition we need to explicitly ensure that the streets are connected to each other. When we call an agent within the role of another agent, we refer to the newer as self, and the oldest to myself (who called the function first).</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))]{
create rodovia {
lanes <- myself.lanes;
shape <- polyline(reverse(myself.shape.points));
linked_road <-myself;
myself.linked_road <- self;
}}}}
species rodovia skills: [skill_road]{
int vias;
int lanes;
aspect base {
draw shape color: #gray;
}
}
</code></pre></div></div>
<p>Now that we have the links from our graph, we just need the nodes. To create the node, we create a temporary line graph, then pass each vertex and create a node agent at that location.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))]{
create rodovia {
lanes <- myself.lanes;
shape <- polyline(reverse(myself.shape.points));
linked_road <-myself;
myself.linked_road <- self;
}}
graph tenp_graph <- as_edge_graph(rodovia);
loop v over: temp_graph.vertices {
create no with: [location::point(v)];
}
}}
species no skills: [skill_road_node];
.
.
.
</code></pre></div></div>
<p>To merge the links and nodes into a steerable graph, we declare a global graph (since it will be used outside init) and use the as_driving_graph() function to return the graph by joining lines and nodes.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>global{
file shape_file_roads <- ("../includes/rodoviasdf.shp");
geometry shape <- envelope(shape_file_roads);
init {
list<geometry> var0 <- clean_network(shape_file_roads.contents, 10, true, true);
create rodovia from: var0 with: [lanes::int(read("nrfaixas")),vias::int((read("nrpistas"))]{
create rodovia {
lanes <- myself.lanes;
shape <- polyline(reverse(myself.shape.points));
linked_road <-myself;
myself.linked_road <- self;
}}
graph tenp_graph <- as_edge_graph(rodovia);
loop v over: temp_graph.vertices {
create no with: [location::point(v)];
}
the_graph <- as_driving_graph(rodovia, no);
}}
.
.
.
</code></pre></div></div>
<p>To create the cars, we need to define some basic elements such as the amount of cars, location and top speed. Here, the initial location will be given by a random node, and the speed and number of cars will be fixed integers, for simplicity. To ensure that the car starts correctly in our system, we must create a random target and calculate its path with the compute_path() function.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>create carro number:10{
location <- one_of(no).location;
max_speed <- 80.km/.h;
no the_target <- one_of(no);
try(do compute_path(graph: the_graph, target:the_target);
}
</code></pre></div></div>
<p>Considering that we must also define the agent (client-person), we have to make it clear that we want to use the advanced_driving attribute by calling it. To define a function that will be called every tick, we use the term reflex. Here we will make the cars drive randomly on each tick.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>species carro skills: [advanced_driving]{
reflex andar_aleatorio {
do drive random;
}
aspect base {
draw sphere(50) color: #yellow;
}
}
</code></pre></div></div>
<p>The visual result of this model is this:</p>
<p><img src="/img/ABM/10.png" alt="m'ladyy" /></p>
<p>Analyzing the equivalent of the colorado descent (A quite busy road in Brasília), we noticed a higher vehicle density in this area.</p>
<p><img src="/img/ABM/11.png" alt="m'ladyy" /></p>
<p>In fact, the region is one of the busiest in the city, and is even undergoing a work of expansion expected to end in 2019.</p>
<p><img src="/img/ABM/12.png" alt="m'ladyy" /></p>
<p><a href="http://www.jornalregional.com.br/noticia/7099/EPIA-NORTE:-Ponto-de-entrada-e-sa%C3%ADda-da-faixa-reversa-do-Colorado-será-deslocado-a-partir-desta-quarta-(6).html">EPIA NORTE: Ponto de entrada e saída da faixa reversa do Colorado será deslocado a partir desta quarta (6)</a></p>
<p>Simulations like this could be used for a variety of purposes. Following the example above, we could use this simulation to analyze traffic if we added one more road in another location, or if we wanted to observe the effect of widening existing roads.</p>
<h2 id="model-extension">Model extension</h2>
<p>This was the basis of the model for traffic simulation in real world cases. It is noteworthy that, although modeling using the advanced driving skill package is relatively complex, the results are much more reliable due to the dozens of attributes that are inherited automatically, such as braking inertia, probability of breaking the car (as a result of an accident), distance from the vehicle ahead, top speed and many others. To check out the article on advanced driving skill, read <a href="https://hal.archives-ouvertes.fr/hal-01055567/document">Traffic simulation with the RANGE platform</a>.</p>
<p>However, it is important to consider that models using simpler packages can have as positive results as the ones presented here. On the platform’s website, a <a href="https://gama-platform.github.io/wiki/RoadTrafficModel">quick tutorial teaches you how to set up a traffic analysis model in a city where residents have a home address, and a workplace</a>. The model, by using a simpler skill package (moving skill) is able to generate this scenario with relative simplicity.</p>
Programação Dinâmica2019-05-30T23:59:07+00:00http://lamfo-unb.github.io/2019/05/30/Programacao-Dinamica<h1 id="introdução">Introdução</h1>
<p>Tratando-se de problemas de alta complexidade, sobretudo aqueles que envolvem a otimização de certos parâmetros, estão disponíveis diversas metodologias de programação que podem facilitar tanto o entendimento quanto o desenvolvimento da solução. Numa breve revisão, sabe-se que os problemas de otimização possuem geralmente os seguintes aspectos:</p>
<ul>
<li>Função objetivo;</li>
<li>Restrições.</li>
</ul>
<p>Para exemplificar, vamos supor que trabalhamos em uma empresa de transportes e precisamos levar uma encomenda da cidade D para a cidade C de acordo com o grafo ilustrado na figura 1.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/dynamicprogramming/graph_example.png" /></p>
<p><em>Figura 1: Grafo (obtido em: https://pt.wikipedia.org/wiki/Problema_do_caminho_m%C3%ADnimo)</em></p>
<p>Os pesos dos arcos representam o custo para ir de uma cidade a outra e queremos gastar o mínimo possível neste trajeto. Logo,</p>
<ul>
<li>Função Objetivo: \(min(\sum Custo_{D,C})\).</li>
<li>Restrições: \(\sum In_i = \sum Out_i\), sendo \(In_i\) as arestas que entram no vértice \(i\) e \(Out_i\) as arestas que saem. Essa restrição, porém, não vale para os vértices de entrada e saída do caminho. Para esses, tem-se que</li>
</ul>
\[In_D = 0, Out_D = 4\]
<p>e</p>
\[In_C = 2, Out_C = 0\]
<p>Uma das formas de resolução deste problema seria listarmos todos os caminhos possíveis entre D e C e, ao final, escolhermos a combinação que gerasse o menor custo. Esses são os chamados algoritmos de força bruta. Contudo, note que usá-los poderia tornar o algoritmo computacionalmente dispendioso à medida que o número de vértices e arcos do grafo aumentam. A segunda maneira para encontrar a solução de tal problema seria perceber que para chegarmos em C necessariamente devemos passar por B ou E. Portanto, encontrar a solução ótima partindo da cidade C seria encontrar, antes, a solução ótima da cidade D para a cidade B ou E que são os vértices vizinhos de C. Seguindo o raciocínio, teríamos as possibilidades expressas pela árvore da figura 2.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/dynamicprogramming/example_tree.png" /></p>
<p><em>Figura 2: Árvore de possibilidades.</em></p>
<p>Veja que a solução do caminho ótimo entre a cidade D e E é requisitada por duas vezes caso utilizássemos um algoritmo recursivo. Mas, e se armazenássemos essa solução na memória? Certamente o programa ficaria mais veloz já que estaríamos evitando procedimentos repetidos. Este processo é exatamente o que chamamos de Programação Dinâmica. Dessa forma, a programação dinâmica é um método que busca encontrar a solução de vários subproblemas para, então, encontrar a solução do problema geral. A grande diferença dessa metodologia é que os subresultados são armazenados em memória já que eles são utilizados em diversos momentos dentro do cômputo da solução.</p>
<h1 id="caracterizando-o-problema">Caracterizando o problema</h1>
<p>Nesta seção, vamos utilizar a Sequência de Fibonacci para introduzir alguns aspectos importantes da programação dinâmica. Primeiramente, é sabido que tal série possui o seguinte comportamento:</p>
<p>0, 1, 1, 2, 3, 5, 8, 13,…</p>
<p>em que,</p>
<p>f[n] = f[n - 1] + f[n - 2], para n > 1;</p>
<p>f[0] = 0; f[1] = 1.</p>
<p>A maior dificuldade para usar programação dinâmica não está nas construção dos algoritmos em si, mas em discernir quando ou em que tipo de situação adotar a técnica. Além disso, por muitas vezes a especificação da solução não é trivial. Contudo, de um modo geral, existem quatro passos fundamentais para resolvermos problemas com essa metodologia, a saber:</p>
<h2 id="1---identificar-o-problema-como-sendo-de-programação-dinâmica">1 - Identificar o problema como sendo de programação dinâmica</h2>
<p>Duas são as características principais para a primeira etapa, a saber:</p>
<ul>
<li>
<p>Subestrutura ótima: a solução ótima do problema provém das soluções de subproblemas dependentes. Note que já na especificação do problema vê-se que para poder encontrar o termo n, é necessário encontrar antes o termo n-1 e n-2, ou seja, a solução ótima depende da melhor resultado de outros dois subproblemas. Para fins de conhecimento, o exemplo anterior também apresentava essa estrutura uma vez que, para se chegar em C, era necessário encontrar o caminho de menor custo para E e B e assim sucessivamente.</p>
</li>
<li>
<p>Sobreposição de soluções: a solução ótima passa pela resolução de subproblemas que aparecem duas ou mais vezes. Pela estrutura ilustrada na Figura 3 - tomando como exemplo n = 4 - perceba que o cálculo de fib(2) é requisitado por duas vezes. Assim, encontrar termos dessa série possui sobreposição de soluções.</p>
</li>
</ul>
<p><img class="center-block thumbnail img-responsive" src="/img/dynamicprogramming/fibtree.png" /></p>
<p><em>Figura 3: Chamadas recursivas para cálculo de termo da série de Fibonacci.</em></p>
<p>Entendendo que realmente se trata de um problema cuja solução pode ser encontrada por meio da programação dinâmica, vamos para a segunda etapa.</p>
<h2 id="2---definir-o-valor-da-solução-ótima-recursivamente">2 - Definir o valor da solução ótima recursivamente</h2>
<p>Para o caso da série de Fibonacci, esta etapa é relativamente simples já que na própria especificação do problema observa-se que a própria função é demandada novamente para descoberta dos termos n-1 e n-2. Levando isso para o python, tem-se:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def fibonacci(n):
if n == 1 or n == 0:
return n
return fibonacci(n-1) + fibonacci(n-2)
</code></pre></div></div>
<h2 id="3---calcular-valor-da-solução-ótima-da-forma-bottom-up-ou-top-down">3 - Calcular valor da solução ótima da forma “bottom-up” ou “top-down”</h2>
<p>Aqui está a diferença no uso de programação dinâmica. Como visto, a ideia da técnica é evitar cálculos repetidos na busca da solução ótima de um problema recursivo. Para isso, cria-se uma estrutura na memória a fim de guardar tais resultados. Há duas abordagens para alcançar tal objetivo as quais serão exploradas a seguir.</p>
<h3 id="abordagem-top-down">Abordagem “Top-Down”</h3>
<p>Na abordagem “top-down” (ou <em>memoization</em>, termo inglês), partimos da solução geral ótima que se deseja encontrar e, então, analisa-se quais subproblemas são necessários resolver até que se chegue em um subproblema com resolução trivial. Importante lembrar que ao longo dos cálculos os resultados são armazenados para que sejam reutilizados. Dessa forma, o algoritmo observa primeiramente na tabela se a solução ótima do subproblema já foi computado. Caso positivo, simplesmente extrai o valor. Caso negativo, resolve e salva o resultado na tabela. O código abaixo mostra a solução para a série de Fibonacci usando essa abordagem:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def fibonacciTopDown(n, table = {}):
if n == 1 or n == 0:
return n
try:
return table[n]
except:
table[n] = fibonacciTopDown(n-1) + fibonacciTopDown(n-2)
return table[n]
</code></pre></div></div>
<h3 id="abordagem-bottom-up">Abordagem “Bottom-up”</h3>
<p>Na abordagem “bottom-up” (ou <em>tabulation</em>, termo inglês), diferente da anterior, a solução ótima começa a ser calculada a partir do subproblema mais trivial. No caso da série de Fibonacci, basta entender que para se calcular o termo n,a resolução sempre inicia pelo fib(0), depois fib(1), fib(2) e assim sucessivamente até chegar em fib(n). O código abaixo mostra a implementação dessa abordagem.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>def fibonacciBottomUp(n, table = {}):
table[0] = 0
table[1] = 1
for cont in range(2, n + 1):
table[cont] = table[cont - 1] + table[cont - 2]
return table[n]
</code></pre></div></div>
<h3 id="abordagem-top-down-x-bottom-up">Abordagem top-down x bottom-up</h3>
<p>Mas afinal, qual a vantagem de se utilizar uma forma ou outra de implementação? A tabela abaixo lista características importantes de cada metodologia.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/dynamicprogramming/memo_vs_tab.png" /></p>
<p><em>Figura 4: Top-Down x Bottom-up.</em></p>
<h1 id="analisando-o-desempenho">Analisando o Desempenho</h1>
<p>Entendidas as características e vantagens de cada abordagem, vamos testar o desempenho de cada uma delas na resolução da série de Fibonacci. Para isso, verificou-se o tempo de execução de cada uma das implementações de acordo com o código a seguir.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import time
for n in range(35, 40):
start = time.time()
result = fibonacci(n)
finish = time.time()
print("===========================================================================")
print("Fibonacci(", n, ")")
print("Resultado - Fibonacci 1 (Original): ", result)
print("Tempo Total de Execução - Fibonacci 1: ", round(finish - start, 2), "segundos")
start = time.time()
result = fibonacciTopDown(n)
finish = time.time()
print("Resultado - Fibonacci 2 (Top-Down): ", result)
print("Tempo Total de Execução - Fibonacci 2: ", round(finish - start, 20), "segundos")
start = time.time()
result = fibonacciBottomUp(n)
finish = time.time()
print("Resultado - Fibonacci 3 (Bottom-Up): ", result)
print("Tempo Total de Execução - Fibonacci 3: ", round(finish - start, 20), "segundos")
print("===========================================================================")
</code></pre></div></div>
<p>Abaixo encontra-se a saída do código acima.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>===========================================================================
Fibonacci( 35 )
Resultado - Fibonacci 1 (Original): 9227465
Tempo Total de Execução - Fibonacci 1: 6.13 segundos
Resultado - Fibonacci 2 (Top-Down): 9227465
Tempo Total de Execução - Fibonacci 2: 3.57627868652344e-06 segundos
Resultado - Fibonacci 3 (Bottom-Up): 9227465
Tempo Total de Execução - Fibonacci 3: 1.740455627441406e-05 segundos
===========================================================================
===========================================================================
Fibonacci( 36 )
Resultado - Fibonacci 1 (Original): 14930352
Tempo Total de Execução - Fibonacci 1: 9.84 segundos
Resultado - Fibonacci 2 (Top-Down): 14930352
Tempo Total de Execução - Fibonacci 2: 3.33786010742188e-06 segundos
Resultado - Fibonacci 3 (Bottom-Up): 14930352
Tempo Total de Execução - Fibonacci 3: 1.454353332519531e-05 segundos
===========================================================================
===========================================================================
Fibonacci( 37 )
Resultado - Fibonacci 1 (Original): 24157817
Tempo Total de Execução - Fibonacci 1: 15.9 segundos
Resultado - Fibonacci 2 (Top-Down): 24157817
Tempo Total de Execução - Fibonacci 2: 5.48362731933594e-06 segundos
Resultado - Fibonacci 3 (Bottom-Up): 24157817
Tempo Total de Execução - Fibonacci 3: 3.743171691894531e-05 segundos
===========================================================================
===========================================================================
Fibonacci( 38 )
Resultado - Fibonacci 1 (Original): 39088169
Tempo Total de Execução - Fibonacci 1: 26.14 segundos
Resultado - Fibonacci 2 (Top-Down): 39088169
Tempo Total de Execução - Fibonacci 2: 3.33786010742188e-06 segundos
Resultado - Fibonacci 3 (Bottom-Up): 39088169
Tempo Total de Execução - Fibonacci 3: 2.574920654296875e-05 segundos
===========================================================================
===========================================================================
Fibonacci( 39 )
Resultado - Fibonacci 1 (Original): 63245986
Tempo Total de Execução - Fibonacci 1: 49.29 segundos
Resultado - Fibonacci 2 (Top-Down): 63245986
Tempo Total de Execução - Fibonacci 2: 7.15255737304688e-06 segundos
Resultado - Fibonacci 3 (Bottom-Up): 63245986
Tempo Total de Execução - Fibonacci 3: 2.717971801757812e-05 segundos
===========================================================================
</code></pre></div></div>
<p>Escolheu-se o cálculo de termos maiores (35 a 39) para mostrar como o código, usando apenas a recursividade, começa a se tornar extremamente lento à medida que n cresce. Por outro lado, com programação dinâmica, tanto a abordagem top-down quanto bottom-up consegue um desempenho muito superior como pôde ser visto. Além disso, observe também que, nesses casos, a abordagem top-down mostrou-se superior.</p>
<h1 id="conclusão">Conclusão</h1>
<p>Neste post foi apresentada uma introdução sobre programação dinâmica e sua utilidade para a busca de soluções ótimas em problemas de otimização que possuem subestrutura ótima e sobreposição de soluções. Apresentou-se também duas metodologias de implementação da programação dinâmica - abordagem top-down e bottom-up - bem como suas vantagens e desvantagens. Vimos o quão lento a resolução pode se tornar com o uso apenas da recursividade e a grande eficiência alcançada no que tange ao tempo de execução dos códigos provindos do uso de tais metodologias. Caso o leitor se interesse, sugere-se o estudo de questões mais avançadas como:</p>
<ul>
<li>
<p>Multiplicação de matrizes encadeadas <a href="https://www.geeksforgeeks.org/matrix-chain-multiplication-dp-8/">[1]</a>;</p>
</li>
<li>
<p>Problema da Mochila <a href="https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/">[2]</a><a href="http://www.ime.unicamp.br/~eabreu/Projeto/RubensCarvalhoRA122181-MS777.pdf">[3]</a>;</p>
</li>
<li>
<p>Problema do Troco <a href="http://prorum.com/?qa=3250/problema-troco-resolve-abordagem-natural-sempre-funciona">[4]</a>;</p>
</li>
<li>
<p>Aplicações em Economia para apreçamento de ativos usando Equações de Euler <a href="https://mitsloan.mit.edu/shared/ods/documents/?DocumentID=4171">[5]</a>.</p>
</li>
</ul>
<h1 id="referências">Referências</h1>
<ul>
<li>
<p>CORMEN, Thomas H. et al. Introduction to algorithms. MIT press, 2009.</p>
</li>
<li>
<p>Geeks for Geeks: https://www.geeksforgeeks.org/dynamic-programming/#concepts</p>
</li>
<li>
<p>Introduction to Computational Thinking and Data Science (MIT Course): https://www.edx.org/course/introduction-to-computational-thinking-and-data-science-2</p>
</li>
</ul>
Introductory Datasets2019-05-17T07:00:00+00:00http://lamfo-unb.github.io/2019/05/17/Introductory-Datasets<h1 id="introduction">Introduction</h1>
<p>Currently, the world is accelerating into a data revolution, and the skills of a data scientist are becoming increasingly valuable in most if not all industries. At the foundation of all data science and machine learning projects is data. The most fundamental skill of a data scientist is to be able to gather and manipulate data effectively, and after this step, they can apply their other abilities to make their data meaningful. In order to learn and develop these skills, it is essential to have a general knowledge of where one can find data. As a result, this blog post compiles some data sources that you can use to develop your skills as a data scientist or even use them for personal projects.</p>
<h3 id="iris-flower-dataset">Iris Flower Dataset</h3>
<p>To start this post, we have the Iris flower dataset. This dataset contains three different types of Iris flowers (Iris Setosa, Iris Versicolour, Iris Virgnica) with 50 plants for each kind that contain five attributes (sepal length, sepal width, petal length, and petal width). The data that the Iris dataset includes is cleaned up and easy to work with. Furthermore, this dataset is an excellent introductory set for people that are beginning to learn machine learning, and it is possibly the best-known dataset in pattern recognition literature. However, this dataset lacks samples for more complicated data science projects.</p>
<h3 id="mnist">MNIST</h3>
<p>The second dataset we will be covering is the MNIST dataset. This dataset contains pictures of handwritten letters and digits from data collected by the National Institute of Standards and Technology. Similar to the Iris flower dataset, the MNIST dataset is excellent for people learning pattern recognition techniques without all the preprocessing that is usually required for a data science project. Furthermore, it provides significantly more data than the Iris flower dataset, and there are probably more useful applications that come with the MNIST dataset. However, it still is an introductory set, and there are other places where you can encounter a wider variety of data for your data science projects.</p>
<h3 id="uci-machine-learning-repository">UCI Machine Learning Repository</h3>
<p>The UCI Machine learning repository is public repository sponsored by UC Irvine and currently hosts 473 datasets. Furthermore, there is a large variety of domains for the datasets since they range from topics such as car evaluation to bank marketing. As a result, the UCI Machine Learning Repository is a great place for aspiring data scientists to find datasets since anyone from beginners to more advanced data scientists can discover datasets that fit their skills and the vast domain of datasets allows for a lot of different possible projects that one could work on.</p>
<h3 id="twitter-api">Twitter API</h3>
<p>Another dataset we will be discussing is Twitter’s API. Twitter’s API provides access to several sources of data such as tweets and account activity; however, it is sometimes limited because some of the more comprehensive data plans are premium and require money. Regardless, even Twitter’s free programs provide extensive and varied datasets that Twitter has made easy to navigate. As a result, these datasets that you can get from Twitter provide large amounts of data with a broad spectrum of possible applications and projects with this data. However, this dataset requires significantly more skill to use it compared to the first three examples.</p>
<h3 id="kaggle">Kaggle</h3>
<p>The final and perhaps most crucial resource for datasets that we will be discussing is Kaggle. Kaggle is a website where people can upload their datasets and assign certain tasks that people can complete, and after a certain amount of time all the submissions are ranked, and the winner can sometimes obtain a lot of prize money. As a result, this website is a haven for many data scientists because it not only provides a great environment to learn and practice the applications of data science skills on real data sets but it sometimes comes with monetary compensation if you win the competition.</p>
<h3 id="conclusion">Conclusion</h3>
<p>In conclusion, data is critical for any data science project, and there are many great places to find it. The resources in this blog are a great start and can be used to practice and increase your skills as a data scientist or for your projects. However, this is only a start, and this blog mentioned only a few of the spots in an ocean of public data ranging from public government data to public, corporate data. Just remember, if you’re not satisfied with the data found from these sources, there is a lot more data beyond the scope of this blog post.</p>
Pay attention - Explicando o mecanismo de atenção2019-05-01T18:00:00+00:00http://lamfo-unb.github.io/2019/05/01/Pay-attention-Explicando-o-mecanismo-de-Atencao<h1 id="pay-attention---explicando-o-mecanismo-de-atenção">Pay Attention - Explicando o Mecanismo de Atenção</h1>
<p>Uma das aplicações mais relevantes atualmente em aprendizado de máquina é a tradução por máquina (<em>machine translation</em>, MT). O seu objetivo é traduzir uma frase de uma linguagem para outra. Um dos principais desafios dessa técnica é que muitas vezes a frase original e a frase traduzida não têm o mesmo número de palavras. Além disso, o modelo precisa generalizar os padrões da linguagem utilizando apenas uma pequena fração de exemplos traduzidos (o número de possíveis frases em uma linguagem é enorme).</p>
<p>As Redes Neurais Recorrentes (RNR) obtiveram bastante sucesso ultimamente para tratar dados sequenciais, como texto (tradução), áudio (identificação de fala) e séries temporais (predição). Modelos sequência-para-sequência (abreviado como seq2seq, do inglês sequence to sequence) são uma classe especial de arquitetura das RNR. Eles são usados para resolver problemas complexos como tradução, chat-bots e resumo de textos.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/attention/imagem2.jpg" /> <em>Adaptado de http://www.wildml.com/2016/01/attention-and-memory-in-deep-learning-and-nlp/</em></p>
<p>Os modelos seq2seq normalmente são formados por uma arquitetura encoder-decoder, onde o encoder processa a sequência de entrada e comprime essa informação em um vetor de contexto de tamanho fixo (o último <em>hidden state</em>).</p>
<p>A imagem acima ilustra essa relação. As palavras “<em>my</em>” e “<em>homework</em>” servem de entrada para o encoder (não foi mostrado, mas há um sinal específico que serve representar o final e começo das sequências). O decoder então faz a tradução com base no h2.</p>
<p>Espera-se que esse seja uma boa representação da sequência de entrada, esse vetor é então “decodificado” e utilizado para gerar a sequência de saída. Esses modelos obtiveram resultados relevantes nos últimos anos, porém, eles possuem duas limitações que afetam seu desempenho:
1) As RNR usam um tamanho fixo para a representação da entrada e saída. Porém, em muitos casos, o tamanho da entrada e saída é diferente. Tome como exemplo a tradução inglês-português: <em>“I did my homework yesterday”</em> (5 palavras) vira “Eu fiz o meu dever de casa ontem” (7 palavras).</p>
<p>2) O uso de um vetor de sequência de tamanho fixo torna-se problemático para sequências de entrada longas, visto que o vetor de contexto deve considerar a informação de toda a sequência de entrada. Na tradução de uma frase longa, por exemplo, há grandes chances da primeira palavra de uma frase em inglês ser altamente correlacionada com a primeira palavra da respectiva tradução em português. Logo, o vetor de contexto teria de ser capaz de representar essa longa dependência no tempo.</p>
<p>O vetor de contexto é o gargalo em modelos como esse. Na teoria, algumas adaptações como o uso de LSTM (Long short-term memory) podem melhorar o desempenho mas isso ainda é um problema na prática.</p>
<p>O mecanismo de atenção surge para suprir essa limitação do vetor de contexto. Em vez de codificar toda a sequência de entrada em um vetor de contexto, o mecanismo de atenção permite o decoder “focar” em diferentes partes da sequência de entrada em cada etapa da geração da saída. Ou seja, o decoder utiliza todos os estados intermediários para gerar a saída.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/attention/att.jpg" /> <em>Adaptado de <br /> <a href="https://arxiv.org/abs/1409.0473">Neural Machine Translation by Jointly Learning to Align and Translate</a></em></p>
<p>A imagem acima representa o mecanismo de atenção, x é a sequência de entrada e y a de saída. É importante notar que agora a saída depende da combinação ponderada de todos os estados de entrada. Os a’s representam os pesos de atenção, ou seja, quanto cada estado de entrada é considerado em cada saída. Por exemplo, se \(a_{2,1}\) é um valor grande, isso significa que a primeira palavra de entrada é importante na geração da segunda palavra na saída.</p>
<p>Uma das vantagens de utilizar o mecanismo de atenção é a interpretabilidade. É possível saber qual parte da entrada foi mais relevante para cada parte da saída.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/attention/att2.jpg" /> <em>Adaptado de http://jalammar.github.io/visualizing-neural-machine-translation-mechanics-of-seq2seq-models-with-attention/</em></p>
<p>A imagem acima mostra a tradução da frase “eu sou estudante” para o inglês. Valores maiores de atenção são representados por cores mais escuras. Perceba que “eu” possui um peso grande para “I” assim como “estudante” possui para “student”.</p>
<h2 id="como-o-mecanismo-de-atenção-funciona">Como o mecanismo de atenção funciona?</h2>
<p><img class="center-block thumbnail img-responsive" src="/img/attention/att3.jpg" /> <em>Adaptado de https://medium.com/syncedreview/a-brief-overview-of-attention-mechanism-13c578ba9129</em></p>
<p>A arquitetura é similar ao encoder-decoder básico, com uma particularidade entre o encoder (azul) e o decoder (vermelho) representados na imagem acima. A diferença principal em relação aos outros modelos seq2seq é o vetor de contexto que considera todo os elementos da entrada. Cada elemento da saída considera o respectivo vetor de contexto e a saída no instante de tempo anterior. A atenção é definida pelas três equações abaixo:</p>
<p><img class="center-block thumbnail img-responsive" src="/img/attention/eq.jpg" /></p>
<p>O <em>score</em> na equação (1) é normalmente uma rede neural simples, os pesos de atenção são normalizados usando <em>softmax</em> em relação ao <em>input</em>. O vetor de contexto é calculado pela soma ponderada dos <em>hidden states</em> em relação aos seus pesos. Esse vetor é calculado para cada palavra na saída. Se considerarmos todos os pesos de atenção, teremos uma matriz de dimensões N x M, onde N é o tamanho do <em>input</em> e M o tamanho do <em>output</em>.
Por último, o modelo utiliza o vetor de contexto e o <em>hidden state</em> para determinar a saída. A equação (3) mostra a tanh como a não linearidade mas pode-se usar outras funções, como ReLU.</p>
<h2 id="atenção-além-da-tradução">Atenção além da tradução</h2>
<p>O mecanismo de atenção nesse post foi introduzido utilizando sua aplicação na tradução. Porém, esse método também é utilizado em outras aplicações. Em <a href="https://arxiv.org/abs/1502.03044">Show,Attend and Tell</a>, o mecanismo de atenção foi aplicado para gerar descrição de imagens. A descrição era gerada por uma RNR com atenção após receber a representação da imagem feito por uma Rede Neural Convolucional.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/attention/caption.png" /><em> Fonte : <br /> <a href="https://arxiv.org/abs/1502.03044">Show,Attend and Tell</a> </em></p>
<p>A parte mais clara das imagens representa maior peso e a imagem sublinhada mostra de qual palavra os pesos são. É possível notar que o modelo identificou de forma correta os exemplos de acordo com a distribuição dos pesos.</p>
<h2 id="conclusões">Conclusões</h2>
<p>O mecanismo de atenção surge como solução para a dificuldade de representar longas sequências em modelos convencionais. Um dos lados negativos dessa abordagem é o custo computacional, visto que é preciso calcular os pesos para cada componente da saída, o que pode tornar o custo computacional razoavelmente alto.</p>
<p><strong>Referências:</strong></p>
<blockquote>
<p>Attention and Memory in Deep Learning and NLP http://www.wildml.com/2016/01/attention-and-memory-in-deep-learning-and-nlp/</p>
</blockquote>
<blockquote>
<p>A Brief Overview of Attention Mechanism https://medium.com/syncedreview/a-brief-overview-of-attention-mechanism-13c578ba9129</p>
</blockquote>
<blockquote>
<p>Attention Based Machine Translation https://towardsdatascience.com/attention-based-neural-machine-translation-b5d129742e2c</p>
</blockquote>
<blockquote>
<p>Augmented RNNs https://distill.pub/2016/augmented-rnns/</p>
</blockquote>
<blockquote>
<p><a href="https://arxiv.org/abs/1409.0473">Neural Machine Translation by Jointly Learning to Align and Translate</a></p>
</blockquote>
<blockquote>
<p><a href="https://arxiv.org/abs/1502.03044">Show,Attend and Tell</a></p>
</blockquote>
Double/Debiased Machine Learning2019-04-27T00:00:00+00:00http://lamfo-unb.github.io/2019/04/27/double-ml<h2 id="conteúdo">Conteúdo</h2>
<ol>
<li><a href="#intro">Introdução</a></li>
<li><a href="#dgp">Processo Gerador de Dados</a></li>
<li><a href="#regr">Regressão Linear</a></li>
<li><a href="#naive-ml">Aprendizado De Máquina</a></li>
<li><a href="#double-ml">Double/Debiased Machine Learning</a></li>
<li><a href="#ref">Referências</a></li>
</ol>
<p><a name="intro"></a></p>
<h2 id="introdução">Introdução</h2>
<p>Digamos que você trabalhe numa empresa de cobranças e construiu um modelo de Aprendizado de Máquina mega <em>deep</em> poderoso que prevê quase perfeitamente que vai pagar ou não a dívida - no set de teste, claro. Ou que você trabalha numa empresa de logística e consegue prever todos os atrasos que irão acontecer. Você então vai todo contente mostrar seu sucesso pro seu chefe ou para a gerência. E, quem diria!, descobre que eles não estão muito interessado em prever essas coisas. Se você pensar bem até que faz sentido. A gerência está muito mais interessada em descobrir <strong>como aumentar o pagamento das dívidas</strong> ou <strong>como diminuir os atrasos</strong>. Nessa caso, previsão pode até ser interesse, mas não é o objetivo principal.</p>
<p>O problema de estimação de impacto está dentro de toda uma literatura sobre <strong>Inferência Causal</strong>. Há anos que cientistas, principalmente da econometria e bioestatística, estudam inferência causal, mas só recentemente o campo vem ganhando relevância na comunidade de aprendizado de máquina.</p>
<p>Hoje, a maioria dos modelos “de prateleira” de aprendizado de máquina não são pensados para otimizar estimação de impacto ou inferência causal. Assim, quem quer responder perguntas de impacto (“como X impacta y”) ou contrafactuais (“como y seria se X fosse diferente do que é”) precisa ainda implementar modelos de inferência causa na mão.</p>
<p>Aqui, vamos ver uma das técnicas que misturam modelos complexos de aprendizado de máquina com fundamentos teóricos de inferência causal. Como exemplo, vamos tentar descobrir como a dosagem de um medicamento impacta no tempo de recuperação de pacientes doentes.</p>
<p><a name="dgp"></a></p>
<h2 id="processo-gerador-de-dados">Processo Gerador de Dados</h2>
<p>Imagine que você foi contratado para descobrir o impacto da dosagem de um remédio no tempo de recuperação de pacientes doentes. Parece um problema fácil. Bastaria ver se pessoa que receberam uma alta dosagem recuperam mais ou menos rápido do que pacientes que receberam uma dosagem menos. Seria fácil… Mas os médicos tendem a dar uma dosagem maior para pacientes em estados mais críticos. Por isso, se a gente simplesmente olhar correlações simples iremos obter algo bem contra intuitivo: mais remédio significa mais tempo no hospital.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/double-ml/corr.png" /></p>
<p>Para o propósito desse tutorial, é melhor usar dados simulados para os quais sabemos exatamente o efeito causal. I ideia será ver como nosso modelo consegue identificar esse efeito. Os dados são simulados de forma a gerar estruturas de confusão, em que uma variável causa tanto o tratamento como a variável resposta. No caso, temos que tanto Sexo do paciente quanto Severidade da doença causam tanto a recuperação quanto o tratamento. Vamos também colocar algumas relações não lineares que são pouco triviais.</p>
\[Sexo \sim \mathcal{B}(0.5)\]
\[Idade \sim \mathcal{G}amma(8, 4)\]
\[Severidade \sim \mathbb{1}_{idade<30} \ \mathcal{B}eta(1, 3) + \mathbb{1}_{idade \geqslant 30} \ \mathcal{B}eta(3, 1.5)\]
\[Tratamento \sim 0.33 * Sexo + 1.5 * Severity + Severity^2 + 0.15 * \mathcal{N}ormal(0, 1)\]
\[Recuperacao \sim \mathcal{N}ormal(2 + 0.5 * Sexo + 0.03 * Idade + \\
0.0003 * Idade^2 + Severidade + log(Severidade) + Sexo * Severidade -
Tratamento)\]
<p>O que é importante perceber no processo acima é que <strong>o efeito causal do medicamento é -1</strong>, isto é, aumentar a dose do medicamento 1mg diminui o tempo no hospital em um dia.</p>
<p><a name="regr"></a></p>
<h2 id="regressão-linear">Regressão Linear</h2>
<p>Se você tem contato com a área de econometria ou estatística seu pais devem ter te falado que sempre que você quer controlar para algum fator em dados observacionais você precisa rodar uma regressão linear. Essa é uma boa intuição. Regressão linear tem uma interpretação de controlar para os fatores incluídos no modelo que simula dados experimentais. Assim, é de se esperar que se a gente controlar as variáveis de confusão, Sexo e Severidade, deveríamos ser capazes de achar o efeito causal do medicamento. Em outras palavras, regressão linear nos daria o efeito do medicamento mantidos Sexo e Severidade constante. Certo? Vamos ver…</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">statsmodels.formula.api</span> <span class="k">as</span> <span class="n">smf</span>
<span class="n">forumla</span> <span class="o">=</span> <span class="s">"recovery ~ sex + age + severity + medication"</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">smf</span><span class="p">.</span><span class="n">ols</span><span class="p">(</span><span class="n">forumla</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="n">df_obs</span><span class="p">).</span><span class="n">fit</span><span class="p">()</span>
<span class="n">model</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
</code></pre></div></div>
<table class="simpletable">
<tr>
<td></td> <th>coef</th> <th>std err</th> <th>t</th> <th>P>|t|</th> <th>[0.025</th> <th>0.975]</th>
</tr>
<tr>
<th>Intercept</th> <td> -1.3349</td> <td> 0.018</td> <td> -75.306</td> <td> 0.000</td> <td> -1.370</td> <td> -1.300</td>
</tr>
<tr>
<th>sex</th> <td> 1.2991</td> <td> 0.015</td> <td> 85.216</td> <td> 0.000</td> <td> 1.269</td> <td> 1.329</td>
</tr>
<tr>
<th>age</th> <td> 0.0514</td> <td> 0.001</td> <td> 87.000</td> <td> 0.000</td> <td> 0.050</td> <td> 0.053</td>
</tr>
<tr>
<th>severity</th> <td> 7.2146</td> <td> 0.083</td> <td> 86.812</td> <td> 0.000</td> <td> 7.052</td> <td> 7.377</td>
</tr>
<tr>
<th>medication</th> <td> -2.0233</td> <td> 0.032</td> <td> -62.274</td> <td> 0.000</td> <td> -2.087</td> <td> -1.960</td>
</tr>
</table>
<p>Ops… Aparentemente não. Nosso modelo de regressão está estimando um efeito causal de <strong>-2.0233</strong> em vez de -1, ou seja, ele está superestimando o efeito causal. Isso acontece porque nosso modelo não está capturando todas as relações não lineares no nosso processo gerador de dados. Se nós fizéssemos um modelo que corresponde com o PGD isso provavelmente não aconteceria e conseguiríamos estimar o impacto causal corretamente. Só que, na vida real, nós raramente conhecemos o PGD.</p>
<p>Por sinal, não linearidade complexas é um dos grandes motivos para usarmos modelos de aprendizado de máquina.</p>
<p><a name="naive-ml"></a></p>
<h2 id="aprendizado-de-máquina">Aprendizado De Máquina</h2>
<p>Se não linearidades são o problema, vamos usar um modelo de aprendizado de máquina, certo? Bom, vamos ver…</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.ensemble</span> <span class="kn">import</span> <span class="n">RandomForestRegressor</span>
<span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">cross_val_score</span>
<span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">df_obs</span><span class="p">.</span><span class="n">drop</span><span class="p">(</span><span class="s">"recovery"</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">df_obs</span><span class="p">[</span><span class="s">"recovery"</span><span class="p">]</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">RandomForestRegressor</span><span class="p">(</span><span class="n">max_depth</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">n_estimators</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=-</span><span class="mi">1</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">cross_val_score</span><span class="p">(</span><span class="n">model</span><span class="p">,</span> <span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">,</span> <span class="n">cv</span><span class="o">=</span><span class="mi">5</span><span class="p">))</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0.9709928 0.96984636 0.9733455 0.96893817 0.96942233]
</code></pre></div></div>
<p>Acima, nós treinamos um modelo de floresta aleatória, com 100 árvores e profundidade máxima de 5. Nossa performance num set de validação é de aproximadamente 0,98, o que é um bom indicativo que nosso modelo está bem ajustado.</p>
<p>Para estimar o efeito causal nós precisaremos ser um pouco espertos. Como estamos lidando com um modelo de aprendizado de máquina, o efeito não precisa ser linear nem constante. Também não é possível simplesmente “ler” o modelo para ver como ele está entendendo o funcionamento do grau de medicamento.</p>
<p>O que vamos fazer então é gerar artificialmente alguns níveis de medicamento, de 0 a 4 em intervalos de 0.1mg. Depois, para cada nível, vamos ver a previsão média do modelo na base toda. Por fim, vamos plotar a previsão média contra o nível de medicamento</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="n">model</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="n">med_level</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">arange</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mf">0.1</span><span class="p">)</span>
<span class="n">y_hats</span> <span class="o">=</span> <span class="p">[</span><span class="n">model</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X</span><span class="p">.</span><span class="n">assign</span><span class="p">(</span><span class="n">medication</span> <span class="o">=</span> <span class="n">med</span><span class="p">)).</span><span class="n">mean</span><span class="p">()</span> <span class="k">for</span> <span class="n">med</span> <span class="ow">in</span> <span class="n">med_level</span><span class="p">]</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">med_level</span><span class="p">,</span> <span class="n">y_hats</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">"Medication Level"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">"Average Prediction of Recovery"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<p><img class="center-block thumbnail img-responsive" src="/img/double-ml/ml-naive.png" /></p>
<p>E mais uma vez, parece que nossa ideia não deu certo. O modelo está prevendo que o medicamento diminui o tempo de recuperação, muito pouco. A queda prevista no tempo de recuperação é apenas de 1,99 dias para 1,96 dias e só acontece após o paciente receber 2mg de medicamento.</p>
<p><a name="double-ml"></a></p>
<h2 id="doubledebiased-machine-learning">Double/Debiased Machine Learning</h2>
<p>Nossa abordagem final envolve um pouco de teoria de regressão linear e modelos de aprendizado de máquina. Em um artigo de 2017, Chernozhukov et al propõe o uso de ortogonalização usando modelos de AM como uma forma de estimar o efeito causal. Começamos definindo \(X\) o conjunto de variáveis de confusão, no nosso caso idade, sexo de severidade. Definindo \(D\) como a nossa variável de tratamento, no nosso caso o nível de medicamento dado ao paciente. E, finalmente, definimos \(Y\) como a nossa variável resposta, dias de recuperação, no nosso caso.</p>
<p>Nós podemos retirar o efeito de \(X\) em \(D\) construindo um regressor \(\hat{V} = D - m(X)\), em que \(m\) é um modelo de regressão estimador de \(D\). \(\hat{V}\) nesse contexto são os resíduos da regressão de \(D\) em \(X\), de forma que \(\hat{V}\) será ortogonal a \(X\).</p>
<p>Analogamente, nós podemos retirar o efeito de \(X\) em \(Y\) construindo um regressor \(\hat{Y} = Y - l(X)\), em que \(l\) é um modelo de regressão estimador de \(Y\). \(\hat{U}\) nesse contexto são os resíduos da regressão de \(Y\) em \(X\), de forma que \(\hat{U}\) será ortogonal a \(X\).</p>
<p>Com isso, nós podemos construir o estimador do efeito causal da seguinte forma:</p>
\[\hat{\theta} = \frac{\hat{V}^T\hat{U}}{\hat{V}^T\hat{V}}\]
<p>Vamos tentar…</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.ensemble</span> <span class="kn">import</span> <span class="n">RandomForestRegressor</span>
<span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">r2_score</span>
<span class="n">X</span> <span class="o">=</span> <span class="n">df_obs</span><span class="p">.</span><span class="n">drop</span><span class="p">(</span><span class="n">columns</span><span class="o">=</span><span class="p">[</span><span class="s">"recovery"</span><span class="p">,</span> <span class="s">"medication"</span><span class="p">]).</span><span class="n">values</span>
<span class="n">Y</span> <span class="o">=</span> <span class="n">df_obs</span><span class="p">[</span><span class="s">"recovery"</span><span class="p">].</span><span class="n">values</span>
<span class="n">D</span> <span class="o">=</span> <span class="n">df_obs</span><span class="p">[</span><span class="s">"medication"</span><span class="p">].</span><span class="n">values</span>
<span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="n">Lhat</span> <span class="o">=</span> <span class="n">RandomForestRegressor</span><span class="p">(</span><span class="n">max_depth</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">n_estimators</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=-</span><span class="mi">1</span><span class="p">).</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">Y</span><span class="p">).</span><span class="n">predict</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">Mhat</span> <span class="o">=</span> <span class="n">RandomForestRegressor</span><span class="p">(</span><span class="n">max_depth</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">n_estimators</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=-</span><span class="mi">1</span><span class="p">).</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">,</span> <span class="n">D</span><span class="p">).</span><span class="n">predict</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">theta</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">((</span><span class="n">D</span> <span class="o">-</span> <span class="n">Mhat</span><span class="p">),</span> <span class="p">(</span><span class="n">Y</span> <span class="o">-</span> <span class="n">Lhat</span><span class="p">))</span> <span class="o">/</span> <span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">D</span> <span class="o">-</span> <span class="n">Mhat</span><span class="p">,</span> <span class="n">D</span> <span class="o">-</span> <span class="n">Mhat</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Causal Effect:"</span><span class="p">,</span> <span class="n">theta</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>-0.9601128788228591
</code></pre></div></div>
<p>Agora sim! O efeito estimado do medicamento é de -0.96. Isso é bem próximo do efeito real, que era -1. Mas por que isso funciona? Bom, para isso precisamos ir um pouco mais fundo em teoria econométrica.</p>
<h3 id="por-que-funciona">Por Que Funciona?</h3>
<p>A primeira coisa que precisamos reconhecer é que o estimador é simplesmente o coeficiente \(\hat{\beta_1}\) da seguinte regressão linear univariada</p>
\[\hat{U} = \beta_0 + \beta_1 \hat{V} + e\]
<p>Se você não acredita em mim, pode verificar isso rodando essa regressão no Python e vendo que o coeficiente é exatamente o mesmo que estimamos acima.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">LinearRegression</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">LinearRegression</span><span class="p">()</span>
<span class="n">model</span><span class="p">.</span><span class="n">fit</span><span class="p">((</span><span class="n">D</span> <span class="o">-</span> <span class="n">Mhat</span><span class="p">).</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span> <span class="n">Y</span> <span class="o">-</span> <span class="n">Lhat</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">model</span><span class="p">.</span><span class="n">coef_</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[-0.96011223]
</code></pre></div></div>
<p>A demonstração matemática é um pouco mais longa, mas você pode conferi-la <a href="https://matheusfacure.github.io/2017/02/16/ols-mechanics/#fwl">neste tutorial que eu fiz</a>. De maneira resumida, o que isso nos mostra que que \(\beta_1\) pode ser entendido como a regressão de y em \(D\) após os termos considerados (projetado) a informação em \(X\). Sendo um pouco mais técnico, podemos usar o teorema de Frisch-Waugh-Lovell para mostrar que parâmetro \(\beta_1\) pode ser obtido rodando duas regressões, isto é, regressão por partes. <strong>Esse parâmetro é matematicamente igual a regredir os resíduos da regressão de \(X\) em \(D\) (ou seja, \(\hat{U}\)) nos resíduos da regressão de \(X\) em \(Y\) (ou seja, \(\hat{V}\))</strong>.</p>
<h3 id="particionando-os-dados">Particionando os Dados</h3>
<p>Podemos ainda ter uma última melhora em cima do estimador acima particionando os dados. Isso envolve separar os dados em treino e teste, treinar os modelos de aprendizado de máquina no dataset de treino, mas computar os resíduos usando o dataset de teste.</p>
<p>No código abaixo, nos fazemos esse particionamento no estilo k-fold, onde criamos 10 datasets de treino e 10 datasets de teste e realizamos 10 iterações de treino, teste e estimação do parâmetro \(\theta\). Por fim, tiramos a média de todos os parâmetros estimados para obter uma estimativa final.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">KFold</span>
<span class="n">kf</span> <span class="o">=</span> <span class="n">KFold</span><span class="p">(</span><span class="n">n_splits</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
<span class="n">thetas</span> <span class="o">=</span> <span class="p">[]</span>
<span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="k">for</span> <span class="n">train</span><span class="p">,</span> <span class="n">test</span> <span class="ow">in</span> <span class="n">kf</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="n">X</span><span class="p">):</span>
<span class="n">Ghat</span> <span class="o">=</span> <span class="n">RandomForestRegressor</span><span class="p">(</span><span class="n">max_depth</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">n_estimators</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=-</span><span class="mi">1</span><span class="p">).</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">train</span><span class="p">],</span><span class="n">Y</span><span class="p">[</span><span class="n">train</span><span class="p">]).</span><span class="n">predict</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">test</span><span class="p">])</span>
<span class="n">Mhat</span> <span class="o">=</span> <span class="n">RandomForestRegressor</span><span class="p">(</span><span class="n">max_depth</span><span class="o">=</span><span class="mi">5</span><span class="p">,</span> <span class="n">n_estimators</span><span class="o">=</span><span class="mi">100</span><span class="p">,</span> <span class="n">n_jobs</span><span class="o">=-</span><span class="mi">1</span><span class="p">).</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">train</span><span class="p">],</span><span class="n">D</span><span class="p">[</span><span class="n">train</span><span class="p">]).</span><span class="n">predict</span><span class="p">(</span><span class="n">X</span><span class="p">[</span><span class="n">test</span><span class="p">])</span>
<span class="n">Vhat</span> <span class="o">=</span> <span class="n">D</span><span class="p">[</span><span class="n">test</span><span class="p">]</span> <span class="o">-</span> <span class="n">Mhat</span>
<span class="n">Uhat</span> <span class="o">=</span> <span class="n">Y</span><span class="p">[</span><span class="n">test</span><span class="p">]</span> <span class="o">-</span> <span class="n">Ghat</span>
<span class="n">thetas</span> <span class="o">+=</span> <span class="p">[</span><span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">Vhat</span><span class="p">,</span><span class="n">Uhat</span><span class="p">))</span><span class="o">/</span><span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">Vhat</span><span class="p">,</span><span class="n">Vhat</span><span class="p">))]</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Causal Effect:"</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">thetas</span><span class="p">))</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Causal Effect: -0.977882592667485
</code></pre></div></div>
<p>O efeito causal estimado é ainda mais próximo do efeito causal real de -1. Isso funciona pois previne problemas de sobre-ajustamento de modelos. Voltando a fórmula do estimador, é intuitivo ver porque isso seria um problema.</p>
\[\hat{\theta} = \frac{\hat{V}^T\hat{U}}{\hat{V}^T\hat{V}}\]
<p>Se alguns dos modelos de aprendizado de máquina sobre-ajustarem, ou \(\hat{V}\) ou \(\hat{U}\) serão artificialmente próximos de zero. Se \(\hat{V} < \hat{U}\) porque \(m\) está sobre ajustado, o denominador da fórmula acima seria muito pequeno e o estimador explodiria para um número muito grande. Se \(\hat{U} < \hat{V}\) porque \(g\) está sobre ajustado, o numerador da fórmula acima seria muito pequeno e o estimador seria jogado para zero.</p>
<p>Separas a amostra de estimação da de computação de resíduo previsse esses problemas.</p>
<p><a name="ref"></a></p>
<h2 id="referências">Referências</h2>
<p>Este post implementa o modelo descrito em <a href="https://arxiv.org/abs/1608.00060">Double/Debiased Machine Learning for Treatment and Causal Parameters</a>, de Chernozhukov et al, 2016. Uma boa referência para quem quiser aprender mais sobre esse modelo é a <a href="https://www.youtube.com/watch?v=eHOjmyoPCFU">palestra dada por Victor Chernozhukov</a>. Como de costume, o código deste post está no <a href="https://github.com/matheusfacure/Tutoriais-de-AM/tree/master/Causal">meu GitHub</a>.</p>
Stacked Generalization (Empilhamento)2019-04-22T12:59:07+00:00http://lamfo-unb.github.io/2019/04/22/stacking<p>Por ser uma tecnica relativamente nova, o “Stacked Generalization” ainda não tem uma tradução amplamente adotada, aqui proponho “empilhamento”, tradução literal para seu outro nome (stacking), como o termo para me referir a ela. Introduzida por Wolpert em 1992<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, essa tecnica de generalização consiste em combinar de formar não linear estimadores para corrigir seus vieses a um dado conjunto de treino, agregando suas capacidades para que se tenha uma melhor previsão.</p>
<p><img src="/img/stacking.png" alt="png" /></p>
<p>Em uma <a href="/2017/08/17/Modelos-Compostos/">postagem anterior</a> apresentei a combinação linear de estimadores, nela ajustamos \(N\) modelos a um conjunto de dados \(D\) e a priori definimos pesos \(W\) para eles combinando em um somatório:</p>
\[\text{given a priori} \ W = (w_1,w_2,...w_N) \ \text{and} \sum W = 1\]
\[\sum_{i=1}^{N} w_{i}M_{i}\]
<p>com isso a media ponderada das predições no geral vão ser menos enviesadas para certas regiões e podem generalizar mais, porém este metodo apresenta duas limitações, os pesos não podem ser alterados depois de verificar o desempenho (se não estariamos agindo como um meta-estimador em cima dos dados de teste) e é uma combinação extremamente simples, não aproveitando bem os pontos fortes dos estimadores \(M\) para certas regiões.</p>
<p>Wolpert então propõe uma alternativa a isso, e se tornasemos os pesos \(W\) em um problema de aprendizado? ou melhor, não só aprendessemos como combinar nossas predições mas também as combinassemos de forma não-linear usando um meta-estimador?</p>
<p>Meta-estimadores são aqueles que usam modelos base para combina-los ou seleciona-los para melhorar em uma metrica de desempenho, por exemplo você leitor quando decide entre usar uma random-forest ou uma regressão logistica para prever o seu modelo você está sendo um meta-estimador. Porém aqui surge o problema de generalização, se continuar melhorando sua regressão ou rforest você poderá acabar dando overfitting aos dados e não conseguindo generalizar, aqui então é necessário aplicar tecnicas de validação cruzada para selecionar o modelo, o mesmo ocorrerá para o empilhamento.</p>
<p>Para o empilhamento é ideal que o dataset seja relativamente grande, o conselho do autor é pelo menos mil registros. Começamos nosso exemplo carregando um dataset relativamente grande, 20mil registros, esse dataset tem como atributos caracteristicas de casas da california e como valor alvo o preço dela, os dados já estão normalizados e não iremos fazer qualquer alteração nele.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.datasets</span> <span class="kn">import</span> <span class="n">fetch_california_housing</span>
<span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">train_test_split</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="n">dataset</span> <span class="o">=</span> <span class="n">fetch_california_housing</span><span class="p">()</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span><span class="n">data</span><span class="o">=</span><span class="n">dataset</span><span class="p">.</span><span class="n">data</span><span class="p">,</span> <span class="n">columns</span><span class="o">=</span><span class="n">dataset</span><span class="p">.</span><span class="n">feature_names</span><span class="p">)</span>
<span class="n">df</span><span class="p">[</span><span class="s">'Price'</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataset</span><span class="p">.</span><span class="n">target</span>
<span class="n">df</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>MedInc</th>
<th>HouseAge</th>
<th>AveRooms</th>
<th>AveBedrms</th>
<th>Population</th>
<th>AveOccup</th>
<th>Latitude</th>
<th>Longitude</th>
<th>Price</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>8.3252</td>
<td>41.0</td>
<td>6.984127</td>
<td>1.023810</td>
<td>322.0</td>
<td>2.555556</td>
<td>37.88</td>
<td>-122.23</td>
<td>4.526</td>
</tr>
<tr>
<th>1</th>
<td>8.3014</td>
<td>21.0</td>
<td>6.238137</td>
<td>0.971880</td>
<td>2401.0</td>
<td>2.109842</td>
<td>37.86</td>
<td>-122.22</td>
<td>3.585</td>
</tr>
<tr>
<th>2</th>
<td>7.2574</td>
<td>52.0</td>
<td>8.288136</td>
<td>1.073446</td>
<td>496.0</td>
<td>2.802260</td>
<td>37.85</td>
<td>-122.24</td>
<td>3.521</td>
</tr>
<tr>
<th>3</th>
<td>5.6431</td>
<td>52.0</td>
<td>5.817352</td>
<td>1.073059</td>
<td>558.0</td>
<td>2.547945</td>
<td>37.85</td>
<td>-122.25</td>
<td>3.413</td>
</tr>
<tr>
<th>4</th>
<td>3.8462</td>
<td>52.0</td>
<td>6.281853</td>
<td>1.081081</td>
<td>565.0</td>
<td>2.181467</td>
<td>37.85</td>
<td>-122.25</td>
<td>3.422</td>
</tr>
</tbody>
</table>
</div>
<p>Aqui separamos em treino e teste de forma (pseudo)aleatorizada para no final avaliarmos o desempenho.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">xtrain</span><span class="p">,</span> <span class="n">xtest</span><span class="p">,</span> <span class="n">ytrain</span><span class="p">,</span> <span class="n">ytest</span> <span class="o">=</span> <span class="n">train_test_split</span><span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="n">drop</span><span class="p">(</span><span class="s">'Price'</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">),</span> <span class="n">df</span><span class="p">.</span><span class="n">Price</span><span class="p">,</span> <span class="n">test_size</span><span class="o">=</span><span class="p">.</span><span class="mi">3</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">42</span><span class="p">)</span>
<span class="n">xtrain</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>MedInc</th>
<th>HouseAge</th>
<th>AveRooms</th>
<th>AveBedrms</th>
<th>Population</th>
<th>AveOccup</th>
<th>Latitude</th>
<th>Longitude</th>
</tr>
</thead>
<tbody>
<tr>
<th>7061</th>
<td>4.1312</td>
<td>35.0</td>
<td>5.882353</td>
<td>0.975490</td>
<td>1218.0</td>
<td>2.985294</td>
<td>33.93</td>
<td>-118.02</td>
</tr>
<tr>
<th>14689</th>
<td>2.8631</td>
<td>20.0</td>
<td>4.401210</td>
<td>1.076613</td>
<td>999.0</td>
<td>2.014113</td>
<td>32.79</td>
<td>-117.09</td>
</tr>
<tr>
<th>17323</th>
<td>4.2026</td>
<td>24.0</td>
<td>5.617544</td>
<td>0.989474</td>
<td>731.0</td>
<td>2.564912</td>
<td>34.59</td>
<td>-120.14</td>
</tr>
<tr>
<th>10056</th>
<td>3.1094</td>
<td>14.0</td>
<td>5.869565</td>
<td>1.094203</td>
<td>302.0</td>
<td>2.188406</td>
<td>39.26</td>
<td>-121.00</td>
</tr>
<tr>
<th>15750</th>
<td>3.3068</td>
<td>52.0</td>
<td>4.801205</td>
<td>1.066265</td>
<td>1526.0</td>
<td>2.298193</td>
<td>37.77</td>
<td>-122.45</td>
</tr>
</tbody>
</table>
</div>
<p>Agora carregamos a validação-cruzada especificamente a <a href="https://scikit-learn.org/stable/modules/cross_validation.html#k-fold">KFold</a>, para que não “percamos” muitos dados, e os modelos que serão usados, aqui não há uma regra de dedo sobre os modelos base, fica a seu criterio, porém para o meta-estimador é usualmente aplicado boosting trees. Aqui escolhi arbitrariamente <a href="https://scikit-learn.org/stable/modules/neighbors.html#nearest-neighbors-regression">kNN</a> e <a href="https://scikit-learn.org/stable/modules/linear_model.html#elastic-net">ElasticNet</a>, mas como meta-estimador usarei o <a href="https://xgboost.readthedocs.io/en/latest/tutorials/model.html">xgboost</a>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">ElasticNet</span>
<span class="kn">from</span> <span class="nn">sklearn.neighbors</span> <span class="kn">import</span> <span class="n">KNeighborsRegressor</span>
<span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">KFold</span>
<span class="kn">import</span> <span class="nn">xgboost</span> <span class="k">as</span> <span class="n">xgb</span>
<span class="n">en</span> <span class="o">=</span> <span class="n">ElasticNet</span><span class="p">()</span>
<span class="n">knn</span> <span class="o">=</span> <span class="n">KNeighborsRegressor</span><span class="p">()</span>
<span class="n">gbm</span> <span class="o">=</span> <span class="n">xgb</span><span class="p">.</span><span class="n">XGBRegressor</span><span class="p">(</span><span class="n">n_estimators</span><span class="o">=</span><span class="mi">1000</span><span class="p">)</span> <span class="c1"># we will early stop to not overfit
</span></code></pre></div></div>
<p>Agora se inicia a criação dos atributos empilhados, para garantir que não tenha vieses e não fiquemos com poucos dados para treinar o meta-etimador os criamos por kfolds, sendo gerados os subconjuntos treino e teste, treinamos o modelo no conjunto de treino e predizemos o valor para o conjunto de teste, da seguinte forma:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">kf</span> <span class="o">=</span> <span class="n">KFold</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">xtrain</span><span class="p">[</span><span class="s">'en'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">train_index</span><span class="p">,</span> <span class="n">test_index</span> <span class="ow">in</span> <span class="n">kf</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="n">xtrain</span><span class="p">):</span>
<span class="n">en</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">train_index</span><span class="p">,</span> <span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">],</span> <span class="n">ytrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">train_index</span><span class="p">])</span>
<span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">test_index</span><span class="p">,</span><span class="mi">8</span><span class="p">]</span> <span class="o">=</span> <span class="n">en</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">test_index</span><span class="p">,</span> <span class="p">:</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span>
</code></pre></div></div>
<p>Fazemos o mesmo para o outro modelo.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">kf</span> <span class="o">=</span> <span class="n">KFold</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">shuffle</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="n">xtrain</span><span class="p">[</span><span class="s">'knn'</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">for</span> <span class="n">train_index</span><span class="p">,</span> <span class="n">test_index</span> <span class="ow">in</span> <span class="n">kf</span><span class="p">.</span><span class="n">split</span><span class="p">(</span><span class="n">xtrain</span><span class="p">):</span>
<span class="n">knn</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">train_index</span><span class="p">,</span> <span class="p">:</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span> <span class="n">ytrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">train_index</span><span class="p">])</span>
<span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">test_index</span><span class="p">,</span><span class="mi">9</span><span class="p">]</span> <span class="o">=</span> <span class="n">knn</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[</span><span class="n">test_index</span><span class="p">,</span> <span class="p">:</span><span class="o">-</span><span class="mi">2</span><span class="p">])</span>
</code></pre></div></div>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">xtrain</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>MedInc</th>
<th>HouseAge</th>
<th>AveRooms</th>
<th>AveBedrms</th>
<th>Population</th>
<th>AveOccup</th>
<th>Latitude</th>
<th>Longitude</th>
<th>en</th>
<th>knn</th>
</tr>
</thead>
<tbody>
<tr>
<th>7061</th>
<td>4.1312</td>
<td>35.0</td>
<td>5.882353</td>
<td>0.975490</td>
<td>1218.0</td>
<td>2.985294</td>
<td>33.93</td>
<td>-118.02</td>
<td>2.203225</td>
<td>2.108000</td>
</tr>
<tr>
<th>14689</th>
<td>2.8631</td>
<td>20.0</td>
<td>4.401210</td>
<td>1.076613</td>
<td>999.0</td>
<td>2.014113</td>
<td>32.79</td>
<td>-117.09</td>
<td>1.706363</td>
<td>1.973400</td>
</tr>
<tr>
<th>17323</th>
<td>4.2026</td>
<td>24.0</td>
<td>5.617544</td>
<td>0.989474</td>
<td>731.0</td>
<td>2.564912</td>
<td>34.59</td>
<td>-120.14</td>
<td>2.091721</td>
<td>2.197800</td>
</tr>
<tr>
<th>10056</th>
<td>3.1094</td>
<td>14.0</td>
<td>5.869565</td>
<td>1.094203</td>
<td>302.0</td>
<td>2.188406</td>
<td>39.26</td>
<td>-121.00</td>
<td>1.698103</td>
<td>2.160600</td>
</tr>
<tr>
<th>15750</th>
<td>3.3068</td>
<td>52.0</td>
<td>4.801205</td>
<td>1.066265</td>
<td>1526.0</td>
<td>2.298193</td>
<td>37.77</td>
<td>-122.45</td>
<td>2.195922</td>
<td>2.388002</td>
</tr>
</tbody>
</table>
</div>
<p>Agora que criamos as features vamos avaliar os modelos nos dados brutos, sem as features empilhadas para verificar seus desempenhos:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">mean_squared_error</span>
<span class="n">en</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,:</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span> <span class="n">ytrain</span><span class="p">)</span>
<span class="n">ypred_en</span> <span class="o">=</span> <span class="n">en</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtest</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">mean_squared_error</span><span class="p">(</span><span class="n">ytest</span><span class="p">,</span> <span class="n">ypred_en</span><span class="p">))</span>
<span class="n">knn</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,:</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span> <span class="n">ytrain</span><span class="p">)</span>
<span class="n">ypred_knn</span> <span class="o">=</span> <span class="n">knn</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtest</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">mean_squared_error</span><span class="p">(</span><span class="n">ytest</span><span class="p">,</span> <span class="n">ypred_knn</span><span class="p">))</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.7562926012142394
1.136942049088978
</code></pre></div></div>
<p>Agora criamos as features com os modelos treinados para os dados de teste:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">xtest</span><span class="p">[</span><span class="s">'en'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ypred_en</span>
<span class="n">xtest</span><span class="p">[</span><span class="s">'knn'</span><span class="p">]</span> <span class="o">=</span> <span class="n">ypred_knn</span>
<span class="n">xtest</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style scoped="">
.dataframe tbody tr th:only-of-type {
vertical-align: middle;
}
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>MedInc</th>
<th>HouseAge</th>
<th>AveRooms</th>
<th>AveBedrms</th>
<th>Population</th>
<th>AveOccup</th>
<th>Latitude</th>
<th>Longitude</th>
<th>en</th>
<th>knn</th>
</tr>
</thead>
<tbody>
<tr>
<th>20046</th>
<td>1.6812</td>
<td>25.0</td>
<td>4.192201</td>
<td>1.022284</td>
<td>1392.0</td>
<td>3.877437</td>
<td>36.06</td>
<td>-119.01</td>
<td>1.470084</td>
<td>1.6230</td>
</tr>
<tr>
<th>3024</th>
<td>2.5313</td>
<td>30.0</td>
<td>5.039384</td>
<td>1.193493</td>
<td>1565.0</td>
<td>2.679795</td>
<td>35.14</td>
<td>-119.46</td>
<td>1.744788</td>
<td>1.0822</td>
</tr>
<tr>
<th>15663</th>
<td>3.4801</td>
<td>52.0</td>
<td>3.977155</td>
<td>1.185877</td>
<td>1310.0</td>
<td>1.360332</td>
<td>37.80</td>
<td>-122.44</td>
<td>2.233643</td>
<td>2.8924</td>
</tr>
<tr>
<th>20484</th>
<td>5.7376</td>
<td>17.0</td>
<td>6.163636</td>
<td>1.020202</td>
<td>1705.0</td>
<td>3.444444</td>
<td>34.28</td>
<td>-118.72</td>
<td>2.413336</td>
<td>2.2456</td>
</tr>
<tr>
<th>9814</th>
<td>3.7250</td>
<td>34.0</td>
<td>5.492991</td>
<td>1.028037</td>
<td>1063.0</td>
<td>2.483645</td>
<td>36.62</td>
<td>-121.93</td>
<td>2.088660</td>
<td>1.6690</td>
</tr>
</tbody>
</table>
</div>
<p>Com os atributos empilhados em mãos agora treinamos dois modelos, um sem utiliza-los, para efeito de comparação e outro utilizando, vamos comparar os resultados:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Without stacked features
</span><span class="n">gbm</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,:</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span> <span class="n">ytrain</span><span class="p">.</span><span class="n">values</span><span class="p">,</span>
<span class="n">eval_set</span><span class="o">=</span><span class="p">[(</span><span class="n">xtest</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,:</span><span class="o">-</span><span class="mi">2</span><span class="p">],</span><span class="n">ytest</span><span class="p">.</span><span class="n">values</span><span class="p">)],</span>
<span class="n">early_stopping_rounds</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span>
<span class="n">verbose</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">ypred</span> <span class="o">=</span> <span class="n">gbm</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtest</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,:</span><span class="o">-</span><span class="mi">2</span><span class="p">])</span>
<span class="k">print</span><span class="p">(</span><span class="s">"Without stacked features"</span><span class="p">,</span> <span class="n">mean_squared_error</span><span class="p">(</span><span class="n">ytest</span><span class="p">,</span> <span class="n">ypred</span><span class="p">))</span>
<span class="c1"># With stacked features
</span><span class="n">gbm</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">,</span> <span class="n">ytrain</span><span class="p">.</span><span class="n">values</span><span class="p">,</span>
<span class="n">eval_set</span><span class="o">=</span><span class="p">[(</span><span class="n">xtest</span><span class="p">,</span><span class="n">ytest</span><span class="p">.</span><span class="n">values</span><span class="p">)],</span>
<span class="n">early_stopping_rounds</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span>
<span class="n">verbose</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="n">ypred</span> <span class="o">=</span> <span class="n">gbm</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtest</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="s">"With stacked features"</span><span class="p">,</span> <span class="n">mean_squared_error</span><span class="p">(</span><span class="n">ytest</span><span class="p">,</span> <span class="n">ypred</span><span class="p">))</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Without stacked features 0.23318853095188977
With stacked features 0.22410766547017014
</code></pre></div></div>
<p>Nos tivemos uma melhora significativa usando atributos “empilhados”, concluindo nosso meta-estimador aprende a melhor forma de combinar as features de outros estimadores, aprendendo seus erros de generalização e como os corrigir, garantindo uma generalização muito melhor.</p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>https://www.sciencedirect.com/science/article/pii/S0893608005800231 <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Sorting Algorithms2019-04-21T23:59:07+00:00http://lamfo-unb.github.io/2019/04/21/Sorting-algorithms<h1 id="what-are-sorting-algorithms">What are Sorting Algorithms?</h1>
<p>Sorting algorithms are ways to organize an array of items from smallest to largest. These algorithms can be used to organize messy data and make it easier to use. Furthermore, having an understanding of these algorithms and how they work is fundamental for a strong understanding of Computer Science which is becoming more and more critical in a world of premade packages. This blog focuses on the speed, uses, advantages, and disadvantages of specific Sorting Algorithms.</p>
<p>Although there is a wide variety of sorting algorithms, this blog explains Straight Insertion, Shell Sort, Bubble Sort, Quick Sort, Selection Sort, and Heap Sort. The first two algorithms (Straight Insertion and Shell Sort) sort arrays with insertion, which is when elements get inserted into the right place. The next 2 (Bubble Sort and Quick Sort) sort arrays with exchanging which is when elements move around the array. The last one is heap sort which sorts through selection where the right elements are selected as the algorithm runs down the array.</p>
<h2 id="big-o-notation">Big-O Notation</h2>
<p>Before this blog goes any further, it is essential to explain the methods that professionals use to analyze and assess algorithm complexity and performance. The current standard is called “Big O notation” named according to its notation which is an “O” followed by a function such as “O(n).”</p>
<h3 id="formal-definition">Formal definition</h3>
<blockquote>
<p><em>Suppose f(x) and g(x) are two functions defined on some subset of the real numbers. We write
f(x) = O(g(x))
(or f(x) = O(g(x)) for x -> ∞ to be more precise) if and only if there exist constants N and C such
that |f(x)| <= C |g(x)| for all x>N.
Intuitively, this means that f does not grow faster than g.</em></p>
</blockquote>
<p>Big O is used to denote either the time complexity of an algorithm or how much space it takes up. This blog focuses mainly on the time complexity part of this notation. The way people can calculate this is by identifying the worst case for the targeted algorithm and formulating a function of its performance given an n amount of elements. For example, if there were an algorithm that searched for the number 2 in an array, then the worst case would be if the 2 was at the very end of the array. Therefore, the Big O notation would be O(n) since it would have to run through the entire n-element array before finding the number 2.</p>
<p>To help you, find below a table with algorithms and its complexity.
<img src="/img/Sorting-algorithms/Complexity.png" alt="image alt" title="Complexity" /></p>
<h2 id="straight-insertion-sort">Straight Insertion Sort</h2>
<p><img src="/img/Sorting-algorithms/Insertion_sort_animation.gif" alt="image alt" title="Straight Insertion" /></p>
<p>Straight insertion sort is one of the most basic sorting algorithms that essentially inserts an element into the right position of an already sorted list. It is usually added at the end of a new array and moves down until it finds an element smaller thank itself (the desired position). The process repeats for all the elements in the unsorted array. Consider the array {3,1,2,5,4}, we begin at 3, and since there are no other elements in the sorted array, the sorted array becomes just {3}. Afterward, we insert 1 which is smaller than 3, so it would move in front of 3 making the array {1,3}. This same process is repeated down the line until we get the array {1,2,3,4,5}.</p>
<p><img src="/img/Sorting-algorithms/Insertion-sort-example-300px.gif" alt="image alt" title="Straight Insertion" /></p>
<p>The advantages of this process are that it is straightforward and easy to implement. Also, it is relatively quick when there are small amounts of elements to sort. It can also turn into binary insertion which is when you compare over longer distances and narrow it down to the right spot instead of comparing against every single element before the right place. However, a straight insertion sort is usually slow whenever the list becomes large.</p>
<p>Main Characteristics:</p>
<ul>
<li>Insertion sort family</li>
<li>Straightforward and simple</li>
<li>Worst case = O(n^2)</li>
</ul>
<p>Python implementation:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 10 17:13:56 2019
@note: Insertion sort algorithm
@source: http://interactivepython.org/courselib/static/pythonds/SortSearch/TheInsertionSort.html
"""
def insertionSort(alist):
for index in range(1,len(alist)):
currentvalue = alist[index]
position = index
while position>0 and alist[position-1]>currentvalue:
alist[position]=alist[position-1]
position = position-1
alist[position]=currentvalue
</code></pre></div></div>
<h2 id="shell-sort">Shell Sort</h2>
<p><img src="/img/Sorting-algorithms/Sorting_shellsort_anim.gif" alt="image alt" title="Shell Sort" /></p>
<p>Shell sort is an insertion sort that first partially sorts its data and then finishes the sort by running an insertion sort algorithm on the entire array. It generally starts by choosing small subsets of the array and sorting those arrays. Afterward, it repeats the same process with larger subsets until it reaches a point where the subset is the array, and the entire thing becomes sorted. The advantage of doing this is that having the array almost entirely sorted helps the final insertion sort achieve or be close to its most efficient scenario.</p>
<p><img src="/img/Sorting-algorithms/Shell_Sort_Algorithm.gif" alt="image alt" title="Shell Sort" /></p>
<p>Furthermore, increasing the size of the subsets is achieved through a decreasing increment term. The increment term essentially chooses every kth element to put into the subset. It starts large, leading to smaller (more spread out) groups, and it becomes smaller until it becomes 1 (all of the array).</p>
<p>The main advantage of this sorting algorithm is that it is more efficient than a regular insertion sort. Also, there is a variety of different algorithms that seek to optimize shell sort by changing the way the increment decreases since the only restriction is that the last term in the sequence of increments is 1. The most popular is usually Knuth’s method which uses the formula h=((3^k)-1)/2 giving us a sequence of intervals of 1 (k=1),4 (k=2),13 (k=3), and so on. On the other hand, shell sort is not as efficient as other sorting algorithms such as quicksort and merge sort.</p>
<p>Main Characteristics:</p>
<ul>
<li>Sorting by insertion</li>
<li>Can optimize algorithm by changing increments</li>
<li>Using Knuth’s method, the worst case is O(n^(3/2))</li>
</ul>
<p>Python implementation:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 10 17:13:56 2019
@note: Insertion sort - Shell Method algorithm
@source: https://www.w3resource.com/python-exercises/data-structures-and-algorithms/python-search-and-sorting-exercise-7.php
"""
def shellSort(alist):
sublistcount = len(alist)//2
while sublistcount > 0:
for start_position in range(sublistcount):
gap_InsertionSort(alist, start_position, sublistcount)
sublistcount = sublistcount // 2
def gap_InsertionSort(nlist,start,gap):
for i in range(start+gap,len(nlist),gap):
current_value = nlist[i]
position = i
while position>=gap and nlist[position-gap]>current_value:
nlist[position]=nlist[position-gap]
position = position-gap
nlist[position]=current_value
</code></pre></div></div>
<h2 id="bubble-sort">Bubble Sort</h2>
<p><img src="/img/Sorting-algorithms/Sorting_bubblesort_anim.gif" alt="image alt" title="Bubble Sort" /></p>
<p>Bubble sort compares adjacent elements of an array and organizes those elements. Its name comes from the fact that large numbers tend to “float” (bubble) to the top. It loops through an array and sees if the number at one position is greater than the number in the following position which would result in the number moving up. This cycle repeats until the algorithm has gone through the array without having to change the order. This method is advantageous because it is simple and works very well for mostly sorted lists. As a result, programmers can quickly and easily implement this sorting algorithm. However, the tradeoff is that this is one of the slower sorting algorithms.</p>
<p>Main Characteristics:
Exchange sorting
Easy to implement
Worst Case = O(n^2)</p>
<p>Python implementation:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 10 18:05:51 2019
@note: Exchanging sort - Bubble Sort algorithm
@source: http://interactivepython.org/runestone/static/pythonds/SortSearch/TheBubbleSort.html
"""
def bubbleSort(alist):
for passnum in range(len(alist)-1,0,-1):
for i in range(passnum):
if alist[i]>alist[i+1]:
temp = alist[i]
alist[i] = alist[i+1]
alist[i+1] = temp
</code></pre></div></div>
<h2 id="quicksort">Quicksort</h2>
<p><img src="/img/Sorting-algorithms/Quicksort.gif" alt="image alt" title="Quicksort" /></p>
<p>Quicksort is one of the most efficient sorting algorithms, and this makes of it one of the most used as well.
The first thing to do is to select a pivot number, this number will separate the data, on its left are the numbers smaller than it and the greater numbers on the right. With this, we got the whole sequence partitioned.
After the data is partitioned, we can assure that the partitions are oriented, we know that we have bigger values on the right and smaller values on the left.
The quicksort uses this divide and conquer algorithm with recursion. So, now that we have the data divided we use recursion to call the same method and pass the left half of the data, and after the right half to keep separating and ordinating the data. At the end of the execution, we will have the data all sorted.</p>
<p>Main characteristics:</p>
<ul>
<li>From the family of Exchange Sort Algorithms</li>
<li>Divide and conquer paradigm</li>
<li>Worst case complexity O(n²)</li>
</ul>
<p><img src="/img/Sorting-algorithms/Quicksort-example.gif" alt="image alt" title="Quicksort" /></p>
<p>Python implementation:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 10 18:09:35 2019
@note: Exchanging sort - Bubble Sort algorithm
@source: http://interactivepython.org/courselib/static/pythonds/SortSearch/TheQuickSort.html
"""
def quickSort(alist):
quickSortHelper(alist,0,len(alist)-1)
def quickSortHelper(alist,first,last):
if first<last:
splitpoint = partition(alist,first,last)
quickSortHelper(alist,first,splitpoint-1)
quickSortHelper(alist,splitpoint+1,last)
def partition(alist,first,last):
pivotvalue = alist[first]
leftmark = first+1
rightmark = last
done = False
while not done:
while leftmark <= rightmark and alist[leftmark] <= pivotvalue:
leftmark = leftmark + 1
while alist[rightmark] >= pivotvalue and rightmark >= leftmark:
rightmark = rightmark -1
if rightmark < leftmark:
done = True
else:
temp = alist[leftmark]
alist[leftmark] = alist[rightmark]
alist[rightmark] = temp
temp = alist[first]
alist[first] = alist[rightmark]
alist[rightmark] = temp
return rightmark
</code></pre></div></div>
<h2 id="heapsort">Heapsort</h2>
<p><img src="/img/Sorting-algorithms/Sorting_heapsort_anim.gif" alt="image alt" title="Heapsort" /></p>
<p>Heapsort is a sorting algorithm based in the structure of a heap. The heap is a specialized data structure found in a tree or a vector.
In the first stage of the algorithm, a tree is created with the values to be sorted, starting from the left, we create the root node, with the first value. Now we create a left child node and insert the next value, at this moment we evaluate if the value set to the child node is bigger than the value at the root node, if yes, we change the values. We do this to all the tree. The initial idea is that the parent nodes always have bigger values than the child nodes.</p>
<p>At the end of the first step, we create a vector starting with the root value and walking from left to right filling the vector.</p>
<p>Now we start to compare parent and child nodes values looking for the biggest value between them, and when we find it, we change places reordering the values. In the first step, we compare the root node with the last leaf in the tree. If the root node is bigger, then we change the values and continue to repeat the process until the last leaf is the larger value. When there are no more values to rearrange, we add the last leaf to the vector and restart the process. We can see this in the image below.</p>
<p><img src="/img/Sorting-algorithms/uv9rgMfetq-heapsort-example.gif" alt="image alt" title="Heapsort" /></p>
<p>The main characteristics of the algorithm are:</p>
<ul>
<li>From the family of sorting by selection</li>
<li>Comparisons in the worst case = O(n log n)</li>
<li>Not stable</li>
</ul>
<p>Python implementation:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sun Mar 10 18:18:25 2019
@source: https://www.geeksforgeeks.org/heap-sort/
"""
# Python program for implementation of heap Sort
# To heapify subtree rooted at index i.
# n is size of heap
def heapify(arr, n, i):
largest = i # Initialize largest as root
l = 2 * i + 1 # left = 2*i + 1
r = 2 * i + 2 # right = 2*i + 2
# See if left child of root exists and is
# greater than root
if l < n and arr[i] < arr[l]:
largest = l
# See if right child of root exists and is
# greater than root
if r < n and arr[largest] < arr[r]:
largest = r
# Change root, if needed
if largest != i:
arr[i],arr[largest] = arr[largest],arr[i] # swap
# Heapify the root.
heapify(arr, n, largest)
# The main function to sort an array of given size
def heapSort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n, -1, -1):
heapify(arr, n, i)
# One by one extract elements
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # swap
heapify(arr, i, 0)
heapSort(arr)
</code></pre></div></div>
<h2 id="benchmark-how-fast-they-are">Benchmark: How fast they are?</h2>
<p>After development of the algorithms it is good for us to test how fast they can be. In this part we developed a simple program using the code above to generate a basic benchmark, just to see how much time they can use to sort a list of integers.
Important observations about the code:</p>
<ul>
<li>Python default recursion call limit is 1,000, in this test we are using big numbers, so we needed to improve that number to run the benchmark without errors. The limit was set to 10,000.</li>
<li>This code just measure the running time of each algorithm.</li>
<li>It was made 20 tests with different size of lists ranging from 2500 to 50000.</li>
<li>The numbers were generate randonly ranging from 1 to 10000.
The results are the following:
Shell sort and Heap Sort algorithms performed well despite the length of the lists, in the other side we found that Insertion sort and Bubble sort algorithms were far the worse, increasing largely the computing time. See the results in the chart below.</li>
</ul>
<p><img src="/img/Sorting-algorithms/benchmarkChart.png" alt="image alt" title="Benchmark" /></p>
<h2 id="conclusion">Conclusion</h2>
<p>In this post, we showed 5 of the most common sorting algorithms used today. Before using any of them is extremely important to know how fast it runs and how much space is going to use. So it’s the tradeoff between complexity, speed, and volume. Another critical characteristic of the sorting algorithms that are important to know is its stability. The stability means that the algorithm keeps the order of elements with equal key values. The best algorithm changes for each different set of data and as a result, understanding our data plays a significant role in the process of choosing the right algorithm.</p>
<p><img src="/img/Sorting-algorithms/stability.png" alt="image alt" title="Stability" /></p>
<p>As we can see, understanding our data plays a very important role in the process of choosing the right algorithm.</p>
<p>If this post got your attention, take a look at video below, it will give you a concise explanation about 15 sorting algorithms.</p>
<p><a href="http://www.youtube.com/watch?v=kPRA0W1kECg" title="15 Sorting algorithms in 6 minutes"><img src="http://img.youtube.com/vi/kPRA0W1kECg/0.jpg" alt="15 Sorting algorithms in 6 minutes" /></a></p>
<p><strong>References:</strong></p>
<blockquote>
<p>Big O Notation - https://en.wikipedia.org/wiki/Big_O_notation</p>
</blockquote>
<blockquote>
<p>Knuth, Donald Ervin, 1938 - The art of computer programming / Donald Ervin Knuth. xiv,782 p. 24 cm.</p>
</blockquote>
<blockquote>
<p>15 Sorting Algorithms in 6 minutes - https://www.youtube.com/watch?v=kPRA0W1kECg</p>
</blockquote>
<blockquote>
<p>Insertion sort - https://pt.wikipedia.org/wiki/Insertion_sort</p>
</blockquote>
<blockquote>
<p>Insertion sort - http://interactivepython.org/courselib/static/pythonds/SortSearch/TheInsertionSort.html</p>
</blockquote>
<blockquote>
<p>Shell sort - https://en.wikipedia.org/wiki/Shellsort</p>
</blockquote>
<blockquote>
<p>Shell sort - http://www.bebetterdeveloper.com/algorithms/sorting/sorting-shell-sort.html</p>
</blockquote>
<blockquote>
<p>Shell sort - https://www.researchgate.net/publication/234791427_ENHANCED_SHELL_SORT_ALGORITHM</p>
</blockquote>
<blockquote>
<p>Shell sort - https://www.w3resource.com/python-exercises/data-structures-and-algorithms/python-search-and-sorting-exercise-7.php</p>
</blockquote>
<blockquote>
<p>Bubble sort - https://en.wikibooks.org/wiki/A-level_Computing/AQA/Paper_1/Fundamentals_of_algorithms/Sorting_algorithms#Bubble_Sort</p>
</blockquote>
<blockquote>
<p>Quicksort - https://commons.wikimedia.org/wiki/File:Quicksort.gif</p>
</blockquote>
<blockquote>
<p>Quicksort - http://interactivepython.org/courselib/static/pythonds/SortSearch/TheQuickSort.html</p>
</blockquote>
<blockquote>
<p>Heapsort Algorithm - https://en.wikipedia.org/wiki/Heapsort</p>
</blockquote>
<blockquote>
<p>Heapsort Algorithm - https://www.geeksforgeeks.org/heap-sort/</p>
</blockquote>
<blockquote>
<p>Bubble sort - http://interactivepython.org/runestone/static/pythonds/SortSearch/TheBubbleSort.html</p>
</blockquote>
<blockquote>
<p>The Advantages & Disadvantages of Sorting Algorithms - Joe Andy - https://sciencing.com/the-advantages-disadvantages-of-sorting-algorithms-12749529.html</p>
</blockquote>
<blockquote>
<p>Sedgewick, R., & Wayne, K. (2011). Algorithms, 4th Edition. (p. I–XII, 1-955). Addison-Wesley. - https://algs4.cs.princeton.edu/20sorting/</p>
</blockquote>
<blockquote>
<p>Sorting algorithms - https://brilliant.org/wiki/sorting-algorithms/</p>
</blockquote>
<blockquote>
<p>A tour of the top 5 sorting algorithms with Python code - https://medium.com/@george.seif94/a-tour-of-the-top-5-sorting-algorithms-with-python-code-43ea9aa02889</p>
</blockquote>
Diagnóstico em Regressão2019-04-13T23:59:07+00:00http://lamfo-unb.github.io/2019/04/13/Diagnostico-em-Regressao<h2 id="diagnóstico-em-regressão">Diagnóstico em Regressão</h2>
<p>Existem situações ao se fazer uma modelagem que o objeto de estudo é a interpretabilidade do modelo, impossibilitando modelos como Suport Vector Machine, Redes Neurais e outros. Para solucionar esse problema, os modelos estatísticos tradicionais como regressão linear e modelos lineares generalizados conseguem captar o efeito das variáveis explicativas sobre a variável resposta. Contudo, cada um desses modelos possui seus pressupostos específicos e para que se possa fazer inferência nos resultados, é necessário que os pressupostos estejam sendo respeitados. Esse post tem como objetivo ensinar técnicas que vão além de retirar valores discrepantes detectados pelo boxplot (acima (abaixo) de 1,5 x 3°(1°) quartil) para melhorar o ajuste de um modelo.</p>
<p>Existem métodos gráficos e testes estatísticos para diagnóstico. Esses métodos tentam identificar basicamente:</p>
<ul>
<li>
<p>Outliers, Valores influentes, Pontos de alavanca</p>
</li>
<li>
<p>Normalidade (ou outra distribuição que seja considerada nos pressupostos)</p>
</li>
<li>
<p>Homocedasticidade (variância constante)</p>
</li>
<li>
<p>Outros pressupostos que variam conforme o modelo</p>
</li>
</ul>
<p>Dividiremos o post nas seguintes etapas: (1) explicaremos as técnicas mais utilizadas, sua importância, interpretação e quando deve ser utilizada; (2) aplicabilidade em um problema de regressão, utilizando uma base real do próprio software R (Iris).</p>
<h2 id="diagnóstico">Diagnóstico</h2>
<p>Métodos de diagnóstico são utilizados para que desvios entre as observações e os valores ajustados do modelo sejam analisados e verificados o seu grau de influência sobre a análise.</p>
<p>Essa diferênça entre o real e o previsto podem surgir por vários motivos, pela função de variância, função de ligação, ausência ou não parâmetro de dispersão, parâmetro de inflação nos zeros, ou ainda pela definição errada da escala da variável ou mesmo porque algumas observações se mostram dependentes ou possuem correlação serial. Discrepâncias pontuais podem ocorrer porque as observações estão nos limites observáveis da variável, erros de digitação, algum fator não controlado (mas relevante) influenciou a sua obtenção ou até mesmo multicolinearidade entre variáveis (correlação alta entre variáveis).</p>
<p>As técnicas de diagnóstico podem ser formais ou informais. As informais baseiam-se em gráficos para detectar padrões visualmente e ver o comportamento dos dados. As formais envolvem especificar o modelo sob pesquisa em uma e verificar via testes, intervalos de confiança e outras medidas específicas para cada modelo, as mais usadas são baseadas nos testes da razão de verossimilhanças e escore.</p>
<p>Esse post terá como foco o modelo de regressão linear na apresentação de fórmulas por simplicidade, a extensão do conteúdo acontece de forma natural para modelos lineares generalizados e outras classes de modelo acrescentando os parâmetros pertinentes.</p>
<p>No modelo de regressão linear, que tem forma \(Y=X\beta + e\), os elementos \(e_i\) do vetor e
são as diferenças entre os valores observados y_i e aqueles esperados \mu_i pelo modelo.
Essa diferença é chamada de resíduo e considera-se como pressuposto do modelo que os resíduos sejam independentes e que tenham distribuição normal (a distribuição esperada pode mudar conforme o modelo), cabe ressaltar que a normalidade deve ser verificada nos resíduos e não na variável resposta Y.</p>
<p>Os resíduos indicam a variação natural dos dados, um fator aleatório (ou não) que o modelo não capturou. Se as pressuposições do modelo são violadas, a análise será levada a resultados duvidosos e não confiáveis para inferência. Essas falhas do modelo nos pressupostos podem ser oriundas de diversos fatores como não linearidade, não-normalidade, heterocedasticidade, não-independência e isso pode ser causado por pontos atípicos (observações discrepantes), que podem influenciar, ou não, no ajuste do modelo.</p>
<p>Depois de ajustado um modelo algumas medidas básicas de pressuposições sempre devem ser verificadas como</p>
<ul>
<li>valores estimados (ou ajustados) \(\hat{\mu}_i\);</li>
<li>Resíduos ordinários \(r_i = y_i - \hat{\mu}_i\) (existem outros tipos de resíduos mas partindo da mesma premissa de diferença de valores);</li>
<li>Variância residual estimada (ou quadrado médio residual) \(\hat{\sigma}^2 = s^2 = \sum(y_i - \hat{\mu}_i)^2/(n - p)\);</li>
<li>Elementos da diagonal (Leverage) da matriz de projeção \(H = X(X^TX)^{-1}X^T\)</li>
</ul>
<p>A diagonal principal da matriz de projeção \(H = X(X^TX)^{-1}X\), em que X denota a matriz modelo, também conhecido como pontos de alavanca, que receberam esse nome por terem um peso desproporcional no
próprio valor ajustado. Esses pontos em geral são remotos no subespaço gerado pelas colunas da matriz X, ou seja, têm um perfil diferente das demais observações no que diz respeito aos valores das variáveis explicativas, conforme o seu afastamento das outras observações esses pontos podem exercer forte influência nas estimativas dos coeficientes da regressão.</p>
<p>Agora serão apresentados algumas métricas usadas para diagnóstico de forma geral.</p>
<h3 id="resíduos">Resíduos</h3>
<ul>
<li>Resíduos ordinários</li>
</ul>
<p>Os resíduos por mínimos quadrados são definidos por \(r_i = y_i - \hat{\mu}_i\).
Pela definição as observações do vetor do termo de erro do modelo são independentes e têm a mesma variância, os resíduos (o erro observavel) obtidos com ajuste do modelo tem a seguinte variância</p>
<p>\(Var(R) = Var[(I - H)Y] = \sigma^2(I - H)\).</p>
<p>Os resíduos ordinários podem não ser adequados devido à heterogeneidade das variâncias e falta de independência. Então, foram construídas padronizações nos resíduos para minimizar esse problema.</p>
<ul>
<li>Resíduos estudentizados internamente (Studentized residuals)</li>
</ul>
<p>Um estimador não viesado para a variância dos resíduos é expresso por
\(\hat{Var}(r_i) = (1 - h_{ii})s^2\)
Como \(E(r_i) = E(Y_i - \hat{\mu}_i) = 0\), o resíduo estudentizado internamente (ou seja, retirando a média e dividindo pelo desvio padrão) é igual a</p>
\[rsi_i = \frac{ri}{s \sqrt{(1 - h_{ii})}\]
<p>Esses resíduos são mais sensíveis do que os anteriores por considerarem variâncias distintas. Ainda assim, um valor discrepante pode mudar drasticamente a variância residual dependendo do modo como se afasta da maioria das observações. Para corrigir esse problema é feita uma pequena alteração na fórmula, que será mostrada a seguir.</p>
<ul>
<li>Resíduos estudentizados externamente (jackknifed residuals, RStudent)</li>
</ul>
<p>Define-se o resíduo estudentizado externamente, como</p>
\[rse_{(i)} = \frac{ri}{s_{(i)} \sqrt{(1 - h_{ii})}\]
<p>sendo \(s^2_{(i)}\) o quadrado médio residual livre da influência da observação i, ou seja, é estimado a variância sem a observação i (por isso a ideia de Jackknife).</p>
<p>A vantagem de usar o resíduo \(rse_{(i)}\), além de ser mais robusto, é que, sob normalidade, tem distribuição t de Student com \((n - p - 1)\) graus de liberdade.</p>
<h3 id="pontos-discrepantes">Pontos discrepantes</h3>
<p>Pontos atípicos são caracterizadas por terem \(h_{ii}\) e/ou resíduos grandes, serem inconsistentes e/ou influentes. Uma observação inconsistente é aquela que se afasta da tendência geral das demais. Quando uma observação está distante das outras em termos das variáveis explicativas, ela pode ser, ou não, influente. Uma observação influente é aquela cuja omissão do conjunto de dados resulta em mudanças substanciais nas estatísticas de diagnóstico do modelo. Essa observação pode ser um outlier (observação aberrante), ou não. Uma observação pode ser influente de 3 maneiras:</p>
<ul>
<li>Ajuste geral do modelo;</li>
<li>Conjunto das estimativas dos parâmetros;</li>
<li>Estimativa de um determinado parâmetro;</li>
</ul>
<p>As estatísticas mais usadas para verificar pontos atípicos são:</p>
<ul>
<li>Leverage: \(h_{ii}\) (já comentado);</li>
<li>\(rse_{(i)}\) (já comentado);</li>
<li>Influência sobre o parâmetro \(\beta_i : DFBetaS(i)\) para \(\beta_i\);</li>
<li>Influência geral: DFFitS(i), D(i).</li>
</ul>
<p>Existem alguns critérios para classificação das observações como discrepantes, contudo cada autor possui o seu critério. De uma forma geral, pode-se classificar uma observação como:</p>
<ul>
<li>
<table>
<tbody>
<tr>
<td>Inconsistente: ponto com \(</td>
<td>rse_{(i)}</td>
<td>\) grande, isto é, tal que \(</td>
<td>rse_{(i)}</td>
<td>> t_{(1-\alpha)/(2n);n-p-1}\);</td>
</tr>
</tbody>
</table>
</li>
<li>Alavanca: ponto com h_{ii} grande, isto é, tal que h_{ii} - 2p/n, no qual p é o número de parâmetros e n o tamanho da amostra. Pode ser classificado como bom, quando consistente, ou ruim, quando inconsistente;</li>
<li>Outlier: ponto inconsistente com leverage pequeno, ou seja, com \(rse_{(i)}\) grande e \(h_{ii}\) pequeno;</li>
<li>Influente: ponto com DFFitS(i), C(i), D(i) ou DFBetaS(i) grande.</li>
</ul>
<p>Essas medidas de influência são descritas abaixo.</p>
<ul>
<li>DFBeta e DFBetaS</li>
</ul>
<p>São usados quando o coeficiente de regressão tem um significado prático. A estatística DFBeta(i) mede a alteração no vetor estimado \hat{\beta} ao se retirar a i-ésima observação da análise, isto é,</p>
\[DFBeta(i) = \hat{\beta} - \hat{\beta}_{(i)} = \frac{ri}{(1 - h_{ii})}(X^TX)^{-1}x_i\]
<p>Portanto, é possível verificar o tamanho da influência nos parâmetros que a ausência de determinada observação pode causar</p>
<ul>
<li>DFFit e DFFitS</li>
</ul>
<p>A estatística DFFit e sua versão estudentizada DFFitS medem a alteração no valor ajustado pela eliminação da observação i, é basicamente o DFBeta ajustado em x_i. São expressas como</p>
\[DFFit(i) = x^T_i(\hat{\beta} - \hat{\beta}_{(i)}) = \hat{\mu}_i - \hat{\mu}_{(i)}\]
<ul>
<li>Distância de Cook</li>
</ul>
<p>É a mais utilizada, é uma medida de afastamento do vetor de estimativas resultante da eliminação da observação i. Tem uma expressão muito semelhante ao DFFitS mas que usa como estimativa da variância residual aquela obtida com todas as n observações, considera o resíduo estudentizado internamente.</p>
\[D_{(i)} = \frac{(\hat{\beta} - \hat{\beta}_{(i)})^T (X^TX)(\hat{\beta} - \hat{\beta}_{(i)})}{p s^2}\]
<h3 id="multicolinearidade">Multicolinearidade</h3>
<p>Para finalizar, outro grande problema ocorrido nos modelos é a multicolinearidade no qual as variáveis independentes possuem relações lineares exatas ou aproximadamente exatas (correlação alta) entre elas mesmas, indicando que duas ou mais variaveis fornecem a mesma informação sobre a variável resposta. Um índício da existência da multicolinearidade é quando o R^2 é bastante alto (acima de 0,7), mas nenhum dos coeficientes da regressão é estatisticamente significativo segundo a estatística t convencional. A importância de se verificar a existência de multicolinearidade é que podem alterar as estimativas dos parâmetros e fornecer erros-padrão elevados no caso de multicolinearidade moderada ou alta.</p>
<ul>
<li>VIF</li>
</ul>
<p>Além de verificar a alteração dos parâmetros e seu desvio padrão ao se retirar uma observação, existe uma medida chamada de VIF (fator de inflação da variância) que é utilizada para verificar a partir das correlações o impacto da variância em cada parâmetro. Conforme o VIF aumenta maior o indício de multicolinearidade, entretanto não existem um ponto de corte bem definido, alguns autores recomendam valores acima de 10 como limiar. O cálculo do VIF é dado pela seguinte fórmula</p>
\[VIF_k = (1-R_k^2)^{-1}\]
<h2 id="banco-de-dados">Banco de dados</h2>
<p>O banco de dados utilizado será a base Iris que possui observações acerca de três espécies de plantas e é uma base muito utilizada e conhecida para análises iniciais por ser um banco pequeno, de fácil entendimento e ajuste do modelo.</p>
<p>O objetivo será modelar o comprimento da sépala usando a largura da pétala e sépala, espécie e comprimento da pétala. Depois do ajuste do modelo, será verificado cada pressuposto e se está de acordo com o esperado.</p>
<h2 id="análise-de-dados">Análise de dados</h2>
<p>Para a análise foi utilizado o banco de dados Iris utilizando o ambiente R de computação estatística.</p>
<p>A base de dados pode ser obtida no próprio repositorio do R, é necessário apenas chamar o banco de dados. A descrição das variáveis está disponível no help do R.</p>
<p>Primeiramente, serão lidos os dados e depois ajustado o modelo de regressão linear.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>library(car)
head(iris)
m <- lm(Sepal.Length~., data=iris)
summary(m)
</code></pre></div></div>
<p><img src="/img/mlg/header.JPG" height="150" width="300" /></p>
<p><img src="/img/mlg/modelo.JPG" height="450" width="450" /></p>
<p>Pelo ajuste do modelo, verificamos que as variáveis são significativas e que o mínimo e máximo dos resídos são inferiores a 1, já sendo um indício que as medidas usando resíduos studentizados devem apresentar valores baixos. Além disso, é necessário verificar a correlação entre as variáveis do modelo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>library(corrplot)
correlacao=cor(iris[,-5])
corrplot(correlacao)
</code></pre></div></div>
<p><img src="/img/mlg/corr.JPG" height="450" width="450" /></p>
<p>Por meio do gráfico de correlação entre as variáveis explicativas é possível verificar que existem algumas variáveis relacionadas e que podem causar multicolineariedade. Essa análise será feita mais adiante.</p>
<p>Primeiramente, será verificado a normalidade dos resíduos studentizados por meio do qqplot e histograma.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>qqPlot(m, main="QQ Plot") #qq plot for studentized resid
# distribution of studentized residuals
library(MASS)
sresid <- studres(m)
hist(sresid, freq=FALSE,
main="Distribution of Studentized Residuals")
xm<-seq(min(sresid),max(sresid),length=40)
ym<-dnorm(xm)
lines(xm, ym)
</code></pre></div></div>
<p><img src="/img/mlg/qqplot.JPG" height="450" width="450" /></p>
<p><img src="/img/mlg/histograma.JPG" height="450" width="450" /></p>
<p>Pelo QQplot, não encontramos indícios de que não existe normalidade nos resíduos porque o comportamento está bem linear e dentro das faixas. As faixas tracejadas são o intervalo de confiança enquanto que o eixo x é o quantil teórico enquanto que o eixo vertical é o empírico. Pelo histograma, é possível ver que os resíduos estão simétricos em torno de 0 e que uma distribuição normal está se ajustando bem aos dados.</p>
<p>O gráfico do leveragePlots é um gráfico de alavancagem para um efeito fixo que mostra o impacto da adição desse efeito ao modelo, dados os outros efeitos já existentes no modelo. Ou seja, são mostrados os resíduos da regressão usando determinada variável desconsiderando as demais, a reta azul é a regressão e quanto mais distante a observação maior a falta de ajuste.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>leveragePlots(m) # leverage plots
</code></pre></div></div>
<p><img src="/img/mlg/leverage.JPG" height="450" width="450" /></p>
<p>Pelos gráficos, é possível analisar que os pontos estão bem próximos da reta e que as distâncias praticamente não ultrapassam 1 nos resíduos, indicando que tem um leverage controlado.</p>
<p>Na sequenência, será feito o gráfico da distância de Cook</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Influential Observations
# Cook's D plot
# identify D values > 4/(n-k-1)
cutoff <- 4/((nrow(mtcars)-length(m$coefficients)-2))
plot(m, which=4, cook.levels=cutoff)
</code></pre></div></div>
<p><img src="/img/mlg/cook.JPG" height="450" width="450" /></p>
<p>Pelo gráfico não existem indícios de alguma observação (número da observação no eixo horizontal) que esteja acima de 0,50 (considerando uma distância grande), pelo contrário, todas estão abaixo de 0,10.</p>
<p>Dado que não existem valores influêntes, o próximo gráfico verifica os pontos de leverage, outliers e discrepantes conjuntamente.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Influence Plot
influencePlot(m, id.method="identify", main="Influence Plot", sub="Circle size is proportial to Cook's Distance" )
</code></pre></div></div>
<p><img src="/img/mlg/influence.JPG" height="450" width="450" /></p>
<p>As linhas acima de 2 e abaixo de -2 indicam os resíduos studentizados mais elevados enquanto que as linhas verticais indicam valores de leverage mais elevados e o tamanho do círculo é proporcional a distância de Cook. Esse gráfico faz a união de diversas medidas e é um ótimo indicativo para quais observações podem se destacar das demais. Nesse estudo, mesmo as observações 42,119 e 135 estarem um pouco afastadas, os valores absolutos de cada medida indicaram que não são observações influentes e que devem atrapalhar de forma geral o ajuste do modelo.</p>
<p>Com relação ao pressuposto da homocedasticidade (variância constante), foi realizado o teste de Breuch-Pagan e NCV que possuem como hipotese nula a homocedasticidade dos resíduos e se baseiam na verossimilhança. Ao realizar os testes, ambos falham em rejeitar a hipotese nula ao nível de 5%, ou seja, não existem indícios de que o pressuposto de homocedasticidade não é respeitado.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Evaluate homoscedasticity
lmtest::bptest(m)
# non-constant error variance test
ncvTest(m)
</code></pre></div></div>
<p><img src="/img/mlg/breuch_pagan.JPG" height="100" width="250" /></p>
<p><img src="/img/mlg/ncv.JPG" height="100" width="250" /></p>
<p>Pela matriz de correlação foi verificado algumas relações entre as variáveis, para verificar o grau de significância disso foi calculado o VIF para cada variável. Pelos resultados, algumas variáveis como comprimento e largura da pétala possuem um valor de VIF que podem influenciar no ajuste, por isso seria interessante refazer o modelo retirando elas e refazer as medidas de diagnóstico para verificar se tem uma alteração brusca nos valores.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Evaluate Collinearity
vif(m) # variance inflation factors
vif(m) > 10 # indício
</code></pre></div></div>
<p><img src="/img/mlg/vif.JPG" height="100" width="250" /></p>
<p><img src="/img/mlg/vif2.JPG" height="100" width="250" /></p>
<p>Para verificar independência dos resíduos foi ajustado o teste de Durbin Watson que possui hipótese nula de ausência de correlação serial e sua estatística do teste é construída somente com os resíduos. Ao nível de 5% de significância não encontramos indícios para rejeitar a hipótese de correlação, portanto é mais um pressuposto atendido.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Test for Autocorrelated Errors
durbinWatsonTest(m)
</code></pre></div></div>
<p><img src="/img/mlg/durbin_watson.JPG" height="100" width="250" /></p>
<p>Para finalizar, a função GVLMA fornece estimativas do ajste do modelo e também verifica automaticamente alguns pressupostos. Ela pode ser útil para uma validação rápida, contudo existem outros pressupostos que são necessários verificar conforme o modelo utilizado.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Global test of model assumptions
library(gvlma)
gvmodel <- gvlma(m)
summary(gvmodel)
</code></pre></div></div>
<p><img src="/img/mlg/gvlma.JPG" height="450" width="450" /></p>
<p>De forma geral os resultados de diagnóstico foram adequados e apenas a medida do VIF que deveria ser verificada com a retirada de uma variável do modelo.</p>
<p>As técnicas aqui expostas não esgotam o assunto e são apenas algumas das mais utilizadas, existem diversos outros testes e gráficos alternativos para se diagnosticar um modelo. A parte de diagnóstico é imprescindivel para validação de um modelo que possua como objetivo a interpretabilidade e entendimento dos resultados.</p>
<h2 id="referências">Referências</h2>
<p>Dobson, Annette J., 1945- An introduction to generalized linear models / Annette J. Dobson and Adrian G. Barnett. – 3rd ed.</p>
<p>Cordeiro, Gauss Moutinho; Demétrio, Clarice Garcia Borges; Moral, Rafael de Andrade. Modelos Lineares Generalizados e Extensões. Piracicaba, setembro de 2016.</p>
<p>Gilberto A. Paula, MODELOS DE REGRESSÃO com apoio computacional.Instituto de Matemática e Estatística Universidade de São Paulo.</p>
Modelos Lineares Generalizados2018-09-29T14:15:07+00:00http://lamfo-unb.github.io/2018/09/29/MLG<h2 id="modelos-lineares-generalizados">Modelos Lineares Generalizados</h2>
<p>Existem situações ao se fazer uma modelagem que o objeto de estudo central não é uma variável quantitativa, impossibilitando a tradicional regressão linear. Para solucionar esse problema, os modelos lineares generalizados surgiram para contornar esse problema e utilizam distribuições que são da família exponencial e possuem determinadas propriedades em comum. Um caso particular dessa família é a distribuição normal, por isso o nome de generalizado.</p>
<p>Existem várias aplicações, mas basicamente existem 3 grandes subgrupos de aplicações:</p>
<ul>
<li>
<p>O primeiro são dados de contagens, como número de carros que passam em uma rodovia a cada minuto, número de homicídios por dia em determinada cidade e número de reclamações de uma determinada seguradora por cliente;</p>
</li>
<li>
<p>O segundo grupo são para dados categóricos que são os mais conhecidos, algumas aplicações são as transações bacárias fraudulentas, uso ou não de um seguro de carro durante o período contratado, a oscilação positiva ou negativa de uma ação;</p>
</li>
<li>
<p>O terceiro grupo, menos conhecido, são dados assimétricos positivos, uma aplicação seria dados de precipitação ou temperatura de determinada cidade.</p>
</li>
</ul>
<p>Dividiremos o post nas seguintes etapas: (1) explicaremos os modelos mais comuns em MLG; (2) aplicabilidade em um problema de contagem, utilizando uma base real.</p>
<h2 id="modelagem">Modelagem</h2>
<p>Os modelos lineares generalizados (mlg) são uma classe de modelos que aumentam as possibilidades de análises para outras distribuições que não seja apenas a distribuição normal, portanto a regressão linear tradicional é um caso particular de MLG, esse fato será discutido mais a frente. Os MLGs são utilizados quando o objetivo do estudo é fazer uma análise sobre uma variável resposta que seja principalmente uma:</p>
<ul>
<li>Contagem;</li>
<li>Categórica;</li>
<li>Assimetria (com valores positivos).</li>
</ul>
<p>Uma abordagem sobre esse tema já foi introduzido no post do Cayan Portela (<a href="https://lamfo-unb.github.io/2017/07/05/Modelo-Tweedie-Poisson/">Modelo Tweedie Poisson Compound para dados de sinistros de veículos</a>), é recomendada a leitura para compreender uma outra extensão desses modelos.</p>
<p>Por definição, para ser um MLG é necessário que a distribuição de probabilidade seja da família exponencial (abordaremos apenas a família exponencial unidimensional, um parâmetro apenas), ou seja, a distribuição pertence a uma classe de distribuições que possuam alguns aspectos em comum, como: satisfazem o lema da fatoração de neyman (estatística suficiente), possuam estatística suf. minimal, média \((\bar{x})\) é suficiente, possa ser escrita no seguinte formato:</p>
\[f(y_i;\theta_i,\phi) = \mbox{exp}\left\{\phi^{-1} [y_i a(\theta_i) - b(\theta_i)] + c(y_i,\phi)\right\}\]
<p>No qual, \(\theta\) é o parâmetro do modelo, \(y\) os dados observados e \(\phi\) um parâmetro de dispersão, que pode ser unitário em casos de distribuições que não possuem ele explicitamente (Poisson é um exemplo). A família exponencial é muito importante porque possui características comuns a várias distribuições famosas como Normal, Poisson, Exponencial, Binomial, Gama, Normal Inversa, Binomial Negativa. Além disso, é chamada de familia exponencial canônica quando a função \(a(\theta_i) = \theta_i\) não ocorre naturalmente, mas pode ser feita uma reparametrização.</p>
<p>Duas propriedades muito importantes dos MLG’s é a relação que a função \(b(\theta_i)\) possui com a média e variância dos dados.
\(E(Y_i) = b'(\theta_i) = {\mu_i}\)</p>
\[Var(Y_i) = \phi b''(\theta_i) = \phi V(\mu_i)\]
<p>No qual \(b’\) e \(b’’\) se referem a primeira e segunda derivada em relação ao parâmetro \(\theta_i\). Note que o parâmetro de dispersão possui um papel importante na variância, podendo inflar a variância dos dados caso seja necessário e, caso não seja, ocorre a equivalência das variâncias indicando que a variância do próprio modelo já consegue capturar toda a dispersão.</p>
<p>No caso da regressão, os MLG’s possuem a seguinte forma:</p>
\[g(\boldsymbol{\mu_i}) = \boldsymbol{x_i\beta_i}\]
<p>No qual, \(\beta_i\) são os coeficientes do modelo, \(x_i\) as observações e a função g é chamada de função de ligação, quando \(\theta_i = g(\mu_i)\) dizemos que \(g\) é a ligação canônica. Um caso particular é quando consideramos a função \(g\) como identidade e a distribuição normal com média e variância desconhecida, dessa forma obtemos o equivalente a regressão linear comum e os métodos de estimação coincidem.</p>
<p>Outro fato relevante é que não existe explicitamente na construção um termo de erro, isso não quer dizer que o modelo não possui erro, apenas que o termo não é nítido como na regressão linear. Em MLG ainda é necessário análise de resíduos para verificar o ajuste e qualidade do modelo.</p>
<p>Na prática, existem alguns modelos considerados baseline e alguns candidatos que podem ter ajuste melhor, além de alguns fatos estilizados conforme cada categoria do MLG listada anteriormente. Cada categoria será análisada a seguir e indicado um roteiro de possíveis variações.</p>
<h3 id="contagem">Contagem</h3>
<p>Para dados de contagem, o modelo principal se baseia na distribuição de poisson (na forma canônica \(\theta_i = log(\mu_i)\)). Ele tem a carácterística de que \(E(Y_i) = Var(Y_i) = \mu_i\), ou seja, a média é igual a variância, conhecido como equidispersão. As ligações mais comuns são logaritmica, raiz e identidade.</p>
<p>Portanto, em situações em que os dados possuem muita variabilidade e é esperado que a igualdade não seja atendida pode ser interessante ajustar modelos que levam isso em consideração. A primeira opção seria o modelo Poisson com disperssão, Poi(\(\mu_i\),\(\phi\)), que insere o parâmetro para capturar a variabilidade. Outra opção, é o modelo Binomial Negativo (com ou sem parâmetro de dispersão) que pela definição não é MLG mas possui características muito semelhantes e possui uma boa capacidade de capturar um efeito \(E(Y_i) < Var(Y_i)\) e além disso consegue, de certa forma, lidar bem com um problema chamado de inflação de zeros que é exatamente uma alta frequência de contagens 0. Outros modelos que podem trabalhar a inflação de zeros são poisson inflacionada de zeros (ZIP), binomial negativa inflacionada de zeros (ZINB) e modelos com barreira (hurdle).</p>
<p>De forma sucinta, para dados de contagem é necessário observar o excesso de zeros e a dispersão. Dessa forma temos a seguinte sugestão de modelos.</p>
<ul>
<li>Sem excesso de zeros e sem dispersão: Poisson;</li>
<li>Sem excesso de zeros e com dispersão: Poisson com dispersão e Binomial negativa sem/com dispersão;</li>
<li>Com excesso de zeros e sem dispersão: Binomial negativa sem/com dispersão, ZIP, ZINB e hurdle.</li>
</ul>
<h3 id="categórica">Categórica</h3>
<p>Para dados categóricos, o modelo principal se baseia na distribuição binomial, o que fornece a regressão logística.Possui a característica de estimar facilmente a razão de chances, uma medida importante e comumente utilizada para mensurar efeitos das variáveis. As ligações mais comuns nessa classe de MLG são logaritmica, exponencial, identidade, normal acumulada e log log complementar.</p>
<p>Geralmente, os modelos são utilizados quando a variável categórica possui apenas duas categorias, mas possuem adaptações para quando possuem 3 ou mais. Quando são mais de duas categorias, é necessário verificar se a relação entre as categorias é nominal (dias da semana por exemplo) ou ordinal (opinião de um filme: gostou, indiferente, não gostou), ou seja, se as categorias possuem ou não uma relação de intensidade. Caso não exista essa relação de intensidade a regressão logística nominal pode ser utilizada e, caso exista, a regressão logística ordinal.</p>
<p>Como já mencionado, para estimar a razão de chance o modelo mais recomendado é a regressão logística, mas isso não impede que outros modelos possam estimar também, mas nesse modelo o resultado é obtido imediatamente exponenciando os coeficientes \(\beta_i\) do modelo. Para se estimar o risco relativo que é outra medida muito utilizada, é usualmente ajustado o modelo log-binomial. Outras medidas como risco absoluto e dose letal podem ser obtidas usando o mesmo modelo binomial mas com ligação identidade e a acumulada da normal (F).</p>
<h3 id="assimétria-com-valores-positivos">Assimétria (com valores positivos)</h3>
<p>Modelos para dados assimétricos positivos podem ser modelados por regressão linear caso a assimetria não seja acentuada. O modelo mais usado para esse tipo de dado é o modelo gama, que possui uma distribuição muito flexível para ajuste. As ligações mais comuns são identidade, inversa e logaritmica. Caso existam muitos outliers, o modelo com a normal invertida é uma sugestão para melhorar o ajuste. A regressão Skew-Normal também é competitiva com as demais modelagens, mas possui a vantagem de aceitar dados negativos e também uma flexibilidade para ajuste.</p>
<p>Essa classe de modelo é menos conhecida e estudada, uma vez que para corrigir a assimetria são feitas transformações como a logaritmica para normalizar os dados e efetuar a regressão linear. Independente da abordagem, é necessário verificar os objetivos da análise e qual modelo consegue de forma mais efetiva cumpri-los.</p>
<h2 id="banco-de-dados">Banco de dados</h2>
<p>O banco de dados utilizado será o mesmo do post feito pelo Cayan sobre o <a href="https://lamfo-unb.github.io/2017/07/05/Modelo-Tweedie-Poisson/">Tweedie-Poisson</a>. Os dados referem-se ao número de sinistros e total de pagamento (valores monetários) gerados, por grupo e número de reclamções que será o objetivo da modelagem nesse post.</p>
<p>O número de reclamações (Claims) é uma variável de contagem que representa quantas reclamações foram feitas. Portanto, o valor 0 significa que não ocorreu reclamação e é algo que pode influenciar na análise como mencionado nos fatos estilizados de modelos de contagem. Além disso, o número de reclamação assume valores elevados, entretanto foi feito um corte na base de dados para permanecer apenas as observações que tiverem no máximo 20 reclamações, uma vez que os valores acima disso são escassos e não possuem tanta relevância no estudo.</p>
<p>Considerando que o objetivo é modelar o número de reclamações, os modelos de contagens são os mais indicados. Portanto, serão analisados 4 modelos (mencionados na seção anterior) como propostas e verificados seu ajuste e erro. Para verificar a qualidade do modelo, foi utilizado o gráfico QQ-norm para verificar a normalidade dos resíduos, distância de Cook para observar a existência de valores influentes no modelo e o gráfico <em>Rootograma</em> que é um gráfico que é semelhante ao histograma mas “pendura” as barras do histograma no valor observado de forma que fica visualmente mais explicito a distância do valor ajustado e observado. Todos esses conceitos serão melhor compreendidos no decorrer da análise.</p>
<h2 id="análise-de-dados">Análise de dados</h2>
<p>Para a análise foi utilizado o banco de dados de sinistros de automóveis na Suécia, no ano de 1977, utilizando o ambiente R de computação estatística.</p>
<p>A base de dados pode ser obtida no link a seguir: StatiSci. A descrição das variáveis está disponível no link.</p>
<p>Primeiramente, serão lidos os dados, uma filtragem para manter apenas reclamações inferiores ou iguais a 20 e o histograma da variável resposta de interesse.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>library(dplyr)
library(MASS)
library(pscl)
library(vcd)
dados <- read.table("http://www.statsci.org/data/general/motorins.txt", sep = "\t", head = TRUE)
dados$Make <- as.factor(dados$Make)
dados <- dados %>% filter( Claims <= 20 ) # 1622 observações, 74% da base original
hist(dados$Claims)
sum(dados$Claims==0)/nrow(dados)
</code></pre></div></div>
<p><img src="/img/mlg/hist.JPG" height="450" width="450" /></p>
<p>Pelo histograma, verifica-se uma quantidade consideravel de contagens baixas, o que pode ser um indício que modelos que possuem a característica de zeros inflados possam ter vantagem (23% das observações possuem contagem 0).</p>
<h3 id="modelagem-1">Modelagem</h3>
<p>Como mencionado, o modelo benchmark inicial pela sua simplicidade e aceitação na literatura é o modelo Poisson. Observando as estimativas do modelo ajustado, é verificado que as variáveis são significativas em sua maioria e seus coeficientes muito pequenos, isso se deve a magnitude de algumas variáveis como Payment.</p>
<p>Ao analisar os gráficos, primeiramente se tem o gráfico QQplot que representa o ajuste dos resíduos do modelo em uma distribuição normal, ou seja, os quantis empíricos dos resíduos são comparados com os quantis teóricos de uma distribuição normal, quanto mais próximo for essa comparação teremos uma reta linear perfeita indicando que o quantil teórico e empirico são iguais, conforme ocorre uma distorção nessa reta existem indícios de que nessa região os resíduos empíricos ‘fogem’ da distribuição teórica. O segundo gráfico remete a distância de Cook para cada observação da amostra, essa distância é uma medida baseada na matriz hessiana (H, hat) levando em consideração a informação de fisher, conforme aumenta essa distância a influência de alguma observação sobre o modelo é grande, indicando que seus coeficientes podem estar estimados de forma equivocada e ter grande variabilidade ao mudar a base de dados. Para valores acima de 0,5 a distância é considerada como ‘alta’, esse valor é muito utilizado na literatura mas sem um rigor matemático para definição.</p>
<p>A partir desse esclarecimento sobre os gráficos, percebe-se uma cauda um pouco pesada no QQplot, mas não distorcendo muito do ideal (ser uma reta linear), além disso não existem observações que sejam influentes nos parâmetros porque a distância de Cook é inferior a 0,5 para todas observações. Com relação ao terceiro gráfico, percebe-se que as barras das contagens mais baixas (de 0 a 5) se distanciam muito da reta das obscissas, ou seja, ocorre um resíduo maior maior nessa faixa, principalmente na contagem 0, que possui a maior discrepância. Conforme as contagens aumentam, as barras se aproximam mais do eixo x, o valor ajustado (comprimento da barra) e observado (linha vermelha) se tornam mais próximos.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>m1 <- glm(Claims ~ ., family = poisson('log'), data = dados)
summary(m1)
par(mfrow=c(1,3))
plot(m1, which=c(2,4))
countreg::rootogram(m1)
</code></pre></div></div>
<p><img src="/img/mlg/m1.JPG" height="450" width="450" /></p>
<p><img src="/img/mlg/plot_m1.JPG" height="450" width="550" /></p>
<p>Pelos gráficos do primeiro modelo, percebe-se que é necessário encontrar um modelo que consiga melhorar o ajuste. Para isso, a distribuição binomial negativa deve conseguir ajustar melhor pela sua capacidade de captar sobredispersão e também, de certa forma, a inflação dos zeros, mas antes disso ajustaremos a Poisson com dispersão.</p>
<p>Ao observarmos os gráficos, verificamos uma diminuição das distâncias de cook e uma leve melhora no QQplot. O gráfico rootograma não foi ajustado por conta da incompatibilidade dos pacotes</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>m2 <- update(m1, family=quasi(link='log', variance='mu'))
summary(m2)
par(mfrow=c(1,2))
plot(m2, which=c(2,4))
</code></pre></div></div>
<p><img src="/img/mlg/m2.JPG" height="450" width="450" /></p>
<p><img src="/img/mlg/plot_m2.JPG" height="450" width="550" /></p>
<p>Ajustando o modelo binomial negativo, percebe-se novamente uma melhora nos 3 gráficos. As contagens mais baixas que não tiveram um ajuste muito bom melhoraram o ajuste no modelo binomial negativo. O ajuste no 0 também melhorou, mas ainda será ajustado o modelo binomial negativo com inflação no zero para verificar se melhora o ajuste. O QQplot também teve uma melhora na cauda (exatamente por conta do ajuste melhor) e a distância de Cook reduziu novamente, mostrando que as observações individualmente não influenciam erroneamente o modelo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>m3 <- glm.nb(Claims ~ ., data=dados)
#summary(m3)
par(mfrow=c(1,3))
plot(m3, which=c(2,4))
countreg::rootogram(m3)
</code></pre></div></div>
<p><img src="/img/mlg/plot_m3.JPG" height="450" width="550" /></p>
<p>Para finalizar, foi ajustado o modelo binomial negativo com inflação nos zeros. Os modelos com inflação no zero colocam uma massa pontual específica no zero, ou seja, uma mistura que assume um modelo específico para o zero e outro modelo para as demais contagens. Mais uma vez os ajustes melhoraram e, especialmente na contagem 0, melhorou a estimativa.</p>
<p>Colocando o erro quadrático médio (EQM) como medida de comparação dos modelos, percebe-se uma redução do EQM conforme aumenta a complexidade do modelo. Portanto, o modelo com menor EQM é o binomial negativo com inflação nos zeros seguido pelo binimoial negativo sem inflação, ambos são bons candidatos, a definição final de qual seria o escolhido seria um trade off entre facilidade de interpretação (no modelo com inflação são dois modelos em 1) e erro.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>m4 <- zeroinfl( Claims ~ . | 1, dist="negbin", data = dados)
#summary(m4)
par(mfrow=c(1,1))
countreg::rootogram(m4)
cat(" Poisson EQM :",mean(residuals(m1)^2),'\n',
"Poisson Dispersão EQM :",mean(residuals(m2)^2),'\n',
"Binomial Negativa EQM :",mean(residuals(m3)^2),'\n',
"Binomial Negativa inflada EQM:",mean(residuals(m4)^2))
</code></pre></div></div>
<p><img src="/img/mlg/plot_m4.JPG" height="450" width="550" /></p>
<p><img src="/img/mlg/eqm.JPG" height="350" width="350" /></p>
<p>Não foi feita uma seleção de variáveis e outras análises pertinentes como validação de um possível modelo final pois o objetivo era expor o conhecimento e modo de usar de cada um, mas são etapas muito importantes e imprescindíveis de uma boa modelagem.</p>
<h2 id="referências">Referências</h2>
<p>Dobson, Annette J., 1945- An introduction to generalized linear models / Annette J. Dobson and Adrian G. Barnett. – 3rd ed.</p>
<p>Gilberto A. Paula, MODELOS DE REGRESSÃO com apoio computacional.Instituto de Matemática e Estatística Universidade de São Paulo.</p>
Sistemas de Recomendação usando Collaborative Filtering2018-09-29T07:00:00+00:00http://lamfo-unb.github.io/2018/09/29/ Sistemas-de-Recomendação-usando-Collaborative-Filtering<h1 id="sistemas-de-recomendação-usando-collaborative-filtering">Sistemas de Recomendação usando Collaborative Filtering</h1>
<p>Técnicas de Collaborative Filtering, ou Filtragem Colaborativa, exploram a ideia de que existem relações entre os produtos e os interesses das pessoas. Muitos sistemas de recomendação usam o Collaborative Filtering para entender essas relações e para dar uma precisa recomendação de um produto que o usuário pode gostar ou mesmo desfrutar.</p>
<p>Para isso filtragem colaborativa baseia esses relacionamentos nas escolhas que um usuário faz ao comprar, assistir, ou curtir alguma coisa. Em seguida, faz conexões com outros usuários de interesses semelhantes para produzir uma previsão.</p>
<p><br /></p>
<p align="center">
<img src="/img/collaborative_filtering_img/CF.gif" />
</p>
<p><br /></p>
<h2 id="cases-de-uso-do-collaborative-filtering"><strong>Cases de uso do Collaborative Filtering</strong></h2>
<p>Um exemplo popular de filtragem colaborativa é a do Netflix.</p>
<p>Tudo no site da empresa é dirigido pelas seleções do cliente que gera uma enorme base de dados, o qual é usada para ser transformada em recomendações para o cliente. Isso faz com que 75% a 80% do que é assistido no site provenha das recomendações ao invés da busca. Tanto que se especula que futuramente só irá sugerir de 3 a 4 filmes ao usuário, sendo que esses serão exatamente aqueles que ele possa quer assistir.</p>
<p>A Netflix ordena essas recomendações, em tal maneira que os itens melhores ranqueados são os mais visíveis para os usuários, na esperança de serem esses os selecionados pelo cliente. A mesma estratégia é usada para definir qual tipo de thumbnail irá ser apresentado ao cliente baseado em suas preferências, ou seja, em imagens de atores ou de cenas do filme.</p>
<p>A empresa julga que isso é tão estratégico que promoveram o Netflix Prize, uma competição aberta a todos e que tinha como objetivo desenvolver o melhor algoritmo para prever notas de usuários em filmes. Diversos algoritmos surgiram com essa competição e a equipe vencedora recebeu um prêmio de 1 milhão de dólares por melhorar as recomendações da Netflix em 10,06%.</p>
<p><br /></p>
<p align="center">
<img src="/img/collaborative_filtering_img/Netflix.png" width="700" />
</p>
<p><br /></p>
<p>A Amazon é outra grande referência em se tratando varejo digital e possui um sistema de recomendação de produtos muito poderoso e reconhecido no mercado. Esse sistema é um dos responsáveis pela alta conversão do site (transações dividido por visitas) que já chegou a ser de 10% e se baseia em diversas fontes de dados, tais como: produtos comprados pelo usuário, quais itens estão no carrinho de compras virtual, itens curtidos ou avaliados, o que outros consumidores viram ou compraram, o que você comprou anteriormente, bem como a frequência com que você olhou determinados livros ou mesmo outros itens durante a navegação ao seu site.</p>
<p>O site da Amazon é completamente personalizado de acordo com o cliente e conforme se navega e interage com o site, os produtos exibidos se alteram. Uma das recomendações utilizadas é o Item-to-Item Collaborative Filtering que é descrito no artigo e por ser de fácil implementação, pode ser utilizado por qualquer tipo de site.</p>
<p><br /></p>
<p align="center">
<img src="/img/collaborative_filtering_img/Amazon.png" width="700" />
</p>
<p><br /></p>
<p>A vantagem de usar o Collaborative Filtering é que os usuários têm uma exposição mais ampla a muitos produtos diferentes podendo estar interessados em alguns deles.</p>
<p>Essa exposição encoraja os usuários a continuarem o uso ou compra do produto. Isso não apenas proporciona uma experiência melhor para ele, como também beneficia o provedor de serviços com maior receita potencial e melhor segurança para seus consumidores.</p>
<h2 id="collaborative-filtering-tradicional"><strong>Collaborative Filtering Tradicional</strong></h2>
<p>Dentro de vários modelos de Collaborative Filtering, o tradicional representa um cliente como um vetor N-dimensional de itens, o qual N é o número de itens de catálogo distinto. Os componentes do vetor são positivos para itens comprados ou com classificação positiva. E negativos para itens com classificação negativa. Para compensar itens mais vendidos, o modelo normalmente multiplica os componentes do vetor pela freqüência inversa (o inverso do número de clientes que compraram ou avaliaram o item), tornando os itens menos conhecidos mais relevantes. Além disso, ele gera recomendações com base em alguns clientes que são mais parecidos com o usuário. Por fim, a similaridade de dois clientes A e B pode ser avaliada de várias maneiras. Uma delas é medir o cosseno do ângulo entre os dois vetores:</p>
<p><br /></p>
<p align="center">
<img src="/img/collaborative_filtering_img/Formula1.png" />
</p>
<p><br /></p>
<p>Onde “•” denota o produto escalar dos dois vetores sobre a normalização dos vetores. Por exemplo:
<br /></p>
<p align="center">
<img src="/img/collaborative_filtering_img/Formula2.png" /><br />
<img src="/img/collaborative_filtering_img/Formula3.png" />
</p>
<p><br /></p>
<p>Em uma situação real, diferentes usuários podem usar diferentes escalas de classificação, o qual a semelhança de cosseno vetorial não levará em conta. Para resolver esse problema, a similaridade de cosseno ajustada é usada ao subtrair a média do usuário correspondente de cada par co-avaliado. A semelhança cosseno ajustada tem a mesma fórmula que a Coeficiente de Correlação de Pearson.</p>
<p><br /></p>
<p align="center">
<img src="/img/collaborative_filtering_img/Formula4.png" />
</p>
<p><br /></p>
<p>Na verdade, correlação Pearson executa semelhança de cosseno com uma normalização das avaliações do usuário de acordo com a sua próprio comportamento de classificação. Assim, pode-se obter valores negativos com a correlação de Pearson, levando em conta a escala de classificação de n pontos.</p>
<h2 id="alguns-desafios-com-collaborative-filtering"><strong>Alguns desafios com Collaborative Filtering</strong></h2>
<p>Um deles é o <strong>Data Sparsity</strong>:</p>
<p>Ter um conjunto de dados grande provavelmente resultará em uma matriz de item/usuário grandes e esparsas, que pode fornecer um bom nível de acurácia, mas também representam um risco para a performance. Em comparação, ter um pequeno conjunto de dados pode resultar em velocidades mais rápidas de respostas, porém menor acurácia das recomendações.</p>
<p>Outra questão a ter em mente é algo chamado de <strong>“Cold Start</strong>”:</p>
<p>Isso acontece quando os novos usuários ou itens não têm um número de quantidade suficiente de avaliações para dar uma recomendação precisa. Novos itens não podem ser recomendados até que alguns usuários os classifiquem e novos usuários são improváveis, dadas a falta de sua classificação ou histórico de compras.</p>
<p>A <strong>escalabilidade</strong> também pode se tornar um problema uma vez que a medida que o número de usuários aumenta e a quantidade de dados expande-se. Dessa forma, algoritmos de filtragem colaborativa vão começar a sofrer quedas no desempenho devido ao aumento do volume.</p>
<p>Os <strong>“Sinônimos”</strong> refere-se à frequência de itens semelhantes, porém rotulados de forma diferentemente espacialmente com sinônimos regionais. Um exemplo disso seria “Penal” vs ‘Estojo’.</p>
<p>Um sistema de recomendação pode tratar esses dois itens de forma diferente por causa de sua rotulagem embora, funcionalmente, sejam muito semelhantes um para o outro.</p>
<p>O termo <strong>‘Gray Sheep’</strong> refere-se aos usuários que têm opiniões que não necessariamente vão se ‘encaixar’ ou são semelhantes a qualquer grupo específico. Esses usuários não concordam ou discordam consistentemente em produtos ou itens, portanto, receberão recomendações não muito assertivas para eles.</p>
<p>Em um sistema de recomendação, os usuários podem avaliar produtos que eles gostam ou não gostam e é isso que o Collaborative Filtering usa para determinar boas recomendações. No entanto, <strong>Shilling Attacks</strong> são o abuso desse sistema classificando certos produtos muito positivamente e/ou outros produtos negativamente independentemente da opinião pessoal. Permitindo que esse produto seja recomendado mais frequentemente.</p>
<p>Em alguns sistemas de recomendação, existem falta de <strong>diversidade</strong> para recomendações. Isso ocorre porque itens populares são recomendados mais frequentemente, pois mais usuários os usam e classificam. Por isso é fácil imaginar que um item popular consegue uma maior quantidade de avaliações. Essas classificações representam informações que são usadas pelo sistema, que por sua vez, cria outras recomendações para outros usuários. Dessa forma, há mais usuários que irão usar, assistir e comprar esses produtos, tornando-os mais populares.</p>
<p>Isso cria um ciclo em que novos itens são apenas uma sombra por trás dos itens populares resultantes na falta de diversidade. Esse fenômeno é conhecido como efeito <strong>‘Long Tail’</strong>.</p>
<p><strong>Algoritmos de Machine Learning</strong></p>
<p>Além das abordagens usando Similaridade de Coseno ou mesmo Correlação de Pearson, que são baseados em operações aritméticas, podemos desenvolver a filtragem colaborativa usando alguns algoritmos de Machine Learning tais como:</p>
<p><strong>Algoritmos baseados em Clusterização (KNN):</strong> A ideia da clusterização é a mesma dos sistemas de recomendação baseados em memória. Em algoritmos baseados em memória, usamos as semelhanças entre usuários e/ou itens e os usamos como pesos para prever uma classificação para um usuário e/ou um item. A diferença é que as semelhanças nessa abordagem são calculadas com base em um modelo de aprendizado não supervisionado, em vez de Correlação de Pearson ou semelhança de cosseno. Nesta abordagem, também limitamos o número de usuários semelhantes como k, o que torna o sistema mais escalável.</p>
<p><strong>Deep Learning (CNN/RNN):</strong> DL é um campo de Machine Learning que permite modelos computacionais compostos por várias camadas de processamento de representação e abstração que ajudam a compreender dados como imagens, sons e textos. Esses métodos melhoraram drasticamente o estado da arte em visão computacional, reconhecimento de voz, processamento de linguagem natural (NLP) e muitos outros domínios, como descoberta de drogas e detecção de células cancerígenas. Um exemplo é a biblioteca Fast.AI que pode dar uma grande acurácia e possui uma relativa facilidade de implementação.</p>
<p><strong>Conclusão</strong></p>
<p>Sistemas de Recomendação, mais especificamente o método de Filtragem Colaborativa, é um tema que demanda grande atenção no cenário atual mercadológico. Este método pode apresentar acurácia elevada, mesmo sendo de fácil implementação. Seu principal objetivo é fazer previsões sobre os interesses de um usuário com base nas preferências de outros usuários que tenham um padrão de comportamento semelhante. Dessa forma, recomenda um produto e/ou serviço para garantir o sucesso no volume de conversão de vendas e no engajamento do serviço.</p>
<p><strong>Referências:</strong></p>
<blockquote>
<p>CARLOS A. GOMEZ-URIBE and NEIL HUNT, Netflix, Inc. The Netflix Recommender System: Algorithms, Business Value, and Innovation</p>
</blockquote>
<blockquote>
<p>SHAPIRA Bracha KANTOR Paul B. RICCI Francesco, ROKACH Lior.
Recommender Systems Handbook. Springer, 2011</p>
</blockquote>
<blockquote>
<p>YORK Jeremy LINDEN Greg, SMITH Brent. Amazon.com recommendations item-to-item collaborative filtering.</p>
</blockquote>
<blockquote>
<p>Xiaoyuan Su and Taghi M. Khoshgoftaar. Review Article - A Survey of Collaborative Filtering Techniques</p>
</blockquote>
<blockquote>
<p>Como funciona o sistema de recomendações da Netflix.
Disponível em: https://help.netflix.com/pt/node/100639. Acesso em: 01 de setembro de 2018;</p>
</blockquote>
<blockquote>
<p>A Global Approach to Recommendations.
Disponível em: https://media.netflix.com/en/company-blog/a-global-approach-to-recommendations. Acesso em: 01 de setembro de 2018;</p>
</blockquote>
<blockquote>
<p>The Netflix Tech Blog
Disponível em: https://media.netflix.com/en/company-blog/a-global-approach-to-recommendations. Acesso em: 01 de setembro de 2018;</p>
</blockquote>
<blockquote>
<p>Netflix may only give you 3 or 4 recommendations in the future.
Disponível em: https://www.huffpostbrasil.com/entry/netflix-recommendations_n_5357619. Acesso em: 01 de setembro de 2018;</p>
</blockquote>
<blockquote>
<p>Amazon’s recommendation secret.
Disponível em: http://fortune.com/2012/07/30/. Acesso em: 01 de setembro de 2018;</p>
</blockquote>
<blockquote>
<p>Collaborative Filtering. - Big Ddata University
Disponível em: http://www.bigdatauniversity.com.br. Acesso em: 01 de setembro de 2018;</p>
</blockquote>
<blockquote>
<p>Aula Aberta - Lecture 43 — Collaborative Filtering | Stanford University – Leskovec, Rajaraman, and Ulman.
Disponível em: https://www.youtube.com/watch?v=h9gpufJFF-0. Acesso em: 01 de setembro de 2018;</p>
</blockquote>
Coletando Dados da Web para Aprendizado de Máquina - Parte 12018-09-03T00:00:00+00:00http://lamfo-unb.github.io/2018/09/03/Coletando-Dados-da-Web-para-aprendizado-de-Máquina-Parte-1<h1 id="coletando-dados-da-web-para-aprendizado-de-máquina---parte-1">Coletando Dados da Web para Aprendizado de Máquina - Parte 1</h1>
<p>Algoritmos de aprendizado de máquina dependem de dados para treiná-los. Para criar um algoritmo para analisar quais parlamentares gastam de forma exorbitante, por exemplo, você necessita extrair dados dessas despesas. Um algoritmo de recomendação de páginas do Facebook, necessita dos dados de quais páginas as pessoas já seguem. Outro exemplo seria um algoritmo de reconhecimento de imagem. Para esse algoritmo, seria necessário obter várias imagens daquilo que você deseja reconhecer.</p>
<p>Em certos casos, a complexidade para criação do modelo não se encontra na tecnologia utilizada, mas na obtenção dos dados. Segundo o Diretor do Centro de Análise Avançada do Escritório de Contabilidade do Governo dos EUA:</p>
<blockquote>
<p><em>“Independente do objetivo, é necessário entender a qualidade dos dados que você possui. A qualidade determina quão confiáveis tais dados são para se tomar boas decisões.”</em></p>
</blockquote>
<blockquote>
<p><em>‘Regardless of the goals, it’s important to understand the quality of the data you have. The quality determines how much you can rely on the data to make good decisions.’</em></p>
</blockquote>
<p>Não somente o tratamento dos dados é uma forma essencial para o futuro da Inteligência Artificial, como também a forma de obtê-los. O primeiro semestre de 2018 foi marcado por uma série de questionamentos entre o senado americano e Mark Zuckerberg, CEO do Facebook. Isso se deu por conta da exposição do uso dos dados pessoais de pelo menos 50 milhões de usuários da plataforma. Tais dados foram coletados por meio de um questionário do Facebook chamado “thisisyourdigitallife”. Esses dados foram coletados por uma empresa de Inteligência Artifical e Data Mining chamada Cambridge Analytica violando as políticas de uso do Facebook. Avaliando o conteúdo que os usuários publicavam e curtiam, eles foram capazes de fazer propagandas políticas de forma mais efetiva durante as eleições presidenciais dos Estados Unidos de 2016 e na votação do Brexit.</p>
<p>Para evitar problemas legais como esse, neste post e no próximo explicaremos como extrair os dados da Web sem ferir os interesses dos proprietários deles. Abordaremos os três principais métodos de obter dados:</p>
<ol>
<li>
<ul>
<li>Lei de Acesso à Informação,</li>
</ul>
</li>
<li>
<ul>
<li>API’s</li>
</ul>
</li>
<li>
<ul>
<li>Web Scrapping.</li>
</ul>
</li>
</ol>
<p><img src="/img/web-scraping/alx_acesso_a_informacao_original.jpg" alt="image alt" title="Lei de acesso a informação" /></p>
<h2 id="1---lei-de-acesso-a-informação">1 - Lei de acesso a informação</h2>
<p>A extração de dados nem sempre requer uma programação extensiva. No caso de sites e órgãos governamentais, a Lei de Acesso à Informação (Lei nº 12.527/2011) permite o acesso à dados com uma simples requisição formal.</p>
<p>Tal lei possibilita a qualquer pessoa, física ou jurídica, sem necessidade de apresentar motivo, o recebimento de informações públicas dos órgãos e entidades. A Lei vale para os três Poderes da União, Estados, Distrito Federal e Municípios, inclusive aos Tribunais de Conta e Ministério Público. Entidades privadas sem fins lucrativos também são obrigadas a dar publicidade a informações referentes ao recebimento e à destinação dos recursos públicos por elas recebidos.</p>
<p>Em pesquisas do <a href="http://lamfo.unb.br/index.php?lang=pt-br">LAMFO</a> tal recurso já foi usado com sucesso. Caso o site não possua uma seção para contato para fazer a requisição, um email ao órgão detalhando quais dados devem ser disponibilizados pode solucionar o problema.</p>
<p><img src="/img/web-scraping/coding_pixabay_JohnsonMartin640_apis.png" alt="image alt" title="Application Program Interface" /></p>
<h2 id="2---apis">2 - API’s</h2>
<p>Sites de maior porte e redes sociais geralmente disponibilizam API’s para acesso. As empresas ligadas ao Facebook (Facebook, Instagram, Messenger), por exemplo, possuem a <a href="https://developers.facebook.com/docs/graph-api/">Graph Api</a> que disponibiliza informações específicas dos usuários.</p>
<p>Uma API é uma forma de tornar pública e acessível as informações de uma empresa. É um servidor que recebe requisições simples HTTP e retorna dados que a empresa possui. Isso é feito para facilitar a análise de informações da empresa ou até mesmo permitir que haja uma interação dos usuários. Um exemplo são os jogos que encontram seus amigos do Facebook. Esses jogos podem ter a permissão de acessar os seus amigos ou outras informações. Todas essas informações são extraídas por uma chamada HTTP e a API geralmente retorna essas informações no formato JSON. Pode parecer uma tarefa difícil, mas em algumas situações, essa requisição HTTP é só uma URL que pode ser digitada em um navegador e no navegador é exibido o JSON. É importante saber como trabalhar com API’s, pois facilita muito a extração de dados.</p>
<p>Tal disponibilidade de dados não é para qualquer uso. Toda API com dados relevantes possui uma página para acesso ao desenvolvedor. Geralmente, para acessar essa página é necessário um cadastro e durante o cadastro são apresentados os termos de uso legal dos dados disponíveis na rede. A Política de Privacidade que deve ser lido e aceito durante a criação de uma conta de desenvolvedor.</p>
<p>Dependendo da API podem existir custos para acessá-la. Algumas empresas até mesmo limitam por quantidade de acessos dentro de um certo período de tempo, como é o caso do <a href="https://openweathermap.org/api">OpenWeatherMap</a>:</p>
<p><img src="/img/web-scraping/openWeather_forecastsCollection.PNG" alt="image alt" title="Weather Collections" /></p>
<p>O acesso aos dados da API é feito por meio de requisições do tipo HTTP e o retorno dos dados pode ser no formato json, xml ou até mesmo texto puro. Para saber como enviar ou como receber as requisições feitas à API, na página de desenvolvedor pode ser encontrada a documentação dela.</p>
<p>A documentação e a Política de Privacidade são as partes fundamentais de uma API. No caso da Cambridge Analytica e do Facebook, o erro estava no descumprimento da Política de Privacidade e na exploração de uma falha de desenvolvimento da API. Tal falha foi corrigida pelo Facebook, mas isso não removeu as informações que a Cambridge Analytica já tinha coletado. Desde então, o Facebook tem feito mudanças limitando o acesso às informações do usuário. Além disso, uma nova política foi implantada que, caso o usuário não acesse o App/Jogo dentro de três meses, o acesso daquele App/Jogo à API do Facebook será cancelado.</p>
<p>Após o cadastro, você terá acesso à uma chave privada e única de identificação de desenvolvedor. Essa chave privada deverá ser enviada nas requisições HTTP. Sites como o any api reúnem uma diversidade de API’s e contém ferramentas para testá-las:
<a href="https://any-api.com/">https://any-api.com/</a></p>
<p>Executaremos um exemplo extraindo os dados climáticos do Open Weather Map. Para isso criaremos uma conta de desenvolvedor para obtermos a chave privada:
<a href="https://home.openweathermap.org/users/sign_up">https://home.openweathermap.org/users/sign_up</a></p>
<p>A criação de conta é simples, username, email e senha. Porém, como dito, a parte mais importante está na leitura da Política de Privacidade. A Política de Privacidade contém o contato da empresa, os seus dados que são coletados, como eles são coletados, como esses dados são usados:
<a href="https://openweathermap.org/privacy-policy">https://openweathermap.org/privacy-policy</a></p>
<p>Após a criação de conta, será perguntado para qual propósito os dados serão usados. Na aba API keys, você pode ver e gerenciar suas chaves privadas da API. Note que após a criação de uma nova chave, somente após 10 minutos ela terá efeito:</p>
<p><img src="/img/web-scraping/openWeather_API_KEY.PNG" alt="image alt" title="API Key" /></p>
<p>Na aba Billing Plans é possível ver o seu plano atual (gratuito) e modificar caso haja necessidade.</p>
<p><img src="/img/web-scraping/plans_openWeather.PNG" alt="image alt" title="API Plans" /></p>
<p>Na página <a href="https://openweathermap.org/api">/api</a> é possível encontrar toda a documentação para a API de clima. Para esse exemplo buscamos os dados de 5 dias atrás, na página <a href="https://openweathermap.org/forecast5">/forecast5</a> veremos a documentação para obtermos dados por meio da requisição HTTP.</p>
<p>Iremos utilizar uma API Key que o próprio openweathermap fornece como teste, mas o melhor é criar uma para sí:</p>
<p><code class="language-plaintext highlighter-rouge">b6907d289e10d714a6e88b30761fae22</code></p>
<p>Em nosso exemplo iremos buscar os dados da cidade de Campos do Jordão. Iremos buscar por ID da cidade. Tomamos a liberdade de já buscar o ID que é 6322174, mas na documentação que passamo acima é possível encontrar a lista de todos os ID’s de cidades, além de outras formas de buscar caso a cidade buscada não possua um ID - buscando por latitude e longitude por exemplo. Agora que temos as informações necessárias para executar a requisição poderíamos criar um código para buscar tudo e salvar em um banco de dados ou em um arquivo. No entanto, é bom saber como testar a requisição, pois nem sempre temos certeza se um erro que possa por ventura aparecer está em nosso código de captura ou em nossa requisição ou até mesmo se o erro está no servidor. Para isso iremos aprender como testar as requisições.</p>
<h2 id="testando-requisições-à-apis">Testando requisições à API’s</h2>
<p>Antes de criar um código que acesse uma API, é sempre bom testá-la para verificar se ela lhe trará os dados que você realmente quer. Uma forma simples para verificar a conexão com a API sem código é utilizar o programa Postman.</p>
<p><img src="/img/web-scraping/postman.PNG" alt="image alt" title="Postman Logo" /></p>
<p>O Postman permite:</p>
<ul>
<li>Executar requisições HTTP dos diversos tipos (POST, GET, PUT, DELETE…) ;</li>
<li>Enviar parâmetros no Header da requisição;</li>
<li>Passar argumentos no Body da requisição;</li>
<li>Passar argumentos na própria URL;</li>
<li>Gerenciar a forma de autenticação (nenhuma, OAuth 1.0, OAuth 2.0…);</li>
<li>Gerenciar a forma de cache da requisição;</li>
<li>Executar testes nas requisições;</li>
<li>Executar uma requisição de tempos em tempos para verificar a performance e o retorno.</li>
</ul>
<p>Além disso tudo, é possível agrupar diversas requisições dentro de uma mesma Collection e essas requisições compartilham das mesmas variáveis que serão enviadas ao servidor.</p>
<p><img src="/img/web-scraping/postmanWorkspace.PNG" alt="image alt" title="Postman Workspace" /></p>
<p>Logo a esquerda ficam as collections. O painel central exibe a URL da requisição e o tipo dela (no caso é uma do tipo GET). Ao clicar em Params, podemos enviar parâmetros pela url por meio de chave e valor, tal como abaixo:
<code class="language-plaintext highlighter-rouge">www.site.com/api.php?senha=123&usuario=usuario123</code>
<img src="/img/web-scraping/PostmanCollections.PNG" alt="image alt" title="Postman Collections" />
<img src="/img/web-scraping/PostmanCollections2.PNG" alt="image alt" title="Postman Collections 2" /></p>
<p>Logo abaixo da URL, é possível configurar os vários tipos de autorizações na aba Authorization. Essa configuração é muito usada quando se trabalha com API’s, pois como explicamos geralmente o acesso à uma API deve ser feito por um usuário. Nela é possível configurar o tipo de autenticação assim como preencher o usuário e senha.
<img src="/img/web-scraping/web-scraping/postmanheaders.PNG" alt="image alt" title="Postman Headers" /></p>
<p>Na aba Headers podemos enviar parâmetros no Header da requisição atribuindo os valores por meio de chave e valor.
<img src="/img/web-scraping/postmanheaders_1.PNG" alt="image alt" title="Postman Headers 1" /></p>
<p>A aba Body só está habilitada para requisições que enviam parâmetros o servidor (POST, PUT..). Nela é possível selecionar diversos tipos de formas de enviar dados ao servidor. A mais comum é o x-www-form-urlencoded, que são dados por chave e valor. É possível que mesmo que um servidor peça um JSON enviando os dados por chave e valor ele aceite. Caso não seja aceito, selecione a opção raw e selecione JSON (application/json). Com isso é possível escrever um JSON no campo para ser enviado. O campo form-data convencionalmente é usado para enviar arquivos (imagens, audios).
<img src="/img/web-scraping/postmanheaders_2.PNG" alt="image alt" title="Postman Headers 2" /></p>
<p>Assim que sua requisição estiver completa, clique no botão Send. Ela será enviada e mais abaixo dos parâmetros estará a resposta. Na resposta, o campo Body pode ser visto na forma Pretty, formatado com quebra de linha e tabulação, ou na forma raw, como ele é recebido sem tratamento. Na forma pretty, é possível selecionar a visualização nos seguintes tipos: JSON, XML, HTML, Text.</p>
<p>Por ser possível visualizar em HTML, vemos que podemos fazer uma requisição a qualquer site e obter o HTML daquela página. Isso é interessante de ser usado em conjunto com os
testes e o monitoramento - execução de tempos em tempos de uma requisição. Dessa forma podemos saber se uma página saiu do ar.</p>
<p>Além do Body da resposta que o servidor enviou, é possível ver os Cookies, Headers, o tempo que demorou a execução, o tamanho da requisição e o status de retorno. Vemos que em nosso exemplo a requisição retornou o Status 200, que é um padrão da Internet para informar que a requisição foi bem sucedida. Nem sempre a requisição é bem sucedida. Para esses casos, o Status é extremamente importante para informar a razão do erro. Um Status de erro que era muito comum de ser exibido ao usuário era o 404 - Página não encontrada. Esse era um erro comum, mas cada número tem um significado diferente. Cada faixa de centena tem um significado[11]:</p>
<ul>
<li>1xx - Trazem uma informação</li>
<li>2xx - Informam sucesso, sendo o 200 sucesso completo sem ressalvas</li>
<li>3xx - Informam um redirecionamento. Ex.: 301 - a página foi mudada para outra URL</li>
<li>4xx - Erros no cliente, em outras palavras, erro na requisição feita. Seja por falta de usuário e senha (401), envio de um formato de media que não é suportado (415) ou qualquer outro erro na requisição será notificado.</li>
<li>5xx - Erros no servidor. O servidor pode estar fora do ar (503) ou até mesmo ter ocorrido um erro de processamento da sua requisição (503)
<img src="/img/web-scraping/postmanheaders_3.PNG" alt=" image alt" title="Postman Headers 3" /></li>
</ul>
<p>A aba de Tests foi deixada para ser tratada por último, pois ela é executada após o retorno da requisição. Nessa aba é possível escrever códigos em Javascript para testar o que veio de retorno, no lugar de ficar procurando no JSON se o retorno lhe interessa. Para criar um novo teste, preencha o valor de tests[‘nome do teste’] com o valor true para um teste que deu certo e false quando errado.
<img src="/img/web-scraping/postmanResultTests.PNG" alt="image alt" title="Resultado de testes" /></p>
<p>Após a execução da requisição, a aba Tests Results irá mostrar quantos e quais testes a requisição passou. Além disso ela indica quantos testes a requisição passou logo no nome da aba, para o exemplo, ela passou em todos os testes (3/3).</p>
<h2 id="voltando-ao-exemplo-do-openweathermap">Voltando ao exemplo do openweathermap</h2>
<p>Sabendo que temos os dados abaixo para executar a requisição, vamos realizar um teste utilizando o Postman
<img src="/img/web-scraping/postmanFullTest.PNG" alt="image alt" title="Teste completo" /></p>
<p>Além disso, vamos criar dois testes. Como o JSON de retorno contém o Status Code, vamos verificar se o Status é 200 criando o teste tests[“Status retorno 200”]. Caso a requisição falhe (e execute o catch) indicaremos que esse teste não passou atribuindo falso ao valor desse teste. O segundo teste verifica se o retorno contém mais de cinco datas com informações sobre o clima. Para este criaremos o teste tests[“Contem 5 ou mais datas”] e verificaremos se na lista de informações sobre o clima temos cinco ou mais elementos.
<img src="/img/web-scraping/postman_test.PNG" alt="image alt" title=" " /></p>
<p>Ao executar nossa requisição, podemos ver o JSON retornado e verificar que a nossa requisição passou em ambos os testes (Test Results 2/2). Além disso, na imagem abaixo, conseguimos observar que a primeira data será um dia de céu limpo (clear sky).
<img src="/img/web-scraping/postmanheaders_2.PNG" alt="image alt" title=" " /></p>
<h2 id="para-saber-mais-do-assunto">Para saber mais do assunto</h2>
<p>Caso seja do seu interesse se aprofundar no estudo de busca de dados por meio de API, temos alguns conteúdos a sugerir, assim como alguns links de referência. Para criar uma API, e disponibilizar os dados que você já tem para outras pessoas, sugerimos o uso da linguagem Node JS e o banco de dados Mongo DB. A criação de uma API por meio do Mongo é facilitada com a biblioteca Express. O banco de dados Mongo não é um banco de dados relacional. Apesar disso parecer um impedimento, na verdade é um facilitador, pois o Mongo é estruturado como um JSON. Isso facilita muito o trabalho de construção de uma API.</p>
<p><a href="https://medium.com/gdg-pato-branco/criando-uma-simples-api-em-node-js-7082f745107f">Criando uma API com Node JS</a></p>
<p><a href="https://udgwebdev.com/um-pouco-de-node-js-e-mongodb-na-pratica/">Usando o Mongo DB com Node JS</a></p>
<p>Para buscar dados por meio de uma API, sugerimos utilizar a linguagem Python. Não só pela facilidade, mas também por ser uma linguagem amplamente utilizada para a análise de dados. Sendo assim, não é necessário uma conversão, tudo é trabalhado na mesma linguagem. Recomendamos a leitura da documentação da biblioteca requests. Com ela conseguimos configurar tudo que fizemos no Postman. A documentação é bem elaborada e em português.</p>
<p><a href="http://docs.python-requests.org/pt_BR/latest/">Documentação Requests</a></p>
<p><a href="http://docs.python-requests.org/pt_BR/latest/user/quickstart.html">Guia de início</a></p>
<h2 id="3---web-scraping">3 - Web Scraping</h2>
<p>O web scraping é caracterizado pela captura de dados na web sem a utilização de uma API ou de um processo manual laborioso e tedioso.
Todo o trabalho de acesso, captura e extração de dados é realizado por Bots, robôs que simulam o acesso de um usuário. Podemos capturar qualquer tipo de dado, não somente textos ou endereços web.
É possível a captura de imagens, endereços residenciais, telefones, e-mails e etc., após a captura os dados podem ser diretamente inseridos em um banco de dados ou em arquivos.</p>
<h2 id="por-quê-fazer">Por quê fazer?</h2>
<p>Como mostrado anteriormente o uso de APIs facilita e organiza a aquisição de dados, mas como apresentado por Ryan Mitchell em seu livro <em>Web Scraping com Python</em>, não é possível o uso de APIs quando [10]:</p>
<blockquote>
<ol>
<li>Os conjuntos de sites não possuem uma API coesa;</li>
<li>Os dados desejados pertencem a um conjunto finito e muito pequeno que o webmaster não achou necessário criar uma API para sua extração;</li>
<li>A origem não tem infraestrutura ou habilidade técnica para desenvolvimento de uma API.
Muitas APIs também contam com limitadores de velocidade ou cotas de requisições por IP, ou seja, dependendo de seu objetivo as APIs sozinhas não forneceram a quantidade ideal de dados, ou no tempo ótimo.
E é aí que vemos o <em>Web Scraping</em> esperando calmamente pelo momento de fazer sua mágica, porque se você consegue acessar uma página no seu navegador, você consegue acessa-lá com um robô.</li>
</ol>
</blockquote>
<p><img src="/img/web-scraping/scraping_robot.png" alt="image alt" title="Web Scraping Droid" /></p>
<p>Quando uma API é disponibilizada, basta que o desenvolvedor siga a documentação e a política de privacidade para que se estabeleça um bom relacionamento entre robô e servidor.</p>
<h2 id="primeiro-o-essencial">Primeiro o essencial</h2>
<p>Uma ponto importante para a boa convivência entre robô e servidor é a utilização do Protocolo de Exclusão de Robôs.
Este protocolo é um método utilizado pelos administradores de páginas web para informar aos robôs que visitam a acessam quais os diretórios podem ou não ser vasculhados, e quais robôs podem acessar os diretórios.</p>
<h2 id="robotstxt-o-começo">Robots.txt. O começo!</h2>
<p>A primeira coisa a ser feita pelos robôs é o acesso ao arquivo robots.txt que por convenção fica na pasta raiz da página, como por exemplo <a href="https://www.google.com/robots.txt">https://www.google.com/robots.txt</a>.</p>
<p><img src="/img/web-scraping/googleRObots.PNG" alt="image alt" title="Robots.txt" /></p>
<p>No exemplo acima, ele diz a todos os robôs(User-agent: *) quais páginas podem (Allow) ser acessadas e quais não(Disallow).</p>
<p><strong>Características essenciais do arquivo[11]:</strong>
Arquivo de texto ASCII ou UTF-8(Não utilize programas de processamento de texto como Word ou LibreOffice);</p>
<ol>
<li>Nome Robots.txt é obrigatório;</li>
<li>Somente 1 arquivo por página web;</li>
<li>O arquivo pode ser aplicado em subdomínios ou em portas.</li>
</ol>
<p>Exemplos:
A. Três diretórios são excluídos a todos os robôs.
<img src="/img/web-scraping/exemploA_robots.PNG" alt="image alt" title="Exemplo 1" /></p>
<p>B. Excluindo todos os robôs de todo o servidor:
<img src="/img/web-scraping/exemploB_robots.PNG" alt="image alt" title="Exemplo 2" /></p>
<p>C. Excluindo um robô específico
<img src="/img/web-scraping/exemploC_robots.PNG" alt="image alt" title="Exemplo 3" /></p>
<p>D. Permitir apenas um robô(ou seja, permite um e não permite nenhum outro):
<img src="/img/web-scraping/exemploD_robots.PNG" alt="image alt" title="Exemplo 4" /></p>
<p>E. Não permitir acesso a arquivos específicos:
<img src="/img/web-scraping/exemploE_robots.PNG" alt="image alt" title="Exemplo 5" /></p>
<p>O arquivo possui sintaxe simples para ser facilmente analisado.
É muito importante frisar que o mostrado acima é um arquivo que indica o que pode ser <strong>acessado ou não</strong>, ele <em>*não</em> é um programa que analisa os robôs na página. Isso quer dizer que você pode fazer o scraping da página sem consulta-lo, mas sem fazer isso seu robô pode acabar acessando páginas protegidas, e pode fazer com que o webmaster o coloque como possível ameaça e bloqueie o acesso de seu robô em qualquer página do servidor.
Resumindo, <em>robots.txt não foi criado com o intuito de ser um controle de acesso</em>. A segurança deve ser feita pelo administrador do servidor, bloqueie as pastas e arquivos que não devem ser listados, não os referencie no arquivo. Lá só deve aparecer o que pode ser acessado e quem pode acessar.</p>
<h2 id="conclusão">Conclusão</h2>
<p>Buscamos através deste post apresentar algumas das formas mais frequentes de aquisição de dados. Neste primeiro momento foi apresentado um projeto completo de aquisição de dados utilizando API’s.
Introduzimos algumas justificativas e informações básicas de uso e regras de boa convivência entre robôs e servidores, através do arquivo robots.txt e sua sintaxe. No próximo post desenvolveremos um robô para captura dos dados em páginas da web que não possuem APIs.</p>
Otimização de Estruturas de Filas2018-07-06T23:25:00+00:00http://lamfo-unb.github.io/2018/07/06/Otimização-de-Filas<h1 id="otimização-de-estruturas-de-filas">Otimização de Estruturas de Filas</h1>
<p>As filas são onipresentes, as pessoas assumem os seus lugares e esperam a sua vez. Essa forma de organização tão comum e onerosa é necessária para organizar demandas que são maiores que a capacidade de prestação do serviço. A Teoria das Filas, tenta através de análises matemáticas detalhadas encontrar um ponto de equilíbrio que satisfaça o cliente, e seja viável economicamente para o provedor do serviço de atendimento.</p>
<p><img src="/img/teoria-filas/fila-banco.png" alt="fila-banco.png" /></p>
<p>A teoria fornece ferramentas de análise que permitem avaliar, por exemplo, se o tempo médio de espera por atendimento está acima do suportável, o tempo médio de ociosidade dos atendentes, tamanho médio da fila, tempo médio de atendimento. Com variáveis de controle é possível criar <em>benchmarks</em> com o cenário planejado, e realizar melhores tomadas de decisões e alocação de recursos. Existem muitos trabalhos atuais aplicando a teoria das filas, a maioria das quais tem sido documentadas na literatura de probabilidade, pesquisa operacional, controle de qualidade e engenharia industrial. Alguns exemplos são fluxo de tráfego (veículos, pessoas, comunicações, etc), escalonamento de leitos em hospitais, etc.</p>
<h1 id="historia-da-teoria-das-filas">Historia da Teoria das Filas</h1>
<p>Os estudos das filas foram iniciados pelo dinamarquês Erlang que publicou seu primeiro trabalho
em 1909 aplicando a teoria de probabilidade ao problema de tráfego de linhas telefônicas.
O objetivo inicial foi estudar o congestionamento e os tempos de espera que ocorriam no momento em que as ligações telefônicas eram realizadas. Com a análise dos problemas de tráfego de ligações e utilizando a teoria de probabilidades nesse estudo, Erlang prova o Processo de Poisson para a distribuição aleatória dos tempos entre as chegadas ao sistema.</p>
<p>Passados os anos, os trabalhos de Kendall e Lindley tiveram grande destaque sobre a teoria das filas. Os objetivos eram determinar o tamanho máximo admissível para a fila, a disciplina e o tempo de espera adequados. Para isso, o sistema seguia pressupostos Markovianos, cujo modelo admite que a entrada de dados são independentes e aleatórios.</p>
<p>Na decada de 60 Little criou sua lei. A lei de Little prova matematicamente que uma estrutura de espera é um processo markoviano de tempo continuo em que as transições de estado são de apenas dois tipos: “nascimentos”, que aumentam a variável de estado em um, e “mortes”, que diminuem o estado em um. Ou seja, um novo cliente no sistema representa um nascimento, e a saída do sistema representa uma morte. Um sistema é dito em equilibrio quando o número de entradas é igual a saída de individuos.</p>
<p><img src="/img/teoria-filas/nascimento-morte.png" alt="nascimento-morte.png" /></p>
<h1 id="entendendo-a-metodologia">Entendendo a Metodologia</h1>
<p>Os tipos de modelos de filas é definido a partir da Notação de Kendall, que
representa cada cadeia de filas pelos símbolos \(A\), \(B\), \(c\), \(K\), \(N\), \(Z\) da seguinte forma:</p>
<p align="center">
$$A/B/c/K/N/Z$$
</p>
<ul>
<li>\(A\): distribuição do tempo entre chegadas;-</li>
<li>\(B\): disciplina de serviços;</li>
<li>\(c\): número de servidores;</li>
<li>\(K\): capacidade total de usuários no sistema;</li>
<li>\(N\): número de usuários potenciais em uma população fonte;</li>
<li>\(Z\): disciplina de atendimento.</li>
</ul>
<p>Usualmente, quando não declarado a capacidade máxima do sistema (\(K\)), e o número de clientes a serem atendidos (\(N\)), estes serão considerados como ilimitados.</p>
<p>A disciplina de atendimento pode admitir duas politicas. First In First Out (primeiro que entra primeiro a sair), ou fila, é a estrutura de atendimento que bancos e hospitais utilizam pois sequem a ordem de chegada em que os primeiros a chegarem serão os primeiros a serem atendidos. Last In First Out (último que entra primeiro a sair) é a estrutura habitualmente chamada de pilha e amplamente utilizada na estacagem de produtos. Caso o modelo não declare qual a disciplina de atendimento, entende-se que será utilizada a disciplina FIFO.</p>
<h2 id="equações-de-little">Equações de Little</h2>
<p>Little utilizando o conceito do processo de nascimento e morte desenvolveu equações teóricas que calculam o desempenho de uma estrutura de espera. Para o modelo $m/m/c$, o número de atendentes é restrito igual a c. Para simplificar a visualização utilizei a notação \(r = \frac{\lambda}{\mu}\) e \(p = \frac{\lambda}{c\mu}\):</p>
<p>Probabilidade do sistema estar vázio</p>
\[P_0=\left ( \sum^{c-1}_{n=0} \frac{r^n}{n!} + \frac{r^c}{c!(1-p)} \right ) ^{-1} , p<1.\]
<p>Probabilidade do sistema possuir n clientes</p>
\[P_n= \frac{\lambda^n}{n!\mu^n}P_0, \quad 1 \leq c,$\]
\[P_n = \frac{\lambda^n}{c^{n-c}\mu^n}, \quad n \geq c.\]
<p>Tempo médio de cada cliente na fila</p>
\[W_q = \frac{r^c}{c!(c\mu)(1-p)^2}P_0\]
<p>Número médio de clientes na fila</p>
\[L_q = \frac{r^cp}{c!(1-p)^2}P_0\]
<p>Número médio de clientes no sistema</p>
\[L = \frac{r^cp}{c!(1-p)^2}P_0+r\]
<p>Tempo médio de cada cliente no sistema</p>
\[W = \frac{1}{\mu}+\frac{r^c}{c!(c\mu)(1-p)^2}P_0\]
<p>O modelo \(M/M/1\) da notação de Kendall é a parametrização mais simples, e mais utilizada para um modelo de fila Markoviana. Neste caso, a distribuição do tempo entre novas chegadas de clientes ao sistema é suposta exponencial (\(M\)). O tempo necessário para realizar cada serviço também segue uma distribuição exponencial (\(M\)). A capacidade máxima do sistema e a população fonte são supostamente infinitas. Nas aplicações desse modelo, denotamos por $\lambda$ e $\mu$ a taxa média de chegada e de atendimento, respectivamente. Além disso, supomos que há apenas um servidor e que a disciplina da fila é FIFO.</p>
<p>A relação entre o tempo médio de chegada e de serviço são as medidas de desempenho do sistema. O pressuposto necessário para a validade da teoria de filas , \(\frac{1}{\mu}$ $\leq\) \(\frac{1}{\lambda}\), torna o modelo convergente.</p>
<h1 id="aplicação">Aplicação</h1>
<p>Via linguagem R, veja também outros artigos <a href="https://lamfo-unb.github.io/2018/03/30/manipulacao-data-table/">[1]</a>, <a href="https://lamfo-unb.github.io/2017/07/22/intro-analise-acoes-1/">[2]</a>, é possível entender como a teoria se comporta com em relação a dados empíricos. Elaborei um algoritmo que simule um sistema real de filas utilizando a parametrização m/m/1.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
options(scipen=999)
library('tidyverse')
#T: período total de simulação;
#tci: instante de tempo em que ocorre a i-ésima chegada;
#tce: tempo entre as chegadas
#tai: instante de tempo em que ocorre o i-ésimo atendimento;
#to: tempo total de ociosidade do servidor;
#te: tempo total de espera na fila;
#tme: tempo médio de espera na fila;
#i: contador;
#t: variável de controle (tempo)
#lambda - Numero medio de clientes que entram/tempo (Poisson)
#1/lambda - Tempo entre clientes (Exponencial)
#mu - Numero de atendimentos desejados/h (Poisson)
#1/mu - Tempo de cada atendimento (Exponencial)
# mi>lambda para que o modelo seja convergente.
simula <- function(tempo,lambda,mu,seed=round(runif(1,min=1,max=2000))){
set.seed(seed)
T <- tempo
t=0
i=1
tc=NULL
tec=NULL
#Gera o vetor, dist.exponencial ,tempo entre as chegadas
while (t < T){ # o algoritmo simula uma linha temporal
tec[i] = (-(1/lambda))*log(runif(1)) #gerador de numeros pseudo-aleatrios
tc[i] = sum(tc[i-1]) + tec[i]
t=tc[i]
i=i+1
}
ta <- NULL
#Gera o vetor, dist.exponencial ,tempo de atendimento
for(i in 1:length(tc)) {ta[i] <- (-(1/mu))*log(runif(1))}
to = tc[1]
te = 0
i = 1
t = tc[1]
n=length(tc)-1
m=0
while (i < n){
if((t+ta[i]) < tc[i+1]){
to=to+tc[i+1]-(t+ta[i])
t=tc[i+1]
if(m >= 0){
m=m-1
}
}
else{
te=te+(t+ta[i])-tc[i+1]
t=t+ta[i]
m=m+1
}
i=i+1
}
tp_espera <-te/n;
prop_ocioso <-to/T;
return(list(W_q=tp_espera,
P_0=prop_ocioso,
L_q=n/tempo))
}
</code></pre></div></div>
<p>Escrevendo as equações de Little na linguagem R</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
equacoes_little <- function(m,lambda,mu){
# taxa de eficiencia
p = lambda / (m * mu)
# probabilidade do sistema estar sem clientes
i = c(0:(m-1))
first = sum( (m * p) ^ i / factorial(i) )
p_0 = 1 / ( first + (m * p) ^ m / ( factorial(m) * (1-p) ) )
# tamanho medio da fila de espera
L_q = p_0 * ( ((m^m) * p^(m+1)) / (factorial(m) * (1-p)^2) )
# tempo medio gasto na fila de espera
W_q = L_q / lambda
# tempo medio gasto pelo cliente no sistema
W = W_q + 1 / mu
# Numero medio de clientes no sistema
L = L_q + lambda / mu
return(list(eficiencia=p,
p_0=p_0,
L_q=L_q,
W_q=W_q,
W=W,
L=L))
}
</code></pre></div></div>
<h2 id="análise-da-simulação-do-modelo-mm1">Análise da simulação do modelo \(m/m/1\)</h2>
<p>Supondo uma situação real em que um gestor necessita de auxilio de dados nas tomadas de decisões sobre uma estrutura de filas. Por exemplo, coletando os dados da fila de atendimento ele quer avaliar o desempenho do sistema. As variáveis preliminares escolhidas são: o tempo médio que cada cliente passa na fila, a probabilidade do atendente estar ocioso e o tamanho médio da fila durante 60h e 120h de funcionamento. Pelos cálculos, a taxa média de chegada de novos clientes é igual 10/h e tempo médio de serviço igual a 11/h, com apenas 1 atendente.</p>
<p>Parâmetros:
\(\lambda = 10/h;\) <br />
\(\mu = 11/h;\) <br />
\(c = 1\) servidor.</p>
<table>
<thead>
<tr>
<th style="text-align: left">Variáveis</th>
<th style="text-align: right">Simulação (60,10,11)</th>
<th style="text-align: right">Simulação (120,10,11)</th>
<th style="text-align: right">Teórico (10,11,1)</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">\(W_q\)</td>
<td style="text-align: right">1.1148517</td>
<td style="text-align: right">0.878</td>
<td style="text-align: right">0.909</td>
</tr>
<tr>
<td style="text-align: left">\(P_0\)</td>
<td style="text-align: right">0.0620553</td>
<td style="text-align: right">0.0841</td>
<td style="text-align: right">0.090</td>
</tr>
<tr>
<td style="text-align: left">\(L_q\)</td>
<td style="text-align: right">10.1500000</td>
<td style="text-align: right">10.080</td>
<td style="text-align: right">9.090</td>
</tr>
</tbody>
</table>
<p>Além disso, o gestor deseja análisar a distribuição de probabilidade da quantidade de clientes no sistema. Ele deseja ajustar o sistema para que a fila seja em torno de 5 pessoas.</p>
<p><img src="/img/teoria-filas/graph-1.png" alt="graph-1.png" /></p>
<p>A probabilidade do sistema possuir mais de 5 clientes está acima dos padrões aceitaveis, então percebeu a necessidade de aumentar a quantidade de atendentes. Utilizando as equações de Little, é possível simular qual seria a melhora na performance caso contratasse novos atendentes. Os resultados obtidos considera que todos atendentes apresentam a mesma eficiência no atendimento.</p>
<table>
<thead>
<tr>
<th style="text-align: left"> </th>
<th style="text-align: right">1 Atendente (atual)</th>
<th style="text-align: right">2 Atendentes</th>
<th style="text-align: right">3 Atendentes</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: left">eficiencia</td>
<td style="text-align: right">0.909</td>
<td style="text-align: right">0.455</td>
<td style="text-align: right">0.303</td>
</tr>
<tr>
<td style="text-align: left">\(P_0\)</td>
<td style="text-align: right">0.091</td>
<td style="text-align: right">0.375</td>
<td style="text-align: right">0.400</td>
</tr>
<tr>
<td style="text-align: left">\(L_q\)</td>
<td style="text-align: right">9.091</td>
<td style="text-align: right">0.237</td>
<td style="text-align: right">0.031</td>
</tr>
<tr>
<td style="text-align: left">\(W_q\)</td>
<td style="text-align: right">0.909</td>
<td style="text-align: right">0.024</td>
<td style="text-align: right">0.003</td>
</tr>
<tr>
<td style="text-align: left">\(W\)</td>
<td style="text-align: right">1.000</td>
<td style="text-align: right">0.115</td>
<td style="text-align: right">0.094</td>
</tr>
<tr>
<td style="text-align: left">\(L\)</td>
<td style="text-align: right">10.000</td>
<td style="text-align: right">1.146</td>
<td style="text-align: right">0.940</td>
</tr>
</tbody>
</table>
<p><img src="/img/teoria-filas/graph-2.png" alt="graph-1.png" /></p>
<p>O sistema com dois atendentes torna o sistema dentro dos padrões desejados e deixa claro a não necessidade de possuir 3 atendentes. O novo sistema apresenta a probabilidade do sistema estar vázio no momento da chegada de novos clientes de 0,45%, a chance do sistema atingir 5 pessoas é baixa, e o tempo de espera médio próximo de 0.</p>
<h3 id="referências">Referências</h3>
<p>D.G Kendall - Stochastic processes occurring in the theory of queues and their analysis by the method of the imbedded Markov chain</p>
<p>D.V Lindley - The theory of queues with a single server</p>
<p>N. K. Jaiswal - Priority queues</p>
Inteligência Artificial na Medicina2018-06-14T22:21:00+00:00http://lamfo-unb.github.io/2018/06/14/Inteligência-Artificial-na-Medicina<h1 id="inteligência-artificial-na-medicina">Inteligência Artificial na Medicina</h1>
<p>Entre as várias aplicações possíveis da Inteligência Artificial. Neste post, focaremos em uma área de aplicação da Inteligência Artificial que tem mostrado muitos avanços nos estudos: a medicina.</p>
<p><img src="https://cdn.apps.joltteam.com/brikbuild/star-of-life-pixel-art-8bit-medical-care-pixel-pixel-art-rod-of-asclepius-snake-eblem-star-of-life-5a24f9b7f6c96a8d297209dd.brickImg.jpg" alt="image alt" title="Im_1" /></p>
<p>De acordo com estudos da consultorial empresarial <a href="https://www.mckinsey.com/industries/pharmaceuticals-and-medical-products/our-insights/how-big-data-can-revolutionize-pharmaceutical-r-and-d">McKinsey</a>, o uso de estratégias de <em>big data</em> podem gerar o valor de US$ 100 bilhões de dólares para o sistema de saúde dos Estados Unidos em melhoria em tomada de decisão, otimização de inovações, melhoria na eficiência de pesquisas e ensaios clínicos e na criação de novos equipamentos médicos.</p>
<p>A utilização de técnicas de Inteligência Artificial, principalmente Aprendizado de Máquina, na área de Saúde já é realidade e os estudos nessa área tem sido cada vez mais financiado por empresas últimos três anos.</p>
<p><img src="https://image.freepik.com/vetores-gratis/conceito-de-ciencia-tecnologia-abstrata-dna-e-link-digital-em-oi-fundo-azul-tech_36402-86.jpg" alt="image alt" title="Im_2" /></p>
<p>Para exemplificar, os avanços neste contexo vamos listar neste post duas das aplicações mais relevantes que já estão sendo realizadas, assim como as tendências para o futuro.</p>
<h2 id="diagnóstico-por-meio-de-imagem">Diagnóstico por meio de Imagem</h2>
<p>Como iniciativa da <a href="https://www.microsoft.com/en-us/research/project/medical-image-analysis/">InnerEye</a>, da Microsoft, a empresa propõe uma ferramenta que consegue diagnosticar anomalias por meio de radiografias utilizando aprendizado de máquina, <em>deep learning</em> e visão computacional. O objetivo principal do Projeto InnerEye é detectar tumores das imagens radiológicas em 3D e aulixiar o dignóstico médico para obteção de resultados mais refinados.</p>
<p><a href="https://www.youtube.com/watch?time_continue=5&v=9IXgVmLxVtQ"><img src="https://maternidadesimples.com.br/wp-content/uploads/2015/01/big-hero-3-e1420415362628.jpg" alt="VIDEO" /></a><em>clique na imagem</em></p>
<p>Além InnerEye, a Google também tem desenvolveu um algoritmo para detectar tumores em mamografias. A Universidade de Stanford tem utilizado ferramentas para diagnosticar a existência de câncer de pele. Empregando Aprendizado de Máquina, estas empresas treinam seus algoritmos com radiografias para observar as imagens, identificar as anomalias e apontar possíveis regiões que precisam da atenção dos médicos.</p>
<h2 id="cirurgia-robótica">Cirurgia Robótica</h2>
<p>Robôs que auxiliam em procedimentos cirúrgicos já são realidade em centros médicos mais especializados. O uso destes robôs permite que os médicos manipulem os membros robóticos pata realizar as cirurgias. Por mais que estes robôs utilizem predominantemente visão computacional, metodologias de aprendizado de máquina também são utilizadas para estabilizar o movimento dos membros robóticos para se assemelharem com os movimentos humanos.</p>
<p><a href="ttps://www.youtube.com/watch?v=SoFzKPzYKHE"><img src="http://i.dailymail.co.uk/i/pix/2013/10/21/article-0-18E33A1C00000578-205_634x605.jpg" alt="VIDEO" /></a></p>
<p>O Video acima (clique na imagem) é um exemplo do funcionamento dos movimentos dos membros robóticos coordenados por um médico do Sistema Da Vinci. No video, o robô simula uma “cirurgia” retirando a pele de uma uva.</p>
<p>Além da manipulação de membros, também já existem robôs autônomos que realizam atividades cirúrgicas como sutura e o aprendizado de máquina é utilizado na melhora de materiais robóticos cirúrgicos e na modelagem do fluxo de trabalho cirúrgico.</p>
<h2 id="tendências-futuras">Tendências Futuras</h2>
<h3 id="medicina-personalizada">Medicina Personalizada</h3>
<p>O grande volume de dados que a área da Medicina possui gera muitas informações acerda dos pacientes, a medicina personalizada promete que as recomendações de saúde e os tratamentos oferecidos para os pacientes serão ajustados de acordo com o histórico médico, as informações genéticas, dieta, grau de stress e entre outros atributos. Utilizando metologias de aprendizado de máquina pretende-se prever receituários, tratamentos</p>
<p><img src="https://static1.squarespace.com/static/5255c13de4b0a1f7f050a236/t/5acab153f950b74252159c3d/1523233116134/robot+doc.jpg?format=500w" alt="image alt" title="Im_4" /></p>
<h3 id="tratamentos-automáticos">Tratamentos Automáticos</h3>
<p>A ideia principal dentro dos Tratamentos Automáticos consiste em algoritmos que auxiliem no monitoramento de pacientes que estão passando por algum tipo de tratamento médico, seja ajustar doses de remédios de acordo com as informações sanguínea, de estresse, de sono e entre outros, ou acompanhando a quantidade de remédios que o paciente está tomando e contatar o médico para mostrar o andamento do tratamento.</p>
<p>Por mais que sejam necessárias muitas discussões acerca de possíveis restrições legais relacionadas com esse tipo de aplicação, os benefícios da utilização principalmente para pacientes que fazem uso de medicação controlada.</p>
<p><img src="https://www.sagaciousnewsnetwork.com/wp-content/uploads/2016/02/Robot-Doctor-Medical-Hands-Pills.jpg" alt="image alt" title="Im_5" /></p>
<h2 id="conclusão">Conclusão</h2>
<p>Neste post, foi aprensentado apenas alguns exemplos de aplicações de Medicina na Inteligência Artificial, a título de curiosidade. Esta área ainda possui uma infinidade de possíveis segmentos que não foram mostrados aqui, entretando espera-se que as pesquisas expostas possam aguçar o interesse dos leitores e estusiastas da área.</p>
<p><img src="https://abovethelaw.com/wp-content/uploads/2015/07/Robot-doctor.jpg" alt="image alt" title="Im_6" /></p>
Gamificação2018-04-20T16:00:00+00:00http://lamfo-unb.github.io/2018/04/20/Gamification<h1 id="gamification">Gamification</h1>
<p>O post dessa semana é dedicado a um tema descontraído, mas ainda assim ligado a disseminação da tecnologia e suas práticas: <strong><em>Gamification</em></strong>! (Gamificação)</p>
<ol>
<li>Introdução</li>
<li>Press any key to start!</li>
<li>Jogadores</li>
<li>Aprendizado de Máquina</li>
<li>Mundo Aberto!</li>
<li>Referências</li>
</ol>
<h2 id="introdução">Introdução</h2>
<p>O termo <em>Gamification</em> ou Gamificação é mais antigo do que imaginamos. O estudo e aplicação de conceitos de jogos em outras áreas teve início em 1980, quando os primeiros jogos virtuais começaram a surgir no mercado.</p>
<p>Mas afinal, o que é gamificação?</p>
<p>A técnica de gamificação consiste em utilizar elementos comuns em jogos e do mundo do entreterimento em outras áreas. Quando os primeiros estudos e tentativas de implementação surgiram, o público não apresentou uma grande taxa de aceitação, sendo somente em 2010 que a técnica se popularizou devido ao acesso e disponibilidade de computadores pessoais e outras tecnologias. Hoje é comum vermos aplicação para aprendizado, gestão, marketing e até mesmo saúde; o que torna a iteração do usuário mais lúdica, agradável e com estímulos positivos para continuar a realizar determinada atividade.</p>
<p><img src="https://cdn.pixabay.com/photo/2013/07/12/16/53/space-invaders-151432_960_720.png" alt="" /></p>
<h2 id="press-any-key-to-start">Press any key to start!</h2>
<p>O processo de criação de um serviço ou ferramenta com base nos princípios e técnicas de gamificação é mais complicado do que parece. Seguindo a risca a literatura sobre o tema, existem diversos elementos que devem ser considerados e harmonizados para garantir que a técnica de gamificação funcione, não basta adotar apenas um elemento separado de um jogo, é necessário realizar um conceito e design do produto como um todo!</p>
<p>Deterding, Dixon, Khaled e Nacke (2011) realizaram uma busca na literatura acadêmica do assunto e levantou as seguintes “camadas” para considerar um serviço ou produto gamificado:</p>
<ol>
<li>Interface: utilizar elementos de jogos que torner a experiência mais concreta (leveis, medalhas por conquistas, títulos);</li>
<li>Mecanismos: padrões de dinâmica ou andamento de jogos ligados a tempo e recursos;</li>
<li>Princípios: conjunto de regras, guias e problemas claros para os “jogadores”;</li>
<li>Modelo: conceito do jogo, normalmente ligado ao objetivo e como o “jogador” será direcionado para o final (como será a jornada);</li>
<li>Métodos: estabelecer o que realmente será feito, fases, desafios e etc (mais abstrato do que as demais camadas por se tratar da parte estratégica da ferramenta).</li>
</ol>
<p>Além das camadas descritas, a gamificação possui outros elementos ligados ao social. A modelagem do jogo dinitivamente é importante, e dependendo de cada modelo, a iteração entre os jogadores se torna diferente: participando de atividades em conjunto ou de maneira competitiva. A capacidade de dividir pontuações, classificações, resultados e respostas constantes de crescimento tornam serviços ou produtos gamificados extremamente atraentes para os jogadores.</p>
<p>Mas cuidado! Existe uma pequena diferença entre gamificação e design iterativo. Quando pensamos em gamificação, tratamos do conjunto de maneira harmoniosa, no qual utilizamos jogos para atingir um objetivo que não entreterimento. O design iterativo por outro lado é quando utilizamos partes ou elementos de jogos de maneira individual, sem pensar no conjunto.</p>
<p>O assunto se tornou tão importante e popular, que universidades como Cambridge oferecem aulas e debatem sobre o tópico. A principal vantagem está na flexibilidade e resposta positiva dos usuários a técnica!</p>
<h2 id="jogadores">Jogadores</h2>
<p>Até agora, parece que apenas nos interessamos no usuário. Claro, é fácil pensar em como os “jogadores” se beneficiam desse técnica, a gamificação torna as atividades mais leves e interessantes de serem executadas, mas existem ganhos para o outro lado também! Empresas que oferecem o serviço ou produto gamificado podem acompanhar o desenvolvimento de seus jogadores.</p>
<p>Primeiro, vamos pensar em uma empresa que oferece um serviço gamificado. Um exemplo é o serviço de aprendizado de línguas, como o oferecido pela Duolingo:</p>
<ul>
<li>Jogador: Acompanhamento do crescimento por leveis e experiência; design de fases que garantem o cumprimento de pré-requisitos; interface descontraída; intuitivo e de fácil compreenção; desafios claros e iteração.</li>
<li>Empresa: Controle de resposta ao serviço; pesquisa de satisfação; acompanhamento do crescimento de mercado; diversificação.</li>
</ul>
<p>O grande ganho para as empresas está no registro e mensuração constante das informações dos jogadores. Claro, é importante que seus jogadores saibam das regras de compartilhamento de informações e para quais fins estão sendo utilizadas!</p>
<h2 id="aprendizado-de-máquina">Aprendizado de Máquina</h2>
<p>A principal dificuldade para treinarmos uma máquina é disposição dos dados. Criar uma máquina capaz de identificar padrões requer uma grande quantidade de dados, que possuam um registro preciso e acompanhavel ao longo do tempo. A gamificação permite fornece um banco de dados com as informações de todos os jogadores!</p>
<p>O exemplo de ensino de línguas ou outros tópicos utiliza do aprendizado de máquina para criar roteiros ou aulas customizadas. O acompanhamento do desempenho do aluno fornece um histórico detalhado de progresso ou de dificuldades do jogador, o que permite fornecer reforços pontuais.</p>
<p>Agora, vamos pensar em aplicar gamificação como uma ferramenta de gestão, e não produto. Existem empresas que já possuem plataformar de treinamento e cursos para funcionários que utilizam gamificação, no qual ao completar cada treinamento o colaborador recebe um nível e uma recompensa ligada ao “rank”. Mas existem ainda outras possibilidades mais estratégicas e de longo prazo.</p>
<p>Hoje, empresas já buscam maneiras de aplicar aprendizado de máquina em suas operações, automatizando atendimentos ou análises simples…mas e a gestão? Será que poderia receber o aprendizado de máquina?</p>
<p>Imagine a área de Gestão de Pessoas. É dever desta área cuidar de política de bonificações, acompanhamento de horas de trabalho, gestão do clima organizacional, formação de times, desenvolvimento e méritos dentro da empresa. Parecem atividades simples, ou que poderiam ser facilmente administradas pelo departamento com um sistema integrado, mas será que seria a melhor maneira?</p>
<p>Utilizando a gamificação, a empresa poderia criar um sistema de acompanhamento de seus funcionários, ou na linguagem do post: “jogadores”. A formação de um bando de dados com os “status” de cada jogador poderia alimentar uma máquina em busca de padrões de comportamento, prevenção de conflitos, identificação de sub-grupos e acompanhamento do bem-estar e rendimento das equipes.</p>
<h2 id="mundo-aberto">Mundo Aberto!</h2>
<p>Saindo um pouco do ambiente corporativo, onde mais podemos ver gamificação? Existem muitas empresas, algumas até sem fins lucrativos, que desenvolvem produtos com gamificação que buscam auxiliar um determinado público.</p>
<p>A área de <strong>saúde</strong> por exemplo. Existem aplicativos que foram desenvolvidos usando o design de gamificação e que possuem o objetivo de tratamento médico, prevenção e reabilitação. A empresa Mindmaze, por exemplo, desenvolve programas de reabilitação neural para derrames com base em gamificação. A ideia é utilizar a abordagem divertida e simples dos jogos para estimular o cérebro para o tratamento de uma maneira que o paciente não se sinta constrangido ou ansioso.</p>
<p>Outra empresa que utiliza gamificação é a Fitbt & Co. A empresa fornece um serviço de acompanhamento de atividades físicas que apresenta o resultado dos treinos, consumo de remédios e vitaminas e a principal ferramenta: placar de competitividade. Os jogadores são <em>rankeados</em> conforme sua performance, mantendo a comunidade ativa e motivada para garantir as posições no placar.</p>
<p><img src="https://cdn.pixabay.com/photo/2016/04/16/09/03/video-game-1332694_960_720.png" alt="" /></p>
<h2 id="referências">Referências</h2>
<p>Deterding, S., Dixon, D., Khaled, R., & Nacke, L. (2011, September). From game design elements to gamefulness: defining gamification. In Proceedings of the 15th international academic MindTrek conference: Envisioning future media environments (pp. 9-15). ACM.</p>
<p>Fitbit & CO: http://medicalfuturist.com/fitbit-helped-change-lifestyle-great-fitbit-surge-review/</p>
<p>Mindmaze: https://www.mindmotionweb.com/</p>
Mantendo o controle na era do Big Data. Manipulação de dados em R com o pacote data.table.2018-03-30T00:00:00+00:00http://lamfo-unb.github.io/2018/03/30/manipulacao-data-table<h3 id="with-big-data-comes-big-responsibilities">“<em>With Big Data, comes big responsibilities…</em>”</h3>
<p><img src="/img/manipulacao_data.table/datatable_r.png" alt="teste" /></p>
<h2 id="desafios-da-era-da-informação-e-o-papel-do-data-scientist">Desafios da era da informação e o papel do <em>data scientist</em></h2>
<p>“<em>Big Data</em>” é uma expressão que está sendo constantemente utilizada em variados contextos, e sintetiza a era de integração tecnológica, velocidade de transmissão de informações e abundância de dados na qual vivemos. Porém, <em>Big Data</em>, que traduz literalmente para “Grandes dados”, por si só não significa nada… Mais que ter grande quantidade de informações, nunca foi mais importante saber fazer uso eficiente e consciente dessa massa de dados – conferir propósito à quase-infinitude de números e letras, transformar meros <em>bytes</em> em valor, em algo que seja útil. Em uma era em que “inteligência artificial” é glorificada e encarada como uma janela para um futuro mais conveniente e confortável, o pensamento crítico típico à inteligência humana assume um papel central – agora mais que nunca – para que haja garantias de que a evolução tecnológica possa solucionar as demandas daqueles que a criou</p>
<p>Para saber fazer bom uso dos dados, primeiro é preciso garantir sua qualidade. Seja para uma análise estatística simplista para um trabalho escolar, ou para uma modelagem complexa que coloca em xeque o bem-estar de milhões de pessoas e a alocação eficiente de bilhões em recursos, a validade de um estudo de <em>data science</em> está intimamente vinculada à qualidade de seu insumo mais fundamental – dados. A qualidade dos dados é um fundamento sobre o qual se assenta a definição de um problema relevante, a elegância das formalizações matemáticas, a compostura daquele que apresenta o PowerPoint dos resultados, a potencial repercussão da análise para o mundo acadêmico, profissional ou social… dados bons são condição necessária para se realizar uma boa análise; dito de outra forma, dados ruins são <strong>garantia</strong> para para uma análise ruim – ou, ainda pior, pode gerar uma análise aparentemente relevante, porém enviesada, de modo que o pesquisador acaba por aceitar algo equivocado que pode se propagar e influenciar negativamente esforços futuros.</p>
<p>Limpeza dos dados é uma das partes menos divertidas do ofício de um <em>data scientist</em>, porém é, disparado, uma das suas habilidades mais primordiais. Saber lidar com um banco de dados complicado, manipular e criar variáveis, filtrar classes de interesse e descartar de observações indesejadas fazem parte da rotina de um cientista de dados, e representam uma grande quantidade de trabalho até que se chegue a uma tabela organizada para, só então, servir de <em>input</em> para algum modelo sofisticado e gerar conclusões potencialmente úteis. No contexto do <em>Big Data</em>, em especial, saber manipular uma base de dados se torna ainda mais essencial, dado que o grande volume de dados gera desafios adicionais – não basta mais apenas tratar bem os dados, mas é necessário fazer isso de maneira <strong>eficiente</strong></p>
<p>Este post apresenta algumas funcionalidades do pacote <em>data.table</em>, uma ferramenta útil para se ter no “canivete” de um cientista de dados. Esperamos que possa ajudar você a controlar suas grandes bases de dados de maneira prática!</p>
<p><img src="/img/manipulacao_data.table/Stock_IoT.jpg" alt="SPSS-sucks" /></p>
<h2 id="datatable-um-instrumento-poderoso"><em>data.table</em>: Um instrumento poderoso</h2>
<p>Usuários R (principalmente iniciantes) lutam, com muita dificuldade diga-se de passagem, ao lidar com grandes conjuntos de dados. Eles são assombrados por avisos repetitivos, mensagens de erro de uso insuficiente de memória. A maioria deles chega a uma conclusão imediata de que a especificação de sua máquina não é poderosa o suficiente. Para desmistificar o assunto resolvi encontrar um conjunto de dados suficientemente grande que, obviamente, conseguisse rodar no meu computador de 8gb de RAM.</p>
<p>Nesse post abordamos os primeiros passo para aprender a manipular um grande conjunto de dados via Data.table, o que de forma alguma substitui uma leitura <a href="https://cran.r-project.org/web/packages/data.table/data.table.pdf"><strong>clique aqui</strong></a> da documentação completa do pacote, e aproveitando o embalo, recomendo muito o curso do próprio criador do data.table <a href="https://www.datacamp.com/courses/data-table-data-manipulation-r-tutorial"><strong>clicando aqui</strong></a> , que aborda de forma simplista, porém muito completa, uma grande gama de possibilidades dentro do pacote do Data.table, inclusive a imagem utilizada é do datacamp feita para o curso.</p>
<p>Para que fosse um desafio, resolvi escolher um banco de dados suficientemente grande que funções nativas no R não fossem capazes de lidar facilmente com ele, uma boa possibilidade para você que procura banco de dados, é o site Kaggle que possui muitos dados armazenados além de serem bem explicados, de diversas áreas, o site é <a href="https://www.kaggle.com/datasets"><strong>esse</strong></a>. O banco que foi utilizado no e projeto, os dados vêm do sistema de compartilhamento de bicicletas Divvy de Chicago, bem como as informações sobre o tempo em Chicago e pode ser encontrado <a href="https://www.kaggle.com/yingwurenjian/chicago-divvy-bicycle-sharing-data"><strong>aqui</strong></a></p>
<p><img src="/img/manipulacao_data.table/fob_transit-divvy-expansion-west-magnum.jpg" alt="ola" /></p>
<h2 id="lendo-o-banco-de-dados">Lendo o banco de dados</h2>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Lendo com a funcão fread()
> chicago_ciclistas <- fread("chicago-divvy-bicycle-sharing-data\\data_raw
.csv",fill=TRUE)
Read 13774715 rows and 27 (of 27) columns from 3.244 GB file in 00:08:31
# Leitura com a função padrão do R
> system.time(chicago_ciclistas <- read.csv("D:\\Dados\\chicago-divvy-bicycle-sharing-data\\data_raw.csv",fill=TRUE))
usuário sistema decorrido
439.54 47.54 1771.05
</code></pre></div></div>
<p>Ou seja, em 8 minutos o R leu o banco de dados que tem tamanho de 3gb, esse tempo de performance ainda pode ser melhorado caso você passe o argumento especificando o que cada coluna é, inteiro/integer ou carácter/fator, enquanto a função nativa do R demorou 47 minutos.</p>
<p>Podemos ver as variáveis do nosso banco de dados.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>names(chicago_ciclistas)
[1] "trip_id" "usertype" "gender" "starttime" "stoptime" "tripduration" "from_station_id"
[8] "from_station_name" "latitude_start" "longitude_start" "dpcapacity_start" "to_station_id" "to_station_name" "latitude_end"
[15] "longitude_end" "dpcapacity_end" "temperature" "windchill" "dewpoint" "humidity" "pressure"
[22] "visibility" "wind_speed" "precipitation" "events" "rain" "conditions"
</code></pre></div></div>
<h2 id="ordenando-o-banco">Ordenando o banco</h2>
<p>O que mais chama atenção no data.table é a simplicidade do código, muitas funções você passa diretamente ao banco, por exemplo a ordenação do banco de dados, pegando a menor duração de viagem:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># função order aplicada dentro do data.table
> chicago_ciclistas <- chicago_ciclistas[order(tripduration)]
trip_id usertype gender starttime stoptime tripduration from_station_id from_station_name latitude_start
1: 4192 Subscriber Male 2013-06-27 12:15:00 2013-06-27 12:16:00 60 28 Larrabee St & Menomonee St 41.91468
2: 5453 Subscriber Male 2013-06-28 11:01:00 2013-06-28 11:02:00 60 51 Clark St & Randolph St 41.88458
3: 6511 Subscriber Male 2013-06-28 16:04:00 2013-06-28 16:05:00 60 48 Larrabee St & Kingsbury St 41.89776
4: 14100 Subscriber Male 2013-07-01 13:54:00 2013-07-01 13:55:00 60 92 Carpenter St & Huron St 41.89456
5: 14113 Subscriber Male 2013-07-01 13:56:00 2013-07-01 13:57:00 60 92 Carpenter St & Huron St 41.89456
</code></pre></div></div>
<p>Ou pegando de maior duração:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> chicago_ciclistas <- chicago_ciclistas[order(-tripduration)]
</code></pre></div></div>
<h2 id="excluindo-nas-do-banco">Excluindo NA’s do banco</h2>
<p>Outra coisa importante é saber excluir NAs do nosso banco de dados , caso não sejam necessários, da mesma forma podemos usar a função is.na() aplicada dentro do data.table:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>chicago_ciclistas[!is.na(starttime)]
</code></pre></div></div>
<p>Reparem que ele identifica os nomes da coluna, na maioria das vezes sem a necessidade das aspas, o que para um usuário R padrão soa um pouco estranho, mas sim, este é o jeito data.table.</p>
<h2 id="fazendo-um-corte-nos-dados">Fazendo um corte nos Dados</h2>
<p>Outra coisa fundamental no processo de análise de dados é o corte ou subset do banco de dados, o processo não foge muito do que já foi feito para tirar as informações perdidas e na ordenação dos dados…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Podemos estar interessados em apenas nos dados do sexo masculino
> sexo_masculino<-chicago_ciclistas[gender=="male"]
# ou viagens acima de 180 segundos
> viagem_longa<-chicago_ciclistas[tripduration>180]
# Ou nos dois juntos
> viagem_longa<-chicago_ciclistas[tripduration>180 & gender=="male"]
</code></pre></div></div>
<h2 id="desduplicando-variáveis">Desduplicando variáveis.</h2>
<p>Função que rende muitas postagens no stack overflow é como retirar informações duplicadas do nosso conjunto de dados, além disso retirar informações duplicadas em conjunto de 2 variáveis em conjunto. Por exemplo, no nosso conjunto de dados tem a trip_id, suponha que seja o usuário dessa estação,e eu quero apenas 1 informação por usuário, e depois eu quero um conjunto de dados com só uma informação de usuário por dia, no segundo precisamos primeiro criar um conjunto de dados so com as duas colunas.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># Apenas uma informação de usuário
>apenas_uma_informacao_id <- chicago_ciclistas[!duplicated(trip_id)]
# Apenas uma informação de usuário por dia
>informacoes_usuario <-chicago_ciclistas[,c("trip_id","starttime")]
>apenas_uma_informacao_id_day <- chicago_ciclistas[!duplicated(informacoes_usuario)]
</code></pre></div></div>
<h2 id="criando-nova-variável">Criando nova variável</h2>
<p>O data table permite alta performance também na criação de novas variaveis usando o formato <strong>:=</strong>, o que pode muito interessante quando combinado com a função by…</p>
<p>Vamos supor que não existisse a variável duração da viagem, poderiamos usar facilmente a variavel starttime e stoptime e criar a variável:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>chicago_ciclistas[,tempo_viagem:=starttime-stoptime]
</code></pre></div></div>
<p>Utilizando o by podiamos criar um tempo de viagem médio por sexo…</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># criando a variável media de viagem por sexo e selecionando as 10 primeiras obs das duas colunas
>chicago_ciclistas[,media_viagem_sexo:=mean(tripduration),by=gender][1:10,c("gender","media_viagem_sexo")]
gender media_viagem_sexo
1: Male 685.9940
2: Male 685.9940
3: Male 685.9940
4: Male 685.9940
5: Male 685.9940
6: Male 685.9940
7: Male 685.9940
8: Male 685.9940
9: Female 807.1566
10: Male 685.9940
</code></pre></div></div>
<h2 id="trabalhando-com-resumo-dos-dados-n">Trabalhando com resumo dos dados (.N)</h2>
<p>Outra questão muito fundamental nesses primeiros passos é o .N que, caso quem se interessar e se aprofundar no pacote, tem muita utilidade dentro de diversas funções, uma por exemplo é resumo, vamos supor que queiramos quantas viagens de uma estação a outra foram feitas, podemos fazer isso via data.table da seguinte forma:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>chicago_ciclistas[,.N,by=c("from_station_name","to_station_name")]
from_station_name to_station_name N
1: Larrabee St & Menomonee St Larrabee St & Menomonee St 809
2: Clark St & Randolph St Clark St & Randolph St 1196
3: Larrabee St & Kingsbury St Larrabee St & Kingsbury St 906
4: Carpenter St & Huron St Carpenter St & Huron St 436
5: Franklin St & Chicago Ave Franklin St & Chicago Ave 813
</code></pre></div></div>
<h3 id="recapitulando-o-que-foi-visto-em-apenas-uma-função">Recapitulando o que foi visto em apenas uma função</h3>
<p>Vamos agora em apenas um comando recapitular boa parte do que foi visto aqui, criando um tempo médio de viagem ao mesmo tempo pelo clima, se choveu ou não, e por sexo. Depois pegamos a quantidade de dados por sexo, clima e a média, e por fim ordenamos pela variável de quantidade(N), pareceu complicado? o código vai parecer um pouco denso, mas é importante que você capitule o funcionamento para ganho de eficiência:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>chicago_ciclistas[,media_viagem_condicao_clima_0_1:=mean(tripduration),by=c("rain","gender")][,.N,by=c("rain","media_viagem_condicao_clima_0_1","gender")][order(-N)]
rain media_viagem_condicao_clima_0_1 gender N
1: 0 687.7778 Male 7262934
2: 0 1792.7700 3671283
3: 0 809.0070 Female 2411877
4: 1 637.4476 Male 266872
5: 1 1649.3833 85649
6: 1 748.5133 Female 76100
</code></pre></div></div>
<h3 id="outros-posts-interessantes-em-linguagem-r">Outros posts interessantes em Linguagem R.</h3>
<p>Recomendo fortemente outros posts interessantes em linguagem R e abordando outros pacotes em outros temas, por exemplo do <a href="https://lamfo-unb.github.io/2017/07/22/intro-analise-acoes-1/"><strong>Post</strong></a> analisando ações no programa R, uma abordagem muito interessante utilizando os pacotes ggplot e quantmod, pacote esse que permite fazer diretamente download de ações, e o outro <a href="https://lamfo-unb.github.io/2017/08/17/Teste-de-Eventos/"><strong>Post</strong></a> com aplicações de teste de Eventos, que tem como base a Teoria dos Mercados Eficientes de Fama (1970), em que se acredita que o mercado absorve as informações públicas disponíveis e realiza o ajuste do preço dos ativos, além disso o <a href="https://www.coursera.org/"><strong>Coursera</strong></a> contém uma grande gama de cursos, que podem ser feitos de graça como ouvinte(sem ganho de certificado) e muito bons como o <a href="https://www.coursera.org/learn/r-programming"><strong>R programming</strong></a>.</p>
<center>
</center>
Processos Gaussianos2018-03-24T14:15:07+00:00http://lamfo-unb.github.io/2018/03/24/gaussian-process<h2 id="conteúdo">Conteúdo</h2>
<ol>
<li><a href="#intro">Introdução</a></li>
<li><a href="#into">Intuição</a></li>
<li><a href="#math">Matemática</a>
<ol>
<li><a href="#kernel">Kernel</a></li>
<li><a href="#cov">Matriz de Covariância</a></li>
<li><a href="#GP">Processo Gaussiano</a></li>
</ol>
</li>
<li><a href="#code">Código</a></li>
<li><a href="#ref">Referências</a></li>
</ol>
<p><a name="intro"></a></p>
<h2 id="introdução">Introdução</h2>
<p>Uma das grandes vantagens de Aprendizado de Máquina é conseguir estimar funções com relações complexas entre as variáveis e cheias de não linearidade. Se quisermos encarar esses problemas com modelos lineares simples, podemos <a href="https://matheusfacure.github.io/2017/03/01/regr-poli/">extender a forma funcional estimada usando mais parâmetros, o que pode ser obtido, por exemplo, fazendo uma expansão polinomial</a>. Sempre podemos aumentar o grau do polinômio estimado, tornando-o arbitrariamente complexo, para assim conseguir ajusta-lo a dados bastante não lineares.</p>
<p><img class="img-responsive center-block thumbnail" src="/img/gp/polregr.png" style="width: 60%;" alt="plinomial_regression" /></p>
<p>Por outro lado, e se não quisermos especificar de antemão o número de parâmetros do modelo? Uma possibilidade é considerar todas as funções que se encaixam nos nossos dados, cada uma com quantos parâmetros forem necessários. É isso que Processos Gaussianos são capazes de fazer: um método <em>não paramétrico</em> para regressão não linear. Note que <em>não paramétrico</em> não deve ser confundido como um modelo sem parâmetros, mas sim entendido como algo que tem muitos parâmetros (infinitos, possivelmente), tanto mais quanto maior for a quantidade de dados.</p>
<p>Mais do que isso, Processos Gaussianos são modelos probabilísticos ou bayesianos. Isso significa que, além de nos fornecer uma estimativa pontual de uma previsão (geralmente a média condicional), os Processos Gaussianos também especificam toda a distribuição preditiva a posteriori, tornando a obtenção de estatísticas de incerteza algo natural. Isso é extremamente importante para aplicações de Aprendizado de Máquina em cenários de alto risco, como medicina, carros autônomos ou concessão de crédito. Nessas áreas, além da previsão, estamos frequentemente interessados no grau de certeza do modelo para que, caso ele seja muito alto, possamos passar a decisão para um especialista humano.</p>
<p><a name="into"></a></p>
<h2 id="intuição">Intuição</h2>
<p>De uma forma bastante simplista, podemos entender Processos Gaussianos como um <strong>interpolador de dados</strong>. Assumindo que não há ruído, um interpolador prevê sempre o valor observado onde há dados. A parte complicada então é saber o que prever entre um e outro ponto. A intuição diz que nossas previsões não mudam bruscamente se as variáveis explicativas não mudarem muito. Por exemplo, se eu observo \(y=0\) quando \(x=0\) então devo esperar que \(y\) seja próximo de zero quando \(x\) por próximo de zero, digamos \(x=0.1\). Na imagem abaixo podemos ver como Processos Gaussianos estão de acordo com essa intuição e fazem uma interpolação bastante elegante.</p>
<figure class="figure center-block thumbnail" style="width: 60%;">
<img src="/img/gp/gprDemoNoiseFree_02.png" class="img-responsive center-block" alt="" />
<figcaption class="figure-caption text-center">Retirada do <a href="https://github.com/probml/pmtk3/blob/30d7a1952f3979b16e92dbfa4cd1ce0e402cf7d8/docs/demoOutput/bookDemos/(15)-Gaussian_processes/gprDemoNoiseFree_02.png">livro de Kevin Murphy</a></figcaption>
</figure>
<p>A imagem mostra 3 amostras de um processo gaussiano definido pelas 5 observações marcadas com <code class="language-plaintext highlighter-rouge">x</code>. Note que, onde há dados, o valor previsto é o mesmo que o observado e não há incerteza (lembre-se de que assumimos ruído zero). Conforme nos afastamos dos dados, a incerteza da interpolação aumenta, denotada pelo alargamento do intervalo de confiança de 95% (em cinza).</p>
<p>Então, recapitulando, se podemos entender Processos Gaussianos como uma espécie de interpolador, que, de quebra nos dá informações de incerteza, precisamos que ele defina duas coisas: uma noção de distância ou similaridade e uma noção de variância. Para entender isso melhor, precisaremos entrar um pouco na matemática</p>
<p><a name="math"></a></p>
<h2 id="matemática">Matemática</h2>
<p><a name="kernel"></a></p>
<h3 id="kernel">Kernel</h3>
<p>A noção de distância entre dois pontos é definida num Processo Gaussiano pelo que chamamos de <strong>kernel</strong>, uma função de dois pontos no espaço, geralmente não linear, que pode ser interpretada como a distância entre os seus pontos de entrada. Um kernel bastante popular é o exponencial quadrático, também conhecido como função de base radial ou kernel gaussiano:</p>
\[k(x,x') = \sigma^2 exp\Bigg(-\frac{(x-x')^2}{2\mathcal{l}^2}\Bigg)\]
<p>Ele tem esses nomes pois é igual a <a href="https://en.wikipedia.org/wiki/Normal_distribution">função gaussiana</a>, tirando o fator de normalização. Isso lhe confere algumas propriedades de distância bastante interessantes. Ele pode ser entendido como uma função gaussiana onde <code class="language-plaintext highlighter-rouge">x</code> é o ponto de máximo e distância aumenta conforme nos afastamos desse ponto. O hyper-parâmetro \(\mathcal{l}\) é como se fosse a variância dessa gaussiana, controlando quão larga é a curva. Dessa forma, \(\mathcal{l}\) muito pequeno nos diz que a distância aumenta rapidamente quando nos afastamos de <code class="language-plaintext highlighter-rouge">x</code> e, por conseguinte, espera-se que a nossa função interpoladora varie muito e rapidamente, sendo pouco suave. Um \(\mathcal{l}\) grande, por sua vez, introduz uma noção de distância que diminui lentamente conforme nos afastamos de <code class="language-plaintext highlighter-rouge">x</code> e, por conseguinte, a função interpoladora será mais suave.</p>
<p>Já o fator de dimensionamento \(\sigma^2\) tem uma interpretação mais simples: eles nos diz o quanto esperamos que nossa distância seja algo fora da média (zero, na imagem abaixo).</p>
<p><img src="/img/gp/GP_params.png" alt="img" /></p>
<p>Claro que existem muitos outros kerneis além do gaussiano, mas falar sobre eles não é o propósito deste post. Caso queira saber mais, confira o <a href="http://www.cs.toronto.edu/~duvenaud/cookbook/">Kernel cookbook</a>, com alguns exemplos de kernels e suas aplicações. Por hora, o que é importante ter em mente é que o kernel é uma função que pode ser <strong>interpretada como a distância ou similaridade entre dois pontos</strong>.</p>
<p><a name="cov"></a></p>
<h3 id="matriz-de-covariância">Matriz de Covariância</h3>
<p>Outra coisa que carrega uma noção de distância são matrizes de covariância. Caso não lembre muito sobre matriz de covariância, pegue um DataFrame qualquer no Pandas e use <a href="https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.cov.html"><code class="language-plaintext highlighter-rouge">df.cov()</code></a>.</p>
<p>Intuitivamente, a matriz de covariância nos diz como cada uma das variáveis são parecidas entre si (ou linearmente dependentes). Isso porque a uma boa parte da <a href="https://en.wikipedia.org/wiki/Covariance">operação de covariância</a> é simplesmente computar a produto interno entre duas colunas, que nada mais é do que a noção mais simples que há de distância. Como exemplo, considere os dados diários de <a href="https://archive.ics.uci.edu/ml/datasets/bike+sharing+dataset">aluguel de Bike</a>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span> <span class="c1"># pada DataFrames
</span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span> <span class="c1"># para computação numérica
</span><span class="kn">from</span> <span class="nn">toolz.curried</span> <span class="kn">import</span> <span class="o">*</span> <span class="c1"># para programação funcional
</span>
<span class="n">data</span> <span class="o">=</span> <span class="n">pipe</span><span class="p">(</span><span class="s">"/Users/matheusfacure/Downloads/Bike-Sharing-Dataset/day.csv"</span><span class="p">,</span>
<span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">,</span>
<span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="n">df</span><span class="p">[[</span><span class="s">"instant"</span><span class="p">,</span> <span class="s">"season"</span><span class="p">,</span> <span class="s">"workingday"</span><span class="p">,</span> <span class="s">"weathersit"</span><span class="p">,</span> <span class="s">"temp"</span><span class="p">,</span> <span class="s">"hum"</span><span class="p">,</span> <span class="s">"windspeed"</span><span class="p">,</span> <span class="s">"cnt"</span><span class="p">]])</span>
<span class="n">pipe</span><span class="p">(</span><span class="n">data</span><span class="p">,</span>
<span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="p">(</span><span class="n">df</span> <span class="o">-</span> <span class="n">df</span><span class="p">.</span><span class="n">mean</span><span class="p">())</span> <span class="o">/</span> <span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">(),</span>
<span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="n">df</span><span class="p">.</span><span class="n">cov</span><span class="p">())</span>
</code></pre></div></div>
<p><img src="/img/gp/cov.png" alt="img" /></p>
<p>No exemplo acima, podemos ver que a quantidade de ciclistas (<code class="language-plaintext highlighter-rouge">cnt</code>) está bastante correlacionada com a estação do ano (<code class="language-plaintext highlighter-rouge">season</code>). De certa forma, isso quer dizer que esses duas colunas estão próximas umas das outras, já quem ter informações sobre uma nos diz muito sobre a outra.</p>
<p>Apenas por diversão, para ver mesmo que covariância nada mais de do que um produto interno (mais uma pequena normalização), você pode conseguir os mesmo resultado acima da seguinte forma</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pipe</span><span class="p">(</span><span class="n">data</span><span class="p">,</span>
<span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="p">(</span><span class="n">df</span> <span class="o">-</span> <span class="n">df</span><span class="p">.</span><span class="n">mean</span><span class="p">())</span> <span class="o">/</span> <span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">(),</span>
<span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="n">df</span><span class="p">.</span><span class="n">T</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">df</span><span class="p">)</span> <span class="o">/</span> <span class="mi">730</span><span class="p">)</span> <span class="c1"># 730 é o fator normalizador
</span></code></pre></div></div>
<p>Estou mostrando isso porque não é possível ressaltar o suficiente que <strong>covariância é uma métrica de similaridade, assim como produtos internos</strong>. Guarde bem isso na sua cabeça que Processos Gaussianos se tornarão algo simples.</p>
<p>Agora, e se, em vez de usar a covariância tradicional de uma base de dados, a gente antes virasse a tabela? Nesse caso a matriz covariância obtida seria \(N\)x\(N\) e nos daria informações sobre o quão similares são as <strong>observações</strong> entre si!</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">pipe</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="c1"># inverte linhas e colunas
</span> <span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="p">(</span><span class="n">df</span> <span class="o">-</span> <span class="n">df</span><span class="p">.</span><span class="n">mean</span><span class="p">())</span> <span class="o">/</span> <span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">(),</span>
<span class="k">lambda</span> <span class="n">df</span><span class="p">:</span> <span class="n">df</span><span class="p">.</span><span class="n">cov</span><span class="p">())</span>
</code></pre></div></div>
<p>Isso parece exatamente o que precisamos num interpolador, isto é, uma noção de distância entre as amostras para prever coisas parecidas para observações também parecidas.</p>
<p>Uma outra ideia é que usar um simples produto interno na hora de computar a covariância talvez não seja a melhor coisa que possamos fazer. E se quisermos usar uma distância não linear? Para isso, podemos substituir o produto interno por uma <strong>função kernel</strong>, que também codifica distância, mas numa forma muito mais flexível e complexa.</p>
<p><a name="GP"></a></p>
<h3 id="processo-gaussiano">Processo Gaussiano</h3>
<p>Vimos que kerneis e matriz de covariância são formas de representar uma noção de distância, que é o que precisamos para criar um bom interpolador. Agora podemos juntar tudo isso que vimos para entender os <strong>Processos Gaussianos</strong>.</p>
<p>Uma coisa bastante surpreendente sobre processos gaussianos é que eles são absurdamente fáceis de implementar, pois não passam de distribuições Gaussianas Multivariadas. Só precisamos definir uma média e uma covariância que teremos nosso GP. Por outro lado, embora fácil, conseguir essa média e covariância envolve bastante teoria de álgebra linear e de distribuições gaussianas. Se você não souber toda essa teoria de cara, não se preocupe pois toda ela está facilmente disponível na internet (por exemplo na Wikipédia) e você só precisa copiar e colar algumas operações algébricas para código.</p>
<p>Formalmente, uma função \(\pmb{f}\) é um <strong>Processos Gaussianos</strong> se qualquer conjunto finito \( \{ \pmb{f}(\pmb{x}_1), \pmb{f}(\pmb{x}_2), …, \pmb{f}(\pmb{x}_n) \} \) segue uma distribuição normal multivariada, onde \(\pmb{x}\) tipicamente representam um vetor observação (linha) numa tabela de dados. Assim como uma gaussiana, um GP é definido por uma função de média \(\pmb{m(x)}\), que é usualmente assumida como zero. Além disso, um PG é definido por uma função de covariância \(k(\boldsymbol x, \boldsymbol x’)\), também conhecida por <strong>kernel</strong>. A função de covariância é usada para construir uma matriz de covariância \(N\)x\(N\). Juntando isso, podemos retirar amostras a priori de um GP com</p>
\[\boldsymbol f \sim \mathcal N(\boldsymbol m_{\boldsymbol X}, \boldsymbol K_{\boldsymbol X \boldsymbol X})\]
<p>Em que \(\pmb{m}\) é da mesma dimensão de \(\pmb{X}\) e \(K\) tem dimensões \(XX^T\). Geralmente assumimos que \(\pmb{m}\) é zero. Isso se traduz para algumas poucas linhas de código Python.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">kernel</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">,</span> <span class="n">l</span><span class="o">=</span><span class="mf">0.1</span><span class="p">,</span> <span class="n">sigma</span><span class="o">=</span><span class="mf">0.1</span><span class="p">):</span>
<span class="n">sqdist</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">A</span><span class="o">**</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">).</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="o">+</span> <span class="n">np</span><span class="p">.</span><span class="nb">sum</span><span class="p">(</span><span class="n">B</span><span class="o">**</span><span class="mi">2</span><span class="p">,</span><span class="mi">1</span><span class="p">)</span> <span class="o">-</span> <span class="mi">2</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">A</span><span class="p">,</span> <span class="n">B</span><span class="p">.</span><span class="n">T</span><span class="p">)</span>
<span class="k">return</span> <span class="n">np</span><span class="p">.</span><span class="n">exp</span><span class="p">(</span><span class="o">-</span><span class="p">.</span><span class="mi">5</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="n">l</span><span class="p">)</span> <span class="o">*</span> <span class="n">sqdist</span><span class="p">)</span> <span class="o">+</span> <span class="n">sigma</span> <span class="o">*</span> <span class="n">np</span><span class="p">.</span><span class="n">kron</span><span class="p">(</span><span class="n">A</span><span class="p">,</span><span class="n">B</span><span class="p">.</span><span class="n">T</span><span class="p">)</span>
<span class="n">plot_xs</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="o">-</span><span class="mi">5</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">300</span><span class="p">),</span> <span class="p">(</span><span class="mi">300</span><span class="p">,</span><span class="mi">1</span><span class="p">))</span>
<span class="n">K_xx</span> <span class="o">=</span> <span class="n">kernel</span><span class="p">(</span><span class="n">plot_xs</span><span class="p">,</span> <span class="n">plot_xs</span><span class="p">,</span> <span class="n">l</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">sigma</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">f_prior</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">multivariate_normal</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">zeros</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">plot_xs</span><span class="p">)),</span> <span class="n">K_xx</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">10</span><span class="p">).</span><span class="n">T</span>
</code></pre></div></div>
<p>A única coisa que talvez não seja muito obvia acima é <code class="language-plaintext highlighter-rouge">np.kron(A,B.T)</code>, que é simplesmente a função <a href="https://pt.wikipedia.org/wiki/Delta_de_Kronecker">Delta Kronecker</a>. Apesar do nome pomposo, ela nada mais é do que uma forma de ver se duas coisas são iguais, retornando 1 se sim e 0 c.c..</p>
<p>Algo muito conveniente sobre distribuições gaussianas é que é possível obter a distribuição condicional a partir da distribuição conjunta de maneira bastante simples. Digamos que você tenha dados de treino \(\pmb{X}\) e \(\pmb{f}=\pmb{y}\) e queria prever para um dado de teste \(\boldsymbol X_*\) a variável resposta \(\boldsymbol f_* = y_*\). Você pode concatenar essas peças em uma gaussiana da seguinte forma.</p>
\[\begin{pmatrix} \boldsymbol y \\ \boldsymbol y_* \end{pmatrix} \sim \mathcal N \left( \begin{pmatrix} \boldsymbol 0 \\ \boldsymbol 0 \end{pmatrix}, \left(\begin{matrix} \boldsymbol K \\\boldsymbol K_{*}\end{matrix} \begin{matrix} \boldsymbol K_{*}^T \\ \boldsymbol K_{**}\end{matrix}\right)\right).\]
<p>Note que \(\boldsymbol K\) é a matriz covariância obtida ao aplicar o kernel em \(\boldsymbol X\) com \(\boldsymbol X\), \(\boldsymbol K_*\) é obtida aplicando o kernel em \(\boldsymbol X\) com \(\boldsymbol X_*\) e \(\boldsymbol K_{**}\) é obtida aplicando o kernel em \(\boldsymbol X_*\) com \(\boldsymbol X_*\). Com isso, podemos sair da distribuição conjunta acima para a distribuição condicional, mostrada abaixo.</p>
\[p(\boldsymbol y_*\vert \boldsymbol X_*, \boldsymbol X, \boldsymbol y) = \mathcal N(\boldsymbol K_{*} \boldsymbol K^{-1}\boldsymbol y, \boldsymbol K_{**} - \boldsymbol K_{*} \boldsymbol K^{-1} \boldsymbol K_{*}).\]
<p>Provar esse resultado envolve bastante matemática e não é o propósito deste post. Você pode achar várias provas desse teorema online, como por exemplo <a href="https://stats.stackexchange.com/questions/30588/deriving-the-conditional-distributions-of-a-multivariate-normal-distribution">essa aqui</a> no StackExchange.</p>
<p><a name="code"></a></p>
<h1 id="código">Código</h1>
<p>Antes de qualquer coisa, como vamos trabalhar com as matrizes de covariância obtidas a partir do kernel, precisamos obtê-las dos dados de treino e teste.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">K_xx</span> <span class="o">=</span> <span class="n">kernel</span><span class="p">(</span><span class="n">X_test</span><span class="p">,</span> <span class="n">X_test</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">sigma_y</span><span class="p">)</span>
<span class="n">K_ss</span> <span class="o">=</span> <span class="n">kernel</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">X_train</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">sigma_y</span><span class="p">)</span>
<span class="n">K_sx</span> <span class="o">=</span> <span class="n">kernel</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">X_test</span><span class="p">,</span> <span class="n">l</span><span class="p">,</span> <span class="n">sigma_y</span><span class="p">)</span>
</code></pre></div></div>
<p>Olhando a fórmula acima podemos notar a inversão de \(\boldsymbol K\), uma matriz NxN. Por questões de instabilidade numérica, implementar a formula acima não é muito recomendado. Por isso, usamos algo chamado de Decomposição de Cholesky, que pode ser entendido como uma espécie de raiz quadrada para matrizes. Assim, se \(\boldsymbol K = \boldsymbol L^T \boldsymbol L \), então \(\boldsymbol L = \texttt{Cholesky}(\boldsymbol K)\). O algoritmo final pode ser descrito nas seguintes linhas</p>
\[\boldsymbol L = cholesky(\boldsymbol K + \boldsymbol \sigma_n^2 I) \\
\boldsymbol \alpha = \boldsymbol L^T \texttt{\\} \boldsymbol L \texttt{\\} \boldsymbol y \\
\mathbb{E}[\boldsymbol y_*] = \boldsymbol K_*^T \boldsymbol \alpha \\
\boldsymbol v = \boldsymbol L \texttt{\\} \boldsymbol K_* \\
Var [\boldsymbol y_*] = \boldsymbol K_{**} - \boldsymbol v^T \boldsymbol v\]
<p>Que se traduz para as seguintes linhas de código Python</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">L</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">cholesky</span><span class="p">(</span><span class="n">K_xx</span> <span class="o">+</span> <span class="n">sigma_y</span><span class="o">*</span><span class="n">np</span><span class="p">.</span><span class="n">eye</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">X_train</span><span class="p">)))</span>
<span class="n">alpha</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">solve</span><span class="p">(</span><span class="n">L</span><span class="p">.</span><span class="n">T</span><span class="p">,</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">solve</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">y_train</span><span class="p">))</span>
<span class="n">mu</span> <span class="o">=</span> <span class="n">K_sx</span><span class="p">.</span><span class="n">T</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">alpha</span><span class="p">).</span><span class="n">squeeze</span><span class="p">()</span>
<span class="n">v</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">linalg</span><span class="p">.</span><span class="n">solve</span><span class="p">(</span><span class="n">L</span><span class="p">,</span> <span class="n">K_sx</span><span class="p">)</span>
<span class="n">cov</span> <span class="o">=</span> <span class="n">K_ss</span> <span class="o">-</span> <span class="n">v</span><span class="p">.</span><span class="n">T</span><span class="p">.</span><span class="n">dot</span><span class="p">(</span><span class="n">v</span><span class="p">)</span>
</code></pre></div></div>
<p>Com a média e covariância, podemos retirar amostrar do nosso Processo Gaussiano e até plotá-las com um intervalo de confiança.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">seed</span><span class="p">(</span><span class="mi">42</span><span class="p">)</span>
<span class="n">f_post</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">random</span><span class="p">.</span><span class="n">multivariate_normal</span><span class="p">(</span><span class="n">mu</span><span class="p">,</span> <span class="n">cov</span><span class="p">,</span> <span class="n">size</span><span class="o">=</span><span class="mi">10</span><span class="p">).</span><span class="n">T</span>
<span class="n">stdv</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">sqrt</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">diagonal</span><span class="p">(</span><span class="n">cov</span><span class="p">))</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">X_test</span><span class="p">,</span> <span class="n">f_post</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">gca</span><span class="p">().</span><span class="n">fill_between</span><span class="p">(</span><span class="n">X_test</span><span class="p">.</span><span class="n">flat</span><span class="p">,</span> <span class="n">mu</span><span class="o">-</span><span class="mi">2</span><span class="o">*</span><span class="n">stdv</span><span class="p">,</span> <span class="n">mu</span><span class="o">+</span><span class="mi">2</span><span class="o">*</span><span class="n">stdv</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"#dddddd"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">'Amostras A Posteriori de um Processo Gaussiano'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span> <span class="s">'bs'</span><span class="p">,</span> <span class="n">ms</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<figure class="figure center-block thumbnail" style="width: 50%;">
<img src="/img/gp/post.png" class="img-responsive center-block" alt="" />
</figure>
<p>Além de bonita, essa imagem mostra como o GP capta bem a intuição bayesiana de colocar mais incerteza onde há menos dados.</p>
<p><a name="ref"></a></p>
<h2 id="referências">Referências</h2>
<p>Este tutorial foi amplamente inspirado na <a href="https://www.youtube.com/watch?v=4vGiHC35j9s">aula de Processos Gaussianos do professor Nando de Freitas</a>, bem como nas suas <a href="http://www.cs.ubc.ca/~nando/540-2013/lectures.html">notas de aula</a>. Cada aula de Nando é uma pérola e recomendo fortemente que você assista todo o seu <a href="https://www.youtube.com/watch?v=w2OtwL5T1ow&list=PLE6Wd9FR--EdyJ5lbFl8UuGjecvVw66F6">curso de Aprendizado de Máquina</a>, lecionado na <em>University of British Columbia</em>.</p>
<p>Além disso, muitas ideas foram tiradas do <a href="http://keyonvafa.com/gp-tutorial/">tutorial sobre Processos Gaussianos</a> de Keyon Vafa, e do tutorial <a href="http://katbailey.github.io/post/gaussian-processes-for-dummies/">Gaussian Processes for Dummies</a>, de Katherine Bailey.</p>
<p>Caso queria se aprofundar mais no assunto, sugiro que comece com o artigo de M. Ebden, <a href="https://www.robots.ox.ac.uk/~mebden/reports/GPtutorial.pdf">Gaussian Processes for Regression: A Quick Introduction</a>. Por fim, recomendo o livro de Kevin P. Murphy, <a href="https://mitpress.mit.edu/books/machine-learning-0">Machine Learning: A Probabilistic Perspective</a></p>
<p>Como de costume, o código deste tutorial está disponível no <a href="https://github.com/matheusfacure/Tutoriais-de-AM/tree/master/Gaussian%20Process">meu GitHub</a>.</p>
Bancos de dados - Onde vivem, O que comem e Como se reproduzem2018-03-15T00:00:00+00:00http://lamfo-unb.github.io/2018/03/15/banco-de-dados<h1 id="bancos-de-dados---onde-vivem-o-que-comem-e-como-se-reproduzem">Bancos de dados - Onde vivem, O que comem e Como se reproduzem</h1>
<p>Esse post tem a intenção de fazer uma introdução no conceito de banco de dados estruturados e dos diferentes modelos de armazenamento de dados.</p>
<p><img src="/img/banco_de_dados/relacionados.png" alt="Inter-relacionados" /></p>
<p>Mas o que são bancos de dados? Bancos de dados nada mais são do que um conjunto de dados inter-relacionados, agrupados em coleções organizadas de forma que faça sentido; ou seja, são dados agrupados e organizados de forma que se possa extrair informações deles.</p>
<p><img src="/img/banco_de_dados/sgbds.jpg" alt="SGBDs" /></p>
<p>Mas se apenas isso constitui um banco de dados, o que são os bancos vendidos por grandes empresas como Oracle, Microsoft dentre outras? O que essas empresas vendem não são apenas arquivos TXT com os dados, mas sim programas que são conhecidos como SGBDs (Sistema de Gerenciamento de Banco de Dados) que tem como finalidade introduzir formas diferentes de tratamento e armazenamento dos dados visando aumentar a velocidade das consultas e das manipulações dos dados, garantir a consistência dos dados armazenados, bem como implementar modelos de armazenamento diferentes que podem se adequar melhor a algumas situações.</p>
<p>Modelos de armazenamento? Como assim “modelos de armazenamento”? Imagine o seguinte cenário, você tem uma tabela do departamento de RH de uma empresa, e a tabela descreve todos os usuários com seus dados e a hierarquia da empresa, até o momento não temos problemas. Então um dia uma diretora da empresa entra em contato com o RH para avisar que ela se casou e resolve acrescentar o sobrenome do seu marido. Como temos uma tabela para conter todos os dados então teríamos que alterar todos os funcionários abaixo dela na hierarquia para constar o seu novo nome, e se algum usuário ficasse com a atualização por fazer não conseguiríamos mais vinculá-lo a diretora que mudou o nome. Com cenários como esse percebemos que precisamos de modelos diferentes de armazenamento, modelos que definitivamente não são mais simples, mas que conseguem expor o conceito da relação dos dados de uma forma mais fácil de ser mapeada.</p>
<p>Modelos de armazenamento:</p>
<p><img src="/img/banco_de_dados/Flat_File_Model.svg.png" alt="Flat" /></p>
<ul>
<li><strong>Modelo plano (Flat File Model):</strong> consiste de uma matriz bidimensional, ou seja, é o famoso “tabelão” onde todos os dados estão em um lugar.</li>
</ul>
<p><img src="/img/banco_de_dados/Relational_Model.png" alt="Relacional" /></p>
<ul>
<li><strong>Modelo relacional (Relational Model):</strong> é o modelo atualmente mais utilizado, no modelo relacional nos dividimos os dados em diversas tabelas e criamos vínculos entre os dados.</li>
</ul>
<p><img src="/img/banco_de_dados/Hierarchical_Model.svg.png" alt="Hierárquico" /></p>
<ul>
<li><strong>Modelo hierárquico (Hierarchical Model):</strong> modelo que conecta as informações por meio de uma estrutura de dados em árvore, limitando o tipo de vínculo entre as informações a uma relação 1:n, ou seja, um registro está relacionado a n registros. Para contextualizar melhor, imagine a hierarquia convencional de uma empresa, o gerente tem muitos funcionários abaixo dele, porém os funcionários abaixo dele só tem um gerente.</li>
</ul>
<p><img src="/img/banco_de_dados/Network_Model.svg.png" alt="Rede" /></p>
<ul>
<li><strong>Modelo em rede (Network Model):</strong> semelhante ao modelo hierárquico, com a diferença que os registros “filhos” pode ser ligado a mais de um registro “pai”.</li>
</ul>
<p><img src="/img/banco_de_dados/Object-Oriented_Model.svg.png" alt="O-Objeto" /></p>
<ul>
<li><strong>Modelo orientado a objeto (Object-Oriented Model):</strong> modelo em que as informações são armazenadas na forma de objetos, visam facilitar a manipulação e comunicação com a aplicação.</li>
</ul>
<p>A forma que os SGBDs utilizam para facilitar a implantação de modelos de dados diferentes é através das constraints, que são limitações de dados, além disso elas também servem para garantir a integridade dos dados. Imagine que você tem banco de dados contendo os dados de clientes e alguém, visando corromper o seu sistema, faça um cadastro utilizando um CPF pertencente a outro cliente, nesse caso as constraints, mais especificamente uma chave única iria garantir que o segundo cadastro não fosse concluído. Mas essa não é a única função delas, elas são também responsáveis, por exemplo, pela garantia de que dados inter-relacionados sejam interdependentes. Isso tudo poderia ser facilmente substituído por regras no código da aplicação, ou por bloqueios manuais se essa fosse a única vantagem da sua utilização, porém a forma que as constraints são feitas otimizam as consultas que as utilizam.</p>
<p>Por exemplo, quando você define o CPF como uma chave única, o SGBD cria uma tabela separada com apenas os CPF e uma referência a qual linha do banco ele pertence em ordem crescente pelo CPF, essa tabela não é visível ao usuário, mas com esse ambiente configurado, todas as consultas e operações que filtrarem pelo CPF vão utilizar essa tabela para fazer a consulta, por ser menor e estar ordenada as consultas serão bem mais rápidas. Usando a mesma ideia é possível criar índices para qualquer campo de uma tabela e até para múltiplos campos ao mesmo tempo, com isso qualquer consulta pode ser otimizada, porém ao fazer isso as inserções na tabela ficaram mais demoradas, pois toda vez que um novo registro for criado todas as tabelas de índice terão que ser atualizadas para manter a ordem.</p>
<p>Quando falamos de banco de dados também é importante falar sobre SQL (Structured Query Language, ou Linguagem de Consulta Estruturada), que é o conjunto de instruções para interação com os dados do modelo relacional, e como o modelo relacional é o mais utilizado, a linguagem SQL acabou que se tornando sinônimo de linguagem de banco de dados.</p>
<p>Dentro do conjunto de comandos que é conhecido como SQL temos algumas subdivisões de comandos que especificam o tipo de requisição que está sendo feita ao banco, são essas subdivisões:</p>
<ul>
<li>
<p><strong>DML (Data Manipulation Language - Linguagem de manipulação de dados):</strong> Comandos responsáveis pela inserção, atualização e limpeza dos dados.</p>
</li>
<li>
<p><strong>DDL (Data Definition Language - Linguagem de Definição de Dados):</strong> Comandos responsáveis pela criação e manutenção das estruturas do banco de dados, como tabelas, índices e views.</p>
</li>
<li>
<p><strong>DCL (Data Control Language - Linguagem de Controle de Dados):</strong> Comandos responsáveis pela manutenção de acessos do banco de dados.</p>
</li>
<li>
<p><strong>DTL (Data Transaction Language - Linguagem de transação de Dados):</strong> Comandos responsáveis pela execução de outros comandos de forma segura, ou seja, comandos DTL criam uma área na memória para que os comandos executados dentro dessa área não tenham efeito até que se tenha certeza que a consulta deve ser executada.</p>
</li>
<li>
<p><strong>DQL (Data Query Language - Linguagem de Consulta de Dados):</strong> Comando responsável pela leitura dos dados do banco.</p>
</li>
</ul>
<p>Resumindo, bancos de dados não são apenas programas feitos para o armazenamento e manipulação de dados, mas sim qualquer forma em que os dados sejam armazenados de maneira que se possa extrair informações coerentes deles. Seus diferentes modelos podem se adequar a diversas situações. Os SGBDs são programas para facilitar modelagens, agilizar consultas e dar mais segurança aos dados, otimizando o uso da informação pelas organizações.</p>
SVM aplicado ao Marketing2017-10-27T00:00:00+00:00http://lamfo-unb.github.io/2017/10/27/svm-aplicado-marketing<h1 id="svm-em-marketing">SVM em Marketing</h1>
<p>A grande maioria das decisões que precisam ser tomadas na área de marketing necessitam de modelos preditivos. Para se obter resultados que sejam úteis para a organização, é preciso que o problema a ser resolvido seja definido da forma mais precisa possível. Dessa forma, Cui e Curry (2005) classificam as previsões em quatro contextos:</p>
<p><strong>1. Previsão Pura:</strong> ocorre em casos onde o conhecimento estrutural do problema não é viável ou necessário, o objetivo é apenas resolver um problema e tomar uma decisão, não entender a sua dinâmica;
<strong>2. Previsão Robusta:</strong> neste contexto, a previsão continua um fator importante, mas não é o único objetivo, também há uma busca por compreender um panorama geral do problema, como tendências, ;
<strong>3. Previsão Analítica:</strong> neste tipo de previsão, os modelos são construídos ou adaptados para solucionar um problema específico de forma mais analítica, ou seja, o objetivo é mais compreender a estrutura do problema, mas ainda assim há acurácia nas previsões;
<strong>4. Previsão e Análise de <em>Gaps</em> Estruturais:</strong> neste contexto, os modelos de previsão buscam aumentar o conhecimento estrutural do processo, assim, de certa forma, o lucro é secundário em relação ao entendimento do problema.</p>
<p>Assim, pode-se dizer que há uma espécie de <em>tradeoff</em> entre a precisão da previsão e a capacidade de explicar o problema. Todavia, isso não quer dizer que uma boa previsão não seja também útil para compreender um problema.</p>
<p>Considerando-se esses tipos de previsão e com o desenvolvimento das áreas de marketing das organizações, as análises e modelos preditivos serão cada vez mais necessários para a tomada de decisão. Neste ponto, as <a href="https://lamfo-unb.github.io/2017/07/13/svm/">máquinas de suporte vetorial</a> geram ótimas previsões. Técnicas desse tipo aliadas à evolução da capacidade computacional e às facilidades atuais de acesso a informação geram cada vez mais dados. Dessa forma, os consumidores se tornam cada vez mais exigentes e específicos e, com isso, os clientes estão cada vez mais segmentados.</p>
<p>Assim, para atender a essas necessidades dos consumidores, os gestores precisam estar mais atentos ao planejamento e às estratégias de marketing para adequá-las aos interesses dos consumidores e também para atingir os mais diversos perfis de consumo. Para este fim, uma opção baseada no SVM é o <a href="https://lamfo-unb.github.io/2017/10/05/Introducao_basica_a_clusterizacao/">Support Vector Clustering (SVC)</a>, que pode ser usado para a segmentação de mercado. Por exemplo, é possível segmentar os clientes de um <em>e-commerce</em> de acordo com a cesta de consumo e características pessoais de cada um, como idade, estado civil, grau de instrução etc.</p>
<p><img src="/img/marketing1/analytics.jpg" height="350" width="500" /></p>
<p>O marketing direto é um ramo em que busca-se obter vendas de pessoas que já possuem certo interesse pela empresa, como por exemplo cupons de desconto para clientes. Assim, faz-se necessário conhecer o perfil da base de consumidores. Para isso, Shin e Cho (2006) construíram um modelo usando SVM com o objetivo de prever a possibilidade de resposta dos consumidores a uma promoção de produto ou serviço.</p>
<p>A precisão do modelo é pautada na quantidade de consumidores que responderão de forma positiva à promoção do produto ou serviço, quanto maior o número de casos positivos, maior a precisão do modelo.</p>
<p>Dessa forma, o SVM buscar por classificar os consumidores entre respondentes e não-respondentes. Embora a metodologia do SVM seja muito útil e ofereça ótimos resultados, esse método também possui algumas complicações na aplicação quando há uma grande quantidade de dados. Há também casos com classes desbalanceadas, que são ocasiões em que há uma desproporção muito grande entre os dados para cada tipo de consumidor ou perfil, por exemplo o número de compradores gerados de um e-mail marketing vai ser muito pequeno em relação ao total que foi enviado a milhares de pessoas.</p>
<p>Outro ponto relevante do SVM, é que diferentemente de outros métodos de aprendizado de máquina, ele fornece um valor binário, isto é -1 ou 1. Para solucionar esta dificuldade e descobrir a propensão de compra do consumidor, é possível estimar a probabilidade com base na distância entre o padrão dos dados e o limite de decisão (o valor que determina se aquele dado pertence a uma classe ou não), ou seja, o padrão que está mais distante do limite de decisão possui maior probabilidade de pertencer à classe representada, e assim é possível estimar as probabilidades de compra dos clientes.</p>
<p><img src="/img/marketing1/svm.png" alt="" class="center-image" /></p>
<p>Ainda no Marketing Direto, é possível explorar o SVM em conjunto com <a href="https://pt.wikipedia.org/wiki/Sistema_especialista">sistemas especialistas</a> - sistemas que buscam executar funções humanas em decisões - para fornecer recomendações de produtos personalizados para cada cliente utilizando os dados das preferências dos próprios consumidores. Atualmente, isso é bastante utilizado por <em>e-commerces</em> como a Amazon. Para avaliar as preferências dos consumidores e dar sugestões de consumos, dois métodos possíveis são o <em>Content-Based System</em> e o <em>Collaborative System</em>.</p>
<p>No <em>Content-Based System</em>, as recomendações são feitas com base nas características do produto e no perfil do consumidor. A avaliação das características é feita com base na descrição do produto e relacionada com o consumo passado do cliente. Isto é, busca-se oferecer sugestões similares ao que o consumidor já adquiriu ou se interessou.</p>
<p>Já o <em>Collaborative System</em> faz recomendações por meio da combinação de preferências de clientes semelhantes. Por exemplo, os clientes A e B compraram uma bola de futebol. Em seguida, o cliente A comprou uma chuteira, assim, assume-se que eles têm preferências semelhantes para outros tipos de produtos e recomenda-se uma chuteira para o cliente B.</p>
<p>Dessa forma, a abordagem em problemas cotidianos de marketing em empresas pode ser melhorada com o uso de aprendizado de máquina e, mais especificamente, o SVM. Em um post futuro, abordaremos um exemplo prático desse tipo de problema.</p>
<p>Referências:</p>
<p>CUI, Dapeng; CURRY, David. Prediction in marketing using the support vector machine. Marketing Science, v. 24, n. 4, p. 595-615, 2005.</p>
<p>SHIN, HyunJung; CHO, Sungzoon. Response modeling with support vector machines. Expert Systems with applications, v. 30, n. 4, p. 746-760, 2006.</p>
Incerteza em Modelos de Deep Learning2017-10-22T14:15:07+00:00http://lamfo-unb.github.io/2017/10/22/Monte-Carlo-Dropout<h2 id="conteúdo">Conteúdo</h2>
<ol>
<li><a href="#intro">Introdução</a></li>
<li><a href="#incerteza">Por que Incerteza é Importante</a></li>
<li><a href="#mc-dropout">Monte-Carlo Dropout: um olhar Bayesiano para <em>Deep Learning</em></a></li>
<li><a href="#obtendo-incerteza">Obtendo Incerteza</a></li>
<li><a href="#regressao">Incerteza em Regressão</a></li>
<li><a href="#classificacao">Incerteza em Classificação</a></li>
<li><a href="#takeaways">Resumindo os Pontos Importantes</a></li>
<li><a href="#ref">Referências</a></li>
</ol>
<p><a name="intro"></a></p>
<h2 id="introdução">Introdução</h2>
<p>Acredito que muitos cientistas de dados (eu inclusive) já cometeram o pecado de negligenciar o rigor dos métodos estatísticos, supondo que validação cruzada seria suficiente para qualquer problema. Isso pode ser verdade em situações simuladas e dados de laboratório, mas a vida real é bem mais complexa. A dinâmica da realidade faz com que as distribuições geradoras de dados estejam sempre mudando. O resultado disso é que os dados que usamos durante o treinamento raramente coincidem perfeitamente com os dados onde o modelo deve fazer suas previsões; há quase sempre um ponto cego, uma nova região multidimensional na qual nosso modelo fica simplesmente perdido. Para piorar, a maioria dos modelos de aprendizado de máquina sequer tem um mecanismo para nos dizer quando algo está errado com suas previsões.</p>
<p>Recentemente, decidi dar um passo atrás e encarar os meus modelos sob uma perspectiva mais crítica. Como saber se meu modelo está aprendendo algo estatisticamente razoável? Quão confiável é o meu modelo? Mais importante ainda, como saber se meu modelo não vai quebrar diante de algo muito diferente de tudo que ele já viu? E como proceder diante dessas situações inusitadas? Este post fala principalmente sobre incerteza e sobre como injetá-la em modelos de redes neurais. Trata-se de um tópico ainda bastante obscuro, mesmo para a comunidade de aprendizado de máquina, mas que acredito que deveria ser encarado com mais atenção.</p>
<p>O que tentarei fazer aqui será lhe convencer de que não basta obter a melhor capacidade preditiva; também é preciso construir modelos que saibam nos dizer o nível de confiança de suas previsões. Em seguida, mostrarei uma técnica extremamente simples para obter incerteza em modelos de <em>Deep Learning</em>. Reconheço que este post trata de um conteúdo um pouco mais avançado, mas tentarei torná-lo o mais intuitivo possível. No entanto, ainda precisarei pressupor, por parte do leitor, conhecimento sobre o básico de <a href="https://matheusfacure.github.io/2017/03/05/ann-intro/">redes neurais</a>, <a href="https://lamfo-unb.github.io/2017/08/04/Uma-visao-amigavel-do-Teorema-de-Bayes/">Teorema de Bayes</a> e <a href="https://lamfo-unb.github.io/2017/04/29/Um-Olhar-Descontraido-Sobre-o-Dilema-Vies-Variancia/">conceitos de regularização</a>.</p>
<p><a name="incerteza"></a></p>
<h2 id="por-que-incerteza-é-importante">Por que Incerteza é Importante</h2>
<p>Digamos que eu treine um modelo de aprendizado de máquina para distinguir entre imagens de cães e gatos. Se eu então pedir que esse modelo classifique a imagem de um cocker spaniel, ele deve me dizer, com grande confiança, que há um cachorro naquela foto. Mas e se eu lhe pedir para classificar um homem? Bom, ele será forçado a prever um cão ou um gato, mas seria bom se também me dissesse que não está nada certo sobre essa previsão.</p>
<p>Troque o exemplo infantil acima por algo mais arriscado, como um carro autônomo, um modelo para diagnóstico de câncer ou um modelo que dá empréstimos automaticamente. Nesses exemplos, o custo de um erro pode ser altíssimo. Aqui, quando diante de um caso estanho, muito melhor seria se, em vez de decidir automaticamente, o modelo nos desse algum sinal sobre sua incerteza, de forma que possamos reagir de acordo, talvez passado a decisão para um humano ou especialista.</p>
<p>Em casos de previsão sobre o futuro, como por exemplo no mercado financeiro, a incerteza também exerce um papel fundamental nas decisões. Um modelo pode prever que uma ação vai subir 20% em 3 meses, mas antes de simplesmente comprá-la é importante saber quão certo o modelo está sobre essa previsão, o que é normalmente representado por um intervalo de confiança. Eu provavelmente tomarei decisões diferentes se meu modelo me disser que a ação vai subir 20%, mas pode ser que ela suba 15% ou 25% (baixa incerteza), ou se ele me disser que ela vai subir 20%, mas pode ser que ela suba 50% ou caia 25% (alta incerteza).</p>
<figure class="figure center-block thumbnail" style="width: 60%;">
<img src="/img/BayesianNN/co2_MC_dropout_relu.jpg" class="img-responsive center-block" alt="" />
<figcaption class="figure-caption text-center">Retirada do <a href="http://www.cs.ox.ac.uk/people/yarin.gal/website/blog_3d801aa532c1ce.html">post de Yarin Gal</a></figcaption>
</figure>
<p>Saber a incerteza do modelo também permite algo que chamamos de <strong>Aprendizagem Ativa</strong>, onde o próprio modelo nos diz quais dados devemos nomear para retreiná-lo de maneira mais eficiente. Como exemplo, se eu tenho um modelo que atua com seguro de carro e que está muito incerto sobre quanto cobrar de idosos que dirigem sedãs, talvez seja uma boa eu incluir na minha base de treinamento mais exemplos de idosos que dirigem sedãs.</p>
<p>Colocando em termos mais gerais, <strong>tão importante quanto saber é saber o que se sabe</strong>, isto é, conhecer os limites do próprio conhecimento. É este tipo de meta conhecimento que estamos tentando dar aos nossos modelos quando falamos de muni-los com incerteza. Idealmente, queremos que os sistemas de inteligência que construirmos consigam também reconhecer, por si próprios, as fronteiras de seu conhecimento e responder de acordo com o seu nível de ignorância.</p>
<p><a name="mc-dropout"></a></p>
<h2 id="monte-carlo-dropout-um-olhar-bayesiano-para-deep-learning">Monte-Carlo Dropout: um olhar Bayesiano para <em>Deep Learning</em></h2>
<p>Em 2015, <a href="http://www.cs.ox.ac.uk/people/yarin.gal/website/">Yarin Gal</a> mostrou que é possível obter incerteza a partir de redes neurais quase que gratuitamente, se olhássemos técnicas de regularização estocásticas, como <em>Dropout</em>, sob uma perspectiva Bayesiana. <a href="http://jmlr.org/papers/v15/srivastava14a.html"><em>Dropout</em></a> (Srivastava et al, 2014) é uma técnica utilizada na maioria das redes neurais modernas para prevenir sobre-ajustamento. Durante o treinamento, <em>Dropout</em> funciona zerando aleatoriamente uma percentagens de neurônios nas camadas da rede neural. No momento de fazer previsões, todos os neurônios são mantidos e a rede neural atua como uma grande mistura de sub-redes menores.</p>
<p><img class="img-responsive center-block thumbnail" src="/img/BayesianNN/dropout.jpeg" style="width: 60%;" alt="dropout" /></p>
<p>Quando <em>Dropout</em> foi lançado como técnica de regularização, ninguém sabia muito porque ele funcionava tão bem. Em 2015, Gal mostrou que <em>Dropout</em> essencialmente performa otimização Bayesiana na rede neural, marginalizando a incerteza do modelo. A seguir tentarei resumir um pouco dessa teoria. <strong>Cuidado! Matemática a frente!</strong> Se você não é muito fã de justificativas matemáticas, sugiro que pule para a <a href="#obtendo-incerteza">próxima parte do post</a>. Se fizer isso, você ainda verá como utilizar a técnica, mesmo sem saber porque ela funciona ou como justificá-la.</p>
<p>Sob a perspectiva Bayesiana, os parâmetros \(\pmb{W}\) do modelo são vistos como variáveis aleatórias. Podemos então definir uma distribuição de probabilidade \(P(\pmb{W})\) a priori para esses parâmetros. Sendo a verossimilhança \(P(\pmb{Y}|\pmb{W},\pmb{X})\), pelo Teorema de Bayes temos que a distribuição dos parâmetros dado o que foi observado nos dados é</p>
\[P(\pmb{W}|\pmb{X}, \pmb{Y}) = \frac{P(\pmb{Y}|\pmb{W}, \pmb{X})P(\pmb{W})}{P(\pmb{Y}|\pmb{X})}\]
<p>Note que, desta forma, uma <strong>previsão é definida como uma distribuição</strong> e a <strong>incerteza pode ser entendida como a dispersão desta distribuição</strong>.</p>
\[P(y_{test}|\pmb{x}_{test}, \pmb{X}, \pmb{Y}) = \int P(y_{test}|\pmb{x}_{test}, \pmb{W}) P(\pmb{W|\pmb{X}, \pmb{Y}}) d\pmb{W}\]
<p>O problema é que a distribuição a posteriori \(P(\pmb{W}|\pmb{X}, \pmb{Y})\) é praticamente impossível de computar. Isso porque estimar o componente normalizador (também chamado de evidência do modelo) \(P(\pmb{Y}|\pmb{X})\) envolve computar uma integral que não pode estimada eficientemente.</p>
\[P(\pmb{W}|\pmb{X}, \pmb{Y}) = \int P(\pmb{Y}|\pmb{X}, \pmb{W})P(\pmb{W})d\pmb{W}\]
<p>Para lidar com esse problema, definimos uma nova probabilidade mais simples \(q_\theta(\pmb{W})\), parametrizada por \(\theta\), e minimizamos a divergência de Kullback-Leibler entre \(q_\theta(\pmb{W})\) e \(P(\pmb{W}|\pmb{X}, \pmb{Y})\). Isso é equivalente a maximização do limite inferior da evidência (ELBO)</p>
\[\mathcal{L}(\theta) = -\int q_\theta(\pmb{W}) \log P(\pmb{Y}|\pmb{X}, \pmb{W})d\pmb{W} - KL(q_\theta(\pmb{W})\|P(\pmb{W}))\]
<p>Para facilitar, nós aproximamos o primeiro termo acima com integração de Monte-Carlo, retirando amostras \(\hat{\pmb{W}} \sim q_\theta(\pmb{W}) \)</p>
\[\mathcal{\hat{L}}(\theta) = - \log P(\pmb{Y}|\pmb{X}, \pmb{\hat{W}}) - KL(q_\theta(\pmb{W})\|P(\pmb{W}))\]
<p>Normalmente, definimos nossa probabilidade a priori como uma gaussiana centrada em zero \(P(\pmb{W}) \sim \mathcal{N}(0, \sigma)\), o que faz com que o segundo termo aja como um regularizador, mantendo os parâmetros pequenos. Mas e \(q_\theta(\cdot)\)? Uma forma de defini-la é por meio de uma distribuição Bernoulli, onde retiramos um vetor \(\pmb{z} \sim \mathcal{B(\theta)}\) com o mesmo número de elementos que colunas em \(\pmb{W}\). Então podemos definir uma amostra \(\pmb{\hat{W}}\) como a multiplicação de cada elemento de \(\pmb{z}\) por uma coluna de uma matriz de parâmetros \(\pmb{M}\), com as mesmas dimensões de \(\pmb{W}\). Em outras palavras, a nós estamos <strong>zerando algumas colunas de</strong> \(\pmb{M}\) para obter \(\pmb{\hat{W}}\). Isso soa familiar???</p>
<p>Toda a matemática acima é bastante complexa, mas se olharmos com calma podemos resumi-la em um algoritmo de otimização com dois passos bastante simples:</p>
<ol>
<li>Aleatoriamente, zere colunas de \(\pmb{M}\) para obter \(\pmb{\hat{W}}\).</li>
<li>Minimize por uma iteração \(- \log P(\pmb{Y}|\pmb{X}, \pmb{\hat{W}}) - KL(q_\theta(\pmb{W})||P(\pmb{W}))\)</li>
</ol>
<p>Caso você ainda não tenha percebido, isso é exatamente o que fazemos quando treinamos uma rede neural com <em>Dropout</em> e regularização \(L_2\). Alias, olhe novamente para o passo 2 e repare que o primeiro termo é a tradicional função custo que otimizamos com gradiente descendente e o segundo termo é análogo a regularização \(L_2\). Isso significa que <strong>qualquer rede neural treinada com <em>Dropout</em> é um modelo Bayesiano</strong>! Isso também explica porque <em>Dropout</em> costuma ser tão efetivo no treinamento de redes neurais: <strong>essa técnica equivale a integrar os parâmetros do modelo</strong>.</p>
<p><a name="obtendo-incerteza"></a></p>
<h2 id="obtendo-incerteza">Obtendo Incerteza</h2>
<p>Agora que temos um fundamento teórico sólido para seguir, resta ver como obter incerteza a partir de redes neurais treinadas com <em>Dropout</em> (e regularização \(L_2\)). Durante o treinamento do modelo, nada muda; mas, <strong>durante o teste mantemos a probabilidade de <em>Dropout</em> fixada durante o treino e realizamos \(T\) <em>forward-pass</em> pela rede, coletando assim \(T\) previsões \(\hat{y}\) para cada amostra</strong>. Assim para cada ponto teremos uma previsão para a média e uma previsão para a variância, que será nossa medida de incerteza.</p>
\[\mathbb{E}(\hat{y}) \approx \frac{1}{T} \sum_{t=1}^T \hat{y_t}\]
\[\begin{align*}
\mathbb{E} (\hat{y}) &\approx \frac{1}{T} \sum_{t=1}^T \hat{y}_t \\
Var ( \hat{y} ) &\approx \tau^{-1} \\
&\quad+ \frac{1}{T} \sum_{t=1}^T \hat{\hat{y}_t}^T \hat{y}_t \\
&\quad- \mathbb{E} (\hat{y})^T \mathbb{E} (\hat{y})
\end{align*}\]
<p>Onde \(\tau = \frac{l^2 p}{2 N \lambda}\) é uma medida de precisão, \(p\) é a probabilidade de <em>Dropout</em>, \(\lambda\) é a força da regularização \(L_2\), \(l\) define a nossa crença a priori da escala de \(\pmb{W}\) e \(N\) é a quantidade de dados. Note que \(\tau\) é negligenciável quando há muitos dados, isto é, quando \(N \rightarrow \infty\). Em Python, isso se traduz para umas poucas linhas de código</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">l</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">tau</span> <span class="o">=</span> <span class="n">l</span><span class="o">**</span><span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">p_dropout</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">X_train</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">lbd</span><span class="p">)</span>
<span class="n">y_hat_mean</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">y_hat</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">y_hat_variance</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">var</span><span class="p">(</span><span class="n">y_hat</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">y_hat_variance</span> <span class="o">+=</span> <span class="n">tau</span><span class="o">**-</span><span class="mi">1</span></code></pre></figure>
<p><a name="regressao"></a></p>
<h2 id="incerteza-em-regressão">Incerteza em Regressão</h2>
<p>Vamos ver como a técnica apresentada acima lida com um problema de regressão. A seguir, vamos tentar prever a quantidade de bicicletas alugadas na hora seguinte, dada as quantidades de bicicletas alugadas nas últimas 10 horas. Para maior conveniência, coloquei o código todo <a href="https://github.com/matheusfacure/Tutoriais-de-AM/blob/master/Redes%20Neurais%20Artificiais/Bayesian-NN/BNN-Regression.ipynb">aqui</a> e focarei apenas nas parte mais interessantes para não estender demais este post.</p>
<p>Vamos usar o pacote <a href="https://keras.io/">Keras</a> com TensorFlow para construir e rodar a rede neural do nosso experimento. Nossa rede neural terá apenas 2 camadas ocultas, cada uma com 100 neurônios. Utilizaremos uma camada de <em>Dropout</em> após cada camada oculta, zerando 50% das unidades. Também colocaremos uma camada de <em>Dropout</em> logo no começo da rede, mas como temos poucas variáveis, a probabilidade de zerar as unidade aqui será apenas 5%.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">from</span> <span class="nn">keras</span> <span class="kn">import</span> <span class="n">backend</span> <span class="k">as</span> <span class="n">K</span>
<span class="kn">from</span> <span class="nn">keras.models</span> <span class="kn">import</span> <span class="n">Sequential</span>
<span class="kn">from</span> <span class="nn">keras.layers</span> <span class="kn">import</span> <span class="n">Dense</span><span class="p">,</span> <span class="n">Dropout</span>
<span class="kn">from</span> <span class="nn">keras.optimizers</span> <span class="kn">import</span> <span class="n">Adam</span>
<span class="kn">from</span> <span class="nn">keras.regularizers</span> <span class="kn">import</span> <span class="n">l2</span>
<span class="n">n_input</span> <span class="o">=</span> <span class="n">X</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># n de variáveis
</span><span class="n">num_out</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># n de previsões
</span>
<span class="n">p_dropout</span> <span class="o">=</span> <span class="mf">0.5</span> <span class="c1"># probabilidade de Dropout
</span><span class="n">lbd</span> <span class="o">=</span> <span class="mf">1e-4</span> <span class="c1"># força da regularização L2
</span>
<span class="n">model</span> <span class="o">=</span> <span class="n">Sequential</span><span class="p">()</span>
<span class="n">model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dropout</span><span class="p">(.</span><span class="mi">05</span><span class="p">,</span> <span class="n">input_shape</span><span class="o">=</span><span class="p">(</span><span class="n">n_input</span><span class="p">,)))</span>
<span class="n">model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dense</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">input_shape</span><span class="o">=</span><span class="p">(</span><span class="n">n_input</span><span class="p">,),</span> <span class="n">kernel_regularizer</span><span class="o">=</span><span class="n">l2</span><span class="p">(</span><span class="n">lbd</span><span class="p">)))</span>
<span class="n">model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dropout</span><span class="p">(</span><span class="n">p_dropout</span><span class="p">))</span>
<span class="n">model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dense</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="s">'relu'</span><span class="p">,</span> <span class="n">kernel_regularizer</span><span class="o">=</span><span class="n">l2</span><span class="p">(</span><span class="n">lbd</span><span class="p">)))</span>
<span class="n">model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dropout</span><span class="p">(</span><span class="n">p_dropout</span><span class="p">))</span>
<span class="n">model</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">Dense</span><span class="p">(</span><span class="n">num_out</span><span class="p">,</span> <span class="n">activation</span><span class="o">=</span><span class="bp">None</span><span class="p">))</span>
<span class="n">model</span><span class="p">.</span><span class="n">summary</span><span class="p">()</span>
<span class="n">opt</span> <span class="o">=</span> <span class="n">Adam</span><span class="p">(</span><span class="n">lr</span><span class="o">=</span><span class="mf">1e-3</span><span class="p">)</span>
<span class="n">model</span><span class="p">.</span><span class="nb">compile</span><span class="p">(</span><span class="n">loss</span><span class="o">=</span><span class="s">'mean_squared_error'</span><span class="p">,</span><span class="n">optimizer</span><span class="o">=</span><span class="n">opt</span><span class="p">)</span></code></pre></figure>
<p>Definido nosso modelo, podemos treiná-lo. Cada mini-lote terá \(\frac{1}{5}\) das amostras e assim treinaremos por 3000 épocas ou 15000 iterações.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">epochs</span> <span class="o">=</span> <span class="mi">3000</span>
<span class="n">model</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">X_train</span><span class="p">,</span> <span class="n">y_train</span><span class="p">,</span>
<span class="n">batch_size</span><span class="o">=</span><span class="n">X_train</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">//</span> <span class="mi">5</span><span class="p">,</span>
<span class="n">epochs</span><span class="o">=</span><span class="n">epochs</span><span class="p">,</span>
<span class="n">verbose</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span></code></pre></figure>
<p>Após o treinamento, a performance do nosso modelo no set de treino é \(R^2=0.73\) e no set de teste, \(R^2=0.77\).</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="kn">from</span> <span class="nn">sklearn</span> <span class="kn">import</span> <span class="n">metrics</span>
<span class="n">y_hat_train</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_train</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">metrics</span><span class="p">.</span><span class="n">r2_score</span><span class="p">(</span><span class="n">y_train</span><span class="p">,</span> <span class="n">y_hat_train</span><span class="p">))</span>
<span class="n">y_hat_test</span> <span class="o">=</span> <span class="n">model</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">X_test</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">metrics</span><span class="p">.</span><span class="n">r2_score</span><span class="p">(</span><span class="n">y_test</span><span class="p">,</span> <span class="n">y_hat_test</span><span class="p">))</span></code></pre></figure>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.729823
0.775525
</code></pre></div></div>
<p>Acima, a previsão é feita da forma tradicional, isto é, colocando a probabilidade de <em>Dropout</em> em 0%, usando assim toda a capacidade da rede. Esse é o padrão do Keras e precisaremos rescrevê-lo para implementar Monte-Carlo <em>Dropout</em>, no qual mantemos as probabilidades de <em>Dropout</em> de treino também durante as previsões. Abaixo, vamos definir uma função que retornará a última camada da rede, (as previsões) dada a camada de entrada (as variáveis). Além disso, vamos definir que está função será usada tal como durante o treinamento, passando <code class="language-plaintext highlighter-rouge">K.learning_phase()</code>.</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">T</span> <span class="o">=</span> <span class="mi">1000</span>
<span class="n">predict_stochastic</span> <span class="o">=</span> <span class="n">K</span><span class="p">.</span><span class="n">function</span><span class="p">([</span><span class="n">model</span><span class="p">.</span><span class="n">layers</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nb">input</span><span class="p">,</span> <span class="n">K</span><span class="p">.</span><span class="n">learning_phase</span><span class="p">()],</span> <span class="p">[</span><span class="n">model</span><span class="p">.</span><span class="n">layers</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">].</span><span class="n">output</span><span class="p">])</span>
<span class="n">y_hat_mc</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">array</span><span class="p">([</span><span class="n">predict_stochastic</span><span class="p">([</span><span class="n">X_test</span><span class="p">,</span> <span class="mi">1</span><span class="p">])</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="n">T</span><span class="p">)])</span>
<span class="n">y_hat_mc</span> <span class="o">=</span> <span class="n">y_hat_mc</span><span class="p">.</span><span class="n">reshape</span><span class="p">(</span><span class="o">-</span><span class="mi">1</span><span class="p">,</span><span class="n">y_test</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]).</span><span class="n">T</span>
<span class="n">y_hat_mc</span><span class="p">.</span><span class="n">shape</span></code></pre></figure>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(500, 1000)
</code></pre></div></div>
<p>Como podemos ver, agora temos 1000 previsões para cada ponto no set de teste. Podemos então obter a média e a variância dessas previsões</p>
<figure class="highlight"><pre><code class="language-python" data-lang="python"><span class="n">l</span> <span class="o">=</span> <span class="mi">10</span>
<span class="n">y_hat_test_mean</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">mean</span><span class="p">(</span><span class="n">y_hat_mc</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">y_hat_test_variance</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">var</span><span class="p">(</span><span class="n">y_hat_mc</span><span class="p">,</span> <span class="n">axis</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="n">tau</span> <span class="o">=</span> <span class="n">l</span><span class="o">**</span><span class="mi">2</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">p_dropout</span><span class="p">)</span> <span class="o">/</span> <span class="p">(</span><span class="mi">2</span> <span class="o">*</span> <span class="n">X_train</span><span class="p">.</span><span class="n">shape</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">*</span> <span class="n">lbd</span><span class="p">)</span>
<span class="n">y_hat_test_variance</span> <span class="o">+=</span> <span class="n">tau</span><span class="o">**-</span><span class="mi">1</span>
<span class="n">metrics</span><span class="p">.</span><span class="n">r2_score</span><span class="p">(</span><span class="n">y_test</span><span class="p">,</span> <span class="n">y_hat_test_mean</span><span class="p">)</span></code></pre></figure>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.91519
</code></pre></div></div>
<p>Note como a performance de teste melhorou com esse procedimento. Mais ainda, agora temos uma métrica de incerteza para cada ponto e podemos ver onde o modelo não sabe bem o que está acontecendo. Também podemos plotar as previsões contra os valores observados e colocar um intervalo de confiança em torno das previsões. Abaixo, mostramos as últimas 200 horas do set de teste. Em torno da linha de previsões, colocamos 4 tons de roxo, cada tom denotando meio desvio padrão.</p>
<p><img class="img-responsive center-block thumbnail" src="/img/BayesianNN/rnn_demanda_test.png" alt="incerteza-demanda" /></p>
<p><a name="classificacao"></a></p>
<h2 id="incerteza-em-classificação">Incerteza em Classificação</h2>
<p>Em problemas de classificação estamos tentando estimar a probabilidade de uma amostra \(\pmb{x}\) pertencer às classes \(\pmb{y}\). Um erro que muitos praticantes cometem é supor que a probabilidade de pertencer a classe \(c\), \(P(y = y_c)\), produzida pelo modelo é equivalente a sua confiança. O que devemos lembrar é que, assim como modelos de regressão prevem o valor esperado de uma amostra, condicionado nos seus covariantes \(\pmb{x}\), modelos de classificação prevem uma probabilidade esperada mas, normalmente, nada nos dizem sobre quão dispersa é essa estimativa.</p>
<p>Para melhor entender a diferença entre incerteza a probabilidade prevista, vamos usar parte da base MNIST, da qual vamos filtrar os números 3, 4 e 5. Vamos treinar uma rede neural para distinguir os 5s dos 3s. Será portanto, um problema de classificação binária, onde, nesse caso, 3 será a classe 1 e 5 será a classe 0. Depois disso, mostraremos ao modelo os 4s, nos quais ele não foi treinado. O código muda muito pouco do exemplo de regressão acima, por isso vou omiti-lo. Caso queira conferi-lo, todo esse experimento <a href="https://github.com/matheusfacure/Tutoriais-de-AM/blob/master/Redes%20Neurais%20Artificiais/Bayesian-NN/BNN-MNIST.ipynb">está disponível no meu GitHub</a>.</p>
<p>A rede neural utilizada aqui foi de duas camadas densamente conectadas, cada uma com 512 neurônios e camadas <em>Dropout</em> após as camadas ocultas e de entrada. A probabilidade de <em>Dropout</em> em todas as camadas foi de 50%. Após treinada, realizamos 1000 <em>forward-passes</em> pela rede para obter as estimativas de Monte-Carlo <em>Dropout</em>. A probabilidade média dessas 1000 estimativas será nossa previsão final e o desvio padrão será nossa métrica de incerteza.</p>
<p>A incerteza média do modelo, computada nos 5s e 3s de teste, é de 0.05. Podemos também plotar \(P(y=3)\) conta o desvio padrão dessa probabilidade. Isso deixará claro que incerteza e probabilidade prevista, embora relacionadas <strong>não são a mesma coisa</strong>.</p>
<p><img class="img-responsive center-block thumbnail" src="/img/BayesianNN/incerteza_prob1.png" alt="incerteza-vc-prop1" /></p>
<p>No gráfico acima, note como há pontos que o modelo prevê como sendo um 3 com 80% de chance, mas, para essa mesma probabilidade prevista, existem amostras com incertezas variando de 0.2 até 0.27 (pontos azuis). A variação na incerteza é ainda maior nas probabilidades previstas muito baixas ou altas. Note como há muitos pontos cuja probabilidade prevista é maior que 95% (ou menor que 5%) e como a incerteza nesses pontos varia de 0 até 0.1. Por fim, vale ressaltar que, embora diferentes, <strong>probabilidade prevista é incerteza estão relacionadas</strong>. Se não fosse o caso, não haveria nenhuma tendência no gráfico acima. O que podemos ver é que a incerteza tende a aumentar perto da fronteira de decisão, isto é, perto dos lugares onde a probabilidade prevista é 50%.</p>
<p>Acima, só analisamos a incerteza do modelo nas imagens de dígitos que ele viu durante o treinamento (3 e 5), mas o que aconteceria se lhe mostrássemos imagens com dígitos 4? Sabemos que ele terá que prever para essas imagens a probabilidade delas ser um 3, afinal é para isso que ele foi treinado, mas queremos que ele faça isso ao mesmo tempo que nos diz estar bastante incerto sobre essas previsões. Isso de fato acontece!</p>
<p>A incerteza média do modelo, quando computada nos 4s, é de 0.28, que é bem maior do que a média de 0.05 obtida no set de teste de 5s e 3s. Além disso, quando plotamos a probabilidade prevista contra o desvio padrão dessas probabilidades, podemos ver que a maioria dos pontos está mais para a direita, reforçando a incerteza geral do modelos ao tentar prever os 4s.</p>
<p><img class="img-responsive center-block thumbnail" src="/img/BayesianNN/incerteza_prob2.png" alt="incerteza-vc-prop2" /></p>
<p>Outro aspecto interessante de Monte-Carlo <em>Dropout</em> é que podemos estudar as incertezas particulares a cada amostra. Por exemplo, abaixo pegamos uma amostra qualquer dos dados de teste (5s e 3s) e plotamos o histograma das probabilidades previstas. Note como na maioria das estimativas de Monte-Carlo <em>Dropout</em> o modelo dá a essa imagem uma probabilidade de 1, indicando que há uma alta chance dela ser um 3. Nesse exemplo particular, o desvio padrão é 0.12.</p>
<p><img class="img-responsive center-block thumbnail" src="/img/BayesianNN/hist1.png" alt="hist1" /></p>
<p>Podemos também ver o que acontece quando mostramos um 4 ao modelo. Note como, desta vez, as probabilidades previstas estão muito mais dispersas. O modelo acha que isso é um 5, já que a maioria das probabilidades previstas são menores que 0.5. Ao mesmo tempo, ele não está nem um pouco certo dessa previsão. Nesse caso particular, o desvio padrão das previsões é de 0.45.</p>
<p><img class="img-responsive center-block thumbnail" src="/img/BayesianNN/hist2.png" alt="hist2" /></p>
<p><a name="takeaways"></a></p>
<h2 id="resumindo-os-pontos-importantes">Resumindo os Pontos Importantes</h2>
<p>Métricas incerteza podem ser extremamente úteis no processo de tomada de decisão. Por exemplo, é possível estabelecer um limite máximo de incerteza que se está disposto a tolerar. Além disso, com informações sobre incerteza por amostra podemos definir quando é necessário ir atrás de mais informações antes de tomar uma decisão. Também podemos utilizar incerteza para realizar aprendizagem ativa, na qual o modelo nos diz quais dados devem ser nomeados e colocados no set de treino.</p>
<p>Além de saber o que o modelo prevê para uma amostra, <strong>Monte-Carlo <em>Dropout</em> nos permite saber qual a certeza que o modelo tem</strong> sobre essa previsão. Em aplicações de regressão, isso nos permite traçar um intervalo de confiança em torno do valor previsto. Nos casos de classificação, vimos que <strong>incerteza e probabilidade prevista são diferentes</strong>, embora relacionadas. A primeira deve ser entendida como uma média de centralidade das previsões enquanto a segunda nos mostra como é a dispersão das probabilidades em torno desta previsão.</p>
<p><a name="ref"></a></p>
<h2 id="referências">Referências</h2>
<p>Este post é baseado no trabalho de Yarin Gal sobre incerteza em modelos de <em>Deep Learning</em>. Para este post, usei informações de sua tese de doutorado, <a href="http://www.cs.ox.ac.uk/people/yarin.gal/website/thesis/thesis.pdf">Uncertainty in Deep Learning</a> (Gal, 2015), seu artigo <a href="https://arxiv.org/abs/1506.02142">Dropout as a Bayesian Approximation: Representing Model Uncertainty in Deep Learning</a> (Gal & Ghahramani, 2015) e um post fantástico do seu blog, <a href="http://www.cs.ox.ac.uk/people/yarin.gal/website/blog_3d801aa532c1ce.html">What my deep model doesn’t know…</a>.</p>
<p>Se você está interessado em saber mais sobre abordagens Bayesianas para <em>Deep Learning</em>, o curso <a href="https://www.coursera.org/learn/bayesian-methods-in-machine-learning">Bayesian Methods for Machine Learning</a> acabou se ser lançado no Coursera. Além disso, no NIPS de 2016 houve um <a href="https://www.youtube.com/channel/UC_LBLWLfKk5rMKDOHoO7vPQ">workshop dedicado exclusivamente a Deep Learning Bayesiano</a>. Por fim, sugiro que de uma olhada na biblioteca de programação <a href="http://edwardlib.org/">Edward</a>. Ela é construída em cima do TensorFlow e conta com a maioria dos modelos Bayesianos usados atualmente.</p>
<p>O código utilizado neste post pode ser integralmente conferido no <a href="https://github.com/matheusfacure/Tutoriais-de-AM/tree/master/Redes%20Neurais%20Artificiais/Bayesian-NN">meu GitHub</a>.</p>
Introdução Básica à Clusterização2017-10-05T17:10:00+00:00http://lamfo-unb.github.io/2017/10/05/Introducao_basica_a_clusterizacao<h1 id="introdução-básica-à-clusterização">Introdução básica à Clusterização</h1>
<h2 id="o-que-é-clusterização">O que é Clusterização?</h2>
<p>Clusterização é o agrupamento automático de instâncias similares, uma <strong>classificação não-supervisionada</strong> dos dados (<a href="https://lamfo-unb.github.io/2017/07/27/tres-tipos-am/" title="Os Três Tipos de Aprendizado de Máquina">esse termo não é familiar? Veja nosso post sobre os três tipos de aprendizado de máquina!</a>). Ou seja, um algoritmo que clusteriza dados classifica eles em conjuntos de dados que ‘se assemelham’ de alguma forma - independentemente de classes predefinidas. <strong>Os grupos gerados por essa classificação são chamados <em>clusters</em></strong>.</p>
<p>Uma forma de clusterização seria, por exemplo, a partir de dados de animais em um zoológico aproximar animais por suas características. Ou seja, a partir dos dados como ‘quantidade de pernas’, ‘quantidade de dentes’, ‘põe ovo’, ‘tem pêlos’ e vários outros, procuramos animais que estão mais próximos. Poderíamos assim clusterizar os dados, separar animais em mamíferos, aves ou répteis mas sem “contar” ao algoritmo sobre estas classificações. Apenas comparando a distância entre dados o algoritmo mostraria que um tigre está “mais próximo” de um leão do que de uma garça.</p>
<p>As imagens a seguir ilustram uma clusterização bem simples de dados com apenas duas dimensões (duas “características”):</p>
<table>
<thead>
<tr>
<th style="text-align: center">Dados</th>
<th style="text-align: center">Dados agrupados em clusters</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><img src="/img/clustering/01-clustering.png" alt="" /></td>
<td style="text-align: center"><img src="/img/clustering/02-clustering.png" alt="" /></td>
</tr>
</tbody>
</table>
<p>Muitas vezes, a similaridade entre os dados é encontrada por métricas de distância. Um dos algoritmos mais básicos para Clusterização chama-se <strong>K-Means</strong>.</p>
<h2 id="k-means">K-Means</h2>
<p>O algoritmo se chama assim pois <strong>encontra k <em>clusters</em> diferentes</strong> no conjunto de dados. O <strong>centro de cada <em>cluster</em> será chamado centróide</strong> e terá a média dos valores neste cluster.</p>
<p>A tarefa do algoritmo é encontrar o centróide mais próximo (por meio de alguma métrica de distância) e atribuir o ponto encontrado a esse cluster. Após este passo, os centróides são atualizados sempre tomando o valor médio de todos os pontos naquele cluster. Para este método são necessários valores numéricos para o cálculo da distância, os valores nominais então podem ser mapeados em valores binários para o mesmo cálculo. Em caso de sucesso, os <strong>dados são separados organicamente</strong> podendo assim ser rotulados e <strong>centróides viram referência</strong> para classificar novos dados.</p>
<p>Para o exemplo utilizaremos o <a href="https://archive.ics.uci.edu/ml/datasets/iris"><em>Iris Data Set</em></a> do <em>UCI Machine Learning Repository</em>. Este é um dos conjuntos de dados mais conhecidos e utilizados para exemplos simples de reconhecimento de padrões. O conjunto de dados contém 3 classes de 50 instâncias cada, onde cada classe se refere a um tipo de planta Iris.</p>
<h3 id="passo-a-passo-do-algoritmo">Passo a passo do algoritmo</h3>
<p>O Κ-means aprimora de forma iterativa seus resultados até alcançar um resultado final. O algoritmo recebe o número de clusters Κ e o conjunto de dados a ser analisado. Em seguida são estabelecidas posições iniciais para os K centróides, que podem ser gerados ou selecionados aleatoriamente dentro do conjunto de dados.</p>
<p>O algoritmo é iterado nos seguintes passos até que se estabilize:</p>
<ul>
<li>
<p><strong>Associação de cada instância a um centróide</strong> - cada centróide define um cluster, então cada instância será associada a seu cluster mais semelhante (centróide mais próximo). A distância será calculada por alguma métrica de distância, em geral utiliza-se a distância euclidiana entre as duas instâncias;</p>
</li>
<li>
<p><strong>Atualização dos centróides</strong> - centróides dos clusters são recalculados, a partir da média entre todas as instâncias associadas àquele cluster.</p>
</li>
</ul>
<h3 id="na-prática-com-python">Na prática com Python</h3>
<p>Para que possamos testar o algoritmo utilizaremos a <strong>linguagem Python</strong> e algumas de suas bibliotecas</p>
<ul>
<li>Se você ainda não tem Python em sua máquina, dê uma olhada no nosso post <a href="https://lamfo-unb.github.io/2017/06/10/Instalando-Python/">Instalando Python para Aprendizado de Máquina</a>;</li>
<li>Crie um diretório de trabalho em sua máquina, uma pasta que conterá seu programa e os dados utilizados. Decidi chamar meu diretório de <em>‘learn-clustering’</em>;</li>
<li>Faça download do <a href="http://archive.ics.uci.edu/ml/machine-learning-databases/iris/"><em>iris.data</em></a> no seu novo diretório;</li>
<li>Crie um novo arquivo python onde escreveremos nosso programa no mesmo diretório principal ou um Jupyter Notebook. Os trechos de código a seguir devem ser codificados dentro do arquivo criado.</li>
</ul>
<h4 id="1-importando-as-pacotes">1. Importando as pacotes</h4>
<p>Usaremos:</p>
<ol>
<li>NumPy (pacote básico para computação científica e matemática, com diversas funções e operações sofisticadas)</li>
<li>Pandas (pacote para manipulação e estruturação de dados)</li>
<li>Matplotlib (pacote para plotagens gráficas em 2D)</li>
<li>sklearn (pacote de Machine Learning contendo a ferramento do algoritmo KMeans pronta)</li>
</ol>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span> <span class="c1"># 1
</span><span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span> <span class="c1"># 2
</span><span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span> <span class="c1"># 3
</span><span class="kn">from</span> <span class="nn">sklearn.cluster</span> <span class="kn">import</span> <span class="n">KMeans</span> <span class="c1"># 4
</span></code></pre></div></div>
<h4 id="2-lendo-o-dataset">2. Lendo o Dataset</h4>
<p>A leitura dos dados é feita a partir da biblioteca Pandas e os dados estão organizados no formato csv (<em>comma-separated values</em>) apesar da extensão <em>‘.data’</em>. Chamaremos o dataset completo de <em>dataset</em>. Os atributos têm seus nomes indicados nos dados, utilizaremos o <em>array ‘headers’</em> para nomeá-las de acordo com a <a href="https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.names">documentação do conjunto de dados</a>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">headers</span> <span class="o">=</span> <span class="p">[</span><span class="s">'sepal length'</span><span class="p">,</span> <span class="s">'sepal width'</span><span class="p">,</span> <span class="s">'petal length'</span><span class="p">,</span> <span class="s">'petal width'</span><span class="p">,</span> <span class="s">'class'</span><span class="p">]</span>
<span class="n">dataset</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">read_csv</span><span class="p">(</span><span class="s">"./iris.data"</span><span class="p">,</span> <span class="n">encoding</span> <span class="o">=</span> <span class="s">"ISO-8859-1"</span><span class="p">,</span> <span class="n">decimal</span><span class="o">=</span><span class="s">","</span><span class="p">,</span> <span class="n">header</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">names</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
</code></pre></div></div>
<p>A variável <em>‘dataset’</em> recebe os dados lidos, <em>‘header=None’</em> indica que os dados no têm cabeçalho e <em>‘names=headers’</em> faz com que os cabeçalhos deste dataset sejam os definidos na variável <em>‘headers’</em></p>
<p>Trecho do Dataset:</p>
<table>
<thead>
<tr>
<th style="text-align: center">sepal length</th>
<th style="text-align: center">sepal width</th>
<th style="text-align: center">petal length</th>
<th style="text-align: center">petal width</th>
<th style="text-align: center">class</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">5.1</td>
<td style="text-align: center">3.5</td>
<td style="text-align: center">1.4</td>
<td style="text-align: center">0.2</td>
<td style="text-align: center">Iris-setosa</td>
</tr>
<tr>
<td style="text-align: center">4.9</td>
<td style="text-align: center">3.0</td>
<td style="text-align: center">1.4</td>
<td style="text-align: center">0.2</td>
<td style="text-align: center">Iris-setosa</td>
</tr>
<tr>
<td style="text-align: center">4.7</td>
<td style="text-align: center">3.2</td>
<td style="text-align: center">1.3</td>
<td style="text-align: center">0.2</td>
<td style="text-align: center">Iris-setosa</td>
</tr>
<tr>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
</tr>
<tr>
<td style="text-align: center">7.0</td>
<td style="text-align: center">3.2</td>
<td style="text-align: center">4.7</td>
<td style="text-align: center">1.4</td>
<td style="text-align: center">Iris-versicolor</td>
</tr>
<tr>
<td style="text-align: center">6.4</td>
<td style="text-align: center">3.2</td>
<td style="text-align: center">4.5</td>
<td style="text-align: center">1.5</td>
<td style="text-align: center">Iris-versicolor</td>
</tr>
<tr>
<td style="text-align: center">6.9</td>
<td style="text-align: center">3.1</td>
<td style="text-align: center">4.9</td>
<td style="text-align: center">1.5</td>
<td style="text-align: center">Iris-versicolor</td>
</tr>
<tr>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
</tr>
<tr>
<td style="text-align: center">6.3</td>
<td style="text-align: center">3.3</td>
<td style="text-align: center">6.0</td>
<td style="text-align: center">2.5</td>
<td style="text-align: center">Iris-virginica</td>
</tr>
<tr>
<td style="text-align: center">5.8</td>
<td style="text-align: center">2.7</td>
<td style="text-align: center">5.1</td>
<td style="text-align: center">1.9</td>
<td style="text-align: center">Iris-virginica</td>
</tr>
<tr>
<td style="text-align: center">7.1</td>
<td style="text-align: center">3.0</td>
<td style="text-align: center">5.9</td>
<td style="text-align: center">2.1</td>
<td style="text-align: center">Iris-virginica</td>
</tr>
</tbody>
</table>
<p>Podemos perceber que cada coluna é referente uma característica daquele espécime de planta. Ou seja, cada caso específico de flor produz uma instância diferente, que têm dados próprios.</p>
<h4 id="3-pré-processando-os-dados">3. Pré-processando os dados</h4>
<p>Para garantirmos dados numéricos, vamos garantir que as colunas sejam do tipo float:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">dataset</span><span class="p">.</span><span class="n">columns</span><span class="p">[</span><span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">]:</span>
<span class="n">dataset</span><span class="p">[</span><span class="n">col</span><span class="p">]</span> <span class="o">=</span> <span class="n">dataset</span><span class="p">[</span><span class="n">col</span><span class="p">].</span><span class="n">astype</span><span class="p">(</span><span class="nb">float</span><span class="p">)</span>
</code></pre></div></div>
<p>Podemos confirmar os tipos de cada coluna do dataset com o ‘dtypes’</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dataset</span><span class="p">.</span><span class="n">dtypes</span>
<span class="n">sepal</span> <span class="n">length</span> <span class="n">float64</span>
<span class="n">sepal</span> <span class="n">width</span> <span class="n">float64</span>
<span class="n">petal</span> <span class="n">length</span> <span class="n">float64</span>
<span class="n">petal</span> <span class="n">width</span> <span class="n">float64</span>
<span class="k">class</span> <span class="nc">object</span>
<span class="n">dtype</span><span class="p">:</span> <span class="nb">object</span>
</code></pre></div></div>
<p>Agora deve ser realizada a divisão dos dados entre variáveis dependentes ( X ) e independente ( y ). Uma definição de variáveis dependentes e independentes pode ser encontrada no nosso post <a href="https://lamfo-unb.github.io/2017/07/27/tres-tipos-am/">Os Três Tipos de Aprendizado de Máquina</a></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">X</span> <span class="o">=</span> <span class="n">dataset</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,</span> <span class="mi">0</span><span class="p">:</span><span class="mi">4</span><span class="p">]</span>
<span class="n">y</span> <span class="o">=</span> <span class="n">dataset</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,</span> <span class="mi">4</span><span class="p">]</span>
</code></pre></div></div>
<p>Agora vamos aplicar o kmeans no conjunto de variáveis dependentes - ou seja, não estamos ‘contando’ ao algoritmo quais são as classes de cada instância de flor, estamos apenas apresentando os dados que cada instância tem. Definimos o número de clusters - k - como 3, uma situação ideal. Existem técnicas para encontrar o melhor k que serão abordadadas em um próximo post.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">kmeans</span> <span class="o">=</span> <span class="n">KMeans</span><span class="p">(</span><span class="n">n_clusters</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">0</span><span class="p">).</span><span class="n">fit</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
<span class="n">X_clustered</span> <span class="o">=</span> <span class="n">kmeans</span><span class="p">.</span><span class="n">fit_predict</span><span class="p">(</span><span class="n">X</span><span class="p">)</span>
</code></pre></div></div>
<p>Existem várias formas de checar a clusterização realizada, uma bem simples é criando uma tabela de resultados contendo a coluna das classes esperadas e a coluna dos clusters criados:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">results</span> <span class="o">=</span> <span class="n">dataset</span><span class="p">[[</span><span class="s">'class'</span><span class="p">]].</span><span class="n">copy</span><span class="p">()</span>
<span class="n">results</span><span class="p">[</span><span class="s">'clusterNumber'</span><span class="p">]</span> <span class="o">=</span> <span class="n">X_clustered</span>
<span class="n">results</span>
</code></pre></div></div>
<p>Tabela <em>‘results’</em></p>
<table>
<thead>
<tr>
<th style="text-align: center">class</th>
<th style="text-align: center">clusterNumber</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center">Iris-setosa</td>
<td style="text-align: center">0</td>
</tr>
<tr>
<td style="text-align: center">Iris-setosa</td>
<td style="text-align: center">0</td>
</tr>
<tr>
<td style="text-align: center">Iris-setosa</td>
<td style="text-align: center">0</td>
</tr>
<tr>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
</tr>
<tr>
<td style="text-align: center">Iris-versicolor</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: center">Iris-versicolor</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: center">Iris-versicolor</td>
<td style="text-align: center">1</td>
</tr>
<tr>
<td style="text-align: center">…</td>
<td style="text-align: center">…</td>
</tr>
<tr>
<td style="text-align: center">Iris-virginica</td>
<td style="text-align: center">2</td>
</tr>
<tr>
<td style="text-align: center">Iris-virginica</td>
<td style="text-align: center">2</td>
</tr>
<tr>
<td style="text-align: center">Iris-virginica</td>
<td style="text-align: center">2</td>
</tr>
</tbody>
</table>
<p>Neste pequeno dataset é simples visualizar que atingimos a clusterização esperada. Podemos agora testar uma abordagem mais gráfica. Primeiramente vamos definir cores para os diferentes tipos de clusters e ‘pintar’ pontos em clusteres diferentes de cores diferentes:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">LABEL_COLOR_MAP</span> <span class="o">=</span> <span class="p">{</span><span class="mi">0</span> <span class="p">:</span> <span class="s">'red'</span><span class="p">,</span> <span class="mi">1</span> <span class="p">:</span> <span class="s">'blue'</span><span class="p">,</span> <span class="mi">2</span><span class="p">:</span> <span class="s">'green'</span><span class="p">}</span>
<span class="n">label_color</span> <span class="o">=</span> <span class="p">[</span><span class="n">LABEL_COLOR_MAP</span><span class="p">[</span><span class="n">l</span><span class="p">]</span> <span class="k">for</span> <span class="n">l</span> <span class="ow">in</span> <span class="n">X_clustered</span><span class="p">]</span>
</code></pre></div></div>
<p>Agora podemos plotar um gráfico que compare duas características em duas dimensões. A lógica a seguir é apenas para que possamos plotar dinamicamente mudando apenas os valores de <em>‘c1’</em> e <em>‘c2’</em> que serão características diferentes a serem comparadas e dispostas nos eixos do gráfico.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">c1</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># valor do índice da coluna, pode ser 0, 1 ou 2
</span><span class="n">c2</span> <span class="o">=</span> <span class="mi">1</span>
<span class="n">labels</span> <span class="o">=</span> <span class="p">[</span><span class="s">'sepal length'</span><span class="p">,</span> <span class="s">'sepal width'</span><span class="p">,</span> <span class="s">'petal length'</span><span class="p">]</span>
<span class="n">c1label</span> <span class="o">=</span> <span class="n">labels</span><span class="p">[</span><span class="n">c1</span><span class="p">]</span>
<span class="n">c2label</span> <span class="o">=</span> <span class="n">labels</span><span class="p">[</span><span class="n">c12</span><span class="p">]</span>
<span class="n">title</span> <span class="o">=</span> <span class="n">xlabel</span> <span class="o">+</span> <span class="s">' x '</span> <span class="o">+</span> <span class="n">ylabel</span>
</code></pre></div></div>
<p>Com as características escolhidas, plotamos o gráfico com Matplotlib:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">plt</span><span class="p">.</span><span class="n">figure</span><span class="p">(</span><span class="n">figsize</span> <span class="o">=</span> <span class="p">(</span><span class="mi">12</span><span class="p">,</span><span class="mi">12</span><span class="p">))</span>
<span class="n">plt</span><span class="p">.</span><span class="n">scatter</span><span class="p">(</span><span class="n">X</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,</span> <span class="n">c1</span><span class="p">],</span><span class="n">X</span><span class="p">.</span><span class="n">iloc</span><span class="p">[:,</span> <span class="n">c2</span><span class="p">],</span> <span class="n">c</span><span class="o">=</span><span class="n">label_color</span><span class="p">,</span> <span class="n">alpha</span><span class="o">=</span><span class="mf">0.3</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="n">c1label</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">18</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="n">c2label</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">18</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">suptitle</span><span class="p">(</span><span class="n">title</span><span class="p">,</span> <span class="n">fontsize</span><span class="o">=</span><span class="mi">20</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">savefig</span><span class="p">(</span><span class="n">title</span> <span class="o">+</span> <span class="s">'.jpg'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<table>
<thead>
<tr>
<th style="text-align: center">sepal length X sepal width</th>
<th style="text-align: center">sepal length X petal length</th>
<th style="text-align: center">sepal width X petal length</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align: center"><img src="/img/clustering/03-clustering.jpg" alt="" /></td>
<td style="text-align: center"><img src="/img/clustering/04-clustering.jpg" alt="" /></td>
<td style="text-align: center"><img src="/img/clustering/05-clustering.jpg" alt="" /></td>
</tr>
</tbody>
</table>
<p>E como podemos ter uma noção da qualidade dos nossos clusters encontrados? A forma mais simples de verificarmos a “qualidade” dos clusters encontrados é medindo os valores <strong>inter-clusters e intra-clusters</strong>.</p>
<ul>
<li>
<p>A distância <strong>inter-clusters</strong> (entre clusters) nos diz o quão distantes estão os clusters dos outros, ou seja, em geral é um bom sinal quando eles estão distantes entre si pois mostram maior isolamento dos grupos e provavelmente uma classificação mais precisa.</p>
</li>
<li>
<p>A distância <strong>intra-cluster</strong> (interna aos clusters) nos diz o quão distantes estão os elementos de um mesmo grupo e o quão distantes estão de seu centróide, ou seja, em geral grupos mais densos com elementos mais próximos têm maior similaridade e tem mais chance de realmente compartilharem a mesma classificação</p>
</li>
</ul>
<p>De uma forma bem simplista, podemos dizer que alcançamos clusters interessantes quando eles se isolam do resto e têm uma “alta densidade”, seus elementos são mais próximos. Naturalmente isto serve apenas para uma análise simples, existem várias técnicas mais avançadas de validação da clusterização que abordaremos em um post futuro.</p>
<p>Neste exemplo fica clara a divisão entre classes diferentes, assim podemos compreender como a clusterização funciona e que existem casos específicos em que a técnica será muito útil. Aplicações possíveis da clusterização incluem:</p>
<ul>
<li><strong>Marketing</strong>: Pesquisa e segmentação de mercado para determinar potenciais grupos homogêneos de consumidores para melhor definir a disposição de produtos que uma estratégia corporativa;</li>
<li><strong>Análise de redes sociais</strong>: Dentro de um grande grupo de pesoas, reconhecer comunidades que compartilhem de alguma preferência ou opinião;</li>
<li><strong>Reconhecimento de imagens</strong>: Clusterização pode ser aplicado para se reconhecer uma pessoa ou um objeto numa foto; os <em>clusters</em> seriam as regiões da imagem que contenham rostos, paisagem, vestimentas, etc.;</li>
<li><strong>Detecção de anomalias</strong>: A análise de clusters pode ser adaptada para a detecção de <em>outliers</em> que destoem da maioria dos outros elementos baseada em alguma métrica de similaridade;</li>
<li><strong>Finanças</strong>: clusterização pode ser utilizado para agrupar empresas por similaridade, o que pode ser bem útil para a construção de portfólios, cuja teoria clássica preconiza que o risco do investidor pode ser diversificado quando se aplica em empresas pouco correlacionadas. A clusterização ainda pode ser usada para a identificação de períodos de alta e baixa volatilidade, o que por sua vez pode subsidiar a construção de estratégias de <em>trading</em> e de gestão do risco.</li>
</ul>
<p>Nem todo resultado terão dados ideais como este conjunto e assim <strong>como qualquer algoritmo ele funcionará para uma finalidade específica</strong>. Por isso, como sempre, conhecer bem o problema, pré-processar os dados corretamente e aplicar técnicas diferentes certamente trarão resultados melhores.</p>
Classificadores Ensemble, tipos Bagging e Boosting2017-09-27T14:15:07+00:00http://lamfo-unb.github.io/2017/09/27/BaggingVsBoosting<h2 id="classificadores-ensemble">Classificadores <em>Ensemble</em></h2>
<p>Estudos recentes têm mostrado que métodos de classificadores <em>ensemble</em> possuem performance melhor do que técnicas de inteligência artificial sozinhas.</p>
<p>Mas você sabe o que é um classificador <em>ensemble</em>?
Um classificador <em>ensemble</em> (também chamado de comitê de <em>learners</em>, mistura de especialistas ou sistema de classificadores múltiplo), consiste em um conjunto de classificadores treinados individualmente, classificadores de base, cujas decisões são de alguma forma combinadas (Marques et al., 2012).</p>
<p>Nesse post apresentarei dois algoritmos <em>ensemble</em> tradicionais, o <em>Bagging</em> e o <em>Boosting</em>; e mais especificamente, o <em>AdaBoost</em>.</p>
<p><img src="https://i.imgur.com/88aeJst.jpg" alt="" /></p>
<h3 id="bagging">Bagging</h3>
<p>O <em>Bagging (Bootstrap Aggregating)</em>, um método proposto por Breiman em 1996, gera um conjunto de dados por amostragem <em>bootstrap</em> dos dados originais (Já falamos de <em>bootstrap</em> aqui: https://lamfo-unb.github.io/2017/06/28/Bootstrap/). O conjunto de dados gera um conjunto de modelos utilizando um algoritmo de aprendizagem simples por meio da combinação por votos para classificação. O seu uso é particularmente atraente quando a informação disponível é de tamanho limitado.</p>
<p>No <em>Bagging</em> os classificadores são treinados de forma independente por diferentes conjuntos de treinamento através do método de inicialização. Para construí-los é necessário montar <em>k</em> conjuntos de treinamento idênticos e replicar esses dados de treinamento de forma aleatória para construir <em>k</em> redes independentes por re-amostragem com reposição. Em seguida, deve-se agregar as <em>k</em> redes através de um método de combinação apropriada, tal como a maioria de votos (Breiman, 1996).</p>
<p>Para garantir que há amostras de treinamento suficientes em cada subconjunto, grandes porções de amostras (75-100%) são colocadas em cada subconjunto. Com isso, os subconjuntos individuais de formação se sobrepõem de forma significativa, com muitos casos fazendo parte da maioria dos subconjuntos e podendo até mesmo aparecer várias vezes num mesmo subconjunto. A fim de assegurar a diversidade de situações, um <em>learner</em> de base relativamente instável é usado para que limites de decisão diferentes possam ser obtidos, considerando-se pequenas perturbações em diferentes amostras de treinamento (Wang, 2011).</p>
<p>O resumo do pseudo código do <em>Bagging</em>, proposto por Breiman, é o seguinte:</p>
<table>
<thead>
<tr>
<th><em>Bagging</em></th>
</tr>
</thead>
<tbody>
<tr>
<td>Entrada: Dataset \(D=\{(z_1,y_1),(x_2y_2),...,(x_m,y_m)\}:\)</td>
</tr>
<tr>
<td>Número de rounds de aprendizagem \(T\).</td>
</tr>
<tr>
<td>Processo: Para \(t=1,2,...,T:\)</td>
</tr>
<tr>
<td>(a.) Forma conjuntos bootstrap de dados \(S_t\) selecionando \(m\) exemplos aleatórios do conjunto de treinamento com substituição e (b.) Deixa \(h_t\) ser o resultado da base de treinamento do algoritmo baseado em \(S_t\)</td>
</tr>
<tr>
<td>fim.</td>
</tr>
<tr>
<td>Saída: Classificador combinado: \(H(x)=maioria(h_{1}(x),...,h_{T}(x))\)</td>
</tr>
</tbody>
</table>
<h3 id="boosting-e-adaboost"><em>Boosting</em> e <em>AdaBoost</em></h3>
<p>No <em>Boosting</em>, de forma semelhante ao <em>Bagging</em>, cada classificador é treinado usando um conjunto de treinamento diferente. A abordagem por <em>Boosting</em> original foi proposta por Schapire em 1990. A principal diferença em relação ao <em>Bagging</em> é que os conjuntos de dados re-amostrados são construídos especificamente para gerar aprendizados complementares e a importância do voto é ponderado com base no desempenho de cada modelo, em vez da atribuição de mesmo peso para todos os votos.
Essencialmente, esse procedimento permite aumentar o desempenho de um limiar arbitrário simplesmente adicionando <em>learners</em> mais fracos. Dada a utilidade desse achado, <em>Boosting</em> é considerado uma das descobertas mais significativas em aprendizado de máquina (LANTZ, 2013).</p>
<p>Já o <strong>AdaBoost</strong>, “<em>Adaptive Boosting</em>”, é uma combinação das ideias de <em>Bagging</em> e <em>Boosting</em> e não exige um grande conjunto de treinamento como o <em>Boosting</em>. Inicialmente, cada exemplo de formação de um determinado conjunto de treinamento tem o mesmo peso.</p>
<p>Para treinar o \(k−esimo\) classificador como um “modelo de aprendizagem fraca”, $n$ conjuntos de amostras de treinamento (n <m) entre \(S\) são usadas para treinar o \(k−esimo\) classificador. Em seguida, o classificador treinado é avaliado por \(S\) para identificar os exemplos de treinamento que não foram classificados corretamente (TSAI, 2014). A rede \(k+1\) é então treinada por um conjunto treinado modificado que reforça a importância desses exemplos classificados incorretamente.</p>
<p>Este procedimento de amostragem será repetido até que $k$ amostras de treinamento sejam construídas para a construção da \(k−esima\) rede. Portanto, a decisão final baseia-se na votação ponderada dos classificadores individuais.
O pseudo código do <em>Adaboost</em>, segundo Wang (2011), é o seguinte:</p>
<table>
<thead>
<tr>
<th><em>Adaboost</em></th>
</tr>
</thead>
<tbody>
<tr>
<td>Entrada: Dataset \(D=\{(z_1,y_1),(x_2,y_2),...,(x_m,y_m)\}\);</td>
</tr>
<tr>
<td>Algoritmo de base de aprendizagem \(L\); Número de rounds de aprendizagem \(T\).</td>
</tr>
<tr>
<td>Processo: \(D_1(i) = 1/m.\) \% Inicializa a distribuição de pesos.</td>
</tr>
<tr>
<td>Para \(t=1,2,...,T\): \(h_1= L(D,D_t);\)</td>
</tr>
<tr>
<td>Treina a base de aprendizado \(h_t\) para D usando a distribuição \(D_t\)</td>
</tr>
<tr>
<td>\(\epsilon_i= Pr_{i \cong D_i} [h_t(x_i \neq y_i)];\)</td>
</tr>
<tr>
<td>Mede o erro de \(h_t\)</td>
</tr>
<tr>
<td>\(\alpha_t = \frac{1}{2}\ln \frac{1 - \epsilon_t}{\epsilon_t}\)</td>
</tr>
<tr>
<td>Determina o peso de \(h_t\)</td>
</tr>
<tr>
<td>\(D_{t+1}(i)=\frac{D_{t}(i)}{Z_t} \left\{\begin{array}{rll} exp({-\alpha_t}) & \hbox{se} & h_{t}(x_{i})= y_i exp({\alpha_t}) & \hbox{se} & h_{t}(x_{i}) \neq y_i \end{array}\right.\)</td>
</tr>
<tr>
<td>Atualiza a distribuição</td>
</tr>
<tr>
<td>\(=\frac{D_{t}(i)exp(-\alpha_{t}y_{i}h_{t}(x_{i}))}{Z_{t}}\) Fator de normalização que permite $D_{t+1}$ ser uma distribuição</td>
</tr>
<tr>
<td>fim.</td>
</tr>
<tr>
<td>Saída: \(H(x)=sign\left( \sum_{t=1}^{T}\alpha_{t}h_{t}(x)\right)\)</td>
</tr>
</tbody>
</table>
<p>O pacote ipred do <em>software</em> R, oferece uma aplicação clássica <em>Bagging</em> em <em>Decision Tree</em>. Para treinar o modelo é utilizada a função “bagging()”. No caso do <em>Adaboost</em>, pode ser utilizado o pacote C50.</p>
<p>Nesse post: https://lamfo-unb.github.io/2017/08/17/Modelos-Compostos/ você encontra uma aplicação com modelos regressivos compostos para estimativas de preço. É mostrado como uma combinação simples entre dois modelos podem impactar significantemente na sua predição.</p>
<p>Em um próximo post apresentaremos outros exemplos práticos de como utilizar esses classificadores <em>ensemble</em>.</p>
<h4 id="referências">Referências</h4>
<p>[Breiman(1996)] Breiman, L., 1996. Bagging Predictors. Machine Learning 24 (2), 123–140.</p>
<p>[Lantz(2013)] Lantz, B., 2013. Machine Learning with R. Packt Publishing Ltd.</p>
<p>[Marques et al.(2012)] Marques, A., Garcia, V., Sanchez, J., Sep 2012. Exploring the behaviour of base classifiers in credit scoring ensembles. Expert Systems with Applications 39 (11), 10244–10250.</p>
<p>[Schapire(1990)] Schapire, R. E., Jun 1990. http://dx.doi.org/10.1007/BF00116037 The strength
of weak learnability. Mach Learn 5 (2), 197–227.</p>
<p>[Tsai et al.(2014) Tsai, Hsu, and Yen] Tsai, C.-F., Hsu, Y.-F., Yen, D. C., Nov 2014. A comparative study of classifier ensembles for bankruptcy prediction. Applied Soft Computing 24, 977–984.</p>
<p>[Wang et al.(2011) Wang, Hao, Ma, and Jiang] Wang, G., Hao, J., Ma, J., Jiang, H., Jan 2011. A comparative assessment of ensemble learning for credit scoring. Expert Systems with Applications 38 (1), 223–230.</p>
Modelos Regressivos Compostos para Estimativas de Preço2017-08-17T10:00:00+00:00http://lamfo-unb.github.io/2017/08/17/Modelos-Compostos<h1 id="modelos-regressivos-compostos-para-estimativas-de-preço">Modelos Regressivos Compostos para Estimativas de Preço</h1>
<p>Determinar preços de determinados itens antes de sua entrada no mercado é essencial para boa aceitação e consumo. Disponibilizar um produto no mercado abaixo do preço de mercado não te gera bons retornos, mas também um valor muito alto não agrada aos compradores, modelos regressivos nesse caso são de grande ajuda para a tomada de decisão acerca da precificação de um insumo. A performance preditiva de modelos compostos comparados a modelos simples tem sido notável nas mais diversas áreas<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup>, modelos simples são aqueles que usam <a href="https://pt.wikipedia.org/wiki/Aprendizado_de_m%C3%A1quina#Abordagens">algoritmos puros do aprendizado de máquina</a>, já modelos compostos combinam as predições de dois ou mais algoritmos na tentativa de melhorar a predição. Nessa postagem buscarei apresentar formas eficientes de combinar modelos para minimizar o erro das predições de preços de metro quadrado de imóveis em Boston.</p>
<h3 id="preparando-os-dados">Preparando os Dados</h3>
<p>Aqui usarei um dataset famoso de preços de casa, mas a técnica aqui abordada pode ser estendida para precificação de quase qualquer coisa. Primeiro importarei e carregarei meu conjunto de dados na variável “boston” utilizando o Pandas, modulo do Python famoso por seus dataframes voltado a analise em finanças. O conjunto de dados advém do módulo Scikit-Learn que usaremos no decorrer desse post para trabalhar com AM, ele forneça ferramentas desde o tratamento dos dados até uma <em>pipeline</em> de aprendizado de máquina. Também usaremos o modulo Numpy.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">%</span><span class="n">matplotlib</span> <span class="n">inline</span>
<span class="kn">from</span> <span class="nn">sklearn.datasets</span> <span class="kn">import</span> <span class="n">load_boston</span>
<span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span>
<span class="kn">import</span> <span class="nn">pandas</span> <span class="k">as</span> <span class="n">pd</span>
<span class="n">boston</span> <span class="o">=</span> <span class="n">load_boston</span><span class="p">()</span>
<span class="n">df</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">(</span>
<span class="n">np</span><span class="p">.</span><span class="n">column_stack</span><span class="p">([</span><span class="n">boston</span><span class="p">.</span><span class="n">data</span><span class="p">,</span> <span class="n">boston</span><span class="p">.</span><span class="n">target</span><span class="p">]),</span>
<span class="n">columns</span><span class="o">=</span><span class="n">np</span><span class="p">.</span><span class="n">r_</span><span class="p">[</span><span class="n">boston</span><span class="p">.</span><span class="n">feature_names</span><span class="p">,</span> <span class="p">[</span><span class="s">'MEDV'</span><span class="p">]])</span>
<span class="n">df</span><span class="p">.</span><span class="n">head</span><span class="p">()</span>
</code></pre></div></div>
<div>
<style>
.dataframe thead tr:only-child th {
text-align: right;
}
.dataframe thead th {
text-align: left;
}
.dataframe tbody tr th {
vertical-align: top;
}
</style>
<table border="1" class="dataframe">
<thead>
<tr style="text-align: right;">
<th></th>
<th>CRIM</th>
<th>ZN</th>
<th>INDUS</th>
<th>CHAS</th>
<th>NOX</th>
<th>RM</th>
<th>AGE</th>
<th>DIS</th>
<th>RAD</th>
<th>TAX</th>
<th>PTRATIO</th>
<th>B</th>
<th>LSTAT</th>
<th>MEDV</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>0.00632</td>
<td>18.0</td>
<td>2.31</td>
<td>0.0</td>
<td>0.538</td>
<td>6.575</td>
<td>65.2</td>
<td>4.0900</td>
<td>1.0</td>
<td>296.0</td>
<td>15.3</td>
<td>396.90</td>
<td>4.98</td>
<td>24.0</td>
</tr>
<tr>
<th>1</th>
<td>0.02731</td>
<td>0.0</td>
<td>7.07</td>
<td>0.0</td>
<td>0.469</td>
<td>6.421</td>
<td>78.9</td>
<td>4.9671</td>
<td>2.0</td>
<td>242.0</td>
<td>17.8</td>
<td>396.90</td>
<td>9.14</td>
<td>21.6</td>
</tr>
<tr>
<th>2</th>
<td>0.02729</td>
<td>0.0</td>
<td>7.07</td>
<td>0.0</td>
<td>0.469</td>
<td>7.185</td>
<td>61.1</td>
<td>4.9671</td>
<td>2.0</td>
<td>242.0</td>
<td>17.8</td>
<td>392.83</td>
<td>4.03</td>
<td>34.7</td>
</tr>
<tr>
<th>3</th>
<td>0.03237</td>
<td>0.0</td>
<td>2.18</td>
<td>0.0</td>
<td>0.458</td>
<td>6.998</td>
<td>45.8</td>
<td>6.0622</td>
<td>3.0</td>
<td>222.0</td>
<td>18.7</td>
<td>394.63</td>
<td>2.94</td>
<td>33.4</td>
</tr>
<tr>
<th>4</th>
<td>0.06905</td>
<td>0.0</td>
<td>2.18</td>
<td>0.0</td>
<td>0.458</td>
<td>7.147</td>
<td>54.2</td>
<td>6.0622</td>
<td>3.0</td>
<td>222.0</td>
<td>18.7</td>
<td>396.90</td>
<td>5.33</td>
<td>36.2</td>
</tr>
</tbody>
</table>
</div>
<p>Aqui carrego meus dados na variável df e mostro as 5 primeiras linhas com o comando head.</p>
<p>Temos informações como criminalidade da região, idade média da população, etc..
Embora não seja o foco dessa postagem, a distribuição dos nossos dados poderá causar grande dificuldade para nosso regressor modela-la, sendo assim aplicarei uma “feature engineering” simples para tornar nossa distribuição mais normal, em posts futuros será explicado em detalhes o que é feature engineering e como utiliza-la para melhorar suas predições. Primeiro vamos ver como está a distribuição que queremos prever ao lado da distribuição “normalizada” por f.log(x+1), (acrescentar um ao valor nos evita ter problemas com zeros).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">seaborn</span> <span class="k">as</span> <span class="n">sns</span>
<span class="kn">import</span> <span class="nn">matplotlib.pyplot</span> <span class="k">as</span> <span class="n">plt</span>
<span class="n">sns</span><span class="p">.</span><span class="nb">set</span><span class="p">(</span><span class="n">style</span><span class="o">=</span><span class="s">"whitegrid"</span><span class="p">,</span> <span class="n">palette</span><span class="o">=</span><span class="s">"coolwarm"</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">df</span><span class="p">.</span><span class="n">plot</span><span class="p">.</span><span class="n">box</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span><span class="mi">6</span><span class="p">),</span> <span class="n">patch_artist</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><matplotlib.axes._subplots.AxesSubplot at 0x7f4ab6772cf8>
</code></pre></div></div>
<p><img src="/img/ensemble/output_6_1.png" alt="png" /></p>
<p>Primeiro carrego as bibliotecas de gráfico que utilizarei no decorrer do texto, defino configurações como estilo e paleta de cores para o gráfico, em seguida monto um dataframe <em>prices</em> para receber duas colunas de valores, uma com o preço sem transformação, outra com o preço tranformado pela função log1p (f.log(x+1)).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">prices</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">({</span><span class="s">"Preço"</span><span class="p">:</span><span class="n">df</span><span class="p">[</span><span class="s">"MEDV"</span><span class="p">],</span> <span class="s">"log(Preço + 1)"</span><span class="p">:</span><span class="n">np</span><span class="p">.</span><span class="n">log1p</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="s">"MEDV"</span><span class="p">])})</span>
<span class="n">prices</span><span class="p">.</span><span class="n">hist</span><span class="p">(</span><span class="n">color</span><span class="o">=</span><span class="s">"#F1684E"</span><span class="p">,</span> <span class="n">bins</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">"Quantidade"</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><matplotlib.text.Text at 0x7f4ab6535e10>
</code></pre></div></div>
<p><img src="/img/ensemble/output_8_1.png" alt="png" /></p>
<p>Podemos ver que nossa distribuição ficou menos espaçada e um pouco mais próxima de uma distribuição normal, mas o Python conta com uma função estatística que nos ajuda avaliar se isso será necessário ou não, através do teste de Box-Cox que terá indícios com o grau de Obliquidade (Skewness).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">scipy.stats</span> <span class="kn">import</span> <span class="n">skew</span>
<span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">df</span><span class="p">.</span><span class="n">keys</span><span class="p">():</span>
<span class="n">sk</span> <span class="o">=</span> <span class="n">skew</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="n">col</span><span class="p">])</span>
<span class="k">if</span> <span class="n">sk</span> <span class="o">></span> <span class="mf">0.75</span><span class="p">:</span>
<span class="k">print</span><span class="p">(</span><span class="n">col</span><span class="p">,</span> <span class="n">sk</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CRIM 5.222039072246122
ZN 2.219063057148425
CHAS 3.395799292642519
DIS 1.0087787565152246
RAD 1.0018334924536951
LSTAT 0.9037707431346133
MEDV 1.104810822864635
</code></pre></div></div>
<h4 id="um-pouco-de-feature-engeneering">Um Pouco de Feature Engeneering</h4>
<p>O teste de Box-Cox<sup id="fnref:5" role="doc-noteref"><a href="#fn:5" class="footnote" rel="footnote">2</a></sup> nos diz que um skew acima de 0.75 pode ser linearizado pela função log(x+1), fazendo a distribuição ficar mais normalizada, abaixo disso posso manter o valor como estava sem necessidades de modificação, vamos olhar o antes e depois de aplicar essa função a nossas distribuições. (Suprimi algumas variáveis para não poluir demais o gráfico).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dfnorm</span> <span class="o">=</span> <span class="p">(</span><span class="n">df</span> <span class="o">-</span> <span class="n">df</span><span class="p">.</span><span class="n">mean</span><span class="p">())</span> <span class="o">/</span> <span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">())</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"CRIM"</span><span class="p">,</span> <span class="s">"ZN"</span><span class="p">,</span> <span class="s">"CHAS"</span><span class="p">,</span><span class="s">"MEDV"</span><span class="p">]:</span>
<span class="n">sns</span><span class="p">.</span><span class="n">kdeplot</span><span class="p">(</span><span class="n">dfnorm</span><span class="p">[</span><span class="n">x</span><span class="p">])</span>
<span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">"Distribuição Valor Médio"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">"Preço"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">"Quantidade"</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><matplotlib.text.Text at 0x7f4ab63bfe80>
</code></pre></div></div>
<p><img src="/img/ensemble/output_12_1.png" alt="png" /></p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">for</span> <span class="n">col</span> <span class="ow">in</span> <span class="n">df</span><span class="p">.</span><span class="n">keys</span><span class="p">():</span>
<span class="n">sk</span> <span class="o">=</span> <span class="n">skew</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="n">col</span><span class="p">])</span>
<span class="k">if</span> <span class="n">sk</span> <span class="o">></span> <span class="mf">0.75</span><span class="p">:</span>
<span class="n">df</span><span class="p">[</span><span class="n">col</span><span class="p">]</span> <span class="o">=</span> <span class="n">np</span><span class="p">.</span><span class="n">log1p</span><span class="p">(</span><span class="n">df</span><span class="p">[</span><span class="n">col</span><span class="p">])</span>
</code></pre></div></div>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dfnorm</span> <span class="o">=</span> <span class="p">(</span><span class="n">df</span> <span class="o">-</span> <span class="n">df</span><span class="p">.</span><span class="n">mean</span><span class="p">())</span> <span class="o">/</span> <span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">())</span>
<span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="p">[</span><span class="s">"CRIM"</span><span class="p">,</span> <span class="s">"ZN"</span><span class="p">,</span> <span class="s">"CHAS"</span><span class="p">,</span><span class="s">"MEDV"</span><span class="p">]:</span>
<span class="n">sns</span><span class="p">.</span><span class="n">kdeplot</span><span class="p">(</span><span class="n">dfnorm</span><span class="p">[</span><span class="n">x</span><span class="p">])</span>
<span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="s">"Distribuição Valor Médio"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">xlabel</span><span class="p">(</span><span class="s">"Preço"</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">ylabel</span><span class="p">(</span><span class="s">"Quantidade"</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><matplotlib.text.Text at 0x7f4ab62d1240>
</code></pre></div></div>
<p><img src="/img/ensemble/output_14_1.png" alt="png" /></p>
<p>Vemos que as distribuições ficaram muito mais centradas e tendendo a distribuição gaussiana<sup id="fnref:2" role="doc-noteref"><a href="#fn:2" class="footnote" rel="footnote">3</a></sup>, o que será excelente para o ajuste dos nossos estimadores<sup id="fnref:3" role="doc-noteref"><a href="#fn:3" class="footnote" rel="footnote">4</a></sup>. Sendo a função logarítmica e a função f.x+1 bijetoras, poderemos retornar ao nosso valor original assim que acabarmos o ajuste do modelo.</p>
<h4 id="simplificando-nossos-dados">Simplificando nossos dados</h4>
<p>Nossos dados ainda podem estar muito complexos, a escala em que se encontram e talvez um excesso de informação necessária podem impossibilitar que nosso modelo atinja a perfeição. Aqui iremos aplicar duas técnicas, a primeira e escalonamento de variáveis pelo máximo-mínimo, transformação que também é reversível é poderá ser desfeita ao preço final, bastando eu guardar as variáveis da minha transformação.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">()</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CRIM 1.020192
ZN 1.620831
INDUS 6.860353
CHAS 0.176055
NOX 0.115878
RM 0.702617
AGE 28.148861
DIS 0.413390
RAD 0.751839
TAX 168.537116
PTRATIO 2.164946
B 91.294864
LSTAT 0.539033
MEDV 0.386966
dtype: float64
</code></pre></div></div>
<p>É visível que algumas variáveis estão extremamente dispersas, podemos mudar isso com a seguinte formula</p>
\[z_i=\frac{x_i-\min(x)}{\max(x)-\min(x)}\]
<p>Assim nossas variáveis estarão entre zero e um, ficando mais simplificada a predição.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dfmin</span><span class="p">,</span> <span class="n">dfmax</span> <span class="o">=</span> <span class="n">df</span><span class="p">.</span><span class="nb">min</span><span class="p">(),</span> <span class="n">df</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span>
<span class="n">df</span> <span class="o">=</span> <span class="p">(</span><span class="n">df</span> <span class="o">-</span> <span class="n">df</span><span class="p">.</span><span class="nb">min</span><span class="p">())</span><span class="o">/</span><span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="nb">max</span><span class="p">()</span><span class="o">-</span><span class="n">df</span><span class="p">.</span><span class="nb">min</span><span class="p">())</span>
<span class="n">df</span><span class="p">.</span><span class="n">std</span><span class="p">()</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>CRIM 0.227050
ZN 0.351200
INDUS 0.251479
CHAS 0.253994
NOX 0.238431
RM 0.134627
AGE 0.289896
DIS 0.227300
RAD 0.297672
TAX 0.321636
PTRATIO 0.230313
B 0.230205
LSTAT 0.202759
MEDV 0.180819
dtype: float64
</code></pre></div></div>
<p>Excelente!!</p>
<h4 id="tudo-pronto">Tudo Pronto</h4>
<p>Finalizado nosso ajuste nos dados após tanto trabalho vamos agora para o ajuste dos nossos modelos, acostume-se, tratar os dados é o que lhe consumirá mais tempo em um processo de aprendizado de máquina. Mas por fim vamos dar uma olhada final em como eles ficaram distribuídos. Usarei a função interna do Pandas, boxplot, se tem dúvida do que esse gráfico representa, veja <a href="https://pt.wikipedia.org/wiki/Diagrama_de_caixa">aqui</a>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">df</span><span class="p">.</span><span class="n">plot</span><span class="p">.</span><span class="n">box</span><span class="p">(</span><span class="n">figsize</span><span class="o">=</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span><span class="mi">6</span><span class="p">),</span> <span class="n">patch_artist</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><matplotlib.axes._subplots.AxesSubplot at 0x7f4ab60049b0>
</code></pre></div></div>
<p><img src="/img/ensemble/output_20_1.png" alt="png" /></p>
<p>Como já discutido em outras postagens, devemos separar os dados em um conjunto de treino e teste, para treinar nosso modelo e para saber quão bem nosso modelo irá prever para casos desconhecidos. Leia <a href="/2017/04/29/Um-Olhar-Descontraido-Sobre-o-Dilema-Vies-Variancia/">essa publicação</a> para entender melhor.</p>
<p>Aqui usamos a função interna do Scikit-Learn para separar os dados, para informações adicionais sobre todas as variáveis das funções abaixo sugiro consultar a <a href="http://scikit-learn.org/stable/documentation.html">documentação oficial</a>. Como primeiro argumento passo meu X, atributos, e segundo argumento meu y, valor que eu desejo prever, por fim passo um inteiro para tornar meus resultados reprodutíveis, tornando os processos aleatórios das funções não-aleatórios.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">train_test_split</span>
<span class="n">xtrain</span><span class="p">,</span> <span class="n">xtest</span><span class="p">,</span> <span class="n">ytrain</span><span class="p">,</span> <span class="n">ytest</span> <span class="o">=</span>\
<span class="n">train_test_split</span><span class="p">(</span><span class="n">df</span><span class="p">.</span><span class="n">drop</span><span class="p">(</span><span class="s">'MEDV'</span><span class="p">,</span><span class="mi">1</span><span class="p">).</span><span class="n">values</span><span class="p">,</span> <span class="n">df</span><span class="p">[</span><span class="s">'MEDV'</span><span class="p">].</span><span class="n">values</span><span class="p">,</span> <span class="n">random_state</span><span class="o">=</span><span class="mi">201</span><span class="p">)</span>
</code></pre></div></div>
<p>Agora importaremos nossos dois modelos, o primeiro é o XGBoost, algoritmo que vem se demonstrando extremamente eficiente em competições e o Ridge famoso algoritmo regressor. Iremos avaliar nossos modelos pelo <a href="https://pt.wikipedia.org/wiki/Erro_quadr%C3%A1tico_m%C3%A9dio">erro médio quadrático</a>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">xgboost</span> <span class="k">as</span> <span class="n">xgb</span>
<span class="kn">from</span> <span class="nn">sklearn.linear_model</span> <span class="kn">import</span> <span class="n">Ridge</span>
<span class="kn">from</span> <span class="nn">sklearn.metrics</span> <span class="kn">import</span> <span class="n">mean_squared_error</span>
</code></pre></div></div>
<p>Aqui executo uma pequena melhoria nos hiperparametros com o GridSearchCV para buscar a combinação dos hiperparametros que me dará uma melhor predição, em seguida ajusto meu modelo aos dados e tendo ele treinando, prevejo para dados que ele desconhece, em seguida avalio o desempenho do modelo como dito.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">sklearn.model_selection</span> <span class="kn">import</span> <span class="n">GridSearchCV</span>
<span class="n">params</span> <span class="o">=</span> <span class="p">{</span><span class="s">'alpha'</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mf">0.1</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">200</span><span class="p">),</span>
<span class="s">'random_state'</span><span class="p">:[</span><span class="mi">2020</span><span class="p">]}</span>
<span class="n">model1</span> <span class="o">=</span> <span class="n">GridSearchCV</span><span class="p">(</span><span class="n">estimator</span> <span class="o">=</span> <span class="n">Ridge</span><span class="p">(),</span> <span class="n">param_grid</span> <span class="o">=</span> <span class="n">params</span><span class="p">)</span>
<span class="n">model1</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">,</span><span class="n">ytrain</span><span class="p">)</span>
<span class="n">linpred</span> <span class="o">=</span> <span class="n">model1</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtest</span><span class="p">)</span>
<span class="n">err1</span> <span class="o">=</span> <span class="n">mean_squared_error</span><span class="p">(</span><span class="n">linpred</span><span class="p">,</span> <span class="n">ytest</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">err1</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.00736161092505
</code></pre></div></div>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">params</span> <span class="o">=</span> <span class="p">{</span><span class="s">'reg_alpha'</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">10</span><span class="p">),</span>
<span class="s">'gamma'</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">),</span>
<span class="s">'reg_lambda'</span><span class="p">:</span> <span class="n">np</span><span class="p">.</span><span class="n">linspace</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">,</span><span class="mi">1</span><span class="p">)}</span>
<span class="n">model2</span> <span class="o">=</span> <span class="n">GridSearchCV</span><span class="p">(</span><span class="n">estimator</span> <span class="o">=</span> <span class="n">xgb</span><span class="p">.</span><span class="n">XGBRegressor</span><span class="p">(),</span> <span class="n">param_grid</span> <span class="o">=</span> <span class="n">params</span><span class="p">)</span>
<span class="n">model2</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">xtrain</span><span class="p">,</span> <span class="n">ytrain</span><span class="p">)</span>
<span class="n">xgbpred</span> <span class="o">=</span> <span class="n">model2</span><span class="p">.</span><span class="n">predict</span><span class="p">(</span><span class="n">xtest</span><span class="p">)</span>
<span class="n">err2</span> <span class="o">=</span> <span class="n">mean_squared_error</span><span class="p">(</span><span class="n">xgbpred</span><span class="p">,</span> <span class="n">ytest</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">err2</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.00526337776169
</code></pre></div></div>
<p>Resultados muito bons, mas será que podemos deixá-los ainda melhor?!
Vamos analisar se as nossas predições têm baixa correlação.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">predictions</span> <span class="o">=</span> <span class="n">pd</span><span class="p">.</span><span class="n">DataFrame</span><span class="p">({</span><span class="s">"XGBoost"</span><span class="p">:</span><span class="n">np</span><span class="p">.</span><span class="n">expm1</span><span class="p">(</span><span class="n">xgbpred</span><span class="p">),</span> <span class="s">"Ridge"</span><span class="p">:</span><span class="n">np</span><span class="p">.</span><span class="n">expm1</span><span class="p">(</span><span class="n">linpred</span><span class="p">)})</span>
<span class="n">predictions</span><span class="p">.</span><span class="n">plot</span><span class="p">(</span><span class="n">x</span> <span class="o">=</span> <span class="s">"XGBoost"</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="s">"Ridge"</span><span class="p">,</span> <span class="n">kind</span> <span class="o">=</span> <span class="s">"scatter"</span><span class="p">,</span> <span class="n">color</span><span class="o">=</span><span class="s">"#85C8DD"</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code><matplotlib.axes._subplots.AxesSubplot at 0x7f4ab32e67b8>
</code></pre></div></div>
<p><img src="/img/ensemble/output_30_1.png" alt="png" /></p>
<p>Como já explicado, uma baixa correlação tende a melhorar significativamente nossa predição, visualmente temos algo significante, vamos olhar agora isso em números</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">scipy</span> <span class="kn">import</span> <span class="n">stats</span>
<span class="n">_</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">r_value</span><span class="p">,</span> <span class="n">_</span><span class="p">,</span> <span class="n">std_err</span> <span class="o">=</span> <span class="n">stats</span><span class="p">.</span><span class="n">linregress</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">expm1</span><span class="p">(</span><span class="n">xgbpred</span><span class="p">),</span><span class="n">np</span><span class="p">.</span><span class="n">expm1</span><span class="p">(</span><span class="n">linpred</span><span class="p">))</span>
<span class="k">print</span><span class="p">(</span><span class="n">r_value</span><span class="p">,</span> <span class="n">std_err</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.923252641379 0.0321275120299
</code></pre></div></div>
<p>Devido nosso r-valor não ser muito alto (<.98), podemos nos beneficiar da combinação das estimativas. Chegamos a parte da motivação inicial combinar os modelos para aumentar o desempenho preditivo. Testarei 3 combinações das predições, média ponderada, media simples e média harmônica.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">err3</span> <span class="o">=</span> <span class="n">mean_squared_error</span><span class="p">(</span><span class="n">xgbpred</span> <span class="o">*</span> <span class="mf">0.8</span> <span class="o">+</span> <span class="n">linpred</span> <span class="o">*</span> <span class="mf">0.2</span><span class="p">,</span> <span class="n">ytest</span><span class="p">)</span> <span class="c1"># media ponderada
</span><span class="n">err4</span> <span class="o">=</span> <span class="n">mean_squared_error</span><span class="p">((</span><span class="n">xgbpred</span> <span class="o">+</span> <span class="n">linpred</span><span class="p">)</span><span class="o">/</span><span class="mi">2</span><span class="p">,</span> <span class="n">ytest</span><span class="p">)</span> <span class="c1"># media simples
</span><span class="n">err5</span> <span class="o">=</span> <span class="n">mean_squared_error</span><span class="p">(</span><span class="n">stats</span><span class="p">.</span><span class="n">hmean</span><span class="p">([</span><span class="n">xgbpred</span><span class="p">,</span> <span class="n">linpred</span><span class="p">]),</span> <span class="n">ytest</span><span class="p">)</span><span class="c1"># media harmonica
</span><span class="k">print</span><span class="p">(</span><span class="n">err3</span><span class="p">,</span> <span class="n">err4</span><span class="p">,</span> <span class="n">err5</span><span class="p">)</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.00499853754395 0.00524298328056 0.00517761354333
</code></pre></div></div>
<p>Excelente, ouve uma melhora significativa, mas o quão significativa?</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="mi">1</span><span class="o">-</span><span class="n">err3</span><span class="o">/</span><span class="n">err2</span>
</code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0.050317539369457931
</code></pre></div></div>
<p>Está aí, 5% de melhora do nosso melhor estimador, bem significativo para algo tão simples, e tais aprimoramentos acima de algoritmos de alto desempenho são de extrema importancia no mundo da ciência de dados, talvez até nos ajudaria a pular milhares de posições rumo ao topo em uma competição valendo 1,2 milhões de dólares<sup id="fnref:4" role="doc-noteref"><a href="#fn:4" class="footnote" rel="footnote">5</a></sup>.</p>
<h3 id="concluindo">Concluindo</h3>
<p>O objetivo principal dessa publicação era demonstrar que uma combinação simples entre dois modelos podem impactar significamente na sua predição, mas durante esse processo fiz alguns tratamentos nos dados que irão te impressionar sobre o impacto na redução do nosso erro, experimente avaliar os modelos sem realizar alguns dos tratamentos que dei aos dados… Em publicações futuras, será explicado mais sobre cada técnica vista aqui.</p>
<h4 id="referências">Referências</h4>
<p><a href="https://en.wikipedia.org/wiki/Inverse-variance_weighting">Inverse Variance</a></p>
<p><a href="https://en.wikipedia.org/wiki/Bootstrap_aggregating">Bootstrap_aggregating Wikipedia</a></p>
<p><a href="https://www.kaggle.com/apapiu/regularized-linear-models">Regularized Linear Models Kernel</a></p>
<div class="footnotes" role="doc-endnotes">
<ol>
<li id="fn:1" role="doc-endnote">
<p>Polikar, R. (2006). “Ensemble based systems in decision making”. IEEE Circuits and Systems Magazine. 6 (3): 21–45. doi:10.1109/MCAS.2006.1688199 <a href="#fnref:1" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:5" role="doc-endnote">
<p>http://www.itl.nist.gov/div898/handbook/eda/section3/eda336.htm <a href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>https://stats.stackexchange.com/questions/298/in-linear-regression-when-is-it-appropriate-to-use-the-log-of-an-independent-va <a href="#fnref:2" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>https://stats.stackexchange.com/questions/18844/when-and-why-should-you-take-the-log-of-a-distribution-of-numbers <a href="#fnref:3" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>https://www.kaggle.com/c/zillow-prize-1 <a href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></p>
</li>
</ol>
</div>
Event Study2017-08-17T10:00:00+00:00http://lamfo-unb.github.io/2017/08/17/Teste-de-Eventos-en<h1 id="event-study">Event Study</h1>
<p>Hello everyone! This week LAMFO brings to you the methodology known as Event Study, we will start with a breaf introduction, referencial and then an exemple using R.</p>
<p>Nowadays isn’t hard to hear or read news about events that change contries or the world. We receive updates, new information and opinions about different topics and we reflect it on our behavior and adjust our plans, but about the market? Do you think that it reacts about those event?</p>
<p>To answer this question was created the Event Study.</p>
<h2 id="methodology">Methodology</h2>
<p>The author Campbell, Lo and Mackinley (1997) were the firsts to define and write about this methodoly. The basic idea is to observe if the value of a company suffers a variation when a event appears, in other words, if the expected “normal return” if affected by an “annomaly”. The development of Event Study has it fundamentals on the Theory of Efficient Markets of Fama (1970), which believes that the markets absorbes the public information and reflects it in stocks prices.</p>
<p>Here are four simple steps to start an Event Study!</p>
<h3 id="step-1-define-the-event">Step 1: Define the Event</h3>
<p><em>But what kind of event are we talking about?</em></p>
<p>We can study any kind of event, we only need to have enough data and the event must be known by the public. As exemples of events we havey:</p>
<ol>
<li>Dividends distribution;</li>
<li>Fusion or aquisition of other company;</li>
<li>Reaquisition of stocks;</li>
<li>New laws or regulations;</li>
<li>Privatization or nationalization;</li>
<li>Political scandals.</li>
</ol>
<p>One the event has been chosen, a time line will be defined with the windows for analysis.</p>
<p><img src="https://i.imgur.com/QJzEnPH.png" alt="" /></p>
<p><strong>Estimation Window:</strong> this window stabilish the normal return expected from the company, from \(T_0\) to \(T_1\). Here we will have a standart to compare the event, since this data hasn’t been “contaminated” by the news of the event.</p>
<p><strong>Event Window:</strong> here is the time where the news about the event get in. The zero moment (\(0\)) will be the exact date that the event came public, after that we stabilish a safaty window to be get the information leak before, from \(T_1\) to \(0\), and to be sure that the market has absorbed all the information, from \(2\) to \(T_2\)</p>
<p>An important detail, there is no fixed number to create the safety window. We can choose three months, fifthteen days or one year before the event, one way to identify the best safety window is testing different periods and analyse the statistic error.</p>
<p><strong>Pos Event Window</strong>: moment after the event and market position.</p>
<h3 id="step-2-companies">Step 2: Companies</h3>
<p>Once the dates are difined, now we need to select the companies that will be analysed and why. Usually, the first option is to get companies with stock exchange, since the returns are easy to get.</p>
<p>The second filter may be the sector or area that the companies are. For exemple, if we were studying the impact of new environmental law, would be interesting select companies from oil or mining industry.</p>
<p>Now we need to colect the return data from those companies. Is important that the data time format be the same, if the event will be marked by a day so the data of the returns must be daily returns.</p>
<h3 id="step-3-stabilish-normal-returns-and-abnormal">Step 3: Stabilish Normal Returns and Abnormal</h3>
<p>Following the time line, we first calculate the normal return of the stocks so then we can analyse the anormality.</p>
<p>A data base with the returns is enough to start the building the normal returns base. Remeber that the time format must be the same and they start at \(T_0\) and be over at \(T_2\).</p>
<p>To verify the existence of abnormal returns, or not, we will use the equation:</p>
\[Ra_{i,t}=R_{i,t} - \mathbb E[R_i|X_t ]\]
<table>
<tbody>
<tr>
<td>Where \(Ra_{i,t}\) is the abnormal return, since it is the difference between the actual return in t(\(R_{i,t}\)) and the normal return ($$E[R_i</td>
<td>X_t ]$$).</td>
</tr>
</tbody>
</table>
<p>Once we already had the base with companies return from \(T_0\) to \(T_2\), we must choose the best model to stablish the standart return:</p>
<ol>
<li>Constant Mean Return Model</li>
<li>Adjusted Market Return</li>
<li>Market Model</li>
<li>Economic Model</li>
</ol>
<h4 id="constant-mean-return-model">Constant Mean Return Model</h4>
<p>The expected normal return is defined by a simple mean of the real return in the estimation window (\(T_0\) a \(T_1\)).</p>
\[Ra_{i,t}=R_{i,t} - \overline R_i\]
<p>One critic to this model is that the assumption that the returns will be constants with the pass of time. In some time formats, where the volatility is high, this characteristic alrady has a problem.</p>
<h4 id="adjusted-market-return">Adjusted Market Return</h4>
<p>This case, the normal return will be difined by the return of the market portfolio (\(Rm\)). This method will require a new data base, in the same time format, from a benchmark.</p>
\[Ra_{i,t}=R_{i,t} - Rm_i\]
<h4 id="market-model">Market Model</h4>
<p>The Market Model has it base on statistic, representing an upgrade from the previous model.</p>
<p>Different from the Adjusted Market Return, the Market Model don’t set as default a market portfolio, but it uses an index such as S&P500 for north-america analysis or IBOVESPA for Brazilian stocks, been defined by:</p>
\[Ra_{i,t}=R_{i,t} - \widehat \alpha_i - \widehat \beta_iR_{m,t}\]
<p>The abnormal return (\(Ra_{i,t}\)) is defined by the difference from the real return of the asset in <strong><em>t</em></strong> and the parameters alpha (\(\alpha\)) and beta (\(\beta\)), estimated by a linear regression in the estimation window.</p>
<p>Using the linear regression in this model represent a big step in forecasting, since it depends on \(R^2\). The bigger the \(R^2\), less variance the abnormal return will have and more accurate the model will be.</p>
<h4 id="economic-models">Economic Models</h4>
<p>Based on the market actions and since our objective is to etimate the stock future return, there are two methodologies available: (1) Capital Asset Pricing Model (CAPM) and (2)Arbitrage Princing Theory (APT). Both of them may be used to the calculus of normal returns, but with their requisits.</p>
<ol>
<li><em>Capital Asset Princing Model</em> (CAPM)</li>
</ol>
\[Ra_{i,t} = R_i - Rf_i - \beta (Rm_i - Rf_i)\]
<p>The abnormal return is the result of the difference between the real return and the estipulated return, considering the sensibility of the asset and market retun (\(Rm\)) and free risk assets returns (\(Rf\)).</p>
<ol>
<li><em>Arbitrage Pricing Theory</em> (APT)</li>
</ol>
\[Ra_{i,t} = R_i - R_f + \beta_1 R_1 + \beta_2 R_2 + \beta_n R_n\]
<p>In this model, we have different risk prizes for different factos, each one with a specific sensibility, this mean that each factor has a beta. To aquire the betas (\(\beta_n\)) will be needed to do a linear regression for factor and asset.</p>
<h3 id="step-4-measuring-and-analyse-the-abnormal-returns">Step 4: Measuring and Analyse the Abnormal Returns</h3>
<p>When the model is set, we are ready to calculate the returns. Usually, we analyse the mean of abnormal return and the accumulative abnormal return.</p>
<p>To validate the results, look the P-VALOR of the model and the \(R^2\). Both of them must be statistic relevant.</p>
<h3 id="applying-the-model">Applying the model</h3>
<p>This exercise will be done using R, the following packages are recommended:</p>
<ul>
<li>quantmod : colect financial data from companies.</li>
<li>eventstudies : automatic package to this methodology</li>
<li>zoo : data base treatment.</li>
<li>xts: treatment of temporal data without ajusts.</li>
</ul>
<h4 id="housing-bubble-in-usa-2008-effects-on-brazilian-companies">Housing Bubble in USA (2008) effects on Brazilian Companies</h4>
<p>We will use the package of Event Study already created in R and after compare the results with the manual estimation of event study. Once we are analysing an economic event in housing sector, we will look for companies with stocks listed in the market (BM&FBOVESPA) and are in the sector. Since this is a simple exercise, we got two companies: Gafisa and Cyrela, and as a parameter for the Market Model the index IBOVESPA.</p>
<h3 id="event-study-using-the-package-eventstudies">Event Study using the package <em>eventstudies</em></h3>
<p>The package is divided in steps, the first one is stabilish the name and the date that the event occured. Since the event is the same for both of them, we will input “2008-03-13” that is the approximently the date that the event came public.</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Step 1: List the assets and the date of the event</span><span class="w">
</span><span class="n">eventsDates</span><span class="o"><-</span><span class="n">data.frame</span><span class="p">(</span><span class="s2">"name"</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="s2">"BVSP"</span><span class="p">,</span><span class="s2">"GAFISA"</span><span class="p">,</span><span class="s2">"CYRELA"</span><span class="p">),</span><span class="w">
</span><span class="s2">"when"</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="s2">"2008-03-13"</span><span class="p">,</span><span class="s2">"2008-03-13"</span><span class="p">,</span><span class="s2">"2008-03-13"</span><span class="p">))</span><span class="w">
</span><span class="c1">#Step 2: Convert the text</span><span class="w">
</span><span class="n">eventsDates</span><span class="o">$</span><span class="n">name</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">eventsDates</span><span class="o">$</span><span class="n">name</span><span class="p">)</span><span class="w">
</span><span class="n">eventsDates</span><span class="o">$</span><span class="n">when</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">eventsDates</span><span class="o">$</span><span class="n">when</span><span class="p">)</span><span class="w">
</span><span class="c1">#Step 3: Return Lists</span><span class="w">
</span><span class="n">BVSP</span><span class="o"><-</span><span class="w"> </span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"^BVSP.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="o"><-</span><span class="n">BVSP</span><span class="p">[,</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">)]</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">BVSP</span><span class="p">)</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="s2">"Date"</span><span class="p">,</span><span class="s2">"BVSP"</span><span class="p">)</span><span class="w">
</span><span class="n">GAFISA</span><span class="o"><-</span><span class="w"> </span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"GFSA3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">GAFISA</span><span class="o"><-</span><span class="n">GAFISA</span><span class="p">[,</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">)]</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">GAFISA</span><span class="p">)</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="s2">"Date"</span><span class="p">,</span><span class="s2">"GAFISA"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRELA</span><span class="o"><-</span><span class="w"> </span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"CYRE3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRELA</span><span class="o"><-</span><span class="n">CYRELA</span><span class="p">[,</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">)]</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">CYRELA</span><span class="p">)</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="s2">"Date"</span><span class="p">,</span><span class="s2">"CYRELA"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Step 4: Merge the data bases</span><span class="w">
</span><span class="n">data</span><span class="o"><-</span><span class="n">merge</span><span class="p">(</span><span class="n">BVSP</span><span class="p">,</span><span class="n">GAFISA</span><span class="p">,</span><span class="n">by</span><span class="o">=</span><span class="s2">"Date"</span><span class="p">,</span><span class="n">all</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w">
</span><span class="n">data</span><span class="o"><-</span><span class="n">merge</span><span class="p">(</span><span class="n">dados</span><span class="p">,</span><span class="n">CYRELA</span><span class="p">,</span><span class="n">by</span><span class="o">=</span><span class="s2">"Date"</span><span class="p">,</span><span class="n">all</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w">
</span><span class="c1">#Step 5: Calculate the return</span><span class="w">
</span><span class="n">data</span><span class="o">$</span><span class="n">BVSP</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">data</span><span class="o">$</span><span class="n">BVSP</span><span class="p">)),</span><span class="w"> </span><span class="n">lag</span><span class="o">=</span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="n">data</span><span class="o">$</span><span class="n">GAFISA</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">data</span><span class="o">$</span><span class="n">GAFISA</span><span class="p">)),</span><span class="w"> </span><span class="n">lag</span><span class="o">=</span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="n">data</span><span class="o">$</span><span class="n">CYRELA</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">data</span><span class="o">$</span><span class="n">CYRELA</span><span class="p">)),</span><span class="w"> </span><span class="n">lag</span><span class="o">=</span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="c1">#Step 6: Convert into zoo objects</span><span class="w">
</span><span class="n">data.zoo</span><span class="o"><-</span><span class="n">read.zoo</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="w">
</span><span class="c1">#Step 7: Event Study Market Model</span><span class="w">
</span><span class="n">es.mm</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">eventstudy</span><span class="p">(</span><span class="n">firm.returns</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">data.zoo</span><span class="p">,</span><span class="w"> </span><span class="c1">#Returns base</span><span class="w">
</span><span class="n">event.list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eventsDatas</span><span class="p">,</span><span class="w"> </span><span class="c1">#Event Dates</span><span class="w">
</span><span class="n">event.window</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="c1">#Safety Window size </span><span class="w">
</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"marketModel"</span><span class="p">,</span><span class="w"> </span><span class="c1">#Abnormal return model</span><span class="w">
</span><span class="n">to.remap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="c1">#Recalculate the return using cumsum</span><span class="w">
</span><span class="n">remap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"cumsum"</span><span class="p">,</span><span class="w"> </span><span class="c1">#Accumulative return</span><span class="w">
</span><span class="n">inference</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="c1">#Inference of the event</span><span class="w">
</span><span class="n">inference.strategy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"bootstrap"</span><span class="p">,</span><span class="w"> </span><span class="c1">#Boostrap to standert error</span><span class="w">
</span><span class="n">model.args</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">market.returns</span><span class="o">=</span><span class="n">dados</span><span class="o">$</span><span class="n">BVSP</span><span class="p">))</span><span class="w"> </span><span class="c1">#Data base with the index IBOVESPA</span><span class="w">
</span><span class="c1">#Step 8: Plot event study</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">es.mm</span><span class="p">)</span><span class="w">
</span><span class="c1">#Step 9: Results</span><span class="w">
</span><span class="n">summary</span><span class="p">(</span><span class="n">es.mm</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>As results we have:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Event</span><span class="w"> </span><span class="n">outcome</span><span class="w"> </span><span class="n">has</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="n">successful</span><span class="w"> </span><span class="n">outcomes</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="n">events</span><span class="o">:</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="s2">"success"</span><span class="w"> </span><span class="s2">"success"</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span></code></pre></div></div>
<p>Aparently the bubble in USA has effected the return in Brazilian companies, but the result is significant? Let’s look into the graphic:</p>
<p><img src="/img/teste_eventos/GAFISA+CYRELA.png" alt="" /></p>
<p>The blue line represent the companies’ return, and since is inside the abnormal area (doted lines) it shows the anormality of the series. However, the five days windw presents results equal zero, this mean that even if the event appears to cause disturbance in the series, it isn’t statistic significant.</p>
<p>Now, let’s calculate withou the package!</p>
<h3 id="event-study-by-hand">Event Study by hand</h3>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rm</span><span class="p">(</span><span class="n">list</span><span class="o">=</span><span class="n">ls</span><span class="p">())</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">quantmod</span><span class="p">)</span><span class="w">
</span><span class="n">GFSA</span><span class="o"><-</span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"GFSA3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRE</span><span class="o"><-</span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"CYRE3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="o"><-</span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"^BVSP.csv"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Convert the date</span><span class="w">
</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="p">)</span><span class="w">
</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="p">,</span><span class="n">format</span><span class="o">=</span><span class="s2">"%Y-%m-%d"</span><span class="p">)</span><span class="w">
</span><span class="n">GFSA</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">xts</span><span class="p">(</span><span class="n">GFSA</span><span class="p">[,</span><span class="m">-1</span><span class="p">],</span><span class="w"> </span><span class="n">order.by</span><span class="o">=</span><span class="n">GFSA</span><span class="p">[,</span><span class="m">1</span><span class="p">])</span><span class="w">
</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="p">)</span><span class="w">
</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="p">,</span><span class="n">format</span><span class="o">=</span><span class="s2">"%Y-%m-%d"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRE</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">xts</span><span class="p">(</span><span class="n">CYRE</span><span class="p">[,</span><span class="m">-1</span><span class="p">],</span><span class="w"> </span><span class="n">order.by</span><span class="o">=</span><span class="n">CYRE</span><span class="p">[,</span><span class="m">1</span><span class="p">])</span><span class="w">
</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="p">,</span><span class="n">format</span><span class="o">=</span><span class="s2">"%Y-%m-%d"</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">xts</span><span class="p">(</span><span class="n">BVSP</span><span class="p">[,</span><span class="m">-1</span><span class="p">],</span><span class="w"> </span><span class="n">order.by</span><span class="o">=</span><span class="n">BVSP</span><span class="p">[,</span><span class="m">1</span><span class="p">])</span><span class="w">
</span><span class="c1">#Bubble in 2008</span><span class="w">
</span><span class="n">startEvent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">as.Date</span><span class="p">(</span><span class="s2">"2008-03-13"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Stabilish the window</span><span class="w">
</span><span class="n">endEvent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">as.Date</span><span class="p">(</span><span class="s2">"2008-03-18"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Start of the series</span><span class="w">
</span><span class="n">startDate</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="s2">"2008-01-01"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Calculate the log-retorn.</span><span class="w">
</span><span class="n">diffGFSA</span><span class="o"><-</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="n">diffCYRE</span><span class="o"><-</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="c1">#Plot the adjusted close series</span><span class="w">
</span><span class="n">plot.xts</span><span class="p">(</span><span class="n">diffGFSA</span><span class="p">,</span><span class="n">major.format</span><span class="o">=</span><span class="s2">"%b/%d/%Y"</span><span class="p">,</span><span class="w">
</span><span class="n">main</span><span class="o">=</span><span class="s2">"GAFISA"</span><span class="p">,</span><span class="n">ylab</span><span class="o">=</span><span class="s2">"Log-return Adj.Close price."</span><span class="p">,</span><span class="n">xlab</span><span class="o">=</span><span class="s2">"Time"</span><span class="p">)</span><span class="w">
</span><span class="n">plot.xts</span><span class="p">(</span><span class="n">diffCYRE</span><span class="p">,</span><span class="n">major.format</span><span class="o">=</span><span class="s2">"%b/%d/%Y"</span><span class="p">,</span><span class="w">
</span><span class="n">main</span><span class="o">=</span><span class="s2">"CYRELA"</span><span class="p">,</span><span class="n">ylab</span><span class="o">=</span><span class="s2">"Log-return Adj.Close price."</span><span class="p">,</span><span class="n">xlab</span><span class="o">=</span><span class="s2">"Time"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/teste_eventos/ações ajustadas GAFISA.png" alt="" />
<img src="/img/teste_eventos/ações ajustadas cyrela.png" alt="" /></p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Estimation Window</span><span class="w">
</span><span class="n">GFSASubset</span><span class="o"><-</span><span class="w"> </span><span class="n">window</span><span class="p">(</span><span class="n">diffGFSA</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">)</span><span class="w">
</span><span class="n">CYRESubset</span><span class="o"><-</span><span class="w"> </span><span class="n">window</span><span class="p">(</span><span class="n">diffCYRE</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">)</span><span class="w">
</span><span class="c1">#BVSP</span><span class="w">
</span><span class="n">diffBVSP</span><span class="o"><-</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="n">BVSPSubset</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">diffBVSP</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">)</span><span class="w">
</span><span class="c1">#Market Model</span><span class="w">
</span><span class="n">MarketModel</span><span class="o"><-</span><span class="n">lm</span><span class="p">(</span><span class="n">GFSASubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="o">~</span><span class="n">BVSPSubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">summary</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)</span><span class="w">
</span><span class="n">MarketModel2</span><span class="o"><-</span><span class="n">lm</span><span class="p">(</span><span class="n">CYRESubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="o">~</span><span class="n">BVSPSubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">summary</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)</span><span class="w">
</span><span class="c1">#Using Market Model</span><span class="w">
</span><span class="n">epsilon</span><span class="o"><-</span><span class="n">diffGFSA</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)[</span><span class="m">1</span><span class="p">]</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)[</span><span class="m">2</span><span class="p">]</span><span class="o">*</span><span class="n">diffBVSP</span><span class="w">
</span><span class="n">epsilon2</span><span class="o"><-</span><span class="n">diffCYRE</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)[</span><span class="m">1</span><span class="p">]</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)[</span><span class="m">2</span><span class="p">]</span><span class="o">*</span><span class="n">diffBVSP</span><span class="w">
</span><span class="c1">#Find epsilon's variance</span><span class="w">
</span><span class="n">BVSPSubset1</span><span class="o"><-</span><span class="n">na.omit</span><span class="p">(</span><span class="n">window</span><span class="p">(</span><span class="n">diffBVSP</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="m">+1</span><span class="p">,</span><span class="w">
</span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">))</span><span class="w">
</span><span class="n">X</span><span class="o"><-</span><span class="n">as.matrix</span><span class="p">(</span><span class="n">cbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="nf">length</span><span class="p">(</span><span class="n">BVSPSubset1</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)),</span><span class="n">BVSPSubset1</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="n">BVSPSubset2</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">diffBVSP</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">endEvent</span><span class="p">)</span><span class="w">
</span><span class="n">Xstar</span><span class="o"><-</span><span class="n">as.matrix</span><span class="p">(</span><span class="n">cbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="nf">length</span><span class="p">(</span><span class="n">BVSPSubset2</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)),</span><span class="n">BVSPSubset2</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="c1">#GAFISA calculus</span><span class="w">
</span><span class="n">V</span><span class="o"><-</span><span class="p">(</span><span class="n">diag</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)))</span><span class="o">+</span><span class="w">
</span><span class="p">((</span><span class="n">X</span><span class="o">%*%</span><span class="n">solve</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">t</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)))</span><span class="w">
</span><span class="n">epsilonStar</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">epsilon</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">endEvent</span><span class="p">)</span><span class="w">
</span><span class="n">CAR</span><span class="o"><-</span><span class="nf">sum</span><span class="p">(</span><span class="n">epsilonStar</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">SCAR</span><span class="o"><-</span><span class="n">CAR</span><span class="o">/</span><span class="nf">sqrt</span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">V</span><span class="p">))</span><span class="w">
</span><span class="c1">#CYRELA calculus</span><span class="w">
</span><span class="n">V2</span><span class="o"><-</span><span class="p">(</span><span class="n">diag</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)))</span><span class="o">+</span><span class="w">
</span><span class="p">((</span><span class="n">X</span><span class="o">%*%</span><span class="n">solve</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">t</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)))</span><span class="w">
</span><span class="n">epsilonStar2</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">epsilon2</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">endEvent</span><span class="p">)</span><span class="w">
</span><span class="n">CAR2</span><span class="o"><-</span><span class="nf">sum</span><span class="p">(</span><span class="n">epsilonStar2</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">SCAR2</span><span class="o"><-</span><span class="n">CAR2</span><span class="o">/</span><span class="nf">sqrt</span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">V2</span><span class="p">))</span><span class="w">
</span><span class="c1">#Critical value of T distribution</span><span class="w">
</span><span class="n">alpha</span><span class="o"><</span><span class="m">-0.05</span><span class="w">
</span><span class="n">df</span><span class="o"><-</span><span class="nf">length</span><span class="p">(</span><span class="n">GFSASubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="m">-2</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">,</span><span class="n">df</span><span class="p">)</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="m">1</span><span class="o">-</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">),</span><span class="n">df</span><span class="p">)</span><span class="w">
</span><span class="n">df2</span><span class="o"><-</span><span class="nf">length</span><span class="p">(</span><span class="n">CYRESubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="m">-2</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">,</span><span class="n">df</span><span class="p">)</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="m">1</span><span class="o">-</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">),</span><span class="n">df</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>The results for both companies are -2.012896 e 2.012896. Since wasn’t found any evidence in favor to reject the null hypothesis, the event has no significant impact over the compnies.</p>
<p>Finished this quick exercise about event study, in case of any doubt or for more info contact the LAMFO team!</p>
Teste de Eventos2017-08-17T10:00:00+00:00http://lamfo-unb.github.io/2017/08/17/Teste-de-Eventos<h1 id="teste-de-eventos">Teste de Eventos</h1>
<p>Olá pessoal! Essa semana o LAMFO traz para vocês a metodologia conhecida como Teste de Eventos, com uma breve introdução, referencial teórico e um exercício prático utilizando R.</p>
<p>Durante o dia, é comum ouvirmos ou lermos alguma notícia sobre acontecimentos ou mudanças no país e no mundo. A todo momento recebemos atualizações, novas informações e opiniões a respeito dos mais diversos temas que refletem em nosso comportamento e até planejamento para o futuro. Mas e o mercado? Será que ele também é afetado pela repercurssão desses eventos?</p>
<p>Para responder essa pergunta, foi criado o Teste de Evento (<em>Event Study</em>).</p>
<h2 id="metodologia">Metodologia</h2>
<p>Os autores Campbell, Lo e Mackinley (1997) foram os primeiros a definir e escrever sobre esta metodologia. A idéia básica é observar se o valor de uma empresa é alterado com o aparecimento de um evento, ou seja, se o “retorno normal” esperado sofre alguma “anormalidade”. O desenvolvimento do Teste de Eventos tem como base a Teoria dos Mercados Eficientes de Fama (1970), em que se acredita que o mercado absorve as informações públicas disponíveis e realiza o ajuste do preço dos ativos.</p>
<p>Apresentaremos quatro passos simples para começar nosso Teste de Eventos!</p>
<h3 id="passo-1-definição-do-evento">Passo 1: Definição do Evento</h3>
<p><em>Mas de que tipo de evento estamos falando?</em></p>
<p>Podemos estudar qualquer tipo de evento, contanto que tenhamos suficientes dados e que ele seja publicamente conhecido. Temos por exemplo eventos como:</p>
<ol>
<li>Distribuição de dividendos;</li>
<li>Fusão e aquisições de outras empresas;</li>
<li>Recompra de ações;</li>
<li>Novas leis e regulamentações;</li>
<li>Privatização ou estatização;</li>
<li>Escândalos políticos.</li>
</ol>
<p>Uma vez escolhido o evento, é preciso definir uma linha do tempo e as janelas de análise.</p>
<p><img src="https://i.imgur.com/QJzEnPH.png" alt="" /></p>
<p><strong>Janela de estimação:</strong> representa o período em que os retornos normais do ativo serão padronizados, de \(T_0\) a \(T_1\). Dessa forma, teremos uma base de comparação de retornos que não foram “contaminados” pelo aparecimento do evento.</p>
<p><strong>Janela do Evento:</strong> intervalo de tempo em que o evento em questão apareceu. A data que o evento ocorreu é determinada como momento zero (\(0\)) e a partir desse marco é estabelecido um “intervalo de segurança” para verificar se houve vazamento de informações privilegiadas antes do acontecimento, \(T_1\) a \(0\), e para englobar o período de absorção do evento pelo mercado, de \(0\) a \(T_2\).</p>
<p>Um detalhe importante é que não existe um número fixo para esta janela. Podemos, por exemplo, ter três meses antes e depois do evento ou até mesmo quinze dias antes e depois para compor a janela. Uma saída seria realizar uma modelagem e avaliar o erro estatístico.</p>
<p><strong>Janela Pós-Evento:</strong> momento após o acontecimento do evento e eventuais movimentações do mercado. É possível observar o impacto do acontecimento a longo prazo.</p>
<h3 id="passo-2-empresas">Passo 2: Empresas</h3>
<p>Com as datas determinadas, agora precisamos selecionar quais empresas farão parte do estudo e porque. Normalmente o primeiro filtro é se a empresa que se deseja estudar possui ações na bolsa de valores, uma vez que utilizamos o retorno para nossos cálculos.</p>
<p>Uma ideia para o segundo filtro seria o setor de empresas, por exemplo, se usassemos o Teste de Eventos para verificar o impacto de novas leis ambientais. Nesse caso, seria interessante selecionar empresas do setor de mineração e petróleo.</p>
<p>Agora é preciso coletar os dados dos retornos da empresa ou empresas selecionadas. É importante ressaltar que a unidade temporal dos dados deve ser a mesma, por exemplo, se o evento estudado for registrado em um dia, as oberservações de retorno também devem ser diárias.</p>
<h3 id="passo-3-estabelecendo-retornos-normais-e-anormais">Passo 3: Estabelecendo Retornos Normais e Anormais</h3>
<p>Como estabelecido na linha do tempo, primeiro estimamos o retorno normal do ativo para depois analisarmos a anormalidade.</p>
<p>Uma base de dado com os retornos da empresa escolhida é o suficiente para iniciar a composição da base de retornos normais. O importante é que a unidade temporal seja a mesma e que as observações se iniciem em \(T_0\) e terminem em, pelo menos, em \(T_2\).</p>
<p>Para verificar se existem ou não retornos anormais, usaremos a seguinte equação base:</p>
\[Ra_{i,t}=R_{i,t} - \mathbb E[R_i|X_t ]\]
<table>
<tbody>
<tr>
<td>Sendo \(Ra_{i,t}\) o retorno anormal, uma vez que será a diferença do retorno real em t (\(R_{i,t}\)) e do retorno normal esperado em determinado período ($$E[R_i</td>
<td>X_t ]$$).</td>
</tr>
</tbody>
</table>
<p>Como já teríamos a base com os retornos da empresa de \(T_0\) a \(T_2\), precisamos escolher qual o melhor modelo para se estabelecer o retorno padrão:</p>
<ol>
<li>Retorno Ajustado a Média</li>
<li>Retorno Ajustado ao Mercado</li>
<li>Modelo de Mercado</li>
<li>Modelos Econômicos</li>
</ol>
<h4 id="retorno-ajustado-a-média">Retorno Ajustado a Média</h4>
<p>O retorno normal esperado aqui será definido pela média simples dos retornos reais da janela de estimação (\(T_0\) a \(T_1\)).</p>
\[Ra_{i,t}=R_{i,t} - \overline R_i\]
<p>Uma crítica a esse modelo é que se assume que os retornos terão retornos médios constantes ao longo do tempo. Dependendo da unidade temporal escolhida, este pressuposto por si só já apresenta uma grande margem de erro.</p>
<h4 id="retorno-ajustado-ao-mercado">Retorno Ajustado ao Mercado</h4>
<p>Neste caso, o retorno normal será definido como o retorno da cateira de mercado (\(Rm\)). Neste método será necessário obter uma base de dado com os retornos na mesma unidade temporal do ativo referência do mercado (<em>benchmark</em>).</p>
\[Ra_{i,t}=R_{i,t} - Rm_i\]
<h4 id="modelo-de-mercado">Modelo de Mercado</h4>
<p>A abordagem do Modelo de Mercado possui sua base na estatística, aprimorando as estimativas realizadas anteriormente pelos demais modelos.</p>
<p>Diferente do Modelo de Retorno Ajustado ao Mercado, o Modelo de Mercado não utiliza o retorno de uma carteira referência, mas sim índices como S&P500 para análises norte-americanas ou IBOVESPA para ações nacionais, sendo definido por:</p>
\[Ra_{i,t}=R_{i,t} - \widehat \alpha_i - \widehat \beta_iR_{m,t}\]
<p>No qual o retorno anormal (\(Ra_{i,t}\)) é definido pelo retorno real do ativo em um período <strong><em>t</em></strong> menos os parâmetros alpha (\(\alpha\)) e beta (\(\beta\)) estimados por uma regressão linear da janela de estimação para o índice de mercado.</p>
<p>Por utilizar regressão linear, o ganho e previsão do modelo depende do R\(^2\). Quanto maior for este indicador, menor será a variância do do retorno anormal, garantindo uma maior estabilidade ao modelo.</p>
<h4 id="modelos-econômicos">Modelos Econômicos</h4>
<p>Com base nas práticas do mercado, se desejamos estimar um valor para o retorno futuro de um ativo existem duas metodologias utilizadas (1) <em>Capital Asset Pricing Model</em> (CAPM) e (2) <em>Arbitrage Pricing Theory</em> (APT). Ambos podem ser utilizados para estimar o retorno normal, porém é preciso ficar atento para os requisitos de cada um, assim como o período da janela de estimação.</p>
<ol>
<li><em>Capital Asset Princing Model</em> (CAPM)</li>
</ol>
\[Ra_{i,t} = R_i - Rf_i - \beta (Rm_i - Rf_i)\]
<p>Em que o retorno anormal é identificado pela diferença do retorno real com o retorno estipulado considerando a sensibilidade do ativo e elementos como retorno de mercado (\(Rm\)) e de ativos livre de risco (\(Rf\)).</p>
<ol>
<li><em>Arbitrage Pricing Theory</em> (APT)</li>
</ol>
\[Ra_{i,t} = R_i - R_f + \beta_1 R_1 + \beta_2 R_2 + \beta_n R_n\]
<p>Neste modelo temos um prêmio pelo risco para fatores diferentes, considerando a sensibilidade do ativo ao fator específico. Para adquirir o Beta (\(\beta_n\)) será preciso realizar uma regressão linear para cada fator e o ativo.</p>
<h3 id="passo-4-mensuração-e-análise-dos-retornos-anormais">Passo 4: Mensuração e Análise dos Retornos Anormais</h3>
<p>Com o modelo definido, agora devemos calcular o comportamento dos retornos. Normalmente, usamos duas métricas para os retornos anormais, o retorno anormal médio da amostra e o retorno anormal acumulado.</p>
<p>Para aceitarmos os resultados, é preciso que o P-Valor do modelo esteja dentro da margem de aceitação ou que o \(R^2\) seja o maior possível.</p>
<h2 id="aplicando-o-modelo">Aplicando o modelo</h2>
<p>A aplicação do Teste de Eventos será realizada utilizando o R, com adicionais de alguns pacotes como:</p>
<ul>
<li>quantmod : coletar os dados de retorno das empresas escolhidas.</li>
<li>eventstudies: pacote específico para utilizar o teste de eventos automaticamente.</li>
<li>zoo: tratamento dos dados da série financeira.</li>
<li>xts: tratamento de dados de séries temporais sem ajustes.</li>
</ul>
<h3 id="estouro-da-bolha-imobiliaria-nos-eua-2008">Estouro da Bolha Imobiliaria nos EUA (2008)</h3>
<p>Usaremos o pacote de Teste de Eventos já existente no R e depois calcularemos o impacto do evento de maneira manual. Como analisamos um evento de caráter econômico e ligado ao setor imobiliário, procuraremos empresas que sejam cotadas na bolsa de valores brasileira (BM&FBOVESPA) e que atuem no setor. Selecionamos para análise as empresas Gafisa e Cyrela e como parâmetro para o modelo de mercado o índice IBOVESPA.</p>
<h3 id="teste-de-eventos-utilizando-o-pacote-eventstudies">Teste de Eventos utilizando o pacote <em>eventstudies</em></h3>
<p>O pacote é dividido em etapas, a primeira delas é estabelecer o nome das empresas e a data em que o evento aconteceu. Como o evento é o mesmo para ambas, colocaremos a data “2008-03-13” referente aproximadamente ao dia em que a notícia da bolha veio a público.</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Passo 1: Listar os ativos e datas dos eventos</span><span class="w">
</span><span class="n">eventosDatas</span><span class="o"><-</span><span class="n">data.frame</span><span class="p">(</span><span class="s2">"name"</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="s2">"BVSP"</span><span class="p">,</span><span class="s2">"GAFISA"</span><span class="p">,</span><span class="s2">"CYRELA"</span><span class="p">),</span><span class="w">
</span><span class="s2">"when"</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="s2">"2008-03-13"</span><span class="p">,</span><span class="s2">"2008-03-13"</span><span class="p">,</span><span class="s2">"2008-03-13"</span><span class="p">))</span><span class="w">
</span><span class="c1">#Passo 2: Converter para texto</span><span class="w">
</span><span class="n">eventosDatas</span><span class="o">$</span><span class="n">name</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">eventosDatas</span><span class="o">$</span><span class="n">name</span><span class="p">)</span><span class="w">
</span><span class="n">eventosDatas</span><span class="o">$</span><span class="n">when</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">eventosDatas</span><span class="o">$</span><span class="n">when</span><span class="p">)</span><span class="w">
</span><span class="c1">#Passo 3: Lista de retornos</span><span class="w">
</span><span class="n">BVSP</span><span class="o"><-</span><span class="w"> </span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"^BVSP.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="o"><-</span><span class="n">BVSP</span><span class="p">[,</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">)]</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">BVSP</span><span class="p">)</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="s2">"Data"</span><span class="p">,</span><span class="s2">"BVSP"</span><span class="p">)</span><span class="w">
</span><span class="n">GAFISA</span><span class="o"><-</span><span class="w"> </span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"GFSA3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">GAFISA</span><span class="o"><-</span><span class="n">GAFISA</span><span class="p">[,</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">)]</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">GAFISA</span><span class="p">)</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="s2">"Data"</span><span class="p">,</span><span class="s2">"GAFISA"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRELA</span><span class="o"><-</span><span class="w"> </span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"CYRE3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRELA</span><span class="o"><-</span><span class="n">CYRELA</span><span class="p">[,</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">6</span><span class="p">)]</span><span class="w">
</span><span class="n">colnames</span><span class="p">(</span><span class="n">CYRELA</span><span class="p">)</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="s2">"Data"</span><span class="p">,</span><span class="s2">"CYRELA"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Passo 4: Junta as bases de dados</span><span class="w">
</span><span class="n">dados</span><span class="o"><-</span><span class="n">merge</span><span class="p">(</span><span class="n">BVSP</span><span class="p">,</span><span class="n">GAFISA</span><span class="p">,</span><span class="n">by</span><span class="o">=</span><span class="s2">"Data"</span><span class="p">,</span><span class="n">all</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w">
</span><span class="n">dados</span><span class="o"><-</span><span class="n">merge</span><span class="p">(</span><span class="n">dados</span><span class="p">,</span><span class="n">CYRELA</span><span class="p">,</span><span class="n">by</span><span class="o">=</span><span class="s2">"Data"</span><span class="p">,</span><span class="n">all</span><span class="o">=</span><span class="nb">T</span><span class="p">)</span><span class="w">
</span><span class="c1">#Passo 5: Calcula o retorno</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">BVSP</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">BVSP</span><span class="p">)),</span><span class="w"> </span><span class="n">lag</span><span class="o">=</span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">GAFISA</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">GAFISA</span><span class="p">)),</span><span class="w"> </span><span class="n">lag</span><span class="o">=</span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">CYRELA</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">CYRELA</span><span class="p">)),</span><span class="w"> </span><span class="n">lag</span><span class="o">=</span><span class="m">1</span><span class="p">))</span><span class="w">
</span><span class="c1">#Passo 6: Converte em objeto zoo</span><span class="w">
</span><span class="n">dados.zoo</span><span class="o"><-</span><span class="n">read.zoo</span><span class="p">(</span><span class="n">dados</span><span class="p">)</span><span class="w">
</span><span class="c1">#Passo 7: Teste de Eventos Market Model</span><span class="w">
</span><span class="n">es.mm</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">eventstudy</span><span class="p">(</span><span class="n">firm.returns</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dados.zoo</span><span class="p">,</span><span class="w"> </span><span class="c1">#Base de retornos</span><span class="w">
</span><span class="n">event.list</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">eventosDatas</span><span class="p">,</span><span class="w"> </span><span class="c1">#Datas dos eventos</span><span class="w">
</span><span class="n">event.window</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5</span><span class="p">,</span><span class="w"> </span><span class="c1">#Tamanho da janela </span><span class="w">
</span><span class="n">type</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"marketModel"</span><span class="p">,</span><span class="w"> </span><span class="c1">#Modelo utilizado</span><span class="w">
</span><span class="n">to.remap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="c1">#Recalculado os retornos usando cumsum</span><span class="w">
</span><span class="n">remap</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"cumsum"</span><span class="p">,</span><span class="w"> </span><span class="c1">#Testa o evento para o retorno acumulado</span><span class="w">
</span><span class="n">inference</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="c1">#Inferência acerca do evento</span><span class="w">
</span><span class="n">inference.strategy</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"bootstrap"</span><span class="p">,</span><span class="w"> </span><span class="c1">#Boostrap para avaliar o erro-padrão</span><span class="w">
</span><span class="n">model.args</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">list</span><span class="p">(</span><span class="n">market.returns</span><span class="o">=</span><span class="n">dados</span><span class="o">$</span><span class="n">BVSP</span><span class="p">))</span><span class="w"> </span><span class="c1">#Adiciona a base do índice do mercado IBOVESPA</span><span class="w">
</span><span class="c1">#Passo 8: Plotar gráfico</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">es.mm</span><span class="p">)</span><span class="w">
</span><span class="c1">#Passo 9: Obersrevar resultados</span><span class="w">
</span><span class="n">summary</span><span class="p">(</span><span class="n">es.mm</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Como resultado temos:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Event</span><span class="w"> </span><span class="n">outcome</span><span class="w"> </span><span class="n">has</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="n">successful</span><span class="w"> </span><span class="n">outcomes</span><span class="w"> </span><span class="n">out</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="m">3</span><span class="w"> </span><span class="n">events</span><span class="o">:</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="s2">"success"</span><span class="w"> </span><span class="s2">"success"</span><span class="w"> </span><span class="s2">"success"</span><span class="w">
</span></code></pre></div></div>
<p>Aparentemente o estouro da bolha nos EUA apresentou um impacto no retorno das empresas brasileiras, mas será que o resultado é significante? Para isso vamos observar o gráfico gerado pelo pacote.</p>
<p><img src="/img/teste_eventos/GAFISA+CYRELA.png" alt="" align="middle" /></p>
<p>Como podemos constatar, a linha azul (que representa o retorno das ações) está dentro da área de anormalidade (linhas pontilhadas). Porém dentro da janela de 5 dias, os resultados encontram-se diversas vezes em zero. Isso significa que mesmo que o evento aparentemente cause uma anormalidade no retorno, não há comprovação estatística.</p>
<p>Agora vamos comparar o resultado com cálculos a mão!</p>
<h3 id="teste-de-eventos-calculado-manualmente">Teste de Eventos calculado manualmente</h3>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">rm</span><span class="p">(</span><span class="n">list</span><span class="o">=</span><span class="n">ls</span><span class="p">())</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">quantmod</span><span class="p">)</span><span class="w">
</span><span class="n">GFSA</span><span class="o"><-</span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"GFSA3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRE</span><span class="o"><-</span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"CYRE3.SA.csv"</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="o"><-</span><span class="n">read.csv</span><span class="p">(</span><span class="s2">"^BVSP.csv"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Converte para data</span><span class="w">
</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="p">)</span><span class="w">
</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Date</span><span class="p">,</span><span class="n">format</span><span class="o">=</span><span class="s2">"%Y-%m-%d"</span><span class="p">)</span><span class="w">
</span><span class="n">GFSA</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">xts</span><span class="p">(</span><span class="n">GFSA</span><span class="p">[,</span><span class="m">-1</span><span class="p">],</span><span class="w"> </span><span class="n">order.by</span><span class="o">=</span><span class="n">GFSA</span><span class="p">[,</span><span class="m">1</span><span class="p">])</span><span class="w">
</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="p">)</span><span class="w">
</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Date</span><span class="p">,</span><span class="n">format</span><span class="o">=</span><span class="s2">"%Y-%m-%d"</span><span class="p">)</span><span class="w">
</span><span class="n">CYRE</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">xts</span><span class="p">(</span><span class="n">CYRE</span><span class="p">[,</span><span class="m">-1</span><span class="p">],</span><span class="w"> </span><span class="n">order.by</span><span class="o">=</span><span class="n">CYRE</span><span class="p">[,</span><span class="m">1</span><span class="p">])</span><span class="w">
</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="nf">as.character</span><span class="p">(</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Date</span><span class="p">,</span><span class="n">format</span><span class="o">=</span><span class="s2">"%Y-%m-%d"</span><span class="p">)</span><span class="w">
</span><span class="n">BVSP</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">xts</span><span class="p">(</span><span class="n">BVSP</span><span class="p">[,</span><span class="m">-1</span><span class="p">],</span><span class="w"> </span><span class="n">order.by</span><span class="o">=</span><span class="n">BVSP</span><span class="p">[,</span><span class="m">1</span><span class="p">])</span><span class="w">
</span><span class="c1">#Estouro da bolha imobiliária em 2008</span><span class="w">
</span><span class="n">startEvent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">as.Date</span><span class="p">(</span><span class="s2">"2008-03-13"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Estabelecido intervalo da janela do evento</span><span class="w">
</span><span class="n">endEvent</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">as.Date</span><span class="p">(</span><span class="s2">"2008-03-18"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Início da série</span><span class="w">
</span><span class="n">startDate</span><span class="o"><-</span><span class="n">as.Date</span><span class="p">(</span><span class="s2">"2008-01-01"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Plota a série temporal dos preços de fechamento ajustado</span><span class="w">
</span><span class="n">plot.xts</span><span class="p">(</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Close</span><span class="p">,</span><span class="n">major.format</span><span class="o">=</span><span class="s2">"%b/%d/%Y"</span><span class="p">,</span><span class="w">
</span><span class="n">main</span><span class="o">=</span><span class="s2">"GAFISA"</span><span class="p">,</span><span class="n">ylab</span><span class="o">=</span><span class="s2">"Adj.Close price."</span><span class="p">,</span><span class="n">xlab</span><span class="o">=</span><span class="s2">"Time"</span><span class="p">)</span><span class="w">
</span><span class="n">plot.xts</span><span class="p">(</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Close</span><span class="p">,</span><span class="n">major.format</span><span class="o">=</span><span class="s2">"%b/%d/%Y"</span><span class="p">,</span><span class="w">
</span><span class="n">main</span><span class="o">=</span><span class="s2">"CYRELA"</span><span class="p">,</span><span class="n">ylab</span><span class="o">=</span><span class="s2">"Adj.Close price."</span><span class="p">,</span><span class="n">xlab</span><span class="o">=</span><span class="s2">"Time"</span><span class="p">)</span><span class="w">
</span><span class="c1">#Calcula o log-retorno.</span><span class="w">
</span><span class="n">diffGFSA</span><span class="o"><-</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">GFSA</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="n">diffCYRE</span><span class="o"><-</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">CYRE</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="c1">#Plota a série temporal dos preços de fechamento ajustado</span><span class="w">
</span><span class="n">plot.xts</span><span class="p">(</span><span class="n">diffGFSA</span><span class="p">,</span><span class="n">major.format</span><span class="o">=</span><span class="s2">"%b/%d/%Y"</span><span class="p">,</span><span class="w">
</span><span class="n">main</span><span class="o">=</span><span class="s2">"GAFISA"</span><span class="p">,</span><span class="n">ylab</span><span class="o">=</span><span class="s2">"Log-return Adj.Close price."</span><span class="p">,</span><span class="n">xlab</span><span class="o">=</span><span class="s2">"Time"</span><span class="p">)</span><span class="w">
</span><span class="n">plot.xts</span><span class="p">(</span><span class="n">diffCYRE</span><span class="p">,</span><span class="n">major.format</span><span class="o">=</span><span class="s2">"%b/%d/%Y"</span><span class="p">,</span><span class="w">
</span><span class="n">main</span><span class="o">=</span><span class="s2">"CYRELA"</span><span class="p">,</span><span class="n">ylab</span><span class="o">=</span><span class="s2">"Log-return Adj.Close price."</span><span class="p">,</span><span class="n">xlab</span><span class="o">=</span><span class="s2">"Time"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/teste_eventos/ações ajustadas GAFISA.png" alt="" align="middle" /></p>
<p><img src="/img/teste_eventos/ações ajustadas cyrela.png" alt="" align="middle" /></p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#Janela de estimação</span><span class="w">
</span><span class="n">GFSASubset</span><span class="o"><-</span><span class="w"> </span><span class="n">window</span><span class="p">(</span><span class="n">diffGFSA</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">)</span><span class="w">
</span><span class="n">CYRESubset</span><span class="o"><-</span><span class="w"> </span><span class="n">window</span><span class="p">(</span><span class="n">diffCYRE</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">)</span><span class="w">
</span><span class="c1">#BVSP</span><span class="w">
</span><span class="n">diffBVSP</span><span class="o"><-</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">BVSP</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="n">BVSPSubset</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">diffBVSP</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">)</span><span class="w">
</span><span class="c1">#Estima o modelo de mercado</span><span class="w">
</span><span class="n">MarketModel</span><span class="o"><-</span><span class="n">lm</span><span class="p">(</span><span class="n">GFSASubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="o">~</span><span class="n">BVSPSubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">summary</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)</span><span class="w">
</span><span class="n">MarketModel2</span><span class="o"><-</span><span class="n">lm</span><span class="p">(</span><span class="n">CYRESubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="o">~</span><span class="n">BVSPSubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">summary</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)</span><span class="w">
</span><span class="c1">#Aplica o Market Model</span><span class="w">
</span><span class="n">epsilon</span><span class="o"><-</span><span class="n">diffGFSA</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)[</span><span class="m">1</span><span class="p">]</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)[</span><span class="m">2</span><span class="p">]</span><span class="o">*</span><span class="n">diffBVSP</span><span class="w">
</span><span class="n">epsilon2</span><span class="o"><-</span><span class="n">diffCYRE</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)[</span><span class="m">1</span><span class="p">]</span><span class="o">-</span><span class="n">coef</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)[</span><span class="m">2</span><span class="p">]</span><span class="o">*</span><span class="n">diffBVSP</span><span class="w">
</span><span class="c1">#Encontra a variância do epsilon</span><span class="w">
</span><span class="n">BVSPSubset1</span><span class="o"><-</span><span class="n">na.omit</span><span class="p">(</span><span class="n">window</span><span class="p">(</span><span class="n">diffBVSP</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startDate</span><span class="m">+1</span><span class="p">,</span><span class="w">
</span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="m">-1</span><span class="p">))</span><span class="w">
</span><span class="n">X</span><span class="o"><-</span><span class="n">as.matrix</span><span class="p">(</span><span class="n">cbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="nf">length</span><span class="p">(</span><span class="n">BVSPSubset1</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)),</span><span class="n">BVSPSubset1</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="n">BVSPSubset2</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">diffBVSP</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">endEvent</span><span class="p">)</span><span class="w">
</span><span class="n">Xstar</span><span class="o"><-</span><span class="n">as.matrix</span><span class="p">(</span><span class="n">cbind</span><span class="p">(</span><span class="nf">rep</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="nf">length</span><span class="p">(</span><span class="n">BVSPSubset2</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)),</span><span class="n">BVSPSubset2</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">))</span><span class="w">
</span><span class="c1">#Calculo para GAFISA</span><span class="w">
</span><span class="n">V</span><span class="o"><-</span><span class="p">(</span><span class="n">diag</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)))</span><span class="o">+</span><span class="w">
</span><span class="p">((</span><span class="n">X</span><span class="o">%*%</span><span class="n">solve</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">t</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel</span><span class="p">)))</span><span class="w">
</span><span class="n">epsilonStar</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">epsilon</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">endEvent</span><span class="p">)</span><span class="w">
</span><span class="n">CAR</span><span class="o"><-</span><span class="nf">sum</span><span class="p">(</span><span class="n">epsilonStar</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">SCAR</span><span class="o"><-</span><span class="n">CAR</span><span class="o">/</span><span class="nf">sqrt</span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">V</span><span class="p">))</span><span class="w">
</span><span class="c1">#Calculo para CYRELA</span><span class="w">
</span><span class="n">V2</span><span class="o"><-</span><span class="p">(</span><span class="n">diag</span><span class="p">(</span><span class="n">nrow</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)))</span><span class="o">+</span><span class="w">
</span><span class="p">((</span><span class="n">X</span><span class="o">%*%</span><span class="n">solve</span><span class="p">(</span><span class="n">t</span><span class="p">(</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">Xstar</span><span class="p">)</span><span class="o">%*%</span><span class="n">t</span><span class="p">(</span><span class="n">X</span><span class="p">))</span><span class="o">*</span><span class="n">var</span><span class="p">(</span><span class="n">residuals</span><span class="p">(</span><span class="n">MarketModel2</span><span class="p">)))</span><span class="w">
</span><span class="n">epsilonStar2</span><span class="o"><-</span><span class="n">window</span><span class="p">(</span><span class="n">epsilon2</span><span class="p">,</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">startEvent</span><span class="p">,</span><span class="w"> </span><span class="n">end</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">endEvent</span><span class="p">)</span><span class="w">
</span><span class="n">CAR2</span><span class="o"><-</span><span class="nf">sum</span><span class="p">(</span><span class="n">epsilonStar2</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="w">
</span><span class="n">SCAR2</span><span class="o"><-</span><span class="n">CAR2</span><span class="o">/</span><span class="nf">sqrt</span><span class="p">(</span><span class="nf">sum</span><span class="p">(</span><span class="n">V2</span><span class="p">))</span><span class="w">
</span><span class="c1">#Valor crítico da distribuição T</span><span class="w">
</span><span class="n">alpha</span><span class="o"><</span><span class="m">-0.05</span><span class="w">
</span><span class="n">df</span><span class="o"><-</span><span class="nf">length</span><span class="p">(</span><span class="n">GFSASubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="m">-2</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">,</span><span class="n">df</span><span class="p">)</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="m">1</span><span class="o">-</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">),</span><span class="n">df</span><span class="p">)</span><span class="w">
</span><span class="n">df2</span><span class="o"><-</span><span class="nf">length</span><span class="p">(</span><span class="n">CYRESubset</span><span class="o">$</span><span class="n">Adj.Close</span><span class="p">)</span><span class="m">-2</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">,</span><span class="n">df</span><span class="p">)</span><span class="w">
</span><span class="n">qt</span><span class="p">(</span><span class="m">1</span><span class="o">-</span><span class="p">(</span><span class="n">alpha</span><span class="o">/</span><span class="m">2</span><span class="p">),</span><span class="n">df</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Os resultados para ambas as empresas são de -2.012896 e 2.012896. Como não foram observadas evidências em favor da rejeição da hipótese nula, o evento não possui efeito no retorno dos ativos.</p>
<p>Assim concluímos nosso exercício sobre teste de eventos! Em caso de dúvidas entre contato com o LAMFO!</p>
Uma visão amigável do Teorema de Bayes2017-08-04T10:00:00+00:00http://lamfo-unb.github.io/2017/08/04/Uma-visao-amigavel-do-Teorema-de-Bayes<link href="https://fonts.googleapis.com/css?family=Rock Salt" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Sofia" rel="stylesheet" />
<h1 id="eventos-probabilidade-e-condicionalidade">Eventos, Probabilidade e Condicionalidade</h1>
<p>No livro <em>The History of Probability</em> o autor Todhunter relata de forma cronológica considerações de aspectos elementares da Teoria da Probabilidade de alguns notáveis personagens da história. No entanto, os primórdios da probabilidade está relatado nas correspondências entre Pierre De Fermat e Blaise Pascal sobre um problema de jogos em lançamento de dados no século XVII, citados em <em>Games, Gods & Gambling</em>.</p>
<p>Probabilidade é a área da matemática responsável por mensurar aquilo que não é determinístico. Os resultados dos lançamentos de dados ou moedas são considerados <strong>experimentos de probabilidade</strong>, pois estão sujeitos ao acaso.</p>
<p>Para o cálculo de probabilidades, considere as seguintes abordagens:</p>
<ul>
<li>
<p><strong>Clássica</strong>: “Suponha que dentre \(n\) resultados possíveis e equiprováveis \(m\) sejam favoráveis. A probabilidade de um evento favorável é \(p = \frac{m}{n}\).” Essa abordagem é o resultado das correspondências entre Fermat e Pascal.</p>
</li>
<li>
<p><strong>Frequentista</strong>: “Foram realizados \(n\) experimentos dos quais \(m\) eram favoráveis. A frequência relativa da ocorrência de um evento favorável é \(\frac{m}{n}\).” Jakob Bernoulli, em seu livro <em>Ars Conjectandi</em>, provou a convergência entre a frequência relativa de ocorrência e a probabilidade \(p\) clássica a medida que aumenta-se o número de experimentos \(n\).</p>
</li>
</ul>
<p>Dito isso, vamos definir como \(P(A)\) a probabilidade de ocorrer o evento \(A\) em um determinado conjunto de valores possíveis \(\Omega\). Antes de tudo vamos aquecer o cérebro compreendendo os importantes conceitos de <strong>independência</strong> e <strong>permutabilidade</strong> para o estudo de probabilidade.</p>
<h2 id="independência">Independência</h2>
<p>Seja uma caixa contendo <strong>2 bolas brancas</strong> e <strong>3 pretas</strong>. Considere o experimento da retirada aleatória e observância da cor da bolas, com representação <strong>Bernoulli</strong> (\(X_1\)) de ocorrência:</p>
<ul>
<li>
<p>\(X_1 = 0\) caso a bola retirada seja branca</p>
</li>
<li>
<p>\(X_1 = 1\) caso a bola retirada seja preta</p>
</li>
</ul>
<p>Pela abordagem clássica, a probabilidade da bola ser branca é \(P(X_1 = 0) = \frac{2}{5}\) e de ser preta \(P(X_1 = 1) = \frac{3}{5}\).</p>
<p>Após a primeira retirada, e sem reposição, você retira mais uma bola. Qual a probabilidade da segunda bola ser branca?</p>
<p>A resposta mais intuitiva é <strong>DEPENDE</strong>. De fato, a probabilidade da segunda retirada (\(X_2\)) está <strong>condicionada</strong> ao resultado da primeira. Perceba, caso a primeira seja branca, restam mais \(1\) branca e as demais \(3\) pretas, e, nesse caso, a probabilidade de uma segunda retirada branca é \(\frac{1}{4}\). Caso a primeira tenha sido preta, seria \(\frac{2}{4}\).</p>
<p>De maneira geral, a probabilidade do evento \(B\) condicionada ao evento \(A\) é representada por \(P(B/A)\). Nesse caso, temos que:</p>
<ul>
<li>
\[P(X_2 = 0|X_1 = 0) = \frac{1}{4}\]
</li>
<li>
\[P(X_2 = 0|X_1 = 1) = \frac{2}{4}\]
</li>
</ul>
<p>Dessa forma, dizemos que o evento \(X_2\) é <strong>dependente</strong> do evento \(X_1\).</p>
<p>A probabilidade conjunta dos eventos \(A\) e \(B\) é expressa pela regra do produto:
\(P( B \cap A) = P(B|A) P(A)\)
que também pode ser expressa por \(P( B \cap A) = P( B , A)\).</p>
<p>Considere agora um outro experimento, o lançamento de uma <strong>moeda honesta</strong> e a observância da face virada para cima. Considere a representação <strong>Bernoulli</strong> (\(X_1\)) de ocorrência:</p>
<ul>
<li>
<p>\(0\) caso o resultado do lançamento seja coroa</p>
</li>
<li>
<p>\(1\) caso o resultado do lançamento seja cara</p>
</li>
</ul>
<p>Por ser justa, a probabilidade do resultado cara é \(P(X_1 = 1) = \frac{1}{2}\) e o de coroa é \(P(X_1 = 0) = \frac{1}{2}\).</p>
<p>Em seguida, a moeda é lançada novamente e o resultado representado por \(X_2\). Perceba que nesse caso, a probabilidade da ocorrência de cara no segundo lançamento também é igual a \(P(X_2 = 1) = \frac{1}{2}\) por não ser afetado pelo resultado do primeiro lançamento.</p>
<p>Dizemos que \(X_2\) é <strong>independente</strong> de \(X_1\), e nesse caso, temos que a regra do produto é:</p>
\[P(X_2 , X_1 ) = P(X_2|X_1) P(X_1)\]
\[P(X_2 , X_1 ) = P(X_2)P(X_1 )\]
<h2 id="permutabilidade">Permutabilidade</h2>
<p>Permutabilidade é a propriedade da alteração no ordenamento de realizações em uma sequência de eventos sem que a probabilidade conjunta seja alterada.</p>
<p>Considere o lançamento de \(5\) moedas não viciadas, com representação semelhante a apresentada anteriormente, sendo observado o seguinte resultado \((1,0,1,1,0)\), isto é, (cara,coroa,cara,cara,cora). Sabemos que os lançamentos são <strong>independentes</strong> e que a probabilidade conjunta desse evento é \(P(1,0,1,1,0) = P(X_5 = 1) \times P(X_4 = 0)\times P(X_3 = 1)\times P(X_2 = 1)\times P(X_1 = 0) = \frac{1}{2^5}\).</p>
<p>Nessa situação, caso fosse observado o evento \((1,1,1,0,0)\), a probabilidade não seria alterada, pois \(P(1,0,1,1,0) = P(1,1,1,0,0) =\frac{1}{2^5}\). Dessa forma, a ordem da ocorrências dos resultados cara não altera a probabilidade conjunta, desde que seja a mesma quantidade de resultados de “sucesso”. Esse é uma versão não rigorosa do Teorema de De Finetti.</p>
<p>De maneira geral, a independência de uma sequência de eventos garante a permutabilidade da mesma.</p>
<p>No entanto, a permutabililidade não é condição necessária para a permutabilidade, apenas suficiente. Isto é, ainda que uma sequência não seja formada por eventos independente, é possível que sejam permutáveis.</p>
<p>Considere a mesma representação do exemplo da caixa com bolas apresentado anteriormente para o caso da retirada de \(5\) bolas sem reposição. Como visto, esses eventos não são <strong>independentes</strong>, pois a probabilidade de um determinado evento na sequência, depende do resultado observado nos eventos anteriores.</p>
<p>Dessa forma, vamos verificar se o evento \((1,0,1,1,0)\) é permutável. Inicialmente, vamos calcular a probabilidade \(P(1,0,1,1,0)\):</p>
<p>\(P(1,0,1,1,0) = P(X_1 = 1)\times P(X_2 = 0 | X_1 = 1) \times P(X_3 = 1 |X_2 = 0 , X_1 = 1) \times P(X_4 = 1|X_3 = 1 ,X_2 = 0 , X_1 = 1) \times P(X_5 = 0|X_4 = 1 , X_3 = 1 ,X_2 = 0 , X_1 = 1)\)
\(P(1,0,1,1,0) = \frac{3}{5} \times \frac{2}{4} \times \frac{2}{3} \times \frac{1}{2} \times \frac{1}{1} = \frac{1}{10}\)</p>
<p>Agora, vamos calcular a probabilidade \(P(1,1,1,0,0)\), alterando o resultado do segundo e o quarto evento:</p>
\[P(1,1,1,0,0) = P(X_1 = 1)\times P(X_2 = 1 | X_1 = 1) \times P(X_3 = 1 |X_2 = 1 , X_1 = 1) \times P(X_4 = 0|X_3 = 1 ,X_2 = 1 , X_1 = 1) \times P(X_5 = 0|X_4 = 0 , X_3 = 1 ,X_2 = 1 , X_1 = 1)\]
\[P(1,1,1,0,0) = \frac{3}{5} \times \frac{2}{4} \times \frac{1}{3} \times \frac{2}{2} \times \frac{1}{1} = \frac{1}{10}\]
<p>Dessa forma, embora essa sequência seja formada por eventos dependentes, a ordem desses eventos não altera a probabilidade conjunta, tornando-a permutável.</p>
<h1 id="teorema-de-bayes">Teorema de Bayes</h1>
<p>O teorema de bayes estabelece a seguinte relação entre dois eventos A e B, com probabilidades, respectivamente, P(A) e P(B):</p>
\[P(A|B) = \frac{P( B | A) }{P(B)}P(A)\]
<p>Considerando os eventos \(A\) e \(B\) permutáveis, o termo \(P(A \cap B)\) é igual a \(P( B \cap A )\) e, dessa forma, pode ser escrita como:</p>
\[P( B \cap A ) = P( B | A)P(A)\]
<p>Por fim, tem-se a seguinte relação:</p>
\[P(A|B) = \frac{P( B | A) }{P(B)}P(A)\]
<p>Nesse caso, o probabilidade \(P(A)\) é denominada probabilidade a <em>priori</em>, isto é, a informação sobre o evento \(A\) antes que se soubesse algo sobre o evento \(B\). Mais adiante, quando se tenha conhecimento sobre \(B\), a probabilidade relacionada ao evento \(A\) deve ser atualizada pela probabilidade do evento \(B\). A probabilidade \(P(A/B)\) é agora denominada probabilidade a <em>posteriori</em>. Sendo a razão \(\frac{P(B/A)}{P(B)}\) o fator de atualização das informações sobre o evento \(A\).</p>
<p>Para compreender com mais detalhes o Teorema de Bayes é necessário entender a <strong>regra da probabilidade total (RPT)</strong>, que expressa a probabilidade total de um resultado por meio de vários eventos disjuntos.</p>
<p>Inicialmente, considere o problema em encontrar o valor para a probabilidade do evento \(A\).</p>
<p><img src="/img/bayes/rpt_1.png" alt="alt text" title="Evento $A$ (a)" /></p>
<p>Considere agora que seja possível particionar o espaço \(\Omega\) em partes \(B_i\) sem intersecções entre si. Note que a união das partes \(B_i\) formam \(\Omega\).</p>
<p><img src="/img/bayes/rpt_2.png" alt="alt text" title="Partições $B_i$ em $\Omega$ (b)" /></p>
<p>A probabilidade \(A\) pode ser determinada pela intersecção entre o evento \(A\) e cada partição \(B_i\).</p>
<p><img src="/img/bayes/rpt_3.png" alt="alt text" title="Intersecções entre $A$ e as partições $B_i$ (c)" /></p>
<p><img src="/img/bayes/rpt_4.png" alt="alt text" title="Calculando a probabilidade em $A$ (d)" /></p>
<p>Nos espaços amostrais \(\Omega\) formados pela união de partes \(B_i\) disjuntas (mutuamente exclusivas) a probabilidade de qualquer evento de \(\Omega\) é:</p>
<p>\(P(A) = P(A \cap B_1) + P(A \cap B_2) + ... + P(A \cap B_N)\)
\(P(A) = P(A | B_1)P(B_1)+P(A | B_2)P(B_2) + ... + P(A | B_N)P(B_N)\)</p>
<p>Dessa forma, a probabilidade do evento \(A\) pode ser representado por:</p>
\[P(A) = \sum_{i=1}^N P(A | B_i)P(B_i)\]
<p><strong>Qual a importância desse resultado?</strong></p>
<h1 id="aplicação-simples">Aplicação simples</h1>
<p>Um amigo muito próximo lhe pediu \(R\$ 1.000,00\) emprestado (\(V_{emprestado}\)) para solução financeira de uma emergência. Você é um investidor nato e não suporta a ideia de perder o patrimônio conquistado. Embora você decida ajudar seu amigo, você está preocupado com o <strong>risco</strong> do não pagamento do empréstimo e, por isso, cobrará juros \(T_{juros}\) sobre o montante inicial emprestado:</p>
\[V_{devolvido} = V_{emprestado} \times (1 + T_{juros})\]
<p>Você percebeu que o <strong>valor devolvido</strong> (\(V_{devolvido}\)) do seu “investimento” ao final do período de empréstimo está sujeito às “variações do mercado”, que, nesse caso, estão relacionadas a um evento \textbf{incerto} do não pagamento da dívida. Com isso, você define o <strong>valor esperado</strong> (\(V_{esperado}\)) como o valor recebido ao final do período considerando tal incerteza.</p>
<p>Seja \(A\) o evento indicativo do pagamento do seu amigo, então o valor esperado (\(V_{esperado}\)) ao final do período de empréstimo é a média ponderada entre as possibilidades de valores devolvidos, \(V_{devolvido}\) e \(0\), e suas respectivas probabilidades, \(P(A)\) e \(1 - P(A)\):</p>
<p>\(V_{esperado} = V_{devolvido} \times P(A) + 0 \times [1 - P(A)]\)
\(V_{esperado} = [V_{emprestado} \times (1 + T_{juros})] \times P(A) + 0 \times [1 - P(A)]\)
\(V_{esperado} = [V_{emprestado} \times (1 + T_{juros})] \times P(A)\)</p>
<p>Da relação anterior, é possível obter a a taxa de juros adotada:</p>
\[T_{juros} = \frac{V_{esperado}}{V_{emprestado} \times P(A)} - 1\]
<p>Você decide que o valor dos juros será determinado de maneira que o valor esperado seja igual ao investimento inicial, isto é, \(V_{esperado}=V_{emprestado}\). Dessa forma, a taxa de juros utilizada será:</p>
\[T_{juros} = \frac{1000}{1000 \times P(A)} - 1 = \frac{1}{P(A)} - 1\]
<p>Você utilizará uma <em>proxy</em> o evento \(A\) baseado no cadastro nacional de bons ou maus pagador. Infelizmente, você não tem acesso à esse cadastro. No entanto, você sabe que, assim como você, seu amigo possui conta no banco ABC, que regularmente publica informações agregadas sobre as operações com os clientes.</p>
<p>Tal banco realizou um levantamento informando que \(1\) em cada \(10\) clientes possuem registo ativo no cadastro nacional de maus pagadores. Dessa forma, a probabilidade do pagamento do seu amigo se concretizar é de \(P(A)=\frac{9}{10} = 90\%\).</p>
<p>Dito isso, utilizando a taxa de juros que você deve adotar é:
\(T_{juros} = \frac{1}{0.9} - 1 = 11.111\%\)</p>
<p>Dessa forma, a <em>priori</em>, seu amigo deveria lhe pagar R$ \(1.111,11\) ao final do período para garantir que, em média e desconsiderando inflação, seu investimento inicial seja recuperado.</p>
<p>Nos informativos do banco também consta que \(2\) em cada \(4\) maus pagadores atrasam o pagamento do boleto, enquanto dentre os bons pagadores, apenas \(1\) a cada \(20\) atrasam suas obrigações.</p>
<p>Durante a conversa, seu amigo te informou que possui boletos atrasados nesse banco. Baseado nessa <strong>nova informação</strong>, qual a probabilidade do seu amigo ser mau pagador dado que atrasou o pagamento? Qual a nova taxa de juros que você deve adotar para proteger seu “investimento”?</p>
<p>O Teorema de Bayes responde diretamente essa pergunta. Antes disso, vamos modelar os eventos e identificar suas probabilidades. Considere o evento \(A\) o cliente ser um bom pagador e o evento \(B\) o atraso do pagamento de um boleto da obrigação financeira nesse banco.</p>
<ul>
<li>Ser bom pagador: evento \(A\). Sendo \(P(A)=\frac{9}{10}\).</li>
<li>Ser mal pagador: evento \(A^{c}\). Sendo \(P(A^{c})=1-P(A)=\frac{1}{10}\).</li>
<li>Atraso no pagamento: evento \(B\). Sendo \(P(B)=\) não informado.</li>
<li>Atraso no pagamento dos bons pagadores: evento \(B/A\). Sendo \(P(B/A)=\frac{1}{20}\).</li>
<li>Atraso no pagamento dos mal pagadores: evento \(B/A^{c}\). Sendo \(P(B/A^{c})=\frac{2}{4}\).</li>
<li>Probabilidade do seu amigo ser bom pagadores caso tenha atrasado o pagamento. \(P(A/B)=\)?.</li>
</ul>
<p>Utilizando o Teorema de Bayes e a RPT em \(P(B)\), tem-se que:</p>
\[P(A|B) =\frac{P( B|A) }{P(B)}P(A)\]
\[P(A|B) = \left[ \frac{P( B | A) }{P(B | A)P(A)+P(B | A^{c})P(A^{c})}\right]P(A)\]
\[P(A|B) = \left[ \frac{\frac{1}{20}}{\frac{1}{20}\frac{9}{10}+\frac{2}{4}\frac{1}{10}}\right]\frac{9}{10}\]
\[P(A|B) = \left[ \frac{38}{20}\right]\frac{9}{10}\]
\[P(A|B) = 47.36\%\]
<p>Dessa forma, após saber que ele não pagou o boleto do banco, a probabilidade de ser bom pagador a <em>posteriori</em> reduz em quase a metade da <em>priori</em>. Dessa forma, a nova taxa de juros é \(\frac{1}{0.4736} - 1 = 111.111\%\), fazendo com que o valor cobrado seja de R$ \(2.111,11\).</p>
<p>Esse é uma versão introdutória do Teorema de Bayes e serve para motivação para posts futuros que exigirão mais pré requisitos em teoria de probabilidades. Enquanto isso, vamos ver uma aplicação me modelos de séries temporais das propriedades do Teorema de Bayes.</p>
<h1 id="modelos-de-espaços-de-estados">Modelos de Espaços de Estados</h1>
<p>Os modelos de Espaços de Estados são uma classe de modelos utilizados para estudar e conhecer séries temporais, conjunto de valores observados ao longo de instantes no tempo, podendo ser representado por \((Y_t)_{(t>0)}\), sendo \(t=1,2,\cdots,T\) o indexador que representa o instante de mensuração da quantidade.</p>
<p>Considere a seguinte estrutura de dependência para a série temporal \(Y_t\):</p>
\[Y_t = f(\theta) + \epsilon_t\]
<p>É importante notar que a \(Y_1,Y_2,....,Y_T\) é <strong>condicionamente independente</strong> por meio de uma função do parâmetro \(\theta\). Em outras palavras, as informações em \(t\) são independentes das em \(t-1\), condicionadas a informação de \(\theta\). Como exemplo, para \(t=2\), essa relação é determinada pelo resultado \(P(Y_2/Y_1,\theta) = P(Y_2/\theta)\). Para \(t\) qualquer, tem-se que \(P(Y_t/Y_1,Y_2,...,Y_{t-1},\theta) = P(Y_t/\theta)\).</p>
<p>Essa propriedade permite que a distribuição conjunta dessa série possa ser reescrita por:</p>
\[P(Y_T,....,Y_1|\theta) = \frac{P(Y_T,....,Y_1,\theta)}{P(\theta)}\]
\[P(Y_T,....,Y_1|\theta) = \frac{P(Y_T|Y_{T-1},....,Y_2,Y_1,\theta)P(Y_{T-1},....,Y_2,Y_1,\theta)}{P(\theta)}\]
\[P(Y_T,....,Y_1|\theta) = P(Y_T|\theta)\frac{P(Y_{T-1},....,Y_2,Y_1,\theta)}{P(\theta)}\]
<p>Replicando esse procedimento para a série inteira, não é difícil chegar a seguinte resultado:</p>
\[P(Y_T,....,Y_1|\theta) = \prod^T_{t=1} P(Y_t|\theta)P(\theta)\]
<p>Dessa forma, a distribuição conjunta dessa série é incrementada sequêncialmente a cada nova informação \(Y_t\) por meio da distribuição condicional \(P(Y_t/\theta)\). Dessa relação, é possível obter <strong>atualizações</strong> sobre \(\theta\). Vamos entender esse conceito com o estudo de um caso.</p>
<h1 id="modelos-gaussianos">Modelos Gaussianos</h1>
<p>Um investidor está interessado em conhecer melhor o comportamento dos retornos mensais do Índice Ibovespa utilizando a estrutura de dependência apresentada anteriormente:</p>
\[Y_t = \theta + \epsilon_t\]
<p>Com \(\epsilon_t \sim N(0,\sigma^2)\), sendo \(\sigma^2\) conhecido e igual a \(5\). Nesse caso, temos a dependência condicional \(Y_1,Y_2,...,Y_T/\theta \sim N(\theta,\sigma^2)\)</p>
<p>Conversando com colegas ele obteve a <strong>informação inicial</strong> de que o comportamento da média dos retornos mensais (\(\theta\)) tem distribuição Normal como média \(\eta_0=2\) e variância \(\phi_0^2 = 2\). Essa é a informação a <em>priori</em> do parâmetro da série temporal de interesse. Com base nessa informação, o investidor pretende observar os índices ao final de cada mês e <strong>atualizar</strong> o conhecimento sobre \(\theta\), a distribuição a <em>posteriori</em>, a medida que novas observações da série do índice mensal do Ibovespa \(Y_t\) estejam disponíveis.</p>
<p>Sabendo que o valor do índice Ibovespa para janeiro de 2017 foi <a href="http://www.bmfbovespa.com.br/pt_br/servicos/market-data/historico/mercado-a-vista/series-historicas/">\(Y_1=7.38\)</a>, qual é a distribuição e os parâmetros da <em>posteriori</em> \(P(\theta/Y_1)\)?</p>
<p>Ao final do primeiro mês o investidor pretende obter a distribuição \(P(\theta/Y_1)\) e para isso utiliza o Teorema de Bayes, chegando a seguinte relação:</p>
\[P(\theta|Y_1) = \frac{P(Y_1,\theta)}{p(Y_1)} = \frac{P(Y_1|\theta) P(\theta)}{\int P(Y_1|\theta) P(\theta)}\]
<p>O desafio, nesse ponto, é obter a distribuição conjunta \(P(Y_1,\theta)\) por meio do produto entre a probabilidade da série \(Y_1\), \(P(Y_1/\theta)\), e a <em>priori</em> do parâmetro \(\theta\), \(P(\theta)\). Utilizando informaçõe das distribuições normais informadas, temos que:</p>
\[P(Y_1,\theta) = P(Y_1|\theta) P(\theta)\]
\[P(Y_1,\theta) = (2 \sigma^2)^{-\frac{1}{2}}e^{[-(2\sigma^2)^{-1}(y_1 - \theta)^2]} \times (2\phi_0^2)^{-\frac{1}{2}}e^{[-(2\phi_0^2)^{-1}(\theta - \eta_0)^2]}\]
\[P(Y_1,\theta) = (2 \sigma^2)^{-\frac{1}{2}} e^{[-(2\sigma^2)^{-1}(y_1^2 - 2y\theta + \theta^2)]} \times (2\phi_0^2)^{-\frac{1}{2}}e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0 + \eta_0^2)]}\]
\[P(Y_1,\theta) = \left[(2 \sigma^2)^{-\frac{1}{2}}(2\phi_0^2)^{-\frac{1}{2}}\right]\times\left[ e^{[-(2\sigma^2)^{-1}( \theta^2 - 2y_1\theta )]} \times e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0)]} \right]\times\left[ e^{[-(2\sigma^2)^{-1}(y^2)]} e^{[-(2\phi_0^2)^{-1}(\eta_0^2)]}\right]\]
\[P(Y_1,\theta) = c3\times\left[ e^{[-(2\sigma^2)^{-1}( \theta^2 - 2y_1\theta )]} \times e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0)]} \right]\]
\[P(Y_1,\theta) = c3\times\left[ e^{[-(2\sigma^2)^{-1}( \theta^2 - 2y\theta )]} \times e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0)]} \right]\]
\[P(Y_1,\theta) = c3\times\left[ e^{[-(2)^{-1}( \theta^2 (\sigma^{-2} + \phi_0^{-2}) - 2\theta(y_1\sigma^{-2} + \eta_0 \phi_0^{-2}) )]} \right]\]
\[P(Y_1,\theta) = c3\times\left[ e^{[-(2)^{-1}(\sigma^{-2} + \phi_0^{-2})( \theta^2 - 2\theta\frac{(y_1\sigma^{-2} + \eta_0 \phi_0^{-2})}{(\sigma^{-2} + \phi_0^{-2})} )]} \right]\]
<p>Perceba que, a menos de constantes, essa distribuição conjunta tem o núcleo de uma distribuição normal com média:</p>
\[\frac{(y\sigma^{-2} + \eta \phi^{-2})}{(\sigma^{-2} + \phi^{-2})} = \frac{y_1\phi^2 + \eta \sigma^2}{\sigma^2 + \eta^2} = \frac{7.38 \times 2 + 2 \times 5}{2 + 5} = 3.53\]
<p>e variância</p>
\[\frac{1}{\sigma^{-2} + \phi^{-2}} = \frac{1}{5^{-1} + 2^{-1}} = 1.42\]
<p>Perceba que o denominador é a integração dessa distribuição conjunta (numerador) com relação a \(\theta\) e, com um pouco de esforço algébrico, é a <strong>constante normalizadora</strong>. Mais detalhes dos processo podem ser consultados em Petris et al (2009).</p>
<p>Dessa forma, temos que \(\theta/Y_1 \sim N(3.53,1.42)\). Essa é a distribuição a <em>posteriori</em> de \(\theta\) com relação a informação \(Y_1\). O gráfico a seguir apresenta a comparação entre as distribuições <em>priori</em> e <em>posteriori</em>.</p>
<p><img src="/img/bayes/priori.png" alt="alt text" title="Comparação entre priori e posteriori" /></p>
<p>A distribuição a <em>posteriori</em> tem seus parâmetros \(\eta_t\) e \(\phi_t\) atualizados no instante \(t\) a medida que se tenha acesso a novas informações da série temporal. Em todos esses instantes, a <em>posteriori</em> obtida no passo \(t\) é a nova <em>priori</em> para a estimação em \(t+1\).</p>
<p>A repetição do processo de estimação em um instante \(t\) qualquer fornece o seguinte resultado:</p>
\[\theta|Y_1,Y_2,...Y_t \sim N(\eta_t,\phi_t)\]
<p>Sendo \(\eta_t\) a média entre a o valor inical \(\eta_0\) e a média da série \(Y_1,...,Y_t\) ponderados pelas variâncias do processo:</p>
\[\eta_t = \frac{\frac{\sum_{i=1}^t y_i}{t} \phi_0^2 + \eta_0 \frac{\sigma^2}{t}}{\frac{\sigma^2}{t} + \eta_0^2}\]
<p>e a variância</p>
\[\phi_t = t\sigma^{-2} + \phi_0^{-2}\]
<p>A programação em R a seguir calcula os valores a <em>posteriori</em> a cada nova observação do índice Ibovespa para o ano 2017. Note que em cada período são utilizadas as informações acumuladas até o instante de análise, determinado pelo comando “y[1:i]”.</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## IBOV time series 2017</span><span class="w">
</span><span class="n">y</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="m">7.38</span><span class="p">,</span><span class="m">3.08</span><span class="p">,</span><span class="m">-2.52</span><span class="p">,</span><span class="m">0.64</span><span class="p">,</span><span class="m">-4.12</span><span class="p">,</span><span class="m">0.3</span><span class="p">,</span><span class="m">4.8</span><span class="p">)</span><span class="w">
</span><span class="c1">## parameters </span><span class="w">
</span><span class="n">sigma</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">5</span><span class="w">
</span><span class="n">eta</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">2</span><span class="w">
</span><span class="n">phi</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="m">2</span><span class="w">
</span><span class="c1">## posteriori eta</span><span class="w">
</span><span class="n">etat</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">y</span><span class="p">,</span><span class="n">sigma</span><span class="p">,</span><span class="n">eta</span><span class="p">,</span><span class="n">phi</span><span class="p">){</span><span class="w">
</span><span class="n">t</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w">
</span><span class="nf">return</span><span class="p">((</span><span class="n">mean</span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="o">*</span><span class="n">phi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">eta</span><span class="o">*</span><span class="n">sigma</span><span class="o">/</span><span class="n">t</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">phi</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">sigma</span><span class="o">/</span><span class="n">t</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c1">## posteriori phit</span><span class="w">
</span><span class="n">phit</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">y</span><span class="p">,</span><span class="n">sigma</span><span class="p">,</span><span class="n">phi</span><span class="p">){</span><span class="w">
</span><span class="n">t</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">length</span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="w">
</span><span class="nf">return</span><span class="p">((</span><span class="n">phi</span><span class="w"> </span><span class="o">*</span><span class="n">sigma</span><span class="p">)</span><span class="o">/</span><span class="p">(</span><span class="n">t</span><span class="o">*</span><span class="n">phi</span><span class="w"> </span><span class="o">+</span><span class="n">sigma</span><span class="w"> </span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="c1">## storing posteriori values </span><span class="w">
</span><span class="n">mus</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
</span><span class="n">ss</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="kc">NULL</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="nf">length</span><span class="p">(</span><span class="n">y</span><span class="p">)){</span><span class="w">
</span><span class="n">mus</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">mus</span><span class="p">,</span><span class="n">etat</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="n">i</span><span class="p">],</span><span class="n">sigma</span><span class="p">,</span><span class="n">eta</span><span class="p">,</span><span class="n">phi</span><span class="p">))</span><span class="w">
</span><span class="n">ss</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="n">ss</span><span class="p">,</span><span class="n">phit</span><span class="p">(</span><span class="n">y</span><span class="p">[</span><span class="m">1</span><span class="o">:</span><span class="n">i</span><span class="p">],</span><span class="n">sigma</span><span class="p">,</span><span class="n">phi</span><span class="p">))</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>O gráfico a seguir apresenta os retornos mensais do Ibovespa durante 2017 e o valor médio a <em>posteriori</em> do parâmetro \(\theta\).</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">## first axis eta</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">mus</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="o">=</span><span class="s2">"o"</span><span class="p">,</span><span class="n">main</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Ibovespa 2017"</span><span class="p">,</span><span class="w">
</span><span class="n">ylab</span><span class="o">=</span><span class="nf">expression</span><span class="p">(</span><span class="n">eta</span><span class="p">),</span><span class="n">xlab</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"t"</span><span class="p">,</span><span class="n">xaxt</span><span class="o">=</span><span class="s1">'n'</span><span class="p">,</span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"red"</span><span class="p">)</span><span class="w">
</span><span class="n">axis</span><span class="p">(</span><span class="n">side</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">at</span><span class="w"> </span><span class="o">=</span><span class="m">1</span><span class="o">:</span><span class="m">7</span><span class="p">,</span><span class="w">
</span><span class="n">labels</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s2">"Jan"</span><span class="p">,</span><span class="s2">"Feb"</span><span class="p">,</span><span class="s2">"Mar"</span><span class="p">,</span><span class="s2">"Apr"</span><span class="p">,</span><span class="s2">"May"</span><span class="p">,</span><span class="s2">"Jun"</span><span class="p">,</span><span class="s2">"Jul"</span><span class="p">))</span><span class="w">
</span><span class="n">legend</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">5.5</span><span class="p">,</span><span class="n">y</span><span class="o">=</span><span class="w"> </span><span class="m">3.6</span><span class="p">,</span><span class="w">
</span><span class="n">legend</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="nf">expression</span><span class="p">(</span><span class="n">eta</span><span class="p">),</span><span class="w"> </span><span class="nf">expression</span><span class="p">(</span><span class="n">Y</span><span class="p">[</span><span class="n">t</span><span class="p">])),</span><span class="w">
</span><span class="n">lty</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="m">2</span><span class="p">),</span><span class="w"> </span><span class="n">pch</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="m">16</span><span class="p">),</span><span class="w"> </span><span class="n">col</span><span class="o">=</span><span class="nf">c</span><span class="p">(</span><span class="s2">"red"</span><span class="p">,</span><span class="w"> </span><span class="s2">"black"</span><span class="p">),</span><span class="n">box.col</span><span class="o">=</span><span class="m">0</span><span class="p">,</span><span class="n">cex</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">.75</span><span class="p">)</span><span class="w">
</span><span class="c1">## second axis ibov time series</span><span class="w">
</span><span class="n">par</span><span class="p">(</span><span class="n">new</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">T</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">y</span><span class="p">,</span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">7</span><span class="p">)</span><span class="o">/</span><span class="m">8</span><span class="p">,</span><span class="w"> </span><span class="n">type</span><span class="o">=</span><span class="s2">"o"</span><span class="p">,</span><span class="w"> </span><span class="n">pch</span><span class="o">=</span><span class="m">16</span><span class="p">,</span><span class="w"> </span><span class="n">lty</span><span class="o">=</span><span class="m">2</span><span class="p">,</span><span class="w"> </span><span class="n">axes</span><span class="o">=</span><span class="nb">F</span><span class="p">,</span><span class="w"> </span><span class="n">xlab</span><span class="o">=</span><span class="kc">NA</span><span class="p">,</span><span class="w"> </span><span class="n">ylab</span><span class="o">=</span><span class="kc">NA</span><span class="p">,</span><span class="w"> </span><span class="n">cex</span><span class="o">=</span><span class="m">1.2</span><span class="p">)</span><span class="w">
</span><span class="n">axis</span><span class="p">(</span><span class="n">side</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">4</span><span class="p">)</span><span class="w">
</span><span class="n">mtext</span><span class="p">(</span><span class="n">side</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">4</span><span class="p">,</span><span class="w"> </span><span class="n">line</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="nf">expression</span><span class="p">(</span><span class="n">y_t</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/bayes/update.png" alt="alt text" title="Estimativas a posteriori em 2017 para o retornos mensais Ibovespa" /></p>
<h1 id="considerações-finais">Considerações finais</h1>
<p>O conteúdo do post, embora simples, apresenta de que maneira a Teoria Bayesiana é utlizada para modelos de séries temporais, permitindo que haja a atualização do conhecimento a medida que se tenha acesso a novas informações.</p>
<p>Por fim, é possível destacar três avanços em estudo nessa área:</p>
<ul>
<li>
<p>estrutura de dependência temporal que incorpore tendência e sazonalidade</p>
</li>
<li>
<p>relações não gaussianas e não-lineares.</p>
</li>
<li>
<p>aumentar número de parâmetros desconhecidos ( ex.: \(\sigma^2\))</p>
</li>
</ul>
<p>O aumento da complexidade requer a utilização de técnicas estatísticas e computacionais mais sofisticadas para lidar com o processo de estimação. É comum encontrar distribuições a <em>posteriori</em> que não tenham formas fechadas ou situações com alta dimensão em virtudo da quantidade de parâmetros e tamanho da série temporal. Nesses casos, técnicas como <a href="https://lamfo-unb.github.io/2017/06/28/Bootstrap/">Bootstrap</a>, MCMC, Gibbs Sampler e Filtro de Partículas podem ser adotadas.</p>
<h2 id="referências">Referências</h2>
<p>Todhunter, Isaac (1873). History of the Mathematical Theories of Attraction and Figure of the Earth from Newton to Laplace.</p>
<p>David, F. N. (1962). Games, gods and gambling.</p>
<p>Petris, Giovanni, Sonia Petrone, and Patrizia Campagnoli. (2009). Dynamic Linear Models With R.</p>
Uma_visão_amigável_do_teorema_de_bayes2017-07-31T00:00:00+00:00http://lamfo-unb.github.io/2017/07/31/Uma_visão_amigável_do_Teorema_de_Bayes<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="pt" xml:lang="pt">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="pandoc" />
<meta name="author" content="Igor Nascimento" />
<title>Fundamentos da Inferência Bayesiana</title>
<script src="data:application/x-javascript;base64,LyohIGpRdWVyeSB2MS4xMS4zIHwgKGMpIDIwMDUsIDIwMTUgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8KIWZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBtb2R1bGUmJiJvYmplY3QiPT10eXBlb2YgbW9kdWxlLmV4cG9ydHM/bW9kdWxlLmV4cG9ydHM9YS5kb2N1bWVudD9iKGEsITApOmZ1bmN0aW9uKGEpe2lmKCFhLmRvY3VtZW50KXRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpO3JldHVybiBiKGEpfTpiKGEpfSgidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6dGhpcyxmdW5jdGlvbihhLGIpe3ZhciBjPVtdLGQ9Yy5zbGljZSxlPWMuY29uY2F0LGY9Yy5wdXNoLGc9Yy5pbmRleE9mLGg9e30saT1oLnRvU3RyaW5nLGo9aC5oYXNPd25Qcm9wZXJ0eSxrPXt9LGw9IjEuMTEuMyIsbT1mdW5jdGlvbihhLGIpe3JldHVybiBuZXcgbS5mbi5pbml0KGEsYil9LG49L15bXHNcdUZFRkZceEEwXSt8W1xzXHVGRUZGXHhBMF0rJC9nLG89L14tbXMtLyxwPS8tKFtcZGEtel0pL2dpLHE9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYi50b1VwcGVyQ2FzZSgpfTttLmZuPW0ucHJvdG90eXBlPXtqcXVlcnk6bCxjb25zdHJ1Y3RvcjptLHNlbGVjdG9yOiIiLGxlbmd0aDowLHRvQXJyYXk6ZnVuY3Rpb24oKXtyZXR1cm4gZC5jYWxsKHRoaXMpfSxnZXQ6ZnVuY3Rpb24oYSl7cmV0dXJuIG51bGwhPWE/MD5hP3RoaXNbYSt0aGlzLmxlbmd0aF06dGhpc1thXTpkLmNhbGwodGhpcyl9LHB1c2hTdGFjazpmdW5jdGlvbihhKXt2YXIgYj1tLm1lcmdlKHRoaXMuY29uc3RydWN0b3IoKSxhKTtyZXR1cm4gYi5wcmV2T2JqZWN0PXRoaXMsYi5jb250ZXh0PXRoaXMuY29udGV4dCxifSxlYWNoOmZ1bmN0aW9uKGEsYil7cmV0dXJuIG0uZWFjaCh0aGlzLGEsYil9LG1hcDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5wdXNoU3RhY2sobS5tYXAodGhpcyxmdW5jdGlvbihiLGMpe3JldHVybiBhLmNhbGwoYixjLGIpfSkpfSxzbGljZTpmdW5jdGlvbigpe3JldHVybiB0aGlzLnB1c2hTdGFjayhkLmFwcGx5KHRoaXMsYXJndW1lbnRzKSl9LGZpcnN0OmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZXEoMCl9LGxhc3Q6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5lcSgtMSl9LGVxOmZ1bmN0aW9uKGEpe3ZhciBiPXRoaXMubGVuZ3RoLGM9K2ErKDA+YT9iOjApO3JldHVybiB0aGlzLnB1c2hTdGFjayhjPj0wJiZiPmM/W3RoaXNbY11dOltdKX0sZW5kOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMucHJldk9iamVjdHx8dGhpcy5jb25zdHJ1Y3RvcihudWxsKX0scHVzaDpmLHNvcnQ6Yy5zb3J0LHNwbGljZTpjLnNwbGljZX0sbS5leHRlbmQ9bS5mbi5leHRlbmQ9ZnVuY3Rpb24oKXt2YXIgYSxiLGMsZCxlLGYsZz1hcmd1bWVudHNbMF18fHt9LGg9MSxpPWFyZ3VtZW50cy5sZW5ndGgsaj0hMTtmb3IoImJvb2xlYW4iPT10eXBlb2YgZyYmKGo9ZyxnPWFyZ3VtZW50c1toXXx8e30saCsrKSwib2JqZWN0Ij09dHlwZW9mIGd8fG0uaXNGdW5jdGlvbihnKXx8KGc9e30pLGg9PT1pJiYoZz10aGlzLGgtLSk7aT5oO2grKylpZihudWxsIT0oZT1hcmd1bWVudHNbaF0pKWZvcihkIGluIGUpYT1nW2RdLGM9ZVtkXSxnIT09YyYmKGomJmMmJihtLmlzUGxhaW5PYmplY3QoYyl8fChiPW0uaXNBcnJheShjKSkpPyhiPyhiPSExLGY9YSYmbS5pc0FycmF5KGEpP2E6W10pOmY9YSYmbS5pc1BsYWluT2JqZWN0KGEpP2E6e30sZ1tkXT1tLmV4dGVuZChqLGYsYykpOnZvaWQgMCE9PWMmJihnW2RdPWMpKTtyZXR1cm4gZ30sbS5leHRlbmQoe2V4cGFuZG86ImpRdWVyeSIrKGwrTWF0aC5yYW5kb20oKSkucmVwbGFjZSgvXEQvZywiIiksaXNSZWFkeTohMCxlcnJvcjpmdW5jdGlvbihhKXt0aHJvdyBuZXcgRXJyb3IoYSl9LG5vb3A6ZnVuY3Rpb24oKXt9LGlzRnVuY3Rpb246ZnVuY3Rpb24oYSl7cmV0dXJuImZ1bmN0aW9uIj09PW0udHlwZShhKX0saXNBcnJheTpBcnJheS5pc0FycmF5fHxmdW5jdGlvbihhKXtyZXR1cm4iYXJyYXkiPT09bS50eXBlKGEpfSxpc1dpbmRvdzpmdW5jdGlvbihhKXtyZXR1cm4gbnVsbCE9YSYmYT09YS53aW5kb3d9LGlzTnVtZXJpYzpmdW5jdGlvbihhKXtyZXR1cm4hbS5pc0FycmF5KGEpJiZhLXBhcnNlRmxvYXQoYSkrMT49MH0saXNFbXB0eU9iamVjdDpmdW5jdGlvbihhKXt2YXIgYjtmb3IoYiBpbiBhKXJldHVybiExO3JldHVybiEwfSxpc1BsYWluT2JqZWN0OmZ1bmN0aW9uKGEpe3ZhciBiO2lmKCFhfHwib2JqZWN0IiE9PW0udHlwZShhKXx8YS5ub2RlVHlwZXx8bS5pc1dpbmRvdyhhKSlyZXR1cm4hMTt0cnl7aWYoYS5jb25zdHJ1Y3RvciYmIWouY2FsbChhLCJjb25zdHJ1Y3RvciIpJiYhai5jYWxsKGEuY29uc3RydWN0b3IucHJvdG90eXBlLCJpc1Byb3RvdHlwZU9mIikpcmV0dXJuITF9Y2F0Y2goYyl7cmV0dXJuITF9aWYoay5vd25MYXN0KWZvcihiIGluIGEpcmV0dXJuIGouY2FsbChhLGIpO2ZvcihiIGluIGEpO3JldHVybiB2b2lkIDA9PT1ifHxqLmNhbGwoYSxiKX0sdHlwZTpmdW5jdGlvbihhKXtyZXR1cm4gbnVsbD09YT9hKyIiOiJvYmplY3QiPT10eXBlb2YgYXx8ImZ1bmN0aW9uIj09dHlwZW9mIGE/aFtpLmNhbGwoYSldfHwib2JqZWN0Ijp0eXBlb2YgYX0sZ2xvYmFsRXZhbDpmdW5jdGlvbihiKXtiJiZtLnRyaW0oYikmJihhLmV4ZWNTY3JpcHR8fGZ1bmN0aW9uKGIpe2EuZXZhbC5jYWxsKGEsYil9KShiKX0sY2FtZWxDYXNlOmZ1bmN0aW9uKGEpe3JldHVybiBhLnJlcGxhY2UobywibXMtIikucmVwbGFjZShwLHEpfSxub2RlTmFtZTpmdW5jdGlvbihhLGIpe3JldHVybiBhLm5vZGVOYW1lJiZhLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT1iLnRvTG93ZXJDYXNlKCl9LGVhY2g6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkLGU9MCxmPWEubGVuZ3RoLGc9cihhKTtpZihjKXtpZihnKXtmb3IoO2Y+ZTtlKyspaWYoZD1iLmFwcGx5KGFbZV0sYyksZD09PSExKWJyZWFrfWVsc2UgZm9yKGUgaW4gYSlpZihkPWIuYXBwbHkoYVtlXSxjKSxkPT09ITEpYnJlYWt9ZWxzZSBpZihnKXtmb3IoO2Y+ZTtlKyspaWYoZD1iLmNhbGwoYVtlXSxlLGFbZV0pLGQ9PT0hMSlicmVha31lbHNlIGZvcihlIGluIGEpaWYoZD1iLmNhbGwoYVtlXSxlLGFbZV0pLGQ9PT0hMSlicmVhaztyZXR1cm4gYX0sdHJpbTpmdW5jdGlvbihhKXtyZXR1cm4gbnVsbD09YT8iIjooYSsiIikucmVwbGFjZShuLCIiKX0sbWFrZUFycmF5OmZ1bmN0aW9uKGEsYil7dmFyIGM9Ynx8W107cmV0dXJuIG51bGwhPWEmJihyKE9iamVjdChhKSk/bS5tZXJnZShjLCJzdHJpbmciPT10eXBlb2YgYT9bYV06YSk6Zi5jYWxsKGMsYSkpLGN9LGluQXJyYXk6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkO2lmKGIpe2lmKGcpcmV0dXJuIGcuY2FsbChiLGEsYyk7Zm9yKGQ9Yi5sZW5ndGgsYz1jPzA+Yz9NYXRoLm1heCgwLGQrYyk6YzowO2Q+YztjKyspaWYoYyBpbiBiJiZiW2NdPT09YSlyZXR1cm4gY31yZXR1cm4tMX0sbWVyZ2U6ZnVuY3Rpb24oYSxiKXt2YXIgYz0rYi5sZW5ndGgsZD0wLGU9YS5sZW5ndGg7d2hpbGUoYz5kKWFbZSsrXT1iW2QrK107aWYoYyE9PWMpd2hpbGUodm9pZCAwIT09YltkXSlhW2UrK109YltkKytdO3JldHVybiBhLmxlbmd0aD1lLGF9LGdyZXA6ZnVuY3Rpb24oYSxiLGMpe2Zvcih2YXIgZCxlPVtdLGY9MCxnPWEubGVuZ3RoLGg9IWM7Zz5mO2YrKylkPSFiKGFbZl0sZiksZCE9PWgmJmUucHVzaChhW2ZdKTtyZXR1cm4gZX0sbWFwOmZ1bmN0aW9uKGEsYixjKXt2YXIgZCxmPTAsZz1hLmxlbmd0aCxoPXIoYSksaT1bXTtpZihoKWZvcig7Zz5mO2YrKylkPWIoYVtmXSxmLGMpLG51bGwhPWQmJmkucHVzaChkKTtlbHNlIGZvcihmIGluIGEpZD1iKGFbZl0sZixjKSxudWxsIT1kJiZpLnB1c2goZCk7cmV0dXJuIGUuYXBwbHkoW10saSl9LGd1aWQ6MSxwcm94eTpmdW5jdGlvbihhLGIpe3ZhciBjLGUsZjtyZXR1cm4ic3RyaW5nIj09dHlwZW9mIGImJihmPWFbYl0sYj1hLGE9ZiksbS5pc0Z1bmN0aW9uKGEpPyhjPWQuY2FsbChhcmd1bWVudHMsMiksZT1mdW5jdGlvbigpe3JldHVybiBhLmFwcGx5KGJ8fHRoaXMsYy5jb25jYXQoZC5jYWxsKGFyZ3VtZW50cykpKX0sZS5ndWlkPWEuZ3VpZD1hLmd1aWR8fG0uZ3VpZCsrLGUpOnZvaWQgMH0sbm93OmZ1bmN0aW9uKCl7cmV0dXJuK25ldyBEYXRlfSxzdXBwb3J0Omt9KSxtLmVhY2goIkJvb2xlYW4gTnVtYmVyIFN0cmluZyBGdW5jdGlvbiBBcnJheSBEYXRlIFJlZ0V4cCBPYmplY3QgRXJyb3IiLnNwbGl0KCIgIiksZnVuY3Rpb24oYSxiKXtoWyJbb2JqZWN0ICIrYisiXSJdPWIudG9Mb3dlckNhc2UoKX0pO2Z1bmN0aW9uIHIoYSl7dmFyIGI9Imxlbmd0aCJpbiBhJiZhLmxlbmd0aCxjPW0udHlwZShhKTtyZXR1cm4iZnVuY3Rpb24iPT09Y3x8bS5pc1dpbmRvdyhhKT8hMToxPT09YS5ub2RlVHlwZSYmYj8hMDoiYXJyYXkiPT09Y3x8MD09PWJ8fCJudW1iZXIiPT10eXBlb2YgYiYmYj4wJiZiLTEgaW4gYX12YXIgcz1mdW5jdGlvbihhKXt2YXIgYixjLGQsZSxmLGcsaCxpLGosayxsLG0sbixvLHAscSxyLHMsdCx1PSJzaXp6bGUiKzEqbmV3IERhdGUsdj1hLmRvY3VtZW50LHc9MCx4PTAseT1oYSgpLHo9aGEoKSxBPWhhKCksQj1mdW5jdGlvbihhLGIpe3JldHVybiBhPT09YiYmKGw9ITApLDB9LEM9MTw8MzEsRD17fS5oYXNPd25Qcm9wZXJ0eSxFPVtdLEY9RS5wb3AsRz1FLnB1c2gsSD1FLnB1c2gsST1FLnNsaWNlLEo9ZnVuY3Rpb24oYSxiKXtmb3IodmFyIGM9MCxkPWEubGVuZ3RoO2Q+YztjKyspaWYoYVtjXT09PWIpcmV0dXJuIGM7cmV0dXJuLTF9LEs9ImNoZWNrZWR8c2VsZWN0ZWR8YXN5bmN8YXV0b2ZvY3VzfGF1dG9wbGF5fGNvbnRyb2xzfGRlZmVyfGRpc2FibGVkfGhpZGRlbnxpc21hcHxsb29wfG11bHRpcGxlfG9wZW58cmVhZG9ubHl8cmVxdWlyZWR8c2NvcGVkIixMPSJbXFx4MjBcXHRcXHJcXG5cXGZdIixNPSIoPzpcXFxcLnxbXFx3LV18W15cXHgwMC1cXHhhMF0pKyIsTj1NLnJlcGxhY2UoInciLCJ3IyIpLE89IlxcWyIrTCsiKigiK00rIikoPzoiK0wrIiooWypeJHwhfl0/PSkiK0wrIiooPzonKCg/OlxcXFwufFteXFxcXCddKSopJ3xcIigoPzpcXFxcLnxbXlxcXFxcIl0pKilcInwoIitOKyIpKXwpIitMKyIqXFxdIixQPSI6KCIrTSsiKSg/OlxcKCgoJygoPzpcXFxcLnxbXlxcXFwnXSkqKSd8XCIoKD86XFxcXC58W15cXFxcXCJdKSopXCIpfCgoPzpcXFxcLnxbXlxcXFwoKVtcXF1dfCIrTysiKSopfC4qKVxcKXwpIixRPW5ldyBSZWdFeHAoTCsiKyIsImciKSxSPW5ldyBSZWdFeHAoIl4iK0wrIit8KCg/Ol58W15cXFxcXSkoPzpcXFxcLikqKSIrTCsiKyQiLCJnIiksUz1uZXcgUmVnRXhwKCJeIitMKyIqLCIrTCsiKiIpLFQ9bmV3IFJlZ0V4cCgiXiIrTCsiKihbPit+XXwiK0wrIikiK0wrIioiKSxVPW5ldyBSZWdFeHAoIj0iK0wrIiooW15cXF0nXCJdKj8pIitMKyIqXFxdIiwiZyIpLFY9bmV3IFJlZ0V4cChQKSxXPW5ldyBSZWdFeHAoIl4iK04rIiQiKSxYPXtJRDpuZXcgUmVnRXhwKCJeIygiK00rIikiKSxDTEFTUzpuZXcgUmVnRXhwKCJeXFwuKCIrTSsiKSIpLFRBRzpuZXcgUmVnRXhwKCJeKCIrTS5yZXBsYWNlKCJ3IiwidyoiKSsiKSIpLEFUVFI6bmV3IFJlZ0V4cCgiXiIrTyksUFNFVURPOm5ldyBSZWdFeHAoIl4iK1ApLENISUxEOm5ldyBSZWdFeHAoIl46KG9ubHl8Zmlyc3R8bGFzdHxudGh8bnRoLWxhc3QpLShjaGlsZHxvZi10eXBlKSg/OlxcKCIrTCsiKihldmVufG9kZHwoKFsrLV18KShcXGQqKW58KSIrTCsiKig/OihbKy1dfCkiK0wrIiooXFxkKyl8KSkiK0wrIipcXCl8KSIsImkiKSxib29sOm5ldyBSZWdFeHAoIl4oPzoiK0srIikkIiwiaSIpLG5lZWRzQ29udGV4dDpuZXcgUmVnRXhwKCJeIitMKyIqWz4rfl18OihldmVufG9kZHxlcXxndHxsdHxudGh8Zmlyc3R8bGFzdCkoPzpcXCgiK0wrIiooKD86LVxcZCk/XFxkKikiK0wrIipcXCl8KSg/PVteLV18JCkiLCJpIil9LFk9L14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaSxaPS9eaFxkJC9pLCQ9L15bXntdK1x7XHMqXFtuYXRpdmUgXHcvLF89L14oPzojKFtcdy1dKyl8KFx3Kyl8XC4oW1x3LV0rKSkkLyxhYT0vWyt+XS8sYmE9Lyd8XFwvZyxjYT1uZXcgUmVnRXhwKCJcXFxcKFtcXGRhLWZdezEsNn0iK0wrIj98KCIrTCsiKXwuKSIsImlnIiksZGE9ZnVuY3Rpb24oYSxiLGMpe3ZhciBkPSIweCIrYi02NTUzNjtyZXR1cm4gZCE9PWR8fGM/YjowPmQ/U3RyaW5nLmZyb21DaGFyQ29kZShkKzY1NTM2KTpTdHJpbmcuZnJvbUNoYXJDb2RlKGQ+PjEwfDU1Mjk2LDEwMjMmZHw1NjMyMCl9LGVhPWZ1bmN0aW9uKCl7bSgpfTt0cnl7SC5hcHBseShFPUkuY2FsbCh2LmNoaWxkTm9kZXMpLHYuY2hpbGROb2RlcyksRVt2LmNoaWxkTm9kZXMubGVuZ3RoXS5ub2RlVHlwZX1jYXRjaChmYSl7SD17YXBwbHk6RS5sZW5ndGg/ZnVuY3Rpb24oYSxiKXtHLmFwcGx5KGEsSS5jYWxsKGIpKX06ZnVuY3Rpb24oYSxiKXt2YXIgYz1hLmxlbmd0aCxkPTA7d2hpbGUoYVtjKytdPWJbZCsrXSk7YS5sZW5ndGg9Yy0xfX19ZnVuY3Rpb24gZ2EoYSxiLGQsZSl7dmFyIGYsaCxqLGssbCxvLHIscyx3LHg7aWYoKGI/Yi5vd25lckRvY3VtZW50fHxiOnYpIT09biYmbShiKSxiPWJ8fG4sZD1kfHxbXSxrPWIubm9kZVR5cGUsInN0cmluZyIhPXR5cGVvZiBhfHwhYXx8MSE9PWsmJjkhPT1rJiYxMSE9PWspcmV0dXJuIGQ7aWYoIWUmJnApe2lmKDExIT09ayYmKGY9Xy5leGVjKGEpKSlpZihqPWZbMV0pe2lmKDk9PT1rKXtpZihoPWIuZ2V0RWxlbWVudEJ5SWQoaiksIWh8fCFoLnBhcmVudE5vZGUpcmV0dXJuIGQ7aWYoaC5pZD09PWopcmV0dXJuIGQucHVzaChoKSxkfWVsc2UgaWYoYi5vd25lckRvY3VtZW50JiYoaD1iLm93bmVyRG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaikpJiZ0KGIsaCkmJmguaWQ9PT1qKXJldHVybiBkLnB1c2goaCksZH1lbHNle2lmKGZbMl0pcmV0dXJuIEguYXBwbHkoZCxiLmdldEVsZW1lbnRzQnlUYWdOYW1lKGEpKSxkO2lmKChqPWZbM10pJiZjLmdldEVsZW1lbnRzQnlDbGFzc05hbWUpcmV0dXJuIEguYXBwbHkoZCxiLmdldEVsZW1lbnRzQnlDbGFzc05hbWUoaikpLGR9aWYoYy5xc2EmJighcXx8IXEudGVzdChhKSkpe2lmKHM9cj11LHc9Yix4PTEhPT1rJiZhLDE9PT1rJiYib2JqZWN0IiE9PWIubm9kZU5hbWUudG9Mb3dlckNhc2UoKSl7bz1nKGEpLChyPWIuZ2V0QXR0cmlidXRlKCJpZCIpKT9zPXIucmVwbGFjZShiYSwiXFwkJiIpOmIuc2V0QXR0cmlidXRlKCJpZCIscykscz0iW2lkPSciK3MrIiddICIsbD1vLmxlbmd0aDt3aGlsZShsLS0pb1tsXT1zK3JhKG9bbF0pO3c9YWEudGVzdChhKSYmcGEoYi5wYXJlbnROb2RlKXx8Yix4PW8uam9pbigiLCIpfWlmKHgpdHJ5e3JldHVybiBILmFwcGx5KGQsdy5xdWVyeVNlbGVjdG9yQWxsKHgpKSxkfWNhdGNoKHkpe31maW5hbGx5e3J8fGIucmVtb3ZlQXR0cmlidXRlKCJpZCIpfX19cmV0dXJuIGkoYS5yZXBsYWNlKFIsIiQxIiksYixkLGUpfWZ1bmN0aW9uIGhhKCl7dmFyIGE9W107ZnVuY3Rpb24gYihjLGUpe3JldHVybiBhLnB1c2goYysiICIpPmQuY2FjaGVMZW5ndGgmJmRlbGV0ZSBiW2Euc2hpZnQoKV0sYltjKyIgIl09ZX1yZXR1cm4gYn1mdW5jdGlvbiBpYShhKXtyZXR1cm4gYVt1XT0hMCxhfWZ1bmN0aW9uIGphKGEpe3ZhciBiPW4uY3JlYXRlRWxlbWVudCgiZGl2Iik7dHJ5e3JldHVybiEhYShiKX1jYXRjaChjKXtyZXR1cm4hMX1maW5hbGx5e2IucGFyZW50Tm9kZSYmYi5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGIpLGI9bnVsbH19ZnVuY3Rpb24ga2EoYSxiKXt2YXIgYz1hLnNwbGl0KCJ8IiksZT1hLmxlbmd0aDt3aGlsZShlLS0pZC5hdHRySGFuZGxlW2NbZV1dPWJ9ZnVuY3Rpb24gbGEoYSxiKXt2YXIgYz1iJiZhLGQ9YyYmMT09PWEubm9kZVR5cGUmJjE9PT1iLm5vZGVUeXBlJiYofmIuc291cmNlSW5kZXh8fEMpLSh+YS5zb3VyY2VJbmRleHx8Qyk7aWYoZClyZXR1cm4gZDtpZihjKXdoaWxlKGM9Yy5uZXh0U2libGluZylpZihjPT09YilyZXR1cm4tMTtyZXR1cm4gYT8xOi0xfWZ1bmN0aW9uIG1hKGEpe3JldHVybiBmdW5jdGlvbihiKXt2YXIgYz1iLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7cmV0dXJuImlucHV0Ij09PWMmJmIudHlwZT09PWF9fWZ1bmN0aW9uIG5hKGEpe3JldHVybiBmdW5jdGlvbihiKXt2YXIgYz1iLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7cmV0dXJuKCJpbnB1dCI9PT1jfHwiYnV0dG9uIj09PWMpJiZiLnR5cGU9PT1hfX1mdW5jdGlvbiBvYShhKXtyZXR1cm4gaWEoZnVuY3Rpb24oYil7cmV0dXJuIGI9K2IsaWEoZnVuY3Rpb24oYyxkKXt2YXIgZSxmPWEoW10sYy5sZW5ndGgsYiksZz1mLmxlbmd0aDt3aGlsZShnLS0pY1tlPWZbZ11dJiYoY1tlXT0hKGRbZV09Y1tlXSkpfSl9KX1mdW5jdGlvbiBwYShhKXtyZXR1cm4gYSYmInVuZGVmaW5lZCIhPXR5cGVvZiBhLmdldEVsZW1lbnRzQnlUYWdOYW1lJiZhfWM9Z2Euc3VwcG9ydD17fSxmPWdhLmlzWE1MPWZ1bmN0aW9uKGEpe3ZhciBiPWEmJihhLm93bmVyRG9jdW1lbnR8fGEpLmRvY3VtZW50RWxlbWVudDtyZXR1cm4gYj8iSFRNTCIhPT1iLm5vZGVOYW1lOiExfSxtPWdhLnNldERvY3VtZW50PWZ1bmN0aW9uKGEpe3ZhciBiLGUsZz1hP2Eub3duZXJEb2N1bWVudHx8YTp2O3JldHVybiBnIT09biYmOT09PWcubm9kZVR5cGUmJmcuZG9jdW1lbnRFbGVtZW50PyhuPWcsbz1nLmRvY3VtZW50RWxlbWVudCxlPWcuZGVmYXVsdFZpZXcsZSYmZSE9PWUudG9wJiYoZS5hZGRFdmVudExpc3RlbmVyP2UuYWRkRXZlbnRMaXN0ZW5lcigidW5sb2FkIixlYSwhMSk6ZS5hdHRhY2hFdmVudCYmZS5hdHRhY2hFdmVudCgib251bmxvYWQiLGVhKSkscD0hZihnKSxjLmF0dHJpYnV0ZXM9amEoZnVuY3Rpb24oYSl7cmV0dXJuIGEuY2xhc3NOYW1lPSJpIiwhYS5nZXRBdHRyaWJ1dGUoImNsYXNzTmFtZSIpfSksYy5nZXRFbGVtZW50c0J5VGFnTmFtZT1qYShmdW5jdGlvbihhKXtyZXR1cm4gYS5hcHBlbmRDaGlsZChnLmNyZWF0ZUNvbW1lbnQoIiIpKSwhYS5nZXRFbGVtZW50c0J5VGFnTmFtZSgiKiIpLmxlbmd0aH0pLGMuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZT0kLnRlc3QoZy5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSxjLmdldEJ5SWQ9amEoZnVuY3Rpb24oYSl7cmV0dXJuIG8uYXBwZW5kQ2hpbGQoYSkuaWQ9dSwhZy5nZXRFbGVtZW50c0J5TmFtZXx8IWcuZ2V0RWxlbWVudHNCeU5hbWUodSkubGVuZ3RofSksYy5nZXRCeUlkPyhkLmZpbmQuSUQ9ZnVuY3Rpb24oYSxiKXtpZigidW5kZWZpbmVkIiE9dHlwZW9mIGIuZ2V0RWxlbWVudEJ5SWQmJnApe3ZhciBjPWIuZ2V0RWxlbWVudEJ5SWQoYSk7cmV0dXJuIGMmJmMucGFyZW50Tm9kZT9bY106W119fSxkLmZpbHRlci5JRD1mdW5jdGlvbihhKXt2YXIgYj1hLnJlcGxhY2UoY2EsZGEpO3JldHVybiBmdW5jdGlvbihhKXtyZXR1cm4gYS5nZXRBdHRyaWJ1dGUoImlkIik9PT1ifX0pOihkZWxldGUgZC5maW5kLklELGQuZmlsdGVyLklEPWZ1bmN0aW9uKGEpe3ZhciBiPWEucmVwbGFjZShjYSxkYSk7cmV0dXJuIGZ1bmN0aW9uKGEpe3ZhciBjPSJ1bmRlZmluZWQiIT10eXBlb2YgYS5nZXRBdHRyaWJ1dGVOb2RlJiZhLmdldEF0dHJpYnV0ZU5vZGUoImlkIik7cmV0dXJuIGMmJmMudmFsdWU9PT1ifX0pLGQuZmluZC5UQUc9Yy5nZXRFbGVtZW50c0J5VGFnTmFtZT9mdW5jdGlvbihhLGIpe3JldHVybiJ1bmRlZmluZWQiIT10eXBlb2YgYi5nZXRFbGVtZW50c0J5VGFnTmFtZT9iLmdldEVsZW1lbnRzQnlUYWdOYW1lKGEpOmMucXNhP2IucXVlcnlTZWxlY3RvckFsbChhKTp2b2lkIDB9OmZ1bmN0aW9uKGEsYil7dmFyIGMsZD1bXSxlPTAsZj1iLmdldEVsZW1lbnRzQnlUYWdOYW1lKGEpO2lmKCIqIj09PWEpe3doaWxlKGM9ZltlKytdKTE9PT1jLm5vZGVUeXBlJiZkLnB1c2goYyk7cmV0dXJuIGR9cmV0dXJuIGZ9LGQuZmluZC5DTEFTUz1jLmdldEVsZW1lbnRzQnlDbGFzc05hbWUmJmZ1bmN0aW9uKGEsYil7cmV0dXJuIHA/Yi5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKGEpOnZvaWQgMH0scj1bXSxxPVtdLChjLnFzYT0kLnRlc3QoZy5xdWVyeVNlbGVjdG9yQWxsKSkmJihqYShmdW5jdGlvbihhKXtvLmFwcGVuZENoaWxkKGEpLmlubmVySFRNTD0iPGEgaWQ9JyIrdSsiJz48L2E+PHNlbGVjdCBpZD0nIit1KyItXGZdJyBtc2FsbG93Y2FwdHVyZT0nJz48b3B0aW9uIHNlbGVjdGVkPScnPjwvb3B0aW9uPjwvc2VsZWN0PiIsYS5xdWVyeVNlbGVjdG9yQWxsKCJbbXNhbGxvd2NhcHR1cmVePScnXSIpLmxlbmd0aCYmcS5wdXNoKCJbKl4kXT0iK0wrIiooPzonJ3xcIlwiKSIpLGEucXVlcnlTZWxlY3RvckFsbCgiW3NlbGVjdGVkXSIpLmxlbmd0aHx8cS5wdXNoKCJcXFsiK0wrIiooPzp2YWx1ZXwiK0srIikiKSxhLnF1ZXJ5U2VsZWN0b3JBbGwoIltpZH49Iit1KyItXSIpLmxlbmd0aHx8cS5wdXNoKCJ+PSIpLGEucXVlcnlTZWxlY3RvckFsbCgiOmNoZWNrZWQiKS5sZW5ndGh8fHEucHVzaCgiOmNoZWNrZWQiKSxhLnF1ZXJ5U2VsZWN0b3JBbGwoImEjIit1KyIrKiIpLmxlbmd0aHx8cS5wdXNoKCIuIy4rWyt+XSIpfSksamEoZnVuY3Rpb24oYSl7dmFyIGI9Zy5jcmVhdGVFbGVtZW50KCJpbnB1dCIpO2Iuc2V0QXR0cmlidXRlKCJ0eXBlIiwiaGlkZGVuIiksYS5hcHBlbmRDaGlsZChiKS5zZXRBdHRyaWJ1dGUoIm5hbWUiLCJEIiksYS5xdWVyeVNlbGVjdG9yQWxsKCJbbmFtZT1kXSIpLmxlbmd0aCYmcS5wdXNoKCJuYW1lIitMKyIqWypeJHwhfl0/PSIpLGEucXVlcnlTZWxlY3RvckFsbCgiOmVuYWJsZWQiKS5sZW5ndGh8fHEucHVzaCgiOmVuYWJsZWQiLCI6ZGlzYWJsZWQiKSxhLnF1ZXJ5U2VsZWN0b3JBbGwoIiosOngiKSxxLnB1c2goIiwuKjoiKX0pKSwoYy5tYXRjaGVzU2VsZWN0b3I9JC50ZXN0KHM9by5tYXRjaGVzfHxvLndlYmtpdE1hdGNoZXNTZWxlY3Rvcnx8by5tb3pNYXRjaGVzU2VsZWN0b3J8fG8ub01hdGNoZXNTZWxlY3Rvcnx8by5tc01hdGNoZXNTZWxlY3RvcikpJiZqYShmdW5jdGlvbihhKXtjLmRpc2Nvbm5lY3RlZE1hdGNoPXMuY2FsbChhLCJkaXYiKSxzLmNhbGwoYSwiW3MhPScnXTp4Iiksci5wdXNoKCIhPSIsUCl9KSxxPXEubGVuZ3RoJiZuZXcgUmVnRXhwKHEuam9pbigifCIpKSxyPXIubGVuZ3RoJiZuZXcgUmVnRXhwKHIuam9pbigifCIpKSxiPSQudGVzdChvLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKSx0PWJ8fCQudGVzdChvLmNvbnRhaW5zKT9mdW5jdGlvbihhLGIpe3ZhciBjPTk9PT1hLm5vZGVUeXBlP2EuZG9jdW1lbnRFbGVtZW50OmEsZD1iJiZiLnBhcmVudE5vZGU7cmV0dXJuIGE9PT1kfHwhKCFkfHwxIT09ZC5ub2RlVHlwZXx8IShjLmNvbnRhaW5zP2MuY29udGFpbnMoZCk6YS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiYmMTYmYS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihkKSkpfTpmdW5jdGlvbihhLGIpe2lmKGIpd2hpbGUoYj1iLnBhcmVudE5vZGUpaWYoYj09PWEpcmV0dXJuITA7cmV0dXJuITF9LEI9Yj9mdW5jdGlvbihhLGIpe2lmKGE9PT1iKXJldHVybiBsPSEwLDA7dmFyIGQ9IWEuY29tcGFyZURvY3VtZW50UG9zaXRpb24tIWIuY29tcGFyZURvY3VtZW50UG9zaXRpb247cmV0dXJuIGQ/ZDooZD0oYS5vd25lckRvY3VtZW50fHxhKT09PShiLm93bmVyRG9jdW1lbnR8fGIpP2EuY29tcGFyZURvY3VtZW50UG9zaXRpb24oYik6MSwxJmR8fCFjLnNvcnREZXRhY2hlZCYmYi5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbihhKT09PWQ/YT09PWd8fGEub3duZXJEb2N1bWVudD09PXYmJnQodixhKT8tMTpiPT09Z3x8Yi5vd25lckRvY3VtZW50PT09diYmdCh2LGIpPzE6az9KKGssYSktSihrLGIpOjA6NCZkPy0xOjEpfTpmdW5jdGlvbihhLGIpe2lmKGE9PT1iKXJldHVybiBsPSEwLDA7dmFyIGMsZD0wLGU9YS5wYXJlbnROb2RlLGY9Yi5wYXJlbnROb2RlLGg9W2FdLGk9W2JdO2lmKCFlfHwhZilyZXR1cm4gYT09PWc/LTE6Yj09PWc/MTplPy0xOmY/MTprP0ooayxhKS1KKGssYik6MDtpZihlPT09ZilyZXR1cm4gbGEoYSxiKTtjPWE7d2hpbGUoYz1jLnBhcmVudE5vZGUpaC51bnNoaWZ0KGMpO2M9Yjt3aGlsZShjPWMucGFyZW50Tm9kZSlpLnVuc2hpZnQoYyk7d2hpbGUoaFtkXT09PWlbZF0pZCsrO3JldHVybiBkP2xhKGhbZF0saVtkXSk6aFtkXT09PXY/LTE6aVtkXT09PXY/MTowfSxnKTpufSxnYS5tYXRjaGVzPWZ1bmN0aW9uKGEsYil7cmV0dXJuIGdhKGEsbnVsbCxudWxsLGIpfSxnYS5tYXRjaGVzU2VsZWN0b3I9ZnVuY3Rpb24oYSxiKXtpZigoYS5vd25lckRvY3VtZW50fHxhKSE9PW4mJm0oYSksYj1iLnJlcGxhY2UoVSwiPSckMSddIiksISghYy5tYXRjaGVzU2VsZWN0b3J8fCFwfHxyJiZyLnRlc3QoYil8fHEmJnEudGVzdChiKSkpdHJ5e3ZhciBkPXMuY2FsbChhLGIpO2lmKGR8fGMuZGlzY29ubmVjdGVkTWF0Y2h8fGEuZG9jdW1lbnQmJjExIT09YS5kb2N1bWVudC5ub2RlVHlwZSlyZXR1cm4gZH1jYXRjaChlKXt9cmV0dXJuIGdhKGIsbixudWxsLFthXSkubGVuZ3RoPjB9LGdhLmNvbnRhaW5zPWZ1bmN0aW9uKGEsYil7cmV0dXJuKGEub3duZXJEb2N1bWVudHx8YSkhPT1uJiZtKGEpLHQoYSxiKX0sZ2EuYXR0cj1mdW5jdGlvbihhLGIpeyhhLm93bmVyRG9jdW1lbnR8fGEpIT09biYmbShhKTt2YXIgZT1kLmF0dHJIYW5kbGVbYi50b0xvd2VyQ2FzZSgpXSxmPWUmJkQuY2FsbChkLmF0dHJIYW5kbGUsYi50b0xvd2VyQ2FzZSgpKT9lKGEsYiwhcCk6dm9pZCAwO3JldHVybiB2b2lkIDAhPT1mP2Y6Yy5hdHRyaWJ1dGVzfHwhcD9hLmdldEF0dHJpYnV0ZShiKTooZj1hLmdldEF0dHJpYnV0ZU5vZGUoYikpJiZmLnNwZWNpZmllZD9mLnZhbHVlOm51bGx9LGdhLmVycm9yPWZ1bmN0aW9uKGEpe3Rocm93IG5ldyBFcnJvcigiU3ludGF4IGVycm9yLCB1bnJlY29nbml6ZWQgZXhwcmVzc2lvbjogIithKX0sZ2EudW5pcXVlU29ydD1mdW5jdGlvbihhKXt2YXIgYixkPVtdLGU9MCxmPTA7aWYobD0hYy5kZXRlY3REdXBsaWNhdGVzLGs9IWMuc29ydFN0YWJsZSYmYS5zbGljZSgwKSxhLnNvcnQoQiksbCl7d2hpbGUoYj1hW2YrK10pYj09PWFbZl0mJihlPWQucHVzaChmKSk7d2hpbGUoZS0tKWEuc3BsaWNlKGRbZV0sMSl9cmV0dXJuIGs9bnVsbCxhfSxlPWdhLmdldFRleHQ9ZnVuY3Rpb24oYSl7dmFyIGIsYz0iIixkPTAsZj1hLm5vZGVUeXBlO2lmKGYpe2lmKDE9PT1mfHw5PT09Znx8MTE9PT1mKXtpZigic3RyaW5nIj09dHlwZW9mIGEudGV4dENvbnRlbnQpcmV0dXJuIGEudGV4dENvbnRlbnQ7Zm9yKGE9YS5maXJzdENoaWxkO2E7YT1hLm5leHRTaWJsaW5nKWMrPWUoYSl9ZWxzZSBpZigzPT09Znx8ND09PWYpcmV0dXJuIGEubm9kZVZhbHVlfWVsc2Ugd2hpbGUoYj1hW2QrK10pYys9ZShiKTtyZXR1cm4gY30sZD1nYS5zZWxlY3RvcnM9e2NhY2hlTGVuZ3RoOjUwLGNyZWF0ZVBzZXVkbzppYSxtYXRjaDpYLGF0dHJIYW5kbGU6e30sZmluZDp7fSxyZWxhdGl2ZTp7Ij4iOntkaXI6InBhcmVudE5vZGUiLGZpcnN0OiEwfSwiICI6e2RpcjoicGFyZW50Tm9kZSJ9LCIrIjp7ZGlyOiJwcmV2aW91c1NpYmxpbmciLGZpcnN0OiEwfSwifiI6e2RpcjoicHJldmlvdXNTaWJsaW5nIn19LHByZUZpbHRlcjp7QVRUUjpmdW5jdGlvbihhKXtyZXR1cm4gYVsxXT1hWzFdLnJlcGxhY2UoY2EsZGEpLGFbM109KGFbM118fGFbNF18fGFbNV18fCIiKS5yZXBsYWNlKGNhLGRhKSwifj0iPT09YVsyXSYmKGFbM109IiAiK2FbM10rIiAiKSxhLnNsaWNlKDAsNCl9LENISUxEOmZ1bmN0aW9uKGEpe3JldHVybiBhWzFdPWFbMV0udG9Mb3dlckNhc2UoKSwibnRoIj09PWFbMV0uc2xpY2UoMCwzKT8oYVszXXx8Z2EuZXJyb3IoYVswXSksYVs0XT0rKGFbNF0/YVs1XSsoYVs2XXx8MSk6MiooImV2ZW4iPT09YVszXXx8Im9kZCI9PT1hWzNdKSksYVs1XT0rKGFbN10rYVs4XXx8Im9kZCI9PT1hWzNdKSk6YVszXSYmZ2EuZXJyb3IoYVswXSksYX0sUFNFVURPOmZ1bmN0aW9uKGEpe3ZhciBiLGM9IWFbNl0mJmFbMl07cmV0dXJuIFguQ0hJTEQudGVzdChhWzBdKT9udWxsOihhWzNdP2FbMl09YVs0XXx8YVs1XXx8IiI6YyYmVi50ZXN0KGMpJiYoYj1nKGMsITApKSYmKGI9Yy5pbmRleE9mKCIpIixjLmxlbmd0aC1iKS1jLmxlbmd0aCkmJihhWzBdPWFbMF0uc2xpY2UoMCxiKSxhWzJdPWMuc2xpY2UoMCxiKSksYS5zbGljZSgwLDMpKX19LGZpbHRlcjp7VEFHOmZ1bmN0aW9uKGEpe3ZhciBiPWEucmVwbGFjZShjYSxkYSkudG9Mb3dlckNhc2UoKTtyZXR1cm4iKiI9PT1hP2Z1bmN0aW9uKCl7cmV0dXJuITB9OmZ1bmN0aW9uKGEpe3JldHVybiBhLm5vZGVOYW1lJiZhLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT1ifX0sQ0xBU1M6ZnVuY3Rpb24oYSl7dmFyIGI9eVthKyIgIl07cmV0dXJuIGJ8fChiPW5ldyBSZWdFeHAoIihefCIrTCsiKSIrYSsiKCIrTCsifCQpIikpJiZ5KGEsZnVuY3Rpb24oYSl7cmV0dXJuIGIudGVzdCgic3RyaW5nIj09dHlwZW9mIGEuY2xhc3NOYW1lJiZhLmNsYXNzTmFtZXx8InVuZGVmaW5lZCIhPXR5cGVvZiBhLmdldEF0dHJpYnV0ZSYmYS5nZXRBdHRyaWJ1dGUoImNsYXNzIil8fCIiKX0pfSxBVFRSOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gZnVuY3Rpb24oZCl7dmFyIGU9Z2EuYXR0cihkLGEpO3JldHVybiBudWxsPT1lPyIhPSI9PT1iOmI/KGUrPSIiLCI9Ij09PWI/ZT09PWM6IiE9Ij09PWI/ZSE9PWM6Il49Ij09PWI/YyYmMD09PWUuaW5kZXhPZihjKToiKj0iPT09Yj9jJiZlLmluZGV4T2YoYyk+LTE6IiQ9Ij09PWI/YyYmZS5zbGljZSgtYy5sZW5ndGgpPT09Yzoifj0iPT09Yj8oIiAiK2UucmVwbGFjZShRLCIgIikrIiAiKS5pbmRleE9mKGMpPi0xOiJ8PSI9PT1iP2U9PT1jfHxlLnNsaWNlKDAsYy5sZW5ndGgrMSk9PT1jKyItIjohMSk6ITB9fSxDSElMRDpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciBmPSJudGgiIT09YS5zbGljZSgwLDMpLGc9Imxhc3QiIT09YS5zbGljZSgtNCksaD0ib2YtdHlwZSI9PT1iO3JldHVybiAxPT09ZCYmMD09PWU/ZnVuY3Rpb24oYSl7cmV0dXJuISFhLnBhcmVudE5vZGV9OmZ1bmN0aW9uKGIsYyxpKXt2YXIgaixrLGwsbSxuLG8scD1mIT09Zz8ibmV4dFNpYmxpbmciOiJwcmV2aW91c1NpYmxpbmciLHE9Yi5wYXJlbnROb2RlLHI9aCYmYi5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLHM9IWkmJiFoO2lmKHEpe2lmKGYpe3doaWxlKHApe2w9Yjt3aGlsZShsPWxbcF0paWYoaD9sLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk9PT1yOjE9PT1sLm5vZGVUeXBlKXJldHVybiExO289cD0ib25seSI9PT1hJiYhbyYmIm5leHRTaWJsaW5nIn1yZXR1cm4hMH1pZihvPVtnP3EuZmlyc3RDaGlsZDpxLmxhc3RDaGlsZF0sZyYmcyl7az1xW3VdfHwocVt1XT17fSksaj1rW2FdfHxbXSxuPWpbMF09PT13JiZqWzFdLG09alswXT09PXcmJmpbMl0sbD1uJiZxLmNoaWxkTm9kZXNbbl07d2hpbGUobD0rK24mJmwmJmxbcF18fChtPW49MCl8fG8ucG9wKCkpaWYoMT09PWwubm9kZVR5cGUmJisrbSYmbD09PWIpe2tbYV09W3csbixtXTticmVha319ZWxzZSBpZihzJiYoaj0oYlt1XXx8KGJbdV09e30pKVthXSkmJmpbMF09PT13KW09alsxXTtlbHNlIHdoaWxlKGw9KytuJiZsJiZsW3BdfHwobT1uPTApfHxvLnBvcCgpKWlmKChoP2wubm9kZU5hbWUudG9Mb3dlckNhc2UoKT09PXI6MT09PWwubm9kZVR5cGUpJiYrK20mJihzJiYoKGxbdV18fChsW3VdPXt9KSlbYV09W3csbV0pLGw9PT1iKSlicmVhaztyZXR1cm4gbS09ZSxtPT09ZHx8bSVkPT09MCYmbS9kPj0wfX19LFBTRVVETzpmdW5jdGlvbihhLGIpe3ZhciBjLGU9ZC5wc2V1ZG9zW2FdfHxkLnNldEZpbHRlcnNbYS50b0xvd2VyQ2FzZSgpXXx8Z2EuZXJyb3IoInVuc3VwcG9ydGVkIHBzZXVkbzogIithKTtyZXR1cm4gZVt1XT9lKGIpOmUubGVuZ3RoPjE/KGM9W2EsYSwiIixiXSxkLnNldEZpbHRlcnMuaGFzT3duUHJvcGVydHkoYS50b0xvd2VyQ2FzZSgpKT9pYShmdW5jdGlvbihhLGMpe3ZhciBkLGY9ZShhLGIpLGc9Zi5sZW5ndGg7d2hpbGUoZy0tKWQ9SihhLGZbZ10pLGFbZF09IShjW2RdPWZbZ10pfSk6ZnVuY3Rpb24oYSl7cmV0dXJuIGUoYSwwLGMpfSk6ZX19LHBzZXVkb3M6e25vdDppYShmdW5jdGlvbihhKXt2YXIgYj1bXSxjPVtdLGQ9aChhLnJlcGxhY2UoUiwiJDEiKSk7cmV0dXJuIGRbdV0/aWEoZnVuY3Rpb24oYSxiLGMsZSl7dmFyIGYsZz1kKGEsbnVsbCxlLFtdKSxoPWEubGVuZ3RoO3doaWxlKGgtLSkoZj1nW2hdKSYmKGFbaF09IShiW2hdPWYpKX0pOmZ1bmN0aW9uKGEsZSxmKXtyZXR1cm4gYlswXT1hLGQoYixudWxsLGYsYyksYlswXT1udWxsLCFjLnBvcCgpfX0pLGhhczppYShmdW5jdGlvbihhKXtyZXR1cm4gZnVuY3Rpb24oYil7cmV0dXJuIGdhKGEsYikubGVuZ3RoPjB9fSksY29udGFpbnM6aWEoZnVuY3Rpb24oYSl7cmV0dXJuIGE9YS5yZXBsYWNlKGNhLGRhKSxmdW5jdGlvbihiKXtyZXR1cm4oYi50ZXh0Q29udGVudHx8Yi5pbm5lclRleHR8fGUoYikpLmluZGV4T2YoYSk+LTF9fSksbGFuZzppYShmdW5jdGlvbihhKXtyZXR1cm4gVy50ZXN0KGF8fCIiKXx8Z2EuZXJyb3IoInVuc3VwcG9ydGVkIGxhbmc6ICIrYSksYT1hLnJlcGxhY2UoY2EsZGEpLnRvTG93ZXJDYXNlKCksZnVuY3Rpb24oYil7dmFyIGM7ZG8gaWYoYz1wP2IubGFuZzpiLmdldEF0dHJpYnV0ZSgieG1sOmxhbmciKXx8Yi5nZXRBdHRyaWJ1dGUoImxhbmciKSlyZXR1cm4gYz1jLnRvTG93ZXJDYXNlKCksYz09PWF8fDA9PT1jLmluZGV4T2YoYSsiLSIpO3doaWxlKChiPWIucGFyZW50Tm9kZSkmJjE9PT1iLm5vZGVUeXBlKTtyZXR1cm4hMX19KSx0YXJnZXQ6ZnVuY3Rpb24oYil7dmFyIGM9YS5sb2NhdGlvbiYmYS5sb2NhdGlvbi5oYXNoO3JldHVybiBjJiZjLnNsaWNlKDEpPT09Yi5pZH0scm9vdDpmdW5jdGlvbihhKXtyZXR1cm4gYT09PW99LGZvY3VzOmZ1bmN0aW9uKGEpe3JldHVybiBhPT09bi5hY3RpdmVFbGVtZW50JiYoIW4uaGFzRm9jdXN8fG4uaGFzRm9jdXMoKSkmJiEhKGEudHlwZXx8YS5ocmVmfHx+YS50YWJJbmRleCl9LGVuYWJsZWQ6ZnVuY3Rpb24oYSl7cmV0dXJuIGEuZGlzYWJsZWQ9PT0hMX0sZGlzYWJsZWQ6ZnVuY3Rpb24oYSl7cmV0dXJuIGEuZGlzYWJsZWQ9PT0hMH0sY2hlY2tlZDpmdW5jdGlvbihhKXt2YXIgYj1hLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7cmV0dXJuImlucHV0Ij09PWImJiEhYS5jaGVja2VkfHwib3B0aW9uIj09PWImJiEhYS5zZWxlY3RlZH0sc2VsZWN0ZWQ6ZnVuY3Rpb24oYSl7cmV0dXJuIGEucGFyZW50Tm9kZSYmYS5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXgsYS5zZWxlY3RlZD09PSEwfSxlbXB0eTpmdW5jdGlvbihhKXtmb3IoYT1hLmZpcnN0Q2hpbGQ7YTthPWEubmV4dFNpYmxpbmcpaWYoYS5ub2RlVHlwZTw2KXJldHVybiExO3JldHVybiEwfSxwYXJlbnQ6ZnVuY3Rpb24oYSl7cmV0dXJuIWQucHNldWRvcy5lbXB0eShhKX0saGVhZGVyOmZ1bmN0aW9uKGEpe3JldHVybiBaLnRlc3QoYS5ub2RlTmFtZSl9LGlucHV0OmZ1bmN0aW9uKGEpe3JldHVybiBZLnRlc3QoYS5ub2RlTmFtZSl9LGJ1dHRvbjpmdW5jdGlvbihhKXt2YXIgYj1hLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7cmV0dXJuImlucHV0Ij09PWImJiJidXR0b24iPT09YS50eXBlfHwiYnV0dG9uIj09PWJ9LHRleHQ6ZnVuY3Rpb24oYSl7dmFyIGI7cmV0dXJuImlucHV0Ij09PWEubm9kZU5hbWUudG9Mb3dlckNhc2UoKSYmInRleHQiPT09YS50eXBlJiYobnVsbD09KGI9YS5nZXRBdHRyaWJ1dGUoInR5cGUiKSl8fCJ0ZXh0Ij09PWIudG9Mb3dlckNhc2UoKSl9LGZpcnN0Om9hKGZ1bmN0aW9uKCl7cmV0dXJuWzBdfSksbGFzdDpvYShmdW5jdGlvbihhLGIpe3JldHVybltiLTFdfSksZXE6b2EoZnVuY3Rpb24oYSxiLGMpe3JldHVyblswPmM/YytiOmNdfSksZXZlbjpvYShmdW5jdGlvbihhLGIpe2Zvcih2YXIgYz0wO2I+YztjKz0yKWEucHVzaChjKTtyZXR1cm4gYX0pLG9kZDpvYShmdW5jdGlvbihhLGIpe2Zvcih2YXIgYz0xO2I+YztjKz0yKWEucHVzaChjKTtyZXR1cm4gYX0pLGx0Om9hKGZ1bmN0aW9uKGEsYixjKXtmb3IodmFyIGQ9MD5jP2MrYjpjOy0tZD49MDspYS5wdXNoKGQpO3JldHVybiBhfSksZ3Q6b2EoZnVuY3Rpb24oYSxiLGMpe2Zvcih2YXIgZD0wPmM/YytiOmM7KytkPGI7KWEucHVzaChkKTtyZXR1cm4gYX0pfX0sZC5wc2V1ZG9zLm50aD1kLnBzZXVkb3MuZXE7Zm9yKGIgaW57cmFkaW86ITAsY2hlY2tib3g6ITAsZmlsZTohMCxwYXNzd29yZDohMCxpbWFnZTohMH0pZC5wc2V1ZG9zW2JdPW1hKGIpO2ZvcihiIGlue3N1Ym1pdDohMCxyZXNldDohMH0pZC5wc2V1ZG9zW2JdPW5hKGIpO2Z1bmN0aW9uIHFhKCl7fXFhLnByb3RvdHlwZT1kLmZpbHRlcnM9ZC5wc2V1ZG9zLGQuc2V0RmlsdGVycz1uZXcgcWEsZz1nYS50b2tlbml6ZT1mdW5jdGlvbihhLGIpe3ZhciBjLGUsZixnLGgsaSxqLGs9elthKyIgIl07aWYoaylyZXR1cm4gYj8wOmsuc2xpY2UoMCk7aD1hLGk9W10saj1kLnByZUZpbHRlcjt3aGlsZShoKXsoIWN8fChlPVMuZXhlYyhoKSkpJiYoZSYmKGg9aC5zbGljZShlWzBdLmxlbmd0aCl8fGgpLGkucHVzaChmPVtdKSksYz0hMSwoZT1ULmV4ZWMoaCkpJiYoYz1lLnNoaWZ0KCksZi5wdXNoKHt2YWx1ZTpjLHR5cGU6ZVswXS5yZXBsYWNlKFIsIiAiKX0pLGg9aC5zbGljZShjLmxlbmd0aCkpO2ZvcihnIGluIGQuZmlsdGVyKSEoZT1YW2ddLmV4ZWMoaCkpfHxqW2ddJiYhKGU9altnXShlKSl8fChjPWUuc2hpZnQoKSxmLnB1c2goe3ZhbHVlOmMsdHlwZTpnLG1hdGNoZXM6ZX0pLGg9aC5zbGljZShjLmxlbmd0aCkpO2lmKCFjKWJyZWFrfXJldHVybiBiP2gubGVuZ3RoOmg/Z2EuZXJyb3IoYSk6eihhLGkpLnNsaWNlKDApfTtmdW5jdGlvbiByYShhKXtmb3IodmFyIGI9MCxjPWEubGVuZ3RoLGQ9IiI7Yz5iO2IrKylkKz1hW2JdLnZhbHVlO3JldHVybiBkfWZ1bmN0aW9uIHNhKGEsYixjKXt2YXIgZD1iLmRpcixlPWMmJiJwYXJlbnROb2RlIj09PWQsZj14Kys7cmV0dXJuIGIuZmlyc3Q/ZnVuY3Rpb24oYixjLGYpe3doaWxlKGI9YltkXSlpZigxPT09Yi5ub2RlVHlwZXx8ZSlyZXR1cm4gYShiLGMsZil9OmZ1bmN0aW9uKGIsYyxnKXt2YXIgaCxpLGo9W3csZl07aWYoZyl7d2hpbGUoYj1iW2RdKWlmKCgxPT09Yi5ub2RlVHlwZXx8ZSkmJmEoYixjLGcpKXJldHVybiEwfWVsc2Ugd2hpbGUoYj1iW2RdKWlmKDE9PT1iLm5vZGVUeXBlfHxlKXtpZihpPWJbdV18fChiW3VdPXt9KSwoaD1pW2RdKSYmaFswXT09PXcmJmhbMV09PT1mKXJldHVybiBqWzJdPWhbMl07aWYoaVtkXT1qLGpbMl09YShiLGMsZykpcmV0dXJuITB9fX1mdW5jdGlvbiB0YShhKXtyZXR1cm4gYS5sZW5ndGg+MT9mdW5jdGlvbihiLGMsZCl7dmFyIGU9YS5sZW5ndGg7d2hpbGUoZS0tKWlmKCFhW2VdKGIsYyxkKSlyZXR1cm4hMTtyZXR1cm4hMH06YVswXX1mdW5jdGlvbiB1YShhLGIsYyl7Zm9yKHZhciBkPTAsZT1iLmxlbmd0aDtlPmQ7ZCsrKWdhKGEsYltkXSxjKTtyZXR1cm4gY31mdW5jdGlvbiB2YShhLGIsYyxkLGUpe2Zvcih2YXIgZixnPVtdLGg9MCxpPWEubGVuZ3RoLGo9bnVsbCE9YjtpPmg7aCsrKShmPWFbaF0pJiYoIWN8fGMoZixkLGUpKSYmKGcucHVzaChmKSxqJiZiLnB1c2goaCkpO3JldHVybiBnfWZ1bmN0aW9uIHdhKGEsYixjLGQsZSxmKXtyZXR1cm4gZCYmIWRbdV0mJihkPXdhKGQpKSxlJiYhZVt1XSYmKGU9d2EoZSxmKSksaWEoZnVuY3Rpb24oZixnLGgsaSl7dmFyIGosayxsLG09W10sbj1bXSxvPWcubGVuZ3RoLHA9Znx8dWEoYnx8IioiLGgubm9kZVR5cGU/W2hdOmgsW10pLHE9IWF8fCFmJiZiP3A6dmEocCxtLGEsaCxpKSxyPWM/ZXx8KGY/YTpvfHxkKT9bXTpnOnE7aWYoYyYmYyhxLHIsaCxpKSxkKXtqPXZhKHIsbiksZChqLFtdLGgsaSksaz1qLmxlbmd0aDt3aGlsZShrLS0pKGw9altrXSkmJihyW25ba11dPSEocVtuW2tdXT1sKSl9aWYoZil7aWYoZXx8YSl7aWYoZSl7aj1bXSxrPXIubGVuZ3RoO3doaWxlKGstLSkobD1yW2tdKSYmai5wdXNoKHFba109bCk7ZShudWxsLHI9W10saixpKX1rPXIubGVuZ3RoO3doaWxlKGstLSkobD1yW2tdKSYmKGo9ZT9KKGYsbCk6bVtrXSk+LTEmJihmW2pdPSEoZ1tqXT1sKSl9fWVsc2Ugcj12YShyPT09Zz9yLnNwbGljZShvLHIubGVuZ3RoKTpyKSxlP2UobnVsbCxnLHIsaSk6SC5hcHBseShnLHIpfSl9ZnVuY3Rpb24geGEoYSl7Zm9yKHZhciBiLGMsZSxmPWEubGVuZ3RoLGc9ZC5yZWxhdGl2ZVthWzBdLnR5cGVdLGg9Z3x8ZC5yZWxhdGl2ZVsiICJdLGk9Zz8xOjAsaz1zYShmdW5jdGlvbihhKXtyZXR1cm4gYT09PWJ9LGgsITApLGw9c2EoZnVuY3Rpb24oYSl7cmV0dXJuIEooYixhKT4tMX0saCwhMCksbT1bZnVuY3Rpb24oYSxjLGQpe3ZhciBlPSFnJiYoZHx8YyE9PWopfHwoKGI9Yykubm9kZVR5cGU/ayhhLGMsZCk6bChhLGMsZCkpO3JldHVybiBiPW51bGwsZX1dO2Y+aTtpKyspaWYoYz1kLnJlbGF0aXZlW2FbaV0udHlwZV0pbT1bc2EodGEobSksYyldO2Vsc2V7aWYoYz1kLmZpbHRlclthW2ldLnR5cGVdLmFwcGx5KG51bGwsYVtpXS5tYXRjaGVzKSxjW3VdKXtmb3IoZT0rK2k7Zj5lO2UrKylpZihkLnJlbGF0aXZlW2FbZV0udHlwZV0pYnJlYWs7cmV0dXJuIHdhKGk+MSYmdGEobSksaT4xJiZyYShhLnNsaWNlKDAsaS0xKS5jb25jYXQoe3ZhbHVlOiIgIj09PWFbaS0yXS50eXBlPyIqIjoiIn0pKS5yZXBsYWNlKFIsIiQxIiksYyxlPmkmJnhhKGEuc2xpY2UoaSxlKSksZj5lJiZ4YShhPWEuc2xpY2UoZSkpLGY+ZSYmcmEoYSkpfW0ucHVzaChjKX1yZXR1cm4gdGEobSl9ZnVuY3Rpb24geWEoYSxiKXt2YXIgYz1iLmxlbmd0aD4wLGU9YS5sZW5ndGg+MCxmPWZ1bmN0aW9uKGYsZyxoLGksayl7dmFyIGwsbSxvLHA9MCxxPSIwIixyPWYmJltdLHM9W10sdD1qLHU9Znx8ZSYmZC5maW5kLlRBRygiKiIsayksdj13Kz1udWxsPT10PzE6TWF0aC5yYW5kb20oKXx8LjEseD11Lmxlbmd0aDtmb3IoayYmKGo9ZyE9PW4mJmcpO3EhPT14JiZudWxsIT0obD11W3FdKTtxKyspe2lmKGUmJmwpe209MDt3aGlsZShvPWFbbSsrXSlpZihvKGwsZyxoKSl7aS5wdXNoKGwpO2JyZWFrfWsmJih3PXYpfWMmJigobD0hbyYmbCkmJnAtLSxmJiZyLnB1c2gobCkpfWlmKHArPXEsYyYmcSE9PXApe209MDt3aGlsZShvPWJbbSsrXSlvKHIscyxnLGgpO2lmKGYpe2lmKHA+MCl3aGlsZShxLS0pcltxXXx8c1txXXx8KHNbcV09Ri5jYWxsKGkpKTtzPXZhKHMpfUguYXBwbHkoaSxzKSxrJiYhZiYmcy5sZW5ndGg+MCYmcCtiLmxlbmd0aD4xJiZnYS51bmlxdWVTb3J0KGkpfXJldHVybiBrJiYodz12LGo9dCkscn07cmV0dXJuIGM/aWEoZik6Zn1yZXR1cm4gaD1nYS5jb21waWxlPWZ1bmN0aW9uKGEsYil7dmFyIGMsZD1bXSxlPVtdLGY9QVthKyIgIl07aWYoIWYpe2J8fChiPWcoYSkpLGM9Yi5sZW5ndGg7d2hpbGUoYy0tKWY9eGEoYltjXSksZlt1XT9kLnB1c2goZik6ZS5wdXNoKGYpO2Y9QShhLHlhKGUsZCkpLGYuc2VsZWN0b3I9YX1yZXR1cm4gZn0saT1nYS5zZWxlY3Q9ZnVuY3Rpb24oYSxiLGUsZil7dmFyIGksaixrLGwsbSxuPSJmdW5jdGlvbiI9PXR5cGVvZiBhJiZhLG89IWYmJmcoYT1uLnNlbGVjdG9yfHxhKTtpZihlPWV8fFtdLDE9PT1vLmxlbmd0aCl7aWYoaj1vWzBdPW9bMF0uc2xpY2UoMCksai5sZW5ndGg+MiYmIklEIj09PShrPWpbMF0pLnR5cGUmJmMuZ2V0QnlJZCYmOT09PWIubm9kZVR5cGUmJnAmJmQucmVsYXRpdmVbalsxXS50eXBlXSl7aWYoYj0oZC5maW5kLklEKGsubWF0Y2hlc1swXS5yZXBsYWNlKGNhLGRhKSxiKXx8W10pWzBdLCFiKXJldHVybiBlO24mJihiPWIucGFyZW50Tm9kZSksYT1hLnNsaWNlKGouc2hpZnQoKS52YWx1ZS5sZW5ndGgpfWk9WC5uZWVkc0NvbnRleHQudGVzdChhKT8wOmoubGVuZ3RoO3doaWxlKGktLSl7aWYoaz1qW2ldLGQucmVsYXRpdmVbbD1rLnR5cGVdKWJyZWFrO2lmKChtPWQuZmluZFtsXSkmJihmPW0oay5tYXRjaGVzWzBdLnJlcGxhY2UoY2EsZGEpLGFhLnRlc3QoalswXS50eXBlKSYmcGEoYi5wYXJlbnROb2RlKXx8YikpKXtpZihqLnNwbGljZShpLDEpLGE9Zi5sZW5ndGgmJnJhKGopLCFhKXJldHVybiBILmFwcGx5KGUsZiksZTticmVha319fXJldHVybihufHxoKGEsbykpKGYsYiwhcCxlLGFhLnRlc3QoYSkmJnBhKGIucGFyZW50Tm9kZSl8fGIpLGV9LGMuc29ydFN0YWJsZT11LnNwbGl0KCIiKS5zb3J0KEIpLmpvaW4oIiIpPT09dSxjLmRldGVjdER1cGxpY2F0ZXM9ISFsLG0oKSxjLnNvcnREZXRhY2hlZD1qYShmdW5jdGlvbihhKXtyZXR1cm4gMSZhLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKG4uY3JlYXRlRWxlbWVudCgiZGl2IikpfSksamEoZnVuY3Rpb24oYSl7cmV0dXJuIGEuaW5uZXJIVE1MPSI8YSBocmVmPScjJz48L2E+IiwiIyI9PT1hLmZpcnN0Q2hpbGQuZ2V0QXR0cmlidXRlKCJocmVmIil9KXx8a2EoInR5cGV8aHJlZnxoZWlnaHR8d2lkdGgiLGZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gYz92b2lkIDA6YS5nZXRBdHRyaWJ1dGUoYiwidHlwZSI9PT1iLnRvTG93ZXJDYXNlKCk/MToyKX0pLGMuYXR0cmlidXRlcyYmamEoZnVuY3Rpb24oYSl7cmV0dXJuIGEuaW5uZXJIVE1MPSI8aW5wdXQvPiIsYS5maXJzdENoaWxkLnNldEF0dHJpYnV0ZSgidmFsdWUiLCIiKSwiIj09PWEuZmlyc3RDaGlsZC5nZXRBdHRyaWJ1dGUoInZhbHVlIil9KXx8a2EoInZhbHVlIixmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGN8fCJpbnB1dCIhPT1hLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk/dm9pZCAwOmEuZGVmYXVsdFZhbHVlfSksamEoZnVuY3Rpb24oYSl7cmV0dXJuIG51bGw9PWEuZ2V0QXR0cmlidXRlKCJkaXNhYmxlZCIpfSl8fGthKEssZnVuY3Rpb24oYSxiLGMpe3ZhciBkO3JldHVybiBjP3ZvaWQgMDphW2JdPT09ITA/Yi50b0xvd2VyQ2FzZSgpOihkPWEuZ2V0QXR0cmlidXRlTm9kZShiKSkmJmQuc3BlY2lmaWVkP2QudmFsdWU6bnVsbH0pLGdhfShhKTttLmZpbmQ9cyxtLmV4cHI9cy5zZWxlY3RvcnMsbS5leHByWyI6Il09bS5leHByLnBzZXVkb3MsbS51bmlxdWU9cy51bmlxdWVTb3J0LG0udGV4dD1zLmdldFRleHQsbS5pc1hNTERvYz1zLmlzWE1MLG0uY29udGFpbnM9cy5jb250YWluczt2YXIgdD1tLmV4cHIubWF0Y2gubmVlZHNDb250ZXh0LHU9L148KFx3KylccypcLz8+KD86PFwvXDE+fCkkLyx2PS9eLlteOiNcW1wuLF0qJC87ZnVuY3Rpb24gdyhhLGIsYyl7aWYobS5pc0Z1bmN0aW9uKGIpKXJldHVybiBtLmdyZXAoYSxmdW5jdGlvbihhLGQpe3JldHVybiEhYi5jYWxsKGEsZCxhKSE9PWN9KTtpZihiLm5vZGVUeXBlKXJldHVybiBtLmdyZXAoYSxmdW5jdGlvbihhKXtyZXR1cm4gYT09PWIhPT1jfSk7aWYoInN0cmluZyI9PXR5cGVvZiBiKXtpZih2LnRlc3QoYikpcmV0dXJuIG0uZmlsdGVyKGIsYSxjKTtiPW0uZmlsdGVyKGIsYSl9cmV0dXJuIG0uZ3JlcChhLGZ1bmN0aW9uKGEpe3JldHVybiBtLmluQXJyYXkoYSxiKT49MCE9PWN9KX1tLmZpbHRlcj1mdW5jdGlvbihhLGIsYyl7dmFyIGQ9YlswXTtyZXR1cm4gYyYmKGE9Ijpub3QoIithKyIpIiksMT09PWIubGVuZ3RoJiYxPT09ZC5ub2RlVHlwZT9tLmZpbmQubWF0Y2hlc1NlbGVjdG9yKGQsYSk/W2RdOltdOm0uZmluZC5tYXRjaGVzKGEsbS5ncmVwKGIsZnVuY3Rpb24oYSl7cmV0dXJuIDE9PT1hLm5vZGVUeXBlfSkpfSxtLmZuLmV4dGVuZCh7ZmluZDpmdW5jdGlvbihhKXt2YXIgYixjPVtdLGQ9dGhpcyxlPWQubGVuZ3RoO2lmKCJzdHJpbmciIT10eXBlb2YgYSlyZXR1cm4gdGhpcy5wdXNoU3RhY2sobShhKS5maWx0ZXIoZnVuY3Rpb24oKXtmb3IoYj0wO2U+YjtiKyspaWYobS5jb250YWlucyhkW2JdLHRoaXMpKXJldHVybiEwfSkpO2ZvcihiPTA7ZT5iO2IrKyltLmZpbmQoYSxkW2JdLGMpO3JldHVybiBjPXRoaXMucHVzaFN0YWNrKGU+MT9tLnVuaXF1ZShjKTpjKSxjLnNlbGVjdG9yPXRoaXMuc2VsZWN0b3I/dGhpcy5zZWxlY3RvcisiICIrYTphLGN9LGZpbHRlcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5wdXNoU3RhY2sodyh0aGlzLGF8fFtdLCExKSl9LG5vdDpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5wdXNoU3RhY2sodyh0aGlzLGF8fFtdLCEwKSl9LGlzOmZ1bmN0aW9uKGEpe3JldHVybiEhdyh0aGlzLCJzdHJpbmciPT10eXBlb2YgYSYmdC50ZXN0KGEpP20oYSk6YXx8W10sITEpLmxlbmd0aH19KTt2YXIgeCx5PWEuZG9jdW1lbnQsej0vXig/OlxzKig8W1x3XFddKz4pW14+XSp8IyhbXHctXSopKSQvLEE9bS5mbi5pbml0PWZ1bmN0aW9uKGEsYil7dmFyIGMsZDtpZighYSlyZXR1cm4gdGhpcztpZigic3RyaW5nIj09dHlwZW9mIGEpe2lmKGM9IjwiPT09YS5jaGFyQXQoMCkmJiI+Ij09PWEuY2hhckF0KGEubGVuZ3RoLTEpJiZhLmxlbmd0aD49Mz9bbnVsbCxhLG51bGxdOnouZXhlYyhhKSwhY3x8IWNbMV0mJmIpcmV0dXJuIWJ8fGIuanF1ZXJ5PyhifHx4KS5maW5kKGEpOnRoaXMuY29uc3RydWN0b3IoYikuZmluZChhKTtpZihjWzFdKXtpZihiPWIgaW5zdGFuY2VvZiBtP2JbMF06YixtLm1lcmdlKHRoaXMsbS5wYXJzZUhUTUwoY1sxXSxiJiZiLm5vZGVUeXBlP2Iub3duZXJEb2N1bWVudHx8Yjp5LCEwKSksdS50ZXN0KGNbMV0pJiZtLmlzUGxhaW5PYmplY3QoYikpZm9yKGMgaW4gYiltLmlzRnVuY3Rpb24odGhpc1tjXSk/dGhpc1tjXShiW2NdKTp0aGlzLmF0dHIoYyxiW2NdKTtyZXR1cm4gdGhpc31pZihkPXkuZ2V0RWxlbWVudEJ5SWQoY1syXSksZCYmZC5wYXJlbnROb2RlKXtpZihkLmlkIT09Y1syXSlyZXR1cm4geC5maW5kKGEpO3RoaXMubGVuZ3RoPTEsdGhpc1swXT1kfXJldHVybiB0aGlzLmNvbnRleHQ9eSx0aGlzLnNlbGVjdG9yPWEsdGhpc31yZXR1cm4gYS5ub2RlVHlwZT8odGhpcy5jb250ZXh0PXRoaXNbMF09YSx0aGlzLmxlbmd0aD0xLHRoaXMpOm0uaXNGdW5jdGlvbihhKT8idW5kZWZpbmVkIiE9dHlwZW9mIHgucmVhZHk/eC5yZWFkeShhKTphKG0pOih2b2lkIDAhPT1hLnNlbGVjdG9yJiYodGhpcy5zZWxlY3Rvcj1hLnNlbGVjdG9yLHRoaXMuY29udGV4dD1hLmNvbnRleHQpLG0ubWFrZUFycmF5KGEsdGhpcykpfTtBLnByb3RvdHlwZT1tLmZuLHg9bSh5KTt2YXIgQj0vXig/OnBhcmVudHN8cHJldig/OlVudGlsfEFsbCkpLyxDPXtjaGlsZHJlbjohMCxjb250ZW50czohMCxuZXh0OiEwLHByZXY6ITB9O20uZXh0ZW5kKHtkaXI6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkPVtdLGU9YVtiXTt3aGlsZShlJiY5IT09ZS5ub2RlVHlwZSYmKHZvaWQgMD09PWN8fDEhPT1lLm5vZGVUeXBlfHwhbShlKS5pcyhjKSkpMT09PWUubm9kZVR5cGUmJmQucHVzaChlKSxlPWVbYl07cmV0dXJuIGR9LHNpYmxpbmc6ZnVuY3Rpb24oYSxiKXtmb3IodmFyIGM9W107YTthPWEubmV4dFNpYmxpbmcpMT09PWEubm9kZVR5cGUmJmEhPT1iJiZjLnB1c2goYSk7cmV0dXJuIGN9fSksbS5mbi5leHRlbmQoe2hhczpmdW5jdGlvbihhKXt2YXIgYixjPW0oYSx0aGlzKSxkPWMubGVuZ3RoO3JldHVybiB0aGlzLmZpbHRlcihmdW5jdGlvbigpe2ZvcihiPTA7ZD5iO2IrKylpZihtLmNvbnRhaW5zKHRoaXMsY1tiXSkpcmV0dXJuITB9KX0sY2xvc2VzdDpmdW5jdGlvbihhLGIpe2Zvcih2YXIgYyxkPTAsZT10aGlzLmxlbmd0aCxmPVtdLGc9dC50ZXN0KGEpfHwic3RyaW5nIiE9dHlwZW9mIGE/bShhLGJ8fHRoaXMuY29udGV4dCk6MDtlPmQ7ZCsrKWZvcihjPXRoaXNbZF07YyYmYyE9PWI7Yz1jLnBhcmVudE5vZGUpaWYoYy5ub2RlVHlwZTwxMSYmKGc/Zy5pbmRleChjKT4tMToxPT09Yy5ub2RlVHlwZSYmbS5maW5kLm1hdGNoZXNTZWxlY3RvcihjLGEpKSl7Zi5wdXNoKGMpO2JyZWFrfXJldHVybiB0aGlzLnB1c2hTdGFjayhmLmxlbmd0aD4xP20udW5pcXVlKGYpOmYpfSxpbmRleDpmdW5jdGlvbihhKXtyZXR1cm4gYT8ic3RyaW5nIj09dHlwZW9mIGE/bS5pbkFycmF5KHRoaXNbMF0sbShhKSk6bS5pbkFycmF5KGEuanF1ZXJ5P2FbMF06YSx0aGlzKTp0aGlzWzBdJiZ0aGlzWzBdLnBhcmVudE5vZGU/dGhpcy5maXJzdCgpLnByZXZBbGwoKS5sZW5ndGg6LTF9LGFkZDpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLnB1c2hTdGFjayhtLnVuaXF1ZShtLm1lcmdlKHRoaXMuZ2V0KCksbShhLGIpKSkpfSxhZGRCYWNrOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmFkZChudWxsPT1hP3RoaXMucHJldk9iamVjdDp0aGlzLnByZXZPYmplY3QuZmlsdGVyKGEpKX19KTtmdW5jdGlvbiBEKGEsYil7ZG8gYT1hW2JdO3doaWxlKGEmJjEhPT1hLm5vZGVUeXBlKTtyZXR1cm4gYX1tLmVhY2goe3BhcmVudDpmdW5jdGlvbihhKXt2YXIgYj1hLnBhcmVudE5vZGU7cmV0dXJuIGImJjExIT09Yi5ub2RlVHlwZT9iOm51bGx9LHBhcmVudHM6ZnVuY3Rpb24oYSl7cmV0dXJuIG0uZGlyKGEsInBhcmVudE5vZGUiKX0scGFyZW50c1VudGlsOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gbS5kaXIoYSwicGFyZW50Tm9kZSIsYyl9LG5leHQ6ZnVuY3Rpb24oYSl7cmV0dXJuIEQoYSwibmV4dFNpYmxpbmciKX0scHJldjpmdW5jdGlvbihhKXtyZXR1cm4gRChhLCJwcmV2aW91c1NpYmxpbmciKX0sbmV4dEFsbDpmdW5jdGlvbihhKXtyZXR1cm4gbS5kaXIoYSwibmV4dFNpYmxpbmciKX0scHJldkFsbDpmdW5jdGlvbihhKXtyZXR1cm4gbS5kaXIoYSwicHJldmlvdXNTaWJsaW5nIil9LG5leHRVbnRpbDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIG0uZGlyKGEsIm5leHRTaWJsaW5nIixjKX0scHJldlVudGlsOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gbS5kaXIoYSwicHJldmlvdXNTaWJsaW5nIixjKX0sc2libGluZ3M6ZnVuY3Rpb24oYSl7cmV0dXJuIG0uc2libGluZygoYS5wYXJlbnROb2RlfHx7fSkuZmlyc3RDaGlsZCxhKX0sY2hpbGRyZW46ZnVuY3Rpb24oYSl7cmV0dXJuIG0uc2libGluZyhhLmZpcnN0Q2hpbGQpfSxjb250ZW50czpmdW5jdGlvbihhKXtyZXR1cm4gbS5ub2RlTmFtZShhLCJpZnJhbWUiKT9hLmNvbnRlbnREb2N1bWVudHx8YS5jb250ZW50V2luZG93LmRvY3VtZW50Om0ubWVyZ2UoW10sYS5jaGlsZE5vZGVzKX19LGZ1bmN0aW9uKGEsYil7bS5mblthXT1mdW5jdGlvbihjLGQpe3ZhciBlPW0ubWFwKHRoaXMsYixjKTtyZXR1cm4iVW50aWwiIT09YS5zbGljZSgtNSkmJihkPWMpLGQmJiJzdHJpbmciPT10eXBlb2YgZCYmKGU9bS5maWx0ZXIoZCxlKSksdGhpcy5sZW5ndGg+MSYmKENbYV18fChlPW0udW5pcXVlKGUpKSxCLnRlc3QoYSkmJihlPWUucmV2ZXJzZSgpKSksdGhpcy5wdXNoU3RhY2soZSl9fSk7dmFyIEU9L1xTKy9nLEY9e307ZnVuY3Rpb24gRyhhKXt2YXIgYj1GW2FdPXt9O3JldHVybiBtLmVhY2goYS5tYXRjaChFKXx8W10sZnVuY3Rpb24oYSxjKXtiW2NdPSEwfSksYn1tLkNhbGxiYWNrcz1mdW5jdGlvbihhKXthPSJzdHJpbmciPT10eXBlb2YgYT9GW2FdfHxHKGEpOm0uZXh0ZW5kKHt9LGEpO3ZhciBiLGMsZCxlLGYsZyxoPVtdLGk9IWEub25jZSYmW10saj1mdW5jdGlvbihsKXtmb3IoYz1hLm1lbW9yeSYmbCxkPSEwLGY9Z3x8MCxnPTAsZT1oLmxlbmd0aCxiPSEwO2gmJmU+ZjtmKyspaWYoaFtmXS5hcHBseShsWzBdLGxbMV0pPT09ITEmJmEuc3RvcE9uRmFsc2Upe2M9ITE7YnJlYWt9Yj0hMSxoJiYoaT9pLmxlbmd0aCYmaihpLnNoaWZ0KCkpOmM/aD1bXTprLmRpc2FibGUoKSl9LGs9e2FkZDpmdW5jdGlvbigpe2lmKGgpe3ZhciBkPWgubGVuZ3RoOyFmdW5jdGlvbiBmKGIpe20uZWFjaChiLGZ1bmN0aW9uKGIsYyl7dmFyIGQ9bS50eXBlKGMpOyJmdW5jdGlvbiI9PT1kP2EudW5pcXVlJiZrLmhhcyhjKXx8aC5wdXNoKGMpOmMmJmMubGVuZ3RoJiYic3RyaW5nIiE9PWQmJmYoYyl9KX0oYXJndW1lbnRzKSxiP2U9aC5sZW5ndGg6YyYmKGc9ZCxqKGMpKX1yZXR1cm4gdGhpc30scmVtb3ZlOmZ1bmN0aW9uKCl7cmV0dXJuIGgmJm0uZWFjaChhcmd1bWVudHMsZnVuY3Rpb24oYSxjKXt2YXIgZDt3aGlsZSgoZD1tLmluQXJyYXkoYyxoLGQpKT4tMSloLnNwbGljZShkLDEpLGImJihlPj1kJiZlLS0sZj49ZCYmZi0tKX0pLHRoaXN9LGhhczpmdW5jdGlvbihhKXtyZXR1cm4gYT9tLmluQXJyYXkoYSxoKT4tMTohKCFofHwhaC5sZW5ndGgpfSxlbXB0eTpmdW5jdGlvbigpe3JldHVybiBoPVtdLGU9MCx0aGlzfSxkaXNhYmxlOmZ1bmN0aW9uKCl7cmV0dXJuIGg9aT1jPXZvaWQgMCx0aGlzfSxkaXNhYmxlZDpmdW5jdGlvbigpe3JldHVybiFofSxsb2NrOmZ1bmN0aW9uKCl7cmV0dXJuIGk9dm9pZCAwLGN8fGsuZGlzYWJsZSgpLHRoaXN9LGxvY2tlZDpmdW5jdGlvbigpe3JldHVybiFpfSxmaXJlV2l0aDpmdW5jdGlvbihhLGMpe3JldHVybiFofHxkJiYhaXx8KGM9Y3x8W10sYz1bYSxjLnNsaWNlP2Muc2xpY2UoKTpjXSxiP2kucHVzaChjKTpqKGMpKSx0aGlzfSxmaXJlOmZ1bmN0aW9uKCl7cmV0dXJuIGsuZmlyZVdpdGgodGhpcyxhcmd1bWVudHMpLHRoaXN9LGZpcmVkOmZ1bmN0aW9uKCl7cmV0dXJuISFkfX07cmV0dXJuIGt9LG0uZXh0ZW5kKHtEZWZlcnJlZDpmdW5jdGlvbihhKXt2YXIgYj1bWyJyZXNvbHZlIiwiZG9uZSIsbS5DYWxsYmFja3MoIm9uY2UgbWVtb3J5IiksInJlc29sdmVkIl0sWyJyZWplY3QiLCJmYWlsIixtLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSwicmVqZWN0ZWQiXSxbIm5vdGlmeSIsInByb2dyZXNzIixtLkNhbGxiYWNrcygibWVtb3J5IildXSxjPSJwZW5kaW5nIixkPXtzdGF0ZTpmdW5jdGlvbigpe3JldHVybiBjfSxhbHdheXM6ZnVuY3Rpb24oKXtyZXR1cm4gZS5kb25lKGFyZ3VtZW50cykuZmFpbChhcmd1bWVudHMpLHRoaXN9LHRoZW46ZnVuY3Rpb24oKXt2YXIgYT1hcmd1bWVudHM7cmV0dXJuIG0uRGVmZXJyZWQoZnVuY3Rpb24oYyl7bS5lYWNoKGIsZnVuY3Rpb24oYixmKXt2YXIgZz1tLmlzRnVuY3Rpb24oYVtiXSkmJmFbYl07ZVtmWzFdXShmdW5jdGlvbigpe3ZhciBhPWcmJmcuYXBwbHkodGhpcyxhcmd1bWVudHMpO2EmJm0uaXNGdW5jdGlvbihhLnByb21pc2UpP2EucHJvbWlzZSgpLmRvbmUoYy5yZXNvbHZlKS5mYWlsKGMucmVqZWN0KS5wcm9ncmVzcyhjLm5vdGlmeSk6Y1tmWzBdKyJXaXRoIl0odGhpcz09PWQ/Yy5wcm9taXNlKCk6dGhpcyxnP1thXTphcmd1bWVudHMpfSl9KSxhPW51bGx9KS5wcm9taXNlKCl9LHByb21pc2U6ZnVuY3Rpb24oYSl7cmV0dXJuIG51bGwhPWE/bS5leHRlbmQoYSxkKTpkfX0sZT17fTtyZXR1cm4gZC5waXBlPWQudGhlbixtLmVhY2goYixmdW5jdGlvbihhLGYpe3ZhciBnPWZbMl0saD1mWzNdO2RbZlsxXV09Zy5hZGQsaCYmZy5hZGQoZnVuY3Rpb24oKXtjPWh9LGJbMV5hXVsyXS5kaXNhYmxlLGJbMl1bMl0ubG9jayksZVtmWzBdXT1mdW5jdGlvbigpe3JldHVybiBlW2ZbMF0rIldpdGgiXSh0aGlzPT09ZT9kOnRoaXMsYXJndW1lbnRzKSx0aGlzfSxlW2ZbMF0rIldpdGgiXT1nLmZpcmVXaXRofSksZC5wcm9taXNlKGUpLGEmJmEuY2FsbChlLGUpLGV9LHdoZW46ZnVuY3Rpb24oYSl7dmFyIGI9MCxjPWQuY2FsbChhcmd1bWVudHMpLGU9Yy5sZW5ndGgsZj0xIT09ZXx8YSYmbS5pc0Z1bmN0aW9uKGEucHJvbWlzZSk/ZTowLGc9MT09PWY/YTptLkRlZmVycmVkKCksaD1mdW5jdGlvbihhLGIsYyl7cmV0dXJuIGZ1bmN0aW9uKGUpe2JbYV09dGhpcyxjW2FdPWFyZ3VtZW50cy5sZW5ndGg+MT9kLmNhbGwoYXJndW1lbnRzKTplLGM9PT1pP2cubm90aWZ5V2l0aChiLGMpOi0tZnx8Zy5yZXNvbHZlV2l0aChiLGMpfX0saSxqLGs7aWYoZT4xKWZvcihpPW5ldyBBcnJheShlKSxqPW5ldyBBcnJheShlKSxrPW5ldyBBcnJheShlKTtlPmI7YisrKWNbYl0mJm0uaXNGdW5jdGlvbihjW2JdLnByb21pc2UpP2NbYl0ucHJvbWlzZSgpLmRvbmUoaChiLGssYykpLmZhaWwoZy5yZWplY3QpLnByb2dyZXNzKGgoYixqLGkpKTotLWY7cmV0dXJuIGZ8fGcucmVzb2x2ZVdpdGgoayxjKSxnLnByb21pc2UoKX19KTt2YXIgSDttLmZuLnJlYWR5PWZ1bmN0aW9uKGEpe3JldHVybiBtLnJlYWR5LnByb21pc2UoKS5kb25lKGEpLHRoaXN9LG0uZXh0ZW5kKHtpc1JlYWR5OiExLHJlYWR5V2FpdDoxLGhvbGRSZWFkeTpmdW5jdGlvbihhKXthP20ucmVhZHlXYWl0Kys6bS5yZWFkeSghMCl9LHJlYWR5OmZ1bmN0aW9uKGEpe2lmKGE9PT0hMD8hLS1tLnJlYWR5V2FpdDohbS5pc1JlYWR5KXtpZigheS5ib2R5KXJldHVybiBzZXRUaW1lb3V0KG0ucmVhZHkpO20uaXNSZWFkeT0hMCxhIT09ITAmJi0tbS5yZWFkeVdhaXQ+MHx8KEgucmVzb2x2ZVdpdGgoeSxbbV0pLG0uZm4udHJpZ2dlckhhbmRsZXImJihtKHkpLnRyaWdnZXJIYW5kbGVyKCJyZWFkeSIpLG0oeSkub2ZmKCJyZWFkeSIpKSl9fX0pO2Z1bmN0aW9uIEkoKXt5LmFkZEV2ZW50TGlzdGVuZXI/KHkucmVtb3ZlRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsSiwhMSksYS5yZW1vdmVFdmVudExpc3RlbmVyKCJsb2FkIixKLCExKSk6KHkuZGV0YWNoRXZlbnQoIm9ucmVhZHlzdGF0ZWNoYW5nZSIsSiksYS5kZXRhY2hFdmVudCgib25sb2FkIixKKSl9ZnVuY3Rpb24gSigpeyh5LmFkZEV2ZW50TGlzdGVuZXJ8fCJsb2FkIj09PWV2ZW50LnR5cGV8fCJjb21wbGV0ZSI9PT15LnJlYWR5U3RhdGUpJiYoSSgpLG0ucmVhZHkoKSl9bS5yZWFkeS5wcm9taXNlPWZ1bmN0aW9uKGIpe2lmKCFIKWlmKEg9bS5EZWZlcnJlZCgpLCJjb21wbGV0ZSI9PT15LnJlYWR5U3RhdGUpc2V0VGltZW91dChtLnJlYWR5KTtlbHNlIGlmKHkuYWRkRXZlbnRMaXN0ZW5lcil5LmFkZEV2ZW50TGlzdGVuZXIoIkRPTUNvbnRlbnRMb2FkZWQiLEosITEpLGEuYWRkRXZlbnRMaXN0ZW5lcigibG9hZCIsSiwhMSk7ZWxzZXt5LmF0dGFjaEV2ZW50KCJvbnJlYWR5c3RhdGVjaGFuZ2UiLEopLGEuYXR0YWNoRXZlbnQoIm9ubG9hZCIsSik7dmFyIGM9ITE7dHJ5e2M9bnVsbD09YS5mcmFtZUVsZW1lbnQmJnkuZG9jdW1lbnRFbGVtZW50fWNhdGNoKGQpe31jJiZjLmRvU2Nyb2xsJiYhZnVuY3Rpb24gZSgpe2lmKCFtLmlzUmVhZHkpe3RyeXtjLmRvU2Nyb2xsKCJsZWZ0Iil9Y2F0Y2goYSl7cmV0dXJuIHNldFRpbWVvdXQoZSw1MCl9SSgpLG0ucmVhZHkoKX19KCl9cmV0dXJuIEgucHJvbWlzZShiKX07dmFyIEs9InVuZGVmaW5lZCIsTDtmb3IoTCBpbiBtKGspKWJyZWFrO2sub3duTGFzdD0iMCIhPT1MLGsuaW5saW5lQmxvY2tOZWVkc0xheW91dD0hMSxtKGZ1bmN0aW9uKCl7dmFyIGEsYixjLGQ7Yz15LmdldEVsZW1lbnRzQnlUYWdOYW1lKCJib2R5IilbMF0sYyYmYy5zdHlsZSYmKGI9eS5jcmVhdGVFbGVtZW50KCJkaXYiKSxkPXkuY3JlYXRlRWxlbWVudCgiZGl2IiksZC5zdHlsZS5jc3NUZXh0PSJwb3NpdGlvbjphYnNvbHV0ZTtib3JkZXI6MDt3aWR0aDowO2hlaWdodDowO3RvcDowO2xlZnQ6LTk5OTlweCIsYy5hcHBlbmRDaGlsZChkKS5hcHBlbmRDaGlsZChiKSx0eXBlb2YgYi5zdHlsZS56b29tIT09SyYmKGIuc3R5bGUuY3NzVGV4dD0iZGlzcGxheTppbmxpbmU7bWFyZ2luOjA7Ym9yZGVyOjA7cGFkZGluZzoxcHg7d2lkdGg6MXB4O3pvb206MSIsay5pbmxpbmVCbG9ja05lZWRzTGF5b3V0PWE9Mz09PWIub2Zmc2V0V2lkdGgsYSYmKGMuc3R5bGUuem9vbT0xKSksYy5yZW1vdmVDaGlsZChkKSl9KSxmdW5jdGlvbigpe3ZhciBhPXkuY3JlYXRlRWxlbWVudCgiZGl2Iik7aWYobnVsbD09ay5kZWxldGVFeHBhbmRvKXtrLmRlbGV0ZUV4cGFuZG89ITA7dHJ5e2RlbGV0ZSBhLnRlc3R9Y2F0Y2goYil7ay5kZWxldGVFeHBhbmRvPSExfX1hPW51bGx9KCksbS5hY2NlcHREYXRhPWZ1bmN0aW9uKGEpe3ZhciBiPW0ubm9EYXRhWyhhLm5vZGVOYW1lKyIgIikudG9Mb3dlckNhc2UoKV0sYz0rYS5ub2RlVHlwZXx8MTtyZXR1cm4gMSE9PWMmJjkhPT1jPyExOiFifHxiIT09ITAmJmEuZ2V0QXR0cmlidXRlKCJjbGFzc2lkIik9PT1ifTt2YXIgTT0vXig/Olx7W1x3XFddKlx9fFxbW1x3XFddKlxdKSQvLE49LyhbQS1aXSkvZztmdW5jdGlvbiBPKGEsYixjKXtpZih2b2lkIDA9PT1jJiYxPT09YS5ub2RlVHlwZSl7dmFyIGQ9ImRhdGEtIitiLnJlcGxhY2UoTiwiLSQxIikudG9Mb3dlckNhc2UoKTtpZihjPWEuZ2V0QXR0cmlidXRlKGQpLCJzdHJpbmciPT10eXBlb2YgYyl7dHJ5e2M9InRydWUiPT09Yz8hMDoiZmFsc2UiPT09Yz8hMToibnVsbCI9PT1jP251bGw6K2MrIiI9PT1jPytjOk0udGVzdChjKT9tLnBhcnNlSlNPTihjKTpjfWNhdGNoKGUpe31tLmRhdGEoYSxiLGMpfWVsc2UgYz12b2lkIDB9cmV0dXJuIGN9ZnVuY3Rpb24gUChhKXt2YXIgYjtmb3IoYiBpbiBhKWlmKCgiZGF0YSIhPT1ifHwhbS5pc0VtcHR5T2JqZWN0KGFbYl0pKSYmInRvSlNPTiIhPT1iKXJldHVybiExOwoKcmV0dXJuITB9ZnVuY3Rpb24gUShhLGIsZCxlKXtpZihtLmFjY2VwdERhdGEoYSkpe3ZhciBmLGcsaD1tLmV4cGFuZG8saT1hLm5vZGVUeXBlLGo9aT9tLmNhY2hlOmEsaz1pP2FbaF06YVtoXSYmaDtpZihrJiZqW2tdJiYoZXx8altrXS5kYXRhKXx8dm9pZCAwIT09ZHx8InN0cmluZyIhPXR5cGVvZiBiKXJldHVybiBrfHwoaz1pP2FbaF09Yy5wb3AoKXx8bS5ndWlkKys6aCksaltrXXx8KGpba109aT97fTp7dG9KU09OOm0ubm9vcH0pLCgib2JqZWN0Ij09dHlwZW9mIGJ8fCJmdW5jdGlvbiI9PXR5cGVvZiBiKSYmKGU/altrXT1tLmV4dGVuZChqW2tdLGIpOmpba10uZGF0YT1tLmV4dGVuZChqW2tdLmRhdGEsYikpLGc9altrXSxlfHwoZy5kYXRhfHwoZy5kYXRhPXt9KSxnPWcuZGF0YSksdm9pZCAwIT09ZCYmKGdbbS5jYW1lbENhc2UoYildPWQpLCJzdHJpbmciPT10eXBlb2YgYj8oZj1nW2JdLG51bGw9PWYmJihmPWdbbS5jYW1lbENhc2UoYildKSk6Zj1nLGZ9fWZ1bmN0aW9uIFIoYSxiLGMpe2lmKG0uYWNjZXB0RGF0YShhKSl7dmFyIGQsZSxmPWEubm9kZVR5cGUsZz1mP20uY2FjaGU6YSxoPWY/YVttLmV4cGFuZG9dOm0uZXhwYW5kbztpZihnW2hdKXtpZihiJiYoZD1jP2dbaF06Z1toXS5kYXRhKSl7bS5pc0FycmF5KGIpP2I9Yi5jb25jYXQobS5tYXAoYixtLmNhbWVsQ2FzZSkpOmIgaW4gZD9iPVtiXTooYj1tLmNhbWVsQ2FzZShiKSxiPWIgaW4gZD9bYl06Yi5zcGxpdCgiICIpKSxlPWIubGVuZ3RoO3doaWxlKGUtLSlkZWxldGUgZFtiW2VdXTtpZihjPyFQKGQpOiFtLmlzRW1wdHlPYmplY3QoZCkpcmV0dXJufShjfHwoZGVsZXRlIGdbaF0uZGF0YSxQKGdbaF0pKSkmJihmP20uY2xlYW5EYXRhKFthXSwhMCk6ay5kZWxldGVFeHBhbmRvfHxnIT1nLndpbmRvdz9kZWxldGUgZ1toXTpnW2hdPW51bGwpfX19bS5leHRlbmQoe2NhY2hlOnt9LG5vRGF0YTp7ImFwcGxldCAiOiEwLCJlbWJlZCAiOiEwLCJvYmplY3QgIjoiY2xzaWQ6RDI3Q0RCNkUtQUU2RC0xMWNmLTk2QjgtNDQ0NTUzNTQwMDAwIn0saGFzRGF0YTpmdW5jdGlvbihhKXtyZXR1cm4gYT1hLm5vZGVUeXBlP20uY2FjaGVbYVttLmV4cGFuZG9dXTphW20uZXhwYW5kb10sISFhJiYhUChhKX0sZGF0YTpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIFEoYSxiLGMpfSxyZW1vdmVEYXRhOmZ1bmN0aW9uKGEsYil7cmV0dXJuIFIoYSxiKX0sX2RhdGE6ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBRKGEsYixjLCEwKX0sX3JlbW92ZURhdGE6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gUihhLGIsITApfX0pLG0uZm4uZXh0ZW5kKHtkYXRhOmZ1bmN0aW9uKGEsYil7dmFyIGMsZCxlLGY9dGhpc1swXSxnPWYmJmYuYXR0cmlidXRlcztpZih2b2lkIDA9PT1hKXtpZih0aGlzLmxlbmd0aCYmKGU9bS5kYXRhKGYpLDE9PT1mLm5vZGVUeXBlJiYhbS5fZGF0YShmLCJwYXJzZWRBdHRycyIpKSl7Yz1nLmxlbmd0aDt3aGlsZShjLS0pZ1tjXSYmKGQ9Z1tjXS5uYW1lLDA9PT1kLmluZGV4T2YoImRhdGEtIikmJihkPW0uY2FtZWxDYXNlKGQuc2xpY2UoNSkpLE8oZixkLGVbZF0pKSk7bS5fZGF0YShmLCJwYXJzZWRBdHRycyIsITApfXJldHVybiBlfXJldHVybiJvYmplY3QiPT10eXBlb2YgYT90aGlzLmVhY2goZnVuY3Rpb24oKXttLmRhdGEodGhpcyxhKX0pOmFyZ3VtZW50cy5sZW5ndGg+MT90aGlzLmVhY2goZnVuY3Rpb24oKXttLmRhdGEodGhpcyxhLGIpfSk6Zj9PKGYsYSxtLmRhdGEoZixhKSk6dm9pZCAwfSxyZW1vdmVEYXRhOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXttLnJlbW92ZURhdGEodGhpcyxhKX0pfX0pLG0uZXh0ZW5kKHtxdWV1ZTpmdW5jdGlvbihhLGIsYyl7dmFyIGQ7cmV0dXJuIGE/KGI9KGJ8fCJmeCIpKyJxdWV1ZSIsZD1tLl9kYXRhKGEsYiksYyYmKCFkfHxtLmlzQXJyYXkoYyk/ZD1tLl9kYXRhKGEsYixtLm1ha2VBcnJheShjKSk6ZC5wdXNoKGMpKSxkfHxbXSk6dm9pZCAwfSxkZXF1ZXVlOmZ1bmN0aW9uKGEsYil7Yj1ifHwiZngiO3ZhciBjPW0ucXVldWUoYSxiKSxkPWMubGVuZ3RoLGU9Yy5zaGlmdCgpLGY9bS5fcXVldWVIb29rcyhhLGIpLGc9ZnVuY3Rpb24oKXttLmRlcXVldWUoYSxiKX07ImlucHJvZ3Jlc3MiPT09ZSYmKGU9Yy5zaGlmdCgpLGQtLSksZSYmKCJmeCI9PT1iJiZjLnVuc2hpZnQoImlucHJvZ3Jlc3MiKSxkZWxldGUgZi5zdG9wLGUuY2FsbChhLGcsZikpLCFkJiZmJiZmLmVtcHR5LmZpcmUoKX0sX3F1ZXVlSG9va3M6ZnVuY3Rpb24oYSxiKXt2YXIgYz1iKyJxdWV1ZUhvb2tzIjtyZXR1cm4gbS5fZGF0YShhLGMpfHxtLl9kYXRhKGEsYyx7ZW1wdHk6bS5DYWxsYmFja3MoIm9uY2UgbWVtb3J5IikuYWRkKGZ1bmN0aW9uKCl7bS5fcmVtb3ZlRGF0YShhLGIrInF1ZXVlIiksbS5fcmVtb3ZlRGF0YShhLGMpfSl9KX19KSxtLmZuLmV4dGVuZCh7cXVldWU6ZnVuY3Rpb24oYSxiKXt2YXIgYz0yO3JldHVybiJzdHJpbmciIT10eXBlb2YgYSYmKGI9YSxhPSJmeCIsYy0tKSxhcmd1bWVudHMubGVuZ3RoPGM/bS5xdWV1ZSh0aGlzWzBdLGEpOnZvaWQgMD09PWI/dGhpczp0aGlzLmVhY2goZnVuY3Rpb24oKXt2YXIgYz1tLnF1ZXVlKHRoaXMsYSxiKTttLl9xdWV1ZUhvb2tzKHRoaXMsYSksImZ4Ij09PWEmJiJpbnByb2dyZXNzIiE9PWNbMF0mJm0uZGVxdWV1ZSh0aGlzLGEpfSl9LGRlcXVldWU6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe20uZGVxdWV1ZSh0aGlzLGEpfSl9LGNsZWFyUXVldWU6ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMucXVldWUoYXx8ImZ4IixbXSl9LHByb21pc2U6ZnVuY3Rpb24oYSxiKXt2YXIgYyxkPTEsZT1tLkRlZmVycmVkKCksZj10aGlzLGc9dGhpcy5sZW5ndGgsaD1mdW5jdGlvbigpey0tZHx8ZS5yZXNvbHZlV2l0aChmLFtmXSl9OyJzdHJpbmciIT10eXBlb2YgYSYmKGI9YSxhPXZvaWQgMCksYT1hfHwiZngiO3doaWxlKGctLSljPW0uX2RhdGEoZltnXSxhKyJxdWV1ZUhvb2tzIiksYyYmYy5lbXB0eSYmKGQrKyxjLmVtcHR5LmFkZChoKSk7cmV0dXJuIGgoKSxlLnByb21pc2UoYil9fSk7dmFyIFM9L1srLV0/KD86XGQqXC58KVxkKyg/OltlRV1bKy1dP1xkK3wpLy5zb3VyY2UsVD1bIlRvcCIsIlJpZ2h0IiwiQm90dG9tIiwiTGVmdCJdLFU9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYT1ifHxhLCJub25lIj09PW0uY3NzKGEsImRpc3BsYXkiKXx8IW0uY29udGFpbnMoYS5vd25lckRvY3VtZW50LGEpfSxWPW0uYWNjZXNzPWZ1bmN0aW9uKGEsYixjLGQsZSxmLGcpe3ZhciBoPTAsaT1hLmxlbmd0aCxqPW51bGw9PWM7aWYoIm9iamVjdCI9PT1tLnR5cGUoYykpe2U9ITA7Zm9yKGggaW4gYyltLmFjY2VzcyhhLGIsaCxjW2hdLCEwLGYsZyl9ZWxzZSBpZih2b2lkIDAhPT1kJiYoZT0hMCxtLmlzRnVuY3Rpb24oZCl8fChnPSEwKSxqJiYoZz8oYi5jYWxsKGEsZCksYj1udWxsKTooaj1iLGI9ZnVuY3Rpb24oYSxiLGMpe3JldHVybiBqLmNhbGwobShhKSxjKX0pKSxiKSlmb3IoO2k+aDtoKyspYihhW2hdLGMsZz9kOmQuY2FsbChhW2hdLGgsYihhW2hdLGMpKSk7cmV0dXJuIGU/YTpqP2IuY2FsbChhKTppP2IoYVswXSxjKTpmfSxXPS9eKD86Y2hlY2tib3h8cmFkaW8pJC9pOyFmdW5jdGlvbigpe3ZhciBhPXkuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSxiPXkuY3JlYXRlRWxlbWVudCgiZGl2IiksYz15LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtpZihiLmlubmVySFRNTD0iICA8bGluay8+PHRhYmxlPjwvdGFibGU+PGEgaHJlZj0nL2EnPmE8L2E+PGlucHV0IHR5cGU9J2NoZWNrYm94Jy8+IixrLmxlYWRpbmdXaGl0ZXNwYWNlPTM9PT1iLmZpcnN0Q2hpbGQubm9kZVR5cGUsay50Ym9keT0hYi5nZXRFbGVtZW50c0J5VGFnTmFtZSgidGJvZHkiKS5sZW5ndGgsay5odG1sU2VyaWFsaXplPSEhYi5nZXRFbGVtZW50c0J5VGFnTmFtZSgibGluayIpLmxlbmd0aCxrLmh0bWw1Q2xvbmU9Ijw6bmF2PjwvOm5hdj4iIT09eS5jcmVhdGVFbGVtZW50KCJuYXYiKS5jbG9uZU5vZGUoITApLm91dGVySFRNTCxhLnR5cGU9ImNoZWNrYm94IixhLmNoZWNrZWQ9ITAsYy5hcHBlbmRDaGlsZChhKSxrLmFwcGVuZENoZWNrZWQ9YS5jaGVja2VkLGIuaW5uZXJIVE1MPSI8dGV4dGFyZWE+eDwvdGV4dGFyZWE+IixrLm5vQ2xvbmVDaGVja2VkPSEhYi5jbG9uZU5vZGUoITApLmxhc3RDaGlsZC5kZWZhdWx0VmFsdWUsYy5hcHBlbmRDaGlsZChiKSxiLmlubmVySFRNTD0iPGlucHV0IHR5cGU9J3JhZGlvJyBjaGVja2VkPSdjaGVja2VkJyBuYW1lPSd0Jy8+IixrLmNoZWNrQ2xvbmU9Yi5jbG9uZU5vZGUoITApLmNsb25lTm9kZSghMCkubGFzdENoaWxkLmNoZWNrZWQsay5ub0Nsb25lRXZlbnQ9ITAsYi5hdHRhY2hFdmVudCYmKGIuYXR0YWNoRXZlbnQoIm9uY2xpY2siLGZ1bmN0aW9uKCl7ay5ub0Nsb25lRXZlbnQ9ITF9KSxiLmNsb25lTm9kZSghMCkuY2xpY2soKSksbnVsbD09ay5kZWxldGVFeHBhbmRvKXtrLmRlbGV0ZUV4cGFuZG89ITA7dHJ5e2RlbGV0ZSBiLnRlc3R9Y2F0Y2goZCl7ay5kZWxldGVFeHBhbmRvPSExfX19KCksZnVuY3Rpb24oKXt2YXIgYixjLGQ9eS5jcmVhdGVFbGVtZW50KCJkaXYiKTtmb3IoYiBpbntzdWJtaXQ6ITAsY2hhbmdlOiEwLGZvY3VzaW46ITB9KWM9Im9uIitiLChrW2IrIkJ1YmJsZXMiXT1jIGluIGEpfHwoZC5zZXRBdHRyaWJ1dGUoYywidCIpLGtbYisiQnViYmxlcyJdPWQuYXR0cmlidXRlc1tjXS5leHBhbmRvPT09ITEpO2Q9bnVsbH0oKTt2YXIgWD0vXig/OmlucHV0fHNlbGVjdHx0ZXh0YXJlYSkkL2ksWT0vXmtleS8sWj0vXig/Om1vdXNlfHBvaW50ZXJ8Y29udGV4dG1lbnUpfGNsaWNrLywkPS9eKD86Zm9jdXNpbmZvY3VzfGZvY3Vzb3V0Ymx1cikkLyxfPS9eKFteLl0qKSg/OlwuKC4rKXwpJC87ZnVuY3Rpb24gYWEoKXtyZXR1cm4hMH1mdW5jdGlvbiBiYSgpe3JldHVybiExfWZ1bmN0aW9uIGNhKCl7dHJ5e3JldHVybiB5LmFjdGl2ZUVsZW1lbnR9Y2F0Y2goYSl7fX1tLmV2ZW50PXtnbG9iYWw6e30sYWRkOmZ1bmN0aW9uKGEsYixjLGQsZSl7dmFyIGYsZyxoLGksaixrLGwsbixvLHAscSxyPW0uX2RhdGEoYSk7aWYocil7Yy5oYW5kbGVyJiYoaT1jLGM9aS5oYW5kbGVyLGU9aS5zZWxlY3RvciksYy5ndWlkfHwoYy5ndWlkPW0uZ3VpZCsrKSwoZz1yLmV2ZW50cyl8fChnPXIuZXZlbnRzPXt9KSwoaz1yLmhhbmRsZSl8fChrPXIuaGFuZGxlPWZ1bmN0aW9uKGEpe3JldHVybiB0eXBlb2YgbT09PUt8fGEmJm0uZXZlbnQudHJpZ2dlcmVkPT09YS50eXBlP3ZvaWQgMDptLmV2ZW50LmRpc3BhdGNoLmFwcGx5KGsuZWxlbSxhcmd1bWVudHMpfSxrLmVsZW09YSksYj0oYnx8IiIpLm1hdGNoKEUpfHxbIiJdLGg9Yi5sZW5ndGg7d2hpbGUoaC0tKWY9Xy5leGVjKGJbaF0pfHxbXSxvPXE9ZlsxXSxwPShmWzJdfHwiIikuc3BsaXQoIi4iKS5zb3J0KCksbyYmKGo9bS5ldmVudC5zcGVjaWFsW29dfHx7fSxvPShlP2ouZGVsZWdhdGVUeXBlOmouYmluZFR5cGUpfHxvLGo9bS5ldmVudC5zcGVjaWFsW29dfHx7fSxsPW0uZXh0ZW5kKHt0eXBlOm8sb3JpZ1R5cGU6cSxkYXRhOmQsaGFuZGxlcjpjLGd1aWQ6Yy5ndWlkLHNlbGVjdG9yOmUsbmVlZHNDb250ZXh0OmUmJm0uZXhwci5tYXRjaC5uZWVkc0NvbnRleHQudGVzdChlKSxuYW1lc3BhY2U6cC5qb2luKCIuIil9LGkpLChuPWdbb10pfHwobj1nW29dPVtdLG4uZGVsZWdhdGVDb3VudD0wLGouc2V0dXAmJmouc2V0dXAuY2FsbChhLGQscCxrKSE9PSExfHwoYS5hZGRFdmVudExpc3RlbmVyP2EuYWRkRXZlbnRMaXN0ZW5lcihvLGssITEpOmEuYXR0YWNoRXZlbnQmJmEuYXR0YWNoRXZlbnQoIm9uIitvLGspKSksai5hZGQmJihqLmFkZC5jYWxsKGEsbCksbC5oYW5kbGVyLmd1aWR8fChsLmhhbmRsZXIuZ3VpZD1jLmd1aWQpKSxlP24uc3BsaWNlKG4uZGVsZWdhdGVDb3VudCsrLDAsbCk6bi5wdXNoKGwpLG0uZXZlbnQuZ2xvYmFsW29dPSEwKTthPW51bGx9fSxyZW1vdmU6ZnVuY3Rpb24oYSxiLGMsZCxlKXt2YXIgZixnLGgsaSxqLGssbCxuLG8scCxxLHI9bS5oYXNEYXRhKGEpJiZtLl9kYXRhKGEpO2lmKHImJihrPXIuZXZlbnRzKSl7Yj0oYnx8IiIpLm1hdGNoKEUpfHxbIiJdLGo9Yi5sZW5ndGg7d2hpbGUoai0tKWlmKGg9Xy5leGVjKGJbal0pfHxbXSxvPXE9aFsxXSxwPShoWzJdfHwiIikuc3BsaXQoIi4iKS5zb3J0KCksbyl7bD1tLmV2ZW50LnNwZWNpYWxbb118fHt9LG89KGQ/bC5kZWxlZ2F0ZVR5cGU6bC5iaW5kVHlwZSl8fG8sbj1rW29dfHxbXSxoPWhbMl0mJm5ldyBSZWdFeHAoIihefFxcLikiK3Auam9pbigiXFwuKD86LipcXC58KSIpKyIoXFwufCQpIiksaT1mPW4ubGVuZ3RoO3doaWxlKGYtLSlnPW5bZl0sIWUmJnEhPT1nLm9yaWdUeXBlfHxjJiZjLmd1aWQhPT1nLmd1aWR8fGgmJiFoLnRlc3QoZy5uYW1lc3BhY2UpfHxkJiZkIT09Zy5zZWxlY3RvciYmKCIqKiIhPT1kfHwhZy5zZWxlY3Rvcil8fChuLnNwbGljZShmLDEpLGcuc2VsZWN0b3ImJm4uZGVsZWdhdGVDb3VudC0tLGwucmVtb3ZlJiZsLnJlbW92ZS5jYWxsKGEsZykpO2kmJiFuLmxlbmd0aCYmKGwudGVhcmRvd24mJmwudGVhcmRvd24uY2FsbChhLHAsci5oYW5kbGUpIT09ITF8fG0ucmVtb3ZlRXZlbnQoYSxvLHIuaGFuZGxlKSxkZWxldGUga1tvXSl9ZWxzZSBmb3IobyBpbiBrKW0uZXZlbnQucmVtb3ZlKGEsbytiW2pdLGMsZCwhMCk7bS5pc0VtcHR5T2JqZWN0KGspJiYoZGVsZXRlIHIuaGFuZGxlLG0uX3JlbW92ZURhdGEoYSwiZXZlbnRzIikpfX0sdHJpZ2dlcjpmdW5jdGlvbihiLGMsZCxlKXt2YXIgZixnLGgsaSxrLGwsbixvPVtkfHx5XSxwPWouY2FsbChiLCJ0eXBlIik/Yi50eXBlOmIscT1qLmNhbGwoYiwibmFtZXNwYWNlIik/Yi5uYW1lc3BhY2Uuc3BsaXQoIi4iKTpbXTtpZihoPWw9ZD1kfHx5LDMhPT1kLm5vZGVUeXBlJiY4IT09ZC5ub2RlVHlwZSYmISQudGVzdChwK20uZXZlbnQudHJpZ2dlcmVkKSYmKHAuaW5kZXhPZigiLiIpPj0wJiYocT1wLnNwbGl0KCIuIikscD1xLnNoaWZ0KCkscS5zb3J0KCkpLGc9cC5pbmRleE9mKCI6Iik8MCYmIm9uIitwLGI9YlttLmV4cGFuZG9dP2I6bmV3IG0uRXZlbnQocCwib2JqZWN0Ij09dHlwZW9mIGImJmIpLGIuaXNUcmlnZ2VyPWU/MjozLGIubmFtZXNwYWNlPXEuam9pbigiLiIpLGIubmFtZXNwYWNlX3JlPWIubmFtZXNwYWNlP25ldyBSZWdFeHAoIihefFxcLikiK3Euam9pbigiXFwuKD86LipcXC58KSIpKyIoXFwufCQpIik6bnVsbCxiLnJlc3VsdD12b2lkIDAsYi50YXJnZXR8fChiLnRhcmdldD1kKSxjPW51bGw9PWM/W2JdOm0ubWFrZUFycmF5KGMsW2JdKSxrPW0uZXZlbnQuc3BlY2lhbFtwXXx8e30sZXx8IWsudHJpZ2dlcnx8ay50cmlnZ2VyLmFwcGx5KGQsYykhPT0hMSkpe2lmKCFlJiYhay5ub0J1YmJsZSYmIW0uaXNXaW5kb3coZCkpe2ZvcihpPWsuZGVsZWdhdGVUeXBlfHxwLCQudGVzdChpK3ApfHwoaD1oLnBhcmVudE5vZGUpO2g7aD1oLnBhcmVudE5vZGUpby5wdXNoKGgpLGw9aDtsPT09KGQub3duZXJEb2N1bWVudHx8eSkmJm8ucHVzaChsLmRlZmF1bHRWaWV3fHxsLnBhcmVudFdpbmRvd3x8YSl9bj0wO3doaWxlKChoPW9bbisrXSkmJiFiLmlzUHJvcGFnYXRpb25TdG9wcGVkKCkpYi50eXBlPW4+MT9pOmsuYmluZFR5cGV8fHAsZj0obS5fZGF0YShoLCJldmVudHMiKXx8e30pW2IudHlwZV0mJm0uX2RhdGEoaCwiaGFuZGxlIiksZiYmZi5hcHBseShoLGMpLGY9ZyYmaFtnXSxmJiZmLmFwcGx5JiZtLmFjY2VwdERhdGEoaCkmJihiLnJlc3VsdD1mLmFwcGx5KGgsYyksYi5yZXN1bHQ9PT0hMSYmYi5wcmV2ZW50RGVmYXVsdCgpKTtpZihiLnR5cGU9cCwhZSYmIWIuaXNEZWZhdWx0UHJldmVudGVkKCkmJighay5fZGVmYXVsdHx8ay5fZGVmYXVsdC5hcHBseShvLnBvcCgpLGMpPT09ITEpJiZtLmFjY2VwdERhdGEoZCkmJmcmJmRbcF0mJiFtLmlzV2luZG93KGQpKXtsPWRbZ10sbCYmKGRbZ109bnVsbCksbS5ldmVudC50cmlnZ2VyZWQ9cDt0cnl7ZFtwXSgpfWNhdGNoKHIpe31tLmV2ZW50LnRyaWdnZXJlZD12b2lkIDAsbCYmKGRbZ109bCl9cmV0dXJuIGIucmVzdWx0fX0sZGlzcGF0Y2g6ZnVuY3Rpb24oYSl7YT1tLmV2ZW50LmZpeChhKTt2YXIgYixjLGUsZixnLGg9W10saT1kLmNhbGwoYXJndW1lbnRzKSxqPShtLl9kYXRhKHRoaXMsImV2ZW50cyIpfHx7fSlbYS50eXBlXXx8W10saz1tLmV2ZW50LnNwZWNpYWxbYS50eXBlXXx8e307aWYoaVswXT1hLGEuZGVsZWdhdGVUYXJnZXQ9dGhpcywhay5wcmVEaXNwYXRjaHx8ay5wcmVEaXNwYXRjaC5jYWxsKHRoaXMsYSkhPT0hMSl7aD1tLmV2ZW50LmhhbmRsZXJzLmNhbGwodGhpcyxhLGopLGI9MDt3aGlsZSgoZj1oW2IrK10pJiYhYS5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpKXthLmN1cnJlbnRUYXJnZXQ9Zi5lbGVtLGc9MDt3aGlsZSgoZT1mLmhhbmRsZXJzW2crK10pJiYhYS5pc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZCgpKSghYS5uYW1lc3BhY2VfcmV8fGEubmFtZXNwYWNlX3JlLnRlc3QoZS5uYW1lc3BhY2UpKSYmKGEuaGFuZGxlT2JqPWUsYS5kYXRhPWUuZGF0YSxjPSgobS5ldmVudC5zcGVjaWFsW2Uub3JpZ1R5cGVdfHx7fSkuaGFuZGxlfHxlLmhhbmRsZXIpLmFwcGx5KGYuZWxlbSxpKSx2b2lkIDAhPT1jJiYoYS5yZXN1bHQ9Yyk9PT0hMSYmKGEucHJldmVudERlZmF1bHQoKSxhLnN0b3BQcm9wYWdhdGlvbigpKSl9cmV0dXJuIGsucG9zdERpc3BhdGNoJiZrLnBvc3REaXNwYXRjaC5jYWxsKHRoaXMsYSksYS5yZXN1bHR9fSxoYW5kbGVyczpmdW5jdGlvbihhLGIpe3ZhciBjLGQsZSxmLGc9W10saD1iLmRlbGVnYXRlQ291bnQsaT1hLnRhcmdldDtpZihoJiZpLm5vZGVUeXBlJiYoIWEuYnV0dG9ufHwiY2xpY2siIT09YS50eXBlKSlmb3IoO2khPXRoaXM7aT1pLnBhcmVudE5vZGV8fHRoaXMpaWYoMT09PWkubm9kZVR5cGUmJihpLmRpc2FibGVkIT09ITB8fCJjbGljayIhPT1hLnR5cGUpKXtmb3IoZT1bXSxmPTA7aD5mO2YrKylkPWJbZl0sYz1kLnNlbGVjdG9yKyIgIix2b2lkIDA9PT1lW2NdJiYoZVtjXT1kLm5lZWRzQ29udGV4dD9tKGMsdGhpcykuaW5kZXgoaSk+PTA6bS5maW5kKGMsdGhpcyxudWxsLFtpXSkubGVuZ3RoKSxlW2NdJiZlLnB1c2goZCk7ZS5sZW5ndGgmJmcucHVzaCh7ZWxlbTppLGhhbmRsZXJzOmV9KX1yZXR1cm4gaDxiLmxlbmd0aCYmZy5wdXNoKHtlbGVtOnRoaXMsaGFuZGxlcnM6Yi5zbGljZShoKX0pLGd9LGZpeDpmdW5jdGlvbihhKXtpZihhW20uZXhwYW5kb10pcmV0dXJuIGE7dmFyIGIsYyxkLGU9YS50eXBlLGY9YSxnPXRoaXMuZml4SG9va3NbZV07Z3x8KHRoaXMuZml4SG9va3NbZV09Zz1aLnRlc3QoZSk/dGhpcy5tb3VzZUhvb2tzOlkudGVzdChlKT90aGlzLmtleUhvb2tzOnt9KSxkPWcucHJvcHM/dGhpcy5wcm9wcy5jb25jYXQoZy5wcm9wcyk6dGhpcy5wcm9wcyxhPW5ldyBtLkV2ZW50KGYpLGI9ZC5sZW5ndGg7d2hpbGUoYi0tKWM9ZFtiXSxhW2NdPWZbY107cmV0dXJuIGEudGFyZ2V0fHwoYS50YXJnZXQ9Zi5zcmNFbGVtZW50fHx5KSwzPT09YS50YXJnZXQubm9kZVR5cGUmJihhLnRhcmdldD1hLnRhcmdldC5wYXJlbnROb2RlKSxhLm1ldGFLZXk9ISFhLm1ldGFLZXksZy5maWx0ZXI/Zy5maWx0ZXIoYSxmKTphfSxwcm9wczoiYWx0S2V5IGJ1YmJsZXMgY2FuY2VsYWJsZSBjdHJsS2V5IGN1cnJlbnRUYXJnZXQgZXZlbnRQaGFzZSBtZXRhS2V5IHJlbGF0ZWRUYXJnZXQgc2hpZnRLZXkgdGFyZ2V0IHRpbWVTdGFtcCB2aWV3IHdoaWNoIi5zcGxpdCgiICIpLGZpeEhvb2tzOnt9LGtleUhvb2tzOntwcm9wczoiY2hhciBjaGFyQ29kZSBrZXkga2V5Q29kZSIuc3BsaXQoIiAiKSxmaWx0ZXI6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gbnVsbD09YS53aGljaCYmKGEud2hpY2g9bnVsbCE9Yi5jaGFyQ29kZT9iLmNoYXJDb2RlOmIua2V5Q29kZSksYX19LG1vdXNlSG9va3M6e3Byb3BzOiJidXR0b24gYnV0dG9ucyBjbGllbnRYIGNsaWVudFkgZnJvbUVsZW1lbnQgb2Zmc2V0WCBvZmZzZXRZIHBhZ2VYIHBhZ2VZIHNjcmVlblggc2NyZWVuWSB0b0VsZW1lbnQiLnNwbGl0KCIgIiksZmlsdGVyOmZ1bmN0aW9uKGEsYil7dmFyIGMsZCxlLGY9Yi5idXR0b24sZz1iLmZyb21FbGVtZW50O3JldHVybiBudWxsPT1hLnBhZ2VYJiZudWxsIT1iLmNsaWVudFgmJihkPWEudGFyZ2V0Lm93bmVyRG9jdW1lbnR8fHksZT1kLmRvY3VtZW50RWxlbWVudCxjPWQuYm9keSxhLnBhZ2VYPWIuY2xpZW50WCsoZSYmZS5zY3JvbGxMZWZ0fHxjJiZjLnNjcm9sbExlZnR8fDApLShlJiZlLmNsaWVudExlZnR8fGMmJmMuY2xpZW50TGVmdHx8MCksYS5wYWdlWT1iLmNsaWVudFkrKGUmJmUuc2Nyb2xsVG9wfHxjJiZjLnNjcm9sbFRvcHx8MCktKGUmJmUuY2xpZW50VG9wfHxjJiZjLmNsaWVudFRvcHx8MCkpLCFhLnJlbGF0ZWRUYXJnZXQmJmcmJihhLnJlbGF0ZWRUYXJnZXQ9Zz09PWEudGFyZ2V0P2IudG9FbGVtZW50OmcpLGEud2hpY2h8fHZvaWQgMD09PWZ8fChhLndoaWNoPTEmZj8xOjImZj8zOjQmZj8yOjApLGF9fSxzcGVjaWFsOntsb2FkOntub0J1YmJsZTohMH0sZm9jdXM6e3RyaWdnZXI6ZnVuY3Rpb24oKXtpZih0aGlzIT09Y2EoKSYmdGhpcy5mb2N1cyl0cnl7cmV0dXJuIHRoaXMuZm9jdXMoKSwhMX1jYXRjaChhKXt9fSxkZWxlZ2F0ZVR5cGU6ImZvY3VzaW4ifSxibHVyOnt0cmlnZ2VyOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXM9PT1jYSgpJiZ0aGlzLmJsdXI/KHRoaXMuYmx1cigpLCExKTp2b2lkIDB9LGRlbGVnYXRlVHlwZToiZm9jdXNvdXQifSxjbGljazp7dHJpZ2dlcjpmdW5jdGlvbigpe3JldHVybiBtLm5vZGVOYW1lKHRoaXMsImlucHV0IikmJiJjaGVja2JveCI9PT10aGlzLnR5cGUmJnRoaXMuY2xpY2s/KHRoaXMuY2xpY2soKSwhMSk6dm9pZCAwfSxfZGVmYXVsdDpmdW5jdGlvbihhKXtyZXR1cm4gbS5ub2RlTmFtZShhLnRhcmdldCwiYSIpfX0sYmVmb3JldW5sb2FkOntwb3N0RGlzcGF0Y2g6ZnVuY3Rpb24oYSl7dm9pZCAwIT09YS5yZXN1bHQmJmEub3JpZ2luYWxFdmVudCYmKGEub3JpZ2luYWxFdmVudC5yZXR1cm5WYWx1ZT1hLnJlc3VsdCl9fX0sc2ltdWxhdGU6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGU9bS5leHRlbmQobmV3IG0uRXZlbnQsYyx7dHlwZTphLGlzU2ltdWxhdGVkOiEwLG9yaWdpbmFsRXZlbnQ6e319KTtkP20uZXZlbnQudHJpZ2dlcihlLG51bGwsYik6bS5ldmVudC5kaXNwYXRjaC5jYWxsKGIsZSksZS5pc0RlZmF1bHRQcmV2ZW50ZWQoKSYmYy5wcmV2ZW50RGVmYXVsdCgpfX0sbS5yZW1vdmVFdmVudD15LnJlbW92ZUV2ZW50TGlzdGVuZXI/ZnVuY3Rpb24oYSxiLGMpe2EucmVtb3ZlRXZlbnRMaXN0ZW5lciYmYS5yZW1vdmVFdmVudExpc3RlbmVyKGIsYywhMSl9OmZ1bmN0aW9uKGEsYixjKXt2YXIgZD0ib24iK2I7YS5kZXRhY2hFdmVudCYmKHR5cGVvZiBhW2RdPT09SyYmKGFbZF09bnVsbCksYS5kZXRhY2hFdmVudChkLGMpKX0sbS5FdmVudD1mdW5jdGlvbihhLGIpe3JldHVybiB0aGlzIGluc3RhbmNlb2YgbS5FdmVudD8oYSYmYS50eXBlPyh0aGlzLm9yaWdpbmFsRXZlbnQ9YSx0aGlzLnR5cGU9YS50eXBlLHRoaXMuaXNEZWZhdWx0UHJldmVudGVkPWEuZGVmYXVsdFByZXZlbnRlZHx8dm9pZCAwPT09YS5kZWZhdWx0UHJldmVudGVkJiZhLnJldHVyblZhbHVlPT09ITE/YWE6YmEpOnRoaXMudHlwZT1hLGImJm0uZXh0ZW5kKHRoaXMsYiksdGhpcy50aW1lU3RhbXA9YSYmYS50aW1lU3RhbXB8fG0ubm93KCksdm9pZCh0aGlzW20uZXhwYW5kb109ITApKTpuZXcgbS5FdmVudChhLGIpfSxtLkV2ZW50LnByb3RvdHlwZT17aXNEZWZhdWx0UHJldmVudGVkOmJhLGlzUHJvcGFnYXRpb25TdG9wcGVkOmJhLGlzSW1tZWRpYXRlUHJvcGFnYXRpb25TdG9wcGVkOmJhLHByZXZlbnREZWZhdWx0OmZ1bmN0aW9uKCl7dmFyIGE9dGhpcy5vcmlnaW5hbEV2ZW50O3RoaXMuaXNEZWZhdWx0UHJldmVudGVkPWFhLGEmJihhLnByZXZlbnREZWZhdWx0P2EucHJldmVudERlZmF1bHQoKTphLnJldHVyblZhbHVlPSExKX0sc3RvcFByb3BhZ2F0aW9uOmZ1bmN0aW9uKCl7dmFyIGE9dGhpcy5vcmlnaW5hbEV2ZW50O3RoaXMuaXNQcm9wYWdhdGlvblN0b3BwZWQ9YWEsYSYmKGEuc3RvcFByb3BhZ2F0aW9uJiZhLnN0b3BQcm9wYWdhdGlvbigpLGEuY2FuY2VsQnViYmxlPSEwKX0sc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uOmZ1bmN0aW9uKCl7dmFyIGE9dGhpcy5vcmlnaW5hbEV2ZW50O3RoaXMuaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQ9YWEsYSYmYS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24mJmEuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCksdGhpcy5zdG9wUHJvcGFnYXRpb24oKX19LG0uZWFjaCh7bW91c2VlbnRlcjoibW91c2VvdmVyIixtb3VzZWxlYXZlOiJtb3VzZW91dCIscG9pbnRlcmVudGVyOiJwb2ludGVyb3ZlciIscG9pbnRlcmxlYXZlOiJwb2ludGVyb3V0In0sZnVuY3Rpb24oYSxiKXttLmV2ZW50LnNwZWNpYWxbYV09e2RlbGVnYXRlVHlwZTpiLGJpbmRUeXBlOmIsaGFuZGxlOmZ1bmN0aW9uKGEpe3ZhciBjLGQ9dGhpcyxlPWEucmVsYXRlZFRhcmdldCxmPWEuaGFuZGxlT2JqO3JldHVybighZXx8ZSE9PWQmJiFtLmNvbnRhaW5zKGQsZSkpJiYoYS50eXBlPWYub3JpZ1R5cGUsYz1mLmhhbmRsZXIuYXBwbHkodGhpcyxhcmd1bWVudHMpLGEudHlwZT1iKSxjfX19KSxrLnN1Ym1pdEJ1YmJsZXN8fChtLmV2ZW50LnNwZWNpYWwuc3VibWl0PXtzZXR1cDpmdW5jdGlvbigpe3JldHVybiBtLm5vZGVOYW1lKHRoaXMsImZvcm0iKT8hMTp2b2lkIG0uZXZlbnQuYWRkKHRoaXMsImNsaWNrLl9zdWJtaXQga2V5cHJlc3MuX3N1Ym1pdCIsZnVuY3Rpb24oYSl7dmFyIGI9YS50YXJnZXQsYz1tLm5vZGVOYW1lKGIsImlucHV0Iil8fG0ubm9kZU5hbWUoYiwiYnV0dG9uIik/Yi5mb3JtOnZvaWQgMDtjJiYhbS5fZGF0YShjLCJzdWJtaXRCdWJibGVzIikmJihtLmV2ZW50LmFkZChjLCJzdWJtaXQuX3N1Ym1pdCIsZnVuY3Rpb24oYSl7YS5fc3VibWl0X2J1YmJsZT0hMH0pLG0uX2RhdGEoYywic3VibWl0QnViYmxlcyIsITApKX0pfSxwb3N0RGlzcGF0Y2g6ZnVuY3Rpb24oYSl7YS5fc3VibWl0X2J1YmJsZSYmKGRlbGV0ZSBhLl9zdWJtaXRfYnViYmxlLHRoaXMucGFyZW50Tm9kZSYmIWEuaXNUcmlnZ2VyJiZtLmV2ZW50LnNpbXVsYXRlKCJzdWJtaXQiLHRoaXMucGFyZW50Tm9kZSxhLCEwKSl9LHRlYXJkb3duOmZ1bmN0aW9uKCl7cmV0dXJuIG0ubm9kZU5hbWUodGhpcywiZm9ybSIpPyExOnZvaWQgbS5ldmVudC5yZW1vdmUodGhpcywiLl9zdWJtaXQiKX19KSxrLmNoYW5nZUJ1YmJsZXN8fChtLmV2ZW50LnNwZWNpYWwuY2hhbmdlPXtzZXR1cDpmdW5jdGlvbigpe3JldHVybiBYLnRlc3QodGhpcy5ub2RlTmFtZSk/KCgiY2hlY2tib3giPT09dGhpcy50eXBlfHwicmFkaW8iPT09dGhpcy50eXBlKSYmKG0uZXZlbnQuYWRkKHRoaXMsInByb3BlcnR5Y2hhbmdlLl9jaGFuZ2UiLGZ1bmN0aW9uKGEpeyJjaGVja2VkIj09PWEub3JpZ2luYWxFdmVudC5wcm9wZXJ0eU5hbWUmJih0aGlzLl9qdXN0X2NoYW5nZWQ9ITApfSksbS5ldmVudC5hZGQodGhpcywiY2xpY2suX2NoYW5nZSIsZnVuY3Rpb24oYSl7dGhpcy5fanVzdF9jaGFuZ2VkJiYhYS5pc1RyaWdnZXImJih0aGlzLl9qdXN0X2NoYW5nZWQ9ITEpLG0uZXZlbnQuc2ltdWxhdGUoImNoYW5nZSIsdGhpcyxhLCEwKX0pKSwhMSk6dm9pZCBtLmV2ZW50LmFkZCh0aGlzLCJiZWZvcmVhY3RpdmF0ZS5fY2hhbmdlIixmdW5jdGlvbihhKXt2YXIgYj1hLnRhcmdldDtYLnRlc3QoYi5ub2RlTmFtZSkmJiFtLl9kYXRhKGIsImNoYW5nZUJ1YmJsZXMiKSYmKG0uZXZlbnQuYWRkKGIsImNoYW5nZS5fY2hhbmdlIixmdW5jdGlvbihhKXshdGhpcy5wYXJlbnROb2RlfHxhLmlzU2ltdWxhdGVkfHxhLmlzVHJpZ2dlcnx8bS5ldmVudC5zaW11bGF0ZSgiY2hhbmdlIix0aGlzLnBhcmVudE5vZGUsYSwhMCl9KSxtLl9kYXRhKGIsImNoYW5nZUJ1YmJsZXMiLCEwKSl9KX0saGFuZGxlOmZ1bmN0aW9uKGEpe3ZhciBiPWEudGFyZ2V0O3JldHVybiB0aGlzIT09Ynx8YS5pc1NpbXVsYXRlZHx8YS5pc1RyaWdnZXJ8fCJyYWRpbyIhPT1iLnR5cGUmJiJjaGVja2JveCIhPT1iLnR5cGU/YS5oYW5kbGVPYmouaGFuZGxlci5hcHBseSh0aGlzLGFyZ3VtZW50cyk6dm9pZCAwfSx0ZWFyZG93bjpmdW5jdGlvbigpe3JldHVybiBtLmV2ZW50LnJlbW92ZSh0aGlzLCIuX2NoYW5nZSIpLCFYLnRlc3QodGhpcy5ub2RlTmFtZSl9fSksay5mb2N1c2luQnViYmxlc3x8bS5lYWNoKHtmb2N1czoiZm9jdXNpbiIsYmx1cjoiZm9jdXNvdXQifSxmdW5jdGlvbihhLGIpe3ZhciBjPWZ1bmN0aW9uKGEpe20uZXZlbnQuc2ltdWxhdGUoYixhLnRhcmdldCxtLmV2ZW50LmZpeChhKSwhMCl9O20uZXZlbnQuc3BlY2lhbFtiXT17c2V0dXA6ZnVuY3Rpb24oKXt2YXIgZD10aGlzLm93bmVyRG9jdW1lbnR8fHRoaXMsZT1tLl9kYXRhKGQsYik7ZXx8ZC5hZGRFdmVudExpc3RlbmVyKGEsYywhMCksbS5fZGF0YShkLGIsKGV8fDApKzEpfSx0ZWFyZG93bjpmdW5jdGlvbigpe3ZhciBkPXRoaXMub3duZXJEb2N1bWVudHx8dGhpcyxlPW0uX2RhdGEoZCxiKS0xO2U/bS5fZGF0YShkLGIsZSk6KGQucmVtb3ZlRXZlbnRMaXN0ZW5lcihhLGMsITApLG0uX3JlbW92ZURhdGEoZCxiKSl9fX0pLG0uZm4uZXh0ZW5kKHtvbjpmdW5jdGlvbihhLGIsYyxkLGUpe3ZhciBmLGc7aWYoIm9iamVjdCI9PXR5cGVvZiBhKXsic3RyaW5nIiE9dHlwZW9mIGImJihjPWN8fGIsYj12b2lkIDApO2ZvcihmIGluIGEpdGhpcy5vbihmLGIsYyxhW2ZdLGUpO3JldHVybiB0aGlzfWlmKG51bGw9PWMmJm51bGw9PWQ/KGQ9YixjPWI9dm9pZCAwKTpudWxsPT1kJiYoInN0cmluZyI9PXR5cGVvZiBiPyhkPWMsYz12b2lkIDApOihkPWMsYz1iLGI9dm9pZCAwKSksZD09PSExKWQ9YmE7ZWxzZSBpZighZClyZXR1cm4gdGhpcztyZXR1cm4gMT09PWUmJihnPWQsZD1mdW5jdGlvbihhKXtyZXR1cm4gbSgpLm9mZihhKSxnLmFwcGx5KHRoaXMsYXJndW1lbnRzKX0sZC5ndWlkPWcuZ3VpZHx8KGcuZ3VpZD1tLmd1aWQrKykpLHRoaXMuZWFjaChmdW5jdGlvbigpe20uZXZlbnQuYWRkKHRoaXMsYSxkLGMsYil9KX0sb25lOmZ1bmN0aW9uKGEsYixjLGQpe3JldHVybiB0aGlzLm9uKGEsYixjLGQsMSl9LG9mZjpmdW5jdGlvbihhLGIsYyl7dmFyIGQsZTtpZihhJiZhLnByZXZlbnREZWZhdWx0JiZhLmhhbmRsZU9iailyZXR1cm4gZD1hLmhhbmRsZU9iaixtKGEuZGVsZWdhdGVUYXJnZXQpLm9mZihkLm5hbWVzcGFjZT9kLm9yaWdUeXBlKyIuIitkLm5hbWVzcGFjZTpkLm9yaWdUeXBlLGQuc2VsZWN0b3IsZC5oYW5kbGVyKSx0aGlzO2lmKCJvYmplY3QiPT10eXBlb2YgYSl7Zm9yKGUgaW4gYSl0aGlzLm9mZihlLGIsYVtlXSk7cmV0dXJuIHRoaXN9cmV0dXJuKGI9PT0hMXx8ImZ1bmN0aW9uIj09dHlwZW9mIGIpJiYoYz1iLGI9dm9pZCAwKSxjPT09ITEmJihjPWJhKSx0aGlzLmVhY2goZnVuY3Rpb24oKXttLmV2ZW50LnJlbW92ZSh0aGlzLGEsYyxiKX0pfSx0cmlnZ2VyOmZ1bmN0aW9uKGEsYil7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe20uZXZlbnQudHJpZ2dlcihhLGIsdGhpcyl9KX0sdHJpZ2dlckhhbmRsZXI6ZnVuY3Rpb24oYSxiKXt2YXIgYz10aGlzWzBdO3JldHVybiBjP20uZXZlbnQudHJpZ2dlcihhLGIsYywhMCk6dm9pZCAwfX0pO2Z1bmN0aW9uIGRhKGEpe3ZhciBiPWVhLnNwbGl0KCJ8IiksYz1hLmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtpZihjLmNyZWF0ZUVsZW1lbnQpd2hpbGUoYi5sZW5ndGgpYy5jcmVhdGVFbGVtZW50KGIucG9wKCkpO3JldHVybiBjfXZhciBlYT0iYWJicnxhcnRpY2xlfGFzaWRlfGF1ZGlvfGJkaXxjYW52YXN8ZGF0YXxkYXRhbGlzdHxkZXRhaWxzfGZpZ2NhcHRpb258ZmlndXJlfGZvb3RlcnxoZWFkZXJ8aGdyb3VwfG1hcmt8bWV0ZXJ8bmF2fG91dHB1dHxwcm9ncmVzc3xzZWN0aW9ufHN1bW1hcnl8dGltZXx2aWRlbyIsZmE9LyBqUXVlcnlcZCs9Iig/Om51bGx8XGQrKSIvZyxnYT1uZXcgUmVnRXhwKCI8KD86IitlYSsiKVtcXHMvPl0iLCJpIiksaGE9L15ccysvLGlhPS88KD8hYXJlYXxicnxjb2x8ZW1iZWR8aHJ8aW1nfGlucHV0fGxpbmt8bWV0YXxwYXJhbSkoKFtcdzpdKylbXj5dKilcLz4vZ2ksamE9LzwoW1x3Ol0rKS8sa2E9Lzx0Ym9keS9pLGxhPS88fCYjP1x3KzsvLG1hPS88KD86c2NyaXB0fHN0eWxlfGxpbmspL2ksbmE9L2NoZWNrZWRccyooPzpbXj1dfD1ccyouY2hlY2tlZC4pL2ksb2E9L14kfFwvKD86amF2YXxlY21hKXNjcmlwdC9pLHBhPS9edHJ1ZVwvKC4qKS8scWE9L15ccyo8ISg/OlxbQ0RBVEFcW3wtLSl8KD86XF1cXXwtLSk+XHMqJC9nLHJhPXtvcHRpb246WzEsIjxzZWxlY3QgbXVsdGlwbGU9J211bHRpcGxlJz4iLCI8L3NlbGVjdD4iXSxsZWdlbmQ6WzEsIjxmaWVsZHNldD4iLCI8L2ZpZWxkc2V0PiJdLGFyZWE6WzEsIjxtYXA+IiwiPC9tYXA+Il0scGFyYW06WzEsIjxvYmplY3Q+IiwiPC9vYmplY3Q+Il0sdGhlYWQ6WzEsIjx0YWJsZT4iLCI8L3RhYmxlPiJdLHRyOlsyLCI8dGFibGU+PHRib2R5PiIsIjwvdGJvZHk+PC90YWJsZT4iXSxjb2w6WzIsIjx0YWJsZT48dGJvZHk+PC90Ym9keT48Y29sZ3JvdXA+IiwiPC9jb2xncm91cD48L3RhYmxlPiJdLHRkOlszLCI8dGFibGU+PHRib2R5Pjx0cj4iLCI8L3RyPjwvdGJvZHk+PC90YWJsZT4iXSxfZGVmYXVsdDprLmh0bWxTZXJpYWxpemU/WzAsIiIsIiJdOlsxLCJYPGRpdj4iLCI8L2Rpdj4iXX0sc2E9ZGEoeSksdGE9c2EuYXBwZW5kQ2hpbGQoeS5jcmVhdGVFbGVtZW50KCJkaXYiKSk7cmEub3B0Z3JvdXA9cmEub3B0aW9uLHJhLnRib2R5PXJhLnRmb290PXJhLmNvbGdyb3VwPXJhLmNhcHRpb249cmEudGhlYWQscmEudGg9cmEudGQ7ZnVuY3Rpb24gdWEoYSxiKXt2YXIgYyxkLGU9MCxmPXR5cGVvZiBhLmdldEVsZW1lbnRzQnlUYWdOYW1lIT09Sz9hLmdldEVsZW1lbnRzQnlUYWdOYW1lKGJ8fCIqIik6dHlwZW9mIGEucXVlcnlTZWxlY3RvckFsbCE9PUs/YS5xdWVyeVNlbGVjdG9yQWxsKGJ8fCIqIik6dm9pZCAwO2lmKCFmKWZvcihmPVtdLGM9YS5jaGlsZE5vZGVzfHxhO251bGwhPShkPWNbZV0pO2UrKykhYnx8bS5ub2RlTmFtZShkLGIpP2YucHVzaChkKTptLm1lcmdlKGYsdWEoZCxiKSk7cmV0dXJuIHZvaWQgMD09PWJ8fGImJm0ubm9kZU5hbWUoYSxiKT9tLm1lcmdlKFthXSxmKTpmfWZ1bmN0aW9uIHZhKGEpe1cudGVzdChhLnR5cGUpJiYoYS5kZWZhdWx0Q2hlY2tlZD1hLmNoZWNrZWQpfWZ1bmN0aW9uIHdhKGEsYil7cmV0dXJuIG0ubm9kZU5hbWUoYSwidGFibGUiKSYmbS5ub2RlTmFtZSgxMSE9PWIubm9kZVR5cGU/YjpiLmZpcnN0Q2hpbGQsInRyIik/YS5nZXRFbGVtZW50c0J5VGFnTmFtZSgidGJvZHkiKVswXXx8YS5hcHBlbmRDaGlsZChhLm93bmVyRG9jdW1lbnQuY3JlYXRlRWxlbWVudCgidGJvZHkiKSk6YX1mdW5jdGlvbiB4YShhKXtyZXR1cm4gYS50eXBlPShudWxsIT09bS5maW5kLmF0dHIoYSwidHlwZSIpKSsiLyIrYS50eXBlLGF9ZnVuY3Rpb24geWEoYSl7dmFyIGI9cGEuZXhlYyhhLnR5cGUpO3JldHVybiBiP2EudHlwZT1iWzFdOmEucmVtb3ZlQXR0cmlidXRlKCJ0eXBlIiksYX1mdW5jdGlvbiB6YShhLGIpe2Zvcih2YXIgYyxkPTA7bnVsbCE9KGM9YVtkXSk7ZCsrKW0uX2RhdGEoYywiZ2xvYmFsRXZhbCIsIWJ8fG0uX2RhdGEoYltkXSwiZ2xvYmFsRXZhbCIpKX1mdW5jdGlvbiBBYShhLGIpe2lmKDE9PT1iLm5vZGVUeXBlJiZtLmhhc0RhdGEoYSkpe3ZhciBjLGQsZSxmPW0uX2RhdGEoYSksZz1tLl9kYXRhKGIsZiksaD1mLmV2ZW50cztpZihoKXtkZWxldGUgZy5oYW5kbGUsZy5ldmVudHM9e307Zm9yKGMgaW4gaClmb3IoZD0wLGU9aFtjXS5sZW5ndGg7ZT5kO2QrKyltLmV2ZW50LmFkZChiLGMsaFtjXVtkXSl9Zy5kYXRhJiYoZy5kYXRhPW0uZXh0ZW5kKHt9LGcuZGF0YSkpfX1mdW5jdGlvbiBCYShhLGIpe3ZhciBjLGQsZTtpZigxPT09Yi5ub2RlVHlwZSl7aWYoYz1iLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCksIWsubm9DbG9uZUV2ZW50JiZiW20uZXhwYW5kb10pe2U9bS5fZGF0YShiKTtmb3IoZCBpbiBlLmV2ZW50cyltLnJlbW92ZUV2ZW50KGIsZCxlLmhhbmRsZSk7Yi5yZW1vdmVBdHRyaWJ1dGUobS5leHBhbmRvKX0ic2NyaXB0Ij09PWMmJmIudGV4dCE9PWEudGV4dD8oeGEoYikudGV4dD1hLnRleHQseWEoYikpOiJvYmplY3QiPT09Yz8oYi5wYXJlbnROb2RlJiYoYi5vdXRlckhUTUw9YS5vdXRlckhUTUwpLGsuaHRtbDVDbG9uZSYmYS5pbm5lckhUTUwmJiFtLnRyaW0oYi5pbm5lckhUTUwpJiYoYi5pbm5lckhUTUw9YS5pbm5lckhUTUwpKToiaW5wdXQiPT09YyYmVy50ZXN0KGEudHlwZSk/KGIuZGVmYXVsdENoZWNrZWQ9Yi5jaGVja2VkPWEuY2hlY2tlZCxiLnZhbHVlIT09YS52YWx1ZSYmKGIudmFsdWU9YS52YWx1ZSkpOiJvcHRpb24iPT09Yz9iLmRlZmF1bHRTZWxlY3RlZD1iLnNlbGVjdGVkPWEuZGVmYXVsdFNlbGVjdGVkOigiaW5wdXQiPT09Y3x8InRleHRhcmVhIj09PWMpJiYoYi5kZWZhdWx0VmFsdWU9YS5kZWZhdWx0VmFsdWUpfX1tLmV4dGVuZCh7Y2xvbmU6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkLGUsZixnLGgsaT1tLmNvbnRhaW5zKGEub3duZXJEb2N1bWVudCxhKTtpZihrLmh0bWw1Q2xvbmV8fG0uaXNYTUxEb2MoYSl8fCFnYS50ZXN0KCI8IithLm5vZGVOYW1lKyI+Iik/Zj1hLmNsb25lTm9kZSghMCk6KHRhLmlubmVySFRNTD1hLm91dGVySFRNTCx0YS5yZW1vdmVDaGlsZChmPXRhLmZpcnN0Q2hpbGQpKSwhKGsubm9DbG9uZUV2ZW50JiZrLm5vQ2xvbmVDaGVja2VkfHwxIT09YS5ub2RlVHlwZSYmMTEhPT1hLm5vZGVUeXBlfHxtLmlzWE1MRG9jKGEpKSlmb3IoZD11YShmKSxoPXVhKGEpLGc9MDtudWxsIT0oZT1oW2ddKTsrK2cpZFtnXSYmQmEoZSxkW2ddKTtpZihiKWlmKGMpZm9yKGg9aHx8dWEoYSksZD1kfHx1YShmKSxnPTA7bnVsbCE9KGU9aFtnXSk7ZysrKUFhKGUsZFtnXSk7ZWxzZSBBYShhLGYpO3JldHVybiBkPXVhKGYsInNjcmlwdCIpLGQubGVuZ3RoPjAmJnphKGQsIWkmJnVhKGEsInNjcmlwdCIpKSxkPWg9ZT1udWxsLGZ9LGJ1aWxkRnJhZ21lbnQ6ZnVuY3Rpb24oYSxiLGMsZCl7Zm9yKHZhciBlLGYsZyxoLGksaixsLG49YS5sZW5ndGgsbz1kYShiKSxwPVtdLHE9MDtuPnE7cSsrKWlmKGY9YVtxXSxmfHwwPT09ZilpZigib2JqZWN0Ij09PW0udHlwZShmKSltLm1lcmdlKHAsZi5ub2RlVHlwZT9bZl06Zik7ZWxzZSBpZihsYS50ZXN0KGYpKXtoPWh8fG8uYXBwZW5kQ2hpbGQoYi5jcmVhdGVFbGVtZW50KCJkaXYiKSksaT0oamEuZXhlYyhmKXx8WyIiLCIiXSlbMV0udG9Mb3dlckNhc2UoKSxsPXJhW2ldfHxyYS5fZGVmYXVsdCxoLmlubmVySFRNTD1sWzFdK2YucmVwbGFjZShpYSwiPCQxPjwvJDI+IikrbFsyXSxlPWxbMF07d2hpbGUoZS0tKWg9aC5sYXN0Q2hpbGQ7aWYoIWsubGVhZGluZ1doaXRlc3BhY2UmJmhhLnRlc3QoZikmJnAucHVzaChiLmNyZWF0ZVRleHROb2RlKGhhLmV4ZWMoZilbMF0pKSwhay50Ym9keSl7Zj0idGFibGUiIT09aXx8a2EudGVzdChmKT8iPHRhYmxlPiIhPT1sWzFdfHxrYS50ZXN0KGYpPzA6aDpoLmZpcnN0Q2hpbGQsZT1mJiZmLmNoaWxkTm9kZXMubGVuZ3RoO3doaWxlKGUtLSltLm5vZGVOYW1lKGo9Zi5jaGlsZE5vZGVzW2VdLCJ0Ym9keSIpJiYhai5jaGlsZE5vZGVzLmxlbmd0aCYmZi5yZW1vdmVDaGlsZChqKX1tLm1lcmdlKHAsaC5jaGlsZE5vZGVzKSxoLnRleHRDb250ZW50PSIiO3doaWxlKGguZmlyc3RDaGlsZCloLnJlbW92ZUNoaWxkKGguZmlyc3RDaGlsZCk7aD1vLmxhc3RDaGlsZH1lbHNlIHAucHVzaChiLmNyZWF0ZVRleHROb2RlKGYpKTtoJiZvLnJlbW92ZUNoaWxkKGgpLGsuYXBwZW5kQ2hlY2tlZHx8bS5ncmVwKHVhKHAsImlucHV0IiksdmEpLHE9MDt3aGlsZShmPXBbcSsrXSlpZigoIWR8fC0xPT09bS5pbkFycmF5KGYsZCkpJiYoZz1tLmNvbnRhaW5zKGYub3duZXJEb2N1bWVudCxmKSxoPXVhKG8uYXBwZW5kQ2hpbGQoZiksInNjcmlwdCIpLGcmJnphKGgpLGMpKXtlPTA7d2hpbGUoZj1oW2UrK10pb2EudGVzdChmLnR5cGV8fCIiKSYmYy5wdXNoKGYpfXJldHVybiBoPW51bGwsb30sY2xlYW5EYXRhOmZ1bmN0aW9uKGEsYil7Zm9yKHZhciBkLGUsZixnLGg9MCxpPW0uZXhwYW5kbyxqPW0uY2FjaGUsbD1rLmRlbGV0ZUV4cGFuZG8sbj1tLmV2ZW50LnNwZWNpYWw7bnVsbCE9KGQ9YVtoXSk7aCsrKWlmKChifHxtLmFjY2VwdERhdGEoZCkpJiYoZj1kW2ldLGc9ZiYmaltmXSkpe2lmKGcuZXZlbnRzKWZvcihlIGluIGcuZXZlbnRzKW5bZV0/bS5ldmVudC5yZW1vdmUoZCxlKTptLnJlbW92ZUV2ZW50KGQsZSxnLmhhbmRsZSk7altmXSYmKGRlbGV0ZSBqW2ZdLGw/ZGVsZXRlIGRbaV06dHlwZW9mIGQucmVtb3ZlQXR0cmlidXRlIT09Sz9kLnJlbW92ZUF0dHJpYnV0ZShpKTpkW2ldPW51bGwsYy5wdXNoKGYpKX19fSksbS5mbi5leHRlbmQoe3RleHQ6ZnVuY3Rpb24oYSl7cmV0dXJuIFYodGhpcyxmdW5jdGlvbihhKXtyZXR1cm4gdm9pZCAwPT09YT9tLnRleHQodGhpcyk6dGhpcy5lbXB0eSgpLmFwcGVuZCgodGhpc1swXSYmdGhpc1swXS5vd25lckRvY3VtZW50fHx5KS5jcmVhdGVUZXh0Tm9kZShhKSl9LG51bGwsYSxhcmd1bWVudHMubGVuZ3RoKX0sYXBwZW5kOmZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZG9tTWFuaXAoYXJndW1lbnRzLGZ1bmN0aW9uKGEpe2lmKDE9PT10aGlzLm5vZGVUeXBlfHwxMT09PXRoaXMubm9kZVR5cGV8fDk9PT10aGlzLm5vZGVUeXBlKXt2YXIgYj13YSh0aGlzLGEpO2IuYXBwZW5kQ2hpbGQoYSl9fSl9LHByZXBlbmQ6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kb21NYW5pcChhcmd1bWVudHMsZnVuY3Rpb24oYSl7aWYoMT09PXRoaXMubm9kZVR5cGV8fDExPT09dGhpcy5ub2RlVHlwZXx8OT09PXRoaXMubm9kZVR5cGUpe3ZhciBiPXdhKHRoaXMsYSk7Yi5pbnNlcnRCZWZvcmUoYSxiLmZpcnN0Q2hpbGQpfX0pfSxiZWZvcmU6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kb21NYW5pcChhcmd1bWVudHMsZnVuY3Rpb24oYSl7dGhpcy5wYXJlbnROb2RlJiZ0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGEsdGhpcyl9KX0sYWZ0ZXI6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kb21NYW5pcChhcmd1bWVudHMsZnVuY3Rpb24oYSl7dGhpcy5wYXJlbnROb2RlJiZ0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGEsdGhpcy5uZXh0U2libGluZyl9KX0scmVtb3ZlOmZ1bmN0aW9uKGEsYil7Zm9yKHZhciBjLGQ9YT9tLmZpbHRlcihhLHRoaXMpOnRoaXMsZT0wO251bGwhPShjPWRbZV0pO2UrKylifHwxIT09Yy5ub2RlVHlwZXx8bS5jbGVhbkRhdGEodWEoYykpLGMucGFyZW50Tm9kZSYmKGImJm0uY29udGFpbnMoYy5vd25lckRvY3VtZW50LGMpJiZ6YSh1YShjLCJzY3JpcHQiKSksYy5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGMpKTtyZXR1cm4gdGhpc30sZW1wdHk6ZnVuY3Rpb24oKXtmb3IodmFyIGEsYj0wO251bGwhPShhPXRoaXNbYl0pO2IrKyl7MT09PWEubm9kZVR5cGUmJm0uY2xlYW5EYXRhKHVhKGEsITEpKTt3aGlsZShhLmZpcnN0Q2hpbGQpYS5yZW1vdmVDaGlsZChhLmZpcnN0Q2hpbGQpO2Eub3B0aW9ucyYmbS5ub2RlTmFtZShhLCJzZWxlY3QiKSYmKGEub3B0aW9ucy5sZW5ndGg9MCl9cmV0dXJuIHRoaXN9LGNsb25lOmZ1bmN0aW9uKGEsYil7cmV0dXJuIGE9bnVsbD09YT8hMTphLGI9bnVsbD09Yj9hOmIsdGhpcy5tYXAoZnVuY3Rpb24oKXtyZXR1cm4gbS5jbG9uZSh0aGlzLGEsYil9KX0saHRtbDpmdW5jdGlvbihhKXtyZXR1cm4gVih0aGlzLGZ1bmN0aW9uKGEpe3ZhciBiPXRoaXNbMF18fHt9LGM9MCxkPXRoaXMubGVuZ3RoO2lmKHZvaWQgMD09PWEpcmV0dXJuIDE9PT1iLm5vZGVUeXBlP2IuaW5uZXJIVE1MLnJlcGxhY2UoZmEsIiIpOnZvaWQgMDtpZighKCJzdHJpbmciIT10eXBlb2YgYXx8bWEudGVzdChhKXx8IWsuaHRtbFNlcmlhbGl6ZSYmZ2EudGVzdChhKXx8IWsubGVhZGluZ1doaXRlc3BhY2UmJmhhLnRlc3QoYSl8fHJhWyhqYS5leGVjKGEpfHxbIiIsIiJdKVsxXS50b0xvd2VyQ2FzZSgpXSkpe2E9YS5yZXBsYWNlKGlhLCI8JDE+PC8kMj4iKTt0cnl7Zm9yKDtkPmM7YysrKWI9dGhpc1tjXXx8e30sMT09PWIubm9kZVR5cGUmJihtLmNsZWFuRGF0YSh1YShiLCExKSksYi5pbm5lckhUTUw9YSk7Yj0wfWNhdGNoKGUpe319YiYmdGhpcy5lbXB0eSgpLmFwcGVuZChhKX0sbnVsbCxhLGFyZ3VtZW50cy5sZW5ndGgpfSxyZXBsYWNlV2l0aDpmdW5jdGlvbigpe3ZhciBhPWFyZ3VtZW50c1swXTtyZXR1cm4gdGhpcy5kb21NYW5pcChhcmd1bWVudHMsZnVuY3Rpb24oYil7YT10aGlzLnBhcmVudE5vZGUsbS5jbGVhbkRhdGEodWEodGhpcykpLGEmJmEucmVwbGFjZUNoaWxkKGIsdGhpcyl9KSxhJiYoYS5sZW5ndGh8fGEubm9kZVR5cGUpP3RoaXM6dGhpcy5yZW1vdmUoKX0sZGV0YWNoOmZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLnJlbW92ZShhLCEwKX0sZG9tTWFuaXA6ZnVuY3Rpb24oYSxiKXthPWUuYXBwbHkoW10sYSk7dmFyIGMsZCxmLGcsaCxpLGo9MCxsPXRoaXMubGVuZ3RoLG49dGhpcyxvPWwtMSxwPWFbMF0scT1tLmlzRnVuY3Rpb24ocCk7aWYocXx8bD4xJiYic3RyaW5nIj09dHlwZW9mIHAmJiFrLmNoZWNrQ2xvbmUmJm5hLnRlc3QocCkpcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbihjKXt2YXIgZD1uLmVxKGMpO3EmJihhWzBdPXAuY2FsbCh0aGlzLGMsZC5odG1sKCkpKSxkLmRvbU1hbmlwKGEsYil9KTtpZihsJiYoaT1tLmJ1aWxkRnJhZ21lbnQoYSx0aGlzWzBdLm93bmVyRG9jdW1lbnQsITEsdGhpcyksYz1pLmZpcnN0Q2hpbGQsMT09PWkuY2hpbGROb2Rlcy5sZW5ndGgmJihpPWMpLGMpKXtmb3IoZz1tLm1hcCh1YShpLCJzY3JpcHQiKSx4YSksZj1nLmxlbmd0aDtsPmo7aisrKWQ9aSxqIT09byYmKGQ9bS5jbG9uZShkLCEwLCEwKSxmJiZtLm1lcmdlKGcsdWEoZCwic2NyaXB0IikpKSxiLmNhbGwodGhpc1tqXSxkLGopO2lmKGYpZm9yKGg9Z1tnLmxlbmd0aC0xXS5vd25lckRvY3VtZW50LG0ubWFwKGcseWEpLGo9MDtmPmo7aisrKWQ9Z1tqXSxvYS50ZXN0KGQudHlwZXx8IiIpJiYhbS5fZGF0YShkLCJnbG9iYWxFdmFsIikmJm0uY29udGFpbnMoaCxkKSYmKGQuc3JjP20uX2V2YWxVcmwmJm0uX2V2YWxVcmwoZC5zcmMpOm0uZ2xvYmFsRXZhbCgoZC50ZXh0fHxkLnRleHRDb250ZW50fHxkLmlubmVySFRNTHx8IiIpLnJlcGxhY2UocWEsIiIpKSk7aT1jPW51bGx9cmV0dXJuIHRoaXN9fSksbS5lYWNoKHthcHBlbmRUbzoiYXBwZW5kIixwcmVwZW5kVG86InByZXBlbmQiLGluc2VydEJlZm9yZToiYmVmb3JlIixpbnNlcnRBZnRlcjoiYWZ0ZXIiLHJlcGxhY2VBbGw6InJlcGxhY2VXaXRoIn0sZnVuY3Rpb24oYSxiKXttLmZuW2FdPWZ1bmN0aW9uKGEpe2Zvcih2YXIgYyxkPTAsZT1bXSxnPW0oYSksaD1nLmxlbmd0aC0xO2g+PWQ7ZCsrKWM9ZD09PWg/dGhpczp0aGlzLmNsb25lKCEwKSxtKGdbZF0pW2JdKGMpLGYuYXBwbHkoZSxjLmdldCgpKTtyZXR1cm4gdGhpcy5wdXNoU3RhY2soZSl9fSk7dmFyIENhLERhPXt9O2Z1bmN0aW9uIEVhKGIsYyl7dmFyIGQsZT1tKGMuY3JlYXRlRWxlbWVudChiKSkuYXBwZW5kVG8oYy5ib2R5KSxmPWEuZ2V0RGVmYXVsdENvbXB1dGVkU3R5bGUmJihkPWEuZ2V0RGVmYXVsdENvbXB1dGVkU3R5bGUoZVswXSkpP2QuZGlzcGxheTptLmNzcyhlWzBdLCJkaXNwbGF5Iik7cmV0dXJuIGUuZGV0YWNoKCksZn1mdW5jdGlvbiBGYShhKXt2YXIgYj15LGM9RGFbYV07cmV0dXJuIGN8fChjPUVhKGEsYiksIm5vbmUiIT09YyYmY3x8KENhPShDYXx8bSgiPGlmcmFtZSBmcmFtZWJvcmRlcj0nMCcgd2lkdGg9JzAnIGhlaWdodD0nMCcvPiIpKS5hcHBlbmRUbyhiLmRvY3VtZW50RWxlbWVudCksYj0oQ2FbMF0uY29udGVudFdpbmRvd3x8Q2FbMF0uY29udGVudERvY3VtZW50KS5kb2N1bWVudCxiLndyaXRlKCksYi5jbG9zZSgpLGM9RWEoYSxiKSxDYS5kZXRhY2goKSksRGFbYV09YyksY30hZnVuY3Rpb24oKXt2YXIgYTtrLnNocmlua1dyYXBCbG9ja3M9ZnVuY3Rpb24oKXtpZihudWxsIT1hKXJldHVybiBhO2E9ITE7dmFyIGIsYyxkO3JldHVybiBjPXkuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImJvZHkiKVswXSxjJiZjLnN0eWxlPyhiPXkuY3JlYXRlRWxlbWVudCgiZGl2IiksZD15LmNyZWF0ZUVsZW1lbnQoImRpdiIpLGQuc3R5bGUuY3NzVGV4dD0icG9zaXRpb246YWJzb2x1dGU7Ym9yZGVyOjA7d2lkdGg6MDtoZWlnaHQ6MDt0b3A6MDtsZWZ0Oi05OTk5cHgiLGMuYXBwZW5kQ2hpbGQoZCkuYXBwZW5kQ2hpbGQoYiksdHlwZW9mIGIuc3R5bGUuem9vbSE9PUsmJihiLnN0eWxlLmNzc1RleHQ9Ii13ZWJraXQtYm94LXNpemluZzpjb250ZW50LWJveDstbW96LWJveC1zaXppbmc6Y29udGVudC1ib3g7Ym94LXNpemluZzpjb250ZW50LWJveDtkaXNwbGF5OmJsb2NrO21hcmdpbjowO2JvcmRlcjowO3BhZGRpbmc6MXB4O3dpZHRoOjFweDt6b29tOjEiLGIuYXBwZW5kQ2hpbGQoeS5jcmVhdGVFbGVtZW50KCJkaXYiKSkuc3R5bGUud2lkdGg9IjVweCIsYT0zIT09Yi5vZmZzZXRXaWR0aCksYy5yZW1vdmVDaGlsZChkKSxhKTp2b2lkIDB9fSgpO3ZhciBHYT0vXm1hcmdpbi8sSGE9bmV3IFJlZ0V4cCgiXigiK1MrIikoPyFweClbYS16JV0rJCIsImkiKSxJYSxKYSxLYT0vXih0b3B8cmlnaHR8Ym90dG9tfGxlZnQpJC87YS5nZXRDb21wdXRlZFN0eWxlPyhJYT1mdW5jdGlvbihiKXtyZXR1cm4gYi5vd25lckRvY3VtZW50LmRlZmF1bHRWaWV3Lm9wZW5lcj9iLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcuZ2V0Q29tcHV0ZWRTdHlsZShiLG51bGwpOmEuZ2V0Q29tcHV0ZWRTdHlsZShiLG51bGwpfSxKYT1mdW5jdGlvbihhLGIsYyl7dmFyIGQsZSxmLGcsaD1hLnN0eWxlO3JldHVybiBjPWN8fElhKGEpLGc9Yz9jLmdldFByb3BlcnR5VmFsdWUoYil8fGNbYl06dm9pZCAwLGMmJigiIiE9PWd8fG0uY29udGFpbnMoYS5vd25lckRvY3VtZW50LGEpfHwoZz1tLnN0eWxlKGEsYikpLEhhLnRlc3QoZykmJkdhLnRlc3QoYikmJihkPWgud2lkdGgsZT1oLm1pbldpZHRoLGY9aC5tYXhXaWR0aCxoLm1pbldpZHRoPWgubWF4V2lkdGg9aC53aWR0aD1nLGc9Yy53aWR0aCxoLndpZHRoPWQsaC5taW5XaWR0aD1lLGgubWF4V2lkdGg9ZikpLHZvaWQgMD09PWc/ZzpnKyIifSk6eS5kb2N1bWVudEVsZW1lbnQuY3VycmVudFN0eWxlJiYoSWE9ZnVuY3Rpb24oYSl7cmV0dXJuIGEuY3VycmVudFN0eWxlfSxKYT1mdW5jdGlvbihhLGIsYyl7dmFyIGQsZSxmLGcsaD1hLnN0eWxlO3JldHVybiBjPWN8fElhKGEpLGc9Yz9jW2JdOnZvaWQgMCxudWxsPT1nJiZoJiZoW2JdJiYoZz1oW2JdKSxIYS50ZXN0KGcpJiYhS2EudGVzdChiKSYmKGQ9aC5sZWZ0LGU9YS5ydW50aW1lU3R5bGUsZj1lJiZlLmxlZnQsZiYmKGUubGVmdD1hLmN1cnJlbnRTdHlsZS5sZWZ0KSxoLmxlZnQ9ImZvbnRTaXplIj09PWI/IjFlbSI6ZyxnPWgucGl4ZWxMZWZ0KyJweCIsaC5sZWZ0PWQsZiYmKGUubGVmdD1mKSksdm9pZCAwPT09Zz9nOmcrIiJ8fCJhdXRvIn0pO2Z1bmN0aW9uIExhKGEsYil7cmV0dXJue2dldDpmdW5jdGlvbigpe3ZhciBjPWEoKTtpZihudWxsIT1jKXJldHVybiBjP3ZvaWQgZGVsZXRlIHRoaXMuZ2V0Oih0aGlzLmdldD1iKS5hcHBseSh0aGlzLGFyZ3VtZW50cyl9fX0hZnVuY3Rpb24oKXt2YXIgYixjLGQsZSxmLGcsaDtpZihiPXkuY3JlYXRlRWxlbWVudCgiZGl2IiksYi5pbm5lckhUTUw9IiAgPGxpbmsvPjx0YWJsZT48L3RhYmxlPjxhIGhyZWY9Jy9hJz5hPC9hPjxpbnB1dCB0eXBlPSdjaGVja2JveCcvPiIsZD1iLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJhIilbMF0sYz1kJiZkLnN0eWxlKXtjLmNzc1RleHQ9ImZsb2F0OmxlZnQ7b3BhY2l0eTouNSIsay5vcGFjaXR5PSIwLjUiPT09Yy5vcGFjaXR5LGsuY3NzRmxvYXQ9ISFjLmNzc0Zsb2F0LGIuc3R5bGUuYmFja2dyb3VuZENsaXA9ImNvbnRlbnQtYm94IixiLmNsb25lTm9kZSghMCkuc3R5bGUuYmFja2dyb3VuZENsaXA9IiIsay5jbGVhckNsb25lU3R5bGU9ImNvbnRlbnQtYm94Ij09PWIuc3R5bGUuYmFja2dyb3VuZENsaXAsay5ib3hTaXppbmc9IiI9PT1jLmJveFNpemluZ3x8IiI9PT1jLk1vekJveFNpemluZ3x8IiI9PT1jLldlYmtpdEJveFNpemluZyxtLmV4dGVuZChrLHtyZWxpYWJsZUhpZGRlbk9mZnNldHM6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbD09ZyYmaSgpLGd9LGJveFNpemluZ1JlbGlhYmxlOmZ1bmN0aW9uKCl7cmV0dXJuIG51bGw9PWYmJmkoKSxmfSxwaXhlbFBvc2l0aW9uOmZ1bmN0aW9uKCl7cmV0dXJuIG51bGw9PWUmJmkoKSxlfSxyZWxpYWJsZU1hcmdpblJpZ2h0OmZ1bmN0aW9uKCl7cmV0dXJuIG51bGw9PWgmJmkoKSxofX0pO2Z1bmN0aW9uIGkoKXt2YXIgYixjLGQsaTtjPXkuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImJvZHkiKVswXSxjJiZjLnN0eWxlJiYoYj15LmNyZWF0ZUVsZW1lbnQoImRpdiIpLGQ9eS5jcmVhdGVFbGVtZW50KCJkaXYiKSxkLnN0eWxlLmNzc1RleHQ9InBvc2l0aW9uOmFic29sdXRlO2JvcmRlcjowO3dpZHRoOjA7aGVpZ2h0OjA7dG9wOjA7bGVmdDotOTk5OXB4IixjLmFwcGVuZENoaWxkKGQpLmFwcGVuZENoaWxkKGIpLGIuc3R5bGUuY3NzVGV4dD0iLXdlYmtpdC1ib3gtc2l6aW5nOmJvcmRlci1ib3g7LW1vei1ib3gtc2l6aW5nOmJvcmRlci1ib3g7Ym94LXNpemluZzpib3JkZXItYm94O2Rpc3BsYXk6YmxvY2s7bWFyZ2luLXRvcDoxJTt0b3A6MSU7Ym9yZGVyOjFweDtwYWRkaW5nOjFweDt3aWR0aDo0cHg7cG9zaXRpb246YWJzb2x1dGUiLGU9Zj0hMSxoPSEwLGEuZ2V0Q29tcHV0ZWRTdHlsZSYmKGU9IjElIiE9PShhLmdldENvbXB1dGVkU3R5bGUoYixudWxsKXx8e30pLnRvcCxmPSI0cHgiPT09KGEuZ2V0Q29tcHV0ZWRTdHlsZShiLG51bGwpfHx7d2lkdGg6IjRweCJ9KS53aWR0aCxpPWIuYXBwZW5kQ2hpbGQoeS5jcmVhdGVFbGVtZW50KCJkaXYiKSksaS5zdHlsZS5jc3NUZXh0PWIuc3R5bGUuY3NzVGV4dD0iLXdlYmtpdC1ib3gtc2l6aW5nOmNvbnRlbnQtYm94Oy1tb3otYm94LXNpemluZzpjb250ZW50LWJveDtib3gtc2l6aW5nOmNvbnRlbnQtYm94O2Rpc3BsYXk6YmxvY2s7bWFyZ2luOjA7Ym9yZGVyOjA7cGFkZGluZzowIixpLnN0eWxlLm1hcmdpblJpZ2h0PWkuc3R5bGUud2lkdGg9IjAiLGIuc3R5bGUud2lkdGg9IjFweCIsaD0hcGFyc2VGbG9hdCgoYS5nZXRDb21wdXRlZFN0eWxlKGksbnVsbCl8fHt9KS5tYXJnaW5SaWdodCksYi5yZW1vdmVDaGlsZChpKSksYi5pbm5lckhUTUw9Ijx0YWJsZT48dHI+PHRkPjwvdGQ+PHRkPnQ8L3RkPjwvdHI+PC90YWJsZT4iLGk9Yi5nZXRFbGVtZW50c0J5VGFnTmFtZSgidGQiKSxpWzBdLnN0eWxlLmNzc1RleHQ9Im1hcmdpbjowO2JvcmRlcjowO3BhZGRpbmc6MDtkaXNwbGF5Om5vbmUiLGc9MD09PWlbMF0ub2Zmc2V0SGVpZ2h0LGcmJihpWzBdLnN0eWxlLmRpc3BsYXk9IiIsaVsxXS5zdHlsZS5kaXNwbGF5PSJub25lIixnPTA9PT1pWzBdLm9mZnNldEhlaWdodCksYy5yZW1vdmVDaGlsZChkKSl9fX0oKSxtLnN3YXA9ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGUsZixnPXt9O2ZvcihmIGluIGIpZ1tmXT1hLnN0eWxlW2ZdLGEuc3R5bGVbZl09YltmXTtlPWMuYXBwbHkoYSxkfHxbXSk7Zm9yKGYgaW4gYilhLnN0eWxlW2ZdPWdbZl07cmV0dXJuIGV9O3ZhciBNYT0vYWxwaGFcKFteKV0qXCkvaSxOYT0vb3BhY2l0eVxzKj1ccyooW14pXSopLyxPYT0vXihub25lfHRhYmxlKD8hLWNbZWFdKS4rKS8sUGE9bmV3IFJlZ0V4cCgiXigiK1MrIikoLiopJCIsImkiKSxRYT1uZXcgUmVnRXhwKCJeKFsrLV0pPSgiK1MrIikiLCJpIiksUmE9e3Bvc2l0aW9uOiJhYnNvbHV0ZSIsdmlzaWJpbGl0eToiaGlkZGVuIixkaXNwbGF5OiJibG9jayJ9LFNhPXtsZXR0ZXJTcGFjaW5nOiIwIixmb250V2VpZ2h0OiI0MDAifSxUYT1bIldlYmtpdCIsIk8iLCJNb3oiLCJtcyJdO2Z1bmN0aW9uIFVhKGEsYil7aWYoYiBpbiBhKXJldHVybiBiO3ZhciBjPWIuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkrYi5zbGljZSgxKSxkPWIsZT1UYS5sZW5ndGg7d2hpbGUoZS0tKWlmKGI9VGFbZV0rYyxiIGluIGEpcmV0dXJuIGI7cmV0dXJuIGR9ZnVuY3Rpb24gVmEoYSxiKXtmb3IodmFyIGMsZCxlLGY9W10sZz0wLGg9YS5sZW5ndGg7aD5nO2crKylkPWFbZ10sZC5zdHlsZSYmKGZbZ109bS5fZGF0YShkLCJvbGRkaXNwbGF5IiksYz1kLnN0eWxlLmRpc3BsYXksYj8oZltnXXx8Im5vbmUiIT09Y3x8KGQuc3R5bGUuZGlzcGxheT0iIiksIiI9PT1kLnN0eWxlLmRpc3BsYXkmJlUoZCkmJihmW2ddPW0uX2RhdGEoZCwib2xkZGlzcGxheSIsRmEoZC5ub2RlTmFtZSkpKSk6KGU9VShkKSwoYyYmIm5vbmUiIT09Y3x8IWUpJiZtLl9kYXRhKGQsIm9sZGRpc3BsYXkiLGU/YzptLmNzcyhkLCJkaXNwbGF5IikpKSk7Zm9yKGc9MDtoPmc7ZysrKWQ9YVtnXSxkLnN0eWxlJiYoYiYmIm5vbmUiIT09ZC5zdHlsZS5kaXNwbGF5JiYiIiE9PWQuc3R5bGUuZGlzcGxheXx8KGQuc3R5bGUuZGlzcGxheT1iP2ZbZ118fCIiOiJub25lIikpO3JldHVybiBhfWZ1bmN0aW9uIFdhKGEsYixjKXt2YXIgZD1QYS5leGVjKGIpO3JldHVybiBkP01hdGgubWF4KDAsZFsxXS0oY3x8MCkpKyhkWzJdfHwicHgiKTpifWZ1bmN0aW9uIFhhKGEsYixjLGQsZSl7Zm9yKHZhciBmPWM9PT0oZD8iYm9yZGVyIjoiY29udGVudCIpPzQ6IndpZHRoIj09PWI/MTowLGc9MDs0PmY7Zis9MikibWFyZ2luIj09PWMmJihnKz1tLmNzcyhhLGMrVFtmXSwhMCxlKSksZD8oImNvbnRlbnQiPT09YyYmKGctPW0uY3NzKGEsInBhZGRpbmciK1RbZl0sITAsZSkpLCJtYXJnaW4iIT09YyYmKGctPW0uY3NzKGEsImJvcmRlciIrVFtmXSsiV2lkdGgiLCEwLGUpKSk6KGcrPW0uY3NzKGEsInBhZGRpbmciK1RbZl0sITAsZSksInBhZGRpbmciIT09YyYmKGcrPW0uY3NzKGEsImJvcmRlciIrVFtmXSsiV2lkdGgiLCEwLGUpKSk7cmV0dXJuIGd9ZnVuY3Rpb24gWWEoYSxiLGMpe3ZhciBkPSEwLGU9IndpZHRoIj09PWI/YS5vZmZzZXRXaWR0aDphLm9mZnNldEhlaWdodCxmPUlhKGEpLGc9ay5ib3hTaXppbmcmJiJib3JkZXItYm94Ij09PW0uY3NzKGEsImJveFNpemluZyIsITEsZik7aWYoMD49ZXx8bnVsbD09ZSl7aWYoZT1KYShhLGIsZiksKDA+ZXx8bnVsbD09ZSkmJihlPWEuc3R5bGVbYl0pLEhhLnRlc3QoZSkpcmV0dXJuIGU7ZD1nJiYoay5ib3hTaXppbmdSZWxpYWJsZSgpfHxlPT09YS5zdHlsZVtiXSksZT1wYXJzZUZsb2F0KGUpfHwwfXJldHVybiBlK1hhKGEsYixjfHwoZz8iYm9yZGVyIjoiY29udGVudCIpLGQsZikrInB4In1tLmV4dGVuZCh7Y3NzSG9va3M6e29wYWNpdHk6e2dldDpmdW5jdGlvbihhLGIpe2lmKGIpe3ZhciBjPUphKGEsIm9wYWNpdHkiKTtyZXR1cm4iIj09PWM/IjEiOmN9fX19LGNzc051bWJlcjp7Y29sdW1uQ291bnQ6ITAsZmlsbE9wYWNpdHk6ITAsZmxleEdyb3c6ITAsZmxleFNocmluazohMCxmb250V2VpZ2h0OiEwLGxpbmVIZWlnaHQ6ITAsb3BhY2l0eTohMCxvcmRlcjohMCxvcnBoYW5zOiEwLHdpZG93czohMCx6SW5kZXg6ITAsem9vbTohMH0sY3NzUHJvcHM6eyJmbG9hdCI6ay5jc3NGbG9hdD8iY3NzRmxvYXQiOiJzdHlsZUZsb2F0In0sc3R5bGU6ZnVuY3Rpb24oYSxiLGMsZCl7aWYoYSYmMyE9PWEubm9kZVR5cGUmJjghPT1hLm5vZGVUeXBlJiZhLnN0eWxlKXt2YXIgZSxmLGcsaD1tLmNhbWVsQ2FzZShiKSxpPWEuc3R5bGU7aWYoYj1tLmNzc1Byb3BzW2hdfHwobS5jc3NQcm9wc1toXT1VYShpLGgpKSxnPW0uY3NzSG9va3NbYl18fG0uY3NzSG9va3NbaF0sdm9pZCAwPT09YylyZXR1cm4gZyYmImdldCJpbiBnJiZ2b2lkIDAhPT0oZT1nLmdldChhLCExLGQpKT9lOmlbYl07aWYoZj10eXBlb2YgYywic3RyaW5nIj09PWYmJihlPVFhLmV4ZWMoYykpJiYoYz0oZVsxXSsxKSplWzJdK3BhcnNlRmxvYXQobS5jc3MoYSxiKSksZj0ibnVtYmVyIiksbnVsbCE9YyYmYz09PWMmJigibnVtYmVyIiE9PWZ8fG0uY3NzTnVtYmVyW2hdfHwoYys9InB4Iiksay5jbGVhckNsb25lU3R5bGV8fCIiIT09Y3x8MCE9PWIuaW5kZXhPZigiYmFja2dyb3VuZCIpfHwoaVtiXT0iaW5oZXJpdCIpLCEoZyYmInNldCJpbiBnJiZ2b2lkIDA9PT0oYz1nLnNldChhLGMsZCkpKSkpdHJ5e2lbYl09Y31jYXRjaChqKXt9fX0sY3NzOmZ1bmN0aW9uKGEsYixjLGQpe3ZhciBlLGYsZyxoPW0uY2FtZWxDYXNlKGIpO3JldHVybiBiPW0uY3NzUHJvcHNbaF18fChtLmNzc1Byb3BzW2hdPVVhKGEuc3R5bGUsaCkpLGc9bS5jc3NIb29rc1tiXXx8bS5jc3NIb29rc1toXSxnJiYiZ2V0ImluIGcmJihmPWcuZ2V0KGEsITAsYykpLHZvaWQgMD09PWYmJihmPUphKGEsYixkKSksIm5vcm1hbCI9PT1mJiZiIGluIFNhJiYoZj1TYVtiXSksIiI9PT1jfHxjPyhlPXBhcnNlRmxvYXQoZiksYz09PSEwfHxtLmlzTnVtZXJpYyhlKT9lfHwwOmYpOmZ9fSksbS5lYWNoKFsiaGVpZ2h0Iiwid2lkdGgiXSxmdW5jdGlvbihhLGIpe20uY3NzSG9va3NbYl09e2dldDpmdW5jdGlvbihhLGMsZCl7cmV0dXJuIGM/T2EudGVzdChtLmNzcyhhLCJkaXNwbGF5IikpJiYwPT09YS5vZmZzZXRXaWR0aD9tLnN3YXAoYSxSYSxmdW5jdGlvbigpe3JldHVybiBZYShhLGIsZCl9KTpZYShhLGIsZCk6dm9pZCAwfSxzZXQ6ZnVuY3Rpb24oYSxjLGQpe3ZhciBlPWQmJklhKGEpO3JldHVybiBXYShhLGMsZD9YYShhLGIsZCxrLmJveFNpemluZyYmImJvcmRlci1ib3giPT09bS5jc3MoYSwiYm94U2l6aW5nIiwhMSxlKSxlKTowKX19fSksay5vcGFjaXR5fHwobS5jc3NIb29rcy5vcGFjaXR5PXtnZXQ6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gTmEudGVzdCgoYiYmYS5jdXJyZW50U3R5bGU/YS5jdXJyZW50U3R5bGUuZmlsdGVyOmEuc3R5bGUuZmlsdGVyKXx8IiIpPy4wMSpwYXJzZUZsb2F0KFJlZ0V4cC4kMSkrIiI6Yj8iMSI6IiJ9LHNldDpmdW5jdGlvbihhLGIpe3ZhciBjPWEuc3R5bGUsZD1hLmN1cnJlbnRTdHlsZSxlPW0uaXNOdW1lcmljKGIpPyJhbHBoYShvcGFjaXR5PSIrMTAwKmIrIikiOiIiLGY9ZCYmZC5maWx0ZXJ8fGMuZmlsdGVyfHwiIjtjLnpvb209MSwoYj49MXx8IiI9PT1iKSYmIiI9PT1tLnRyaW0oZi5yZXBsYWNlKE1hLCIiKSkmJmMucmVtb3ZlQXR0cmlidXRlJiYoYy5yZW1vdmVBdHRyaWJ1dGUoImZpbHRlciIpLCIiPT09Ynx8ZCYmIWQuZmlsdGVyKXx8KGMuZmlsdGVyPU1hLnRlc3QoZik/Zi5yZXBsYWNlKE1hLGUpOmYrIiAiK2UpfX0pLG0uY3NzSG9va3MubWFyZ2luUmlnaHQ9TGEoay5yZWxpYWJsZU1hcmdpblJpZ2h0LGZ1bmN0aW9uKGEsYil7cmV0dXJuIGI/bS5zd2FwKGEse2Rpc3BsYXk6ImlubGluZS1ibG9jayJ9LEphLFthLCJtYXJnaW5SaWdodCJdKTp2b2lkIDB9KSxtLmVhY2goe21hcmdpbjoiIixwYWRkaW5nOiIiLGJvcmRlcjoiV2lkdGgifSxmdW5jdGlvbihhLGIpe20uY3NzSG9va3NbYStiXT17ZXhwYW5kOmZ1bmN0aW9uKGMpe2Zvcih2YXIgZD0wLGU9e30sZj0ic3RyaW5nIj09dHlwZW9mIGM/Yy5zcGxpdCgiICIpOltjXTs0PmQ7ZCsrKWVbYStUW2RdK2JdPWZbZF18fGZbZC0yXXx8ZlswXTtyZXR1cm4gZX19LEdhLnRlc3QoYSl8fChtLmNzc0hvb2tzW2ErYl0uc2V0PVdhKX0pLG0uZm4uZXh0ZW5kKHtjc3M6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gVih0aGlzLGZ1bmN0aW9uKGEsYixjKXt2YXIgZCxlLGY9e30sZz0wO2lmKG0uaXNBcnJheShiKSl7Zm9yKGQ9SWEoYSksZT1iLmxlbmd0aDtlPmc7ZysrKWZbYltnXV09bS5jc3MoYSxiW2ddLCExLGQpO3JldHVybiBmfXJldHVybiB2b2lkIDAhPT1jP20uc3R5bGUoYSxiLGMpOm0uY3NzKGEsYil9LGEsYixhcmd1bWVudHMubGVuZ3RoPjEpfSxzaG93OmZ1bmN0aW9uKCl7cmV0dXJuIFZhKHRoaXMsITApfSxoaWRlOmZ1bmN0aW9uKCl7cmV0dXJuIFZhKHRoaXMpfSx0b2dnbGU6ZnVuY3Rpb24oYSl7cmV0dXJuImJvb2xlYW4iPT10eXBlb2YgYT9hP3RoaXMuc2hvdygpOnRoaXMuaGlkZSgpOnRoaXMuZWFjaChmdW5jdGlvbigpe1UodGhpcyk/bSh0aGlzKS5zaG93KCk6bSh0aGlzKS5oaWRlKCl9KX19KTtmdW5jdGlvbiBaYShhLGIsYyxkLGUpewpyZXR1cm4gbmV3IFphLnByb3RvdHlwZS5pbml0KGEsYixjLGQsZSl9bS5Ud2Vlbj1aYSxaYS5wcm90b3R5cGU9e2NvbnN0cnVjdG9yOlphLGluaXQ6ZnVuY3Rpb24oYSxiLGMsZCxlLGYpe3RoaXMuZWxlbT1hLHRoaXMucHJvcD1jLHRoaXMuZWFzaW5nPWV8fCJzd2luZyIsdGhpcy5vcHRpb25zPWIsdGhpcy5zdGFydD10aGlzLm5vdz10aGlzLmN1cigpLHRoaXMuZW5kPWQsdGhpcy51bml0PWZ8fChtLmNzc051bWJlcltjXT8iIjoicHgiKX0sY3VyOmZ1bmN0aW9uKCl7dmFyIGE9WmEucHJvcEhvb2tzW3RoaXMucHJvcF07cmV0dXJuIGEmJmEuZ2V0P2EuZ2V0KHRoaXMpOlphLnByb3BIb29rcy5fZGVmYXVsdC5nZXQodGhpcyl9LHJ1bjpmdW5jdGlvbihhKXt2YXIgYixjPVphLnByb3BIb29rc1t0aGlzLnByb3BdO3JldHVybiB0aGlzLm9wdGlvbnMuZHVyYXRpb24/dGhpcy5wb3M9Yj1tLmVhc2luZ1t0aGlzLmVhc2luZ10oYSx0aGlzLm9wdGlvbnMuZHVyYXRpb24qYSwwLDEsdGhpcy5vcHRpb25zLmR1cmF0aW9uKTp0aGlzLnBvcz1iPWEsdGhpcy5ub3c9KHRoaXMuZW5kLXRoaXMuc3RhcnQpKmIrdGhpcy5zdGFydCx0aGlzLm9wdGlvbnMuc3RlcCYmdGhpcy5vcHRpb25zLnN0ZXAuY2FsbCh0aGlzLmVsZW0sdGhpcy5ub3csdGhpcyksYyYmYy5zZXQ/Yy5zZXQodGhpcyk6WmEucHJvcEhvb2tzLl9kZWZhdWx0LnNldCh0aGlzKSx0aGlzfX0sWmEucHJvdG90eXBlLmluaXQucHJvdG90eXBlPVphLnByb3RvdHlwZSxaYS5wcm9wSG9va3M9e19kZWZhdWx0OntnZXQ6ZnVuY3Rpb24oYSl7dmFyIGI7cmV0dXJuIG51bGw9PWEuZWxlbVthLnByb3BdfHxhLmVsZW0uc3R5bGUmJm51bGwhPWEuZWxlbS5zdHlsZVthLnByb3BdPyhiPW0uY3NzKGEuZWxlbSxhLnByb3AsIiIpLGImJiJhdXRvIiE9PWI/YjowKTphLmVsZW1bYS5wcm9wXX0sc2V0OmZ1bmN0aW9uKGEpe20uZnguc3RlcFthLnByb3BdP20uZnguc3RlcFthLnByb3BdKGEpOmEuZWxlbS5zdHlsZSYmKG51bGwhPWEuZWxlbS5zdHlsZVttLmNzc1Byb3BzW2EucHJvcF1dfHxtLmNzc0hvb2tzW2EucHJvcF0pP20uc3R5bGUoYS5lbGVtLGEucHJvcCxhLm5vdythLnVuaXQpOmEuZWxlbVthLnByb3BdPWEubm93fX19LFphLnByb3BIb29rcy5zY3JvbGxUb3A9WmEucHJvcEhvb2tzLnNjcm9sbExlZnQ9e3NldDpmdW5jdGlvbihhKXthLmVsZW0ubm9kZVR5cGUmJmEuZWxlbS5wYXJlbnROb2RlJiYoYS5lbGVtW2EucHJvcF09YS5ub3cpfX0sbS5lYXNpbmc9e2xpbmVhcjpmdW5jdGlvbihhKXtyZXR1cm4gYX0sc3dpbmc6ZnVuY3Rpb24oYSl7cmV0dXJuLjUtTWF0aC5jb3MoYSpNYXRoLlBJKS8yfX0sbS5meD1aYS5wcm90b3R5cGUuaW5pdCxtLmZ4LnN0ZXA9e307dmFyICRhLF9hLGFiPS9eKD86dG9nZ2xlfHNob3d8aGlkZSkkLyxiYj1uZXcgUmVnRXhwKCJeKD86KFsrLV0pPXwpKCIrUysiKShbYS16JV0qKSQiLCJpIiksY2I9L3F1ZXVlSG9va3MkLyxkYj1baWJdLGViPXsiKiI6W2Z1bmN0aW9uKGEsYil7dmFyIGM9dGhpcy5jcmVhdGVUd2VlbihhLGIpLGQ9Yy5jdXIoKSxlPWJiLmV4ZWMoYiksZj1lJiZlWzNdfHwobS5jc3NOdW1iZXJbYV0/IiI6InB4IiksZz0obS5jc3NOdW1iZXJbYV18fCJweCIhPT1mJiYrZCkmJmJiLmV4ZWMobS5jc3MoYy5lbGVtLGEpKSxoPTEsaT0yMDtpZihnJiZnWzNdIT09Zil7Zj1mfHxnWzNdLGU9ZXx8W10sZz0rZHx8MTtkbyBoPWh8fCIuNSIsZy89aCxtLnN0eWxlKGMuZWxlbSxhLGcrZik7d2hpbGUoaCE9PShoPWMuY3VyKCkvZCkmJjEhPT1oJiYtLWkpfXJldHVybiBlJiYoZz1jLnN0YXJ0PStnfHwrZHx8MCxjLnVuaXQ9ZixjLmVuZD1lWzFdP2crKGVbMV0rMSkqZVsyXTorZVsyXSksY31dfTtmdW5jdGlvbiBmYigpe3JldHVybiBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7JGE9dm9pZCAwfSksJGE9bS5ub3coKX1mdW5jdGlvbiBnYihhLGIpe3ZhciBjLGQ9e2hlaWdodDphfSxlPTA7Zm9yKGI9Yj8xOjA7ND5lO2UrPTItYiljPVRbZV0sZFsibWFyZ2luIitjXT1kWyJwYWRkaW5nIitjXT1hO3JldHVybiBiJiYoZC5vcGFjaXR5PWQud2lkdGg9YSksZH1mdW5jdGlvbiBoYihhLGIsYyl7Zm9yKHZhciBkLGU9KGViW2JdfHxbXSkuY29uY2F0KGViWyIqIl0pLGY9MCxnPWUubGVuZ3RoO2c+ZjtmKyspaWYoZD1lW2ZdLmNhbGwoYyxiLGEpKXJldHVybiBkfWZ1bmN0aW9uIGliKGEsYixjKXt2YXIgZCxlLGYsZyxoLGksaixsLG49dGhpcyxvPXt9LHA9YS5zdHlsZSxxPWEubm9kZVR5cGUmJlUoYSkscj1tLl9kYXRhKGEsImZ4c2hvdyIpO2MucXVldWV8fChoPW0uX3F1ZXVlSG9va3MoYSwiZngiKSxudWxsPT1oLnVucXVldWVkJiYoaC51bnF1ZXVlZD0wLGk9aC5lbXB0eS5maXJlLGguZW1wdHkuZmlyZT1mdW5jdGlvbigpe2gudW5xdWV1ZWR8fGkoKX0pLGgudW5xdWV1ZWQrKyxuLmFsd2F5cyhmdW5jdGlvbigpe24uYWx3YXlzKGZ1bmN0aW9uKCl7aC51bnF1ZXVlZC0tLG0ucXVldWUoYSwiZngiKS5sZW5ndGh8fGguZW1wdHkuZmlyZSgpfSl9KSksMT09PWEubm9kZVR5cGUmJigiaGVpZ2h0ImluIGJ8fCJ3aWR0aCJpbiBiKSYmKGMub3ZlcmZsb3c9W3Aub3ZlcmZsb3cscC5vdmVyZmxvd1gscC5vdmVyZmxvd1ldLGo9bS5jc3MoYSwiZGlzcGxheSIpLGw9Im5vbmUiPT09aj9tLl9kYXRhKGEsIm9sZGRpc3BsYXkiKXx8RmEoYS5ub2RlTmFtZSk6aiwiaW5saW5lIj09PWwmJiJub25lIj09PW0uY3NzKGEsImZsb2F0IikmJihrLmlubGluZUJsb2NrTmVlZHNMYXlvdXQmJiJpbmxpbmUiIT09RmEoYS5ub2RlTmFtZSk/cC56b29tPTE6cC5kaXNwbGF5PSJpbmxpbmUtYmxvY2siKSksYy5vdmVyZmxvdyYmKHAub3ZlcmZsb3c9ImhpZGRlbiIsay5zaHJpbmtXcmFwQmxvY2tzKCl8fG4uYWx3YXlzKGZ1bmN0aW9uKCl7cC5vdmVyZmxvdz1jLm92ZXJmbG93WzBdLHAub3ZlcmZsb3dYPWMub3ZlcmZsb3dbMV0scC5vdmVyZmxvd1k9Yy5vdmVyZmxvd1syXX0pKTtmb3IoZCBpbiBiKWlmKGU9YltkXSxhYi5leGVjKGUpKXtpZihkZWxldGUgYltkXSxmPWZ8fCJ0b2dnbGUiPT09ZSxlPT09KHE/ImhpZGUiOiJzaG93Iikpe2lmKCJzaG93IiE9PWV8fCFyfHx2b2lkIDA9PT1yW2RdKWNvbnRpbnVlO3E9ITB9b1tkXT1yJiZyW2RdfHxtLnN0eWxlKGEsZCl9ZWxzZSBqPXZvaWQgMDtpZihtLmlzRW1wdHlPYmplY3QobykpImlubGluZSI9PT0oIm5vbmUiPT09aj9GYShhLm5vZGVOYW1lKTpqKSYmKHAuZGlzcGxheT1qKTtlbHNle3I/ImhpZGRlbiJpbiByJiYocT1yLmhpZGRlbik6cj1tLl9kYXRhKGEsImZ4c2hvdyIse30pLGYmJihyLmhpZGRlbj0hcSkscT9tKGEpLnNob3coKTpuLmRvbmUoZnVuY3Rpb24oKXttKGEpLmhpZGUoKX0pLG4uZG9uZShmdW5jdGlvbigpe3ZhciBiO20uX3JlbW92ZURhdGEoYSwiZnhzaG93Iik7Zm9yKGIgaW4gbyltLnN0eWxlKGEsYixvW2JdKX0pO2ZvcihkIGluIG8pZz1oYihxP3JbZF06MCxkLG4pLGQgaW4gcnx8KHJbZF09Zy5zdGFydCxxJiYoZy5lbmQ9Zy5zdGFydCxnLnN0YXJ0PSJ3aWR0aCI9PT1kfHwiaGVpZ2h0Ij09PWQ/MTowKSl9fWZ1bmN0aW9uIGpiKGEsYil7dmFyIGMsZCxlLGYsZztmb3IoYyBpbiBhKWlmKGQ9bS5jYW1lbENhc2UoYyksZT1iW2RdLGY9YVtjXSxtLmlzQXJyYXkoZikmJihlPWZbMV0sZj1hW2NdPWZbMF0pLGMhPT1kJiYoYVtkXT1mLGRlbGV0ZSBhW2NdKSxnPW0uY3NzSG9va3NbZF0sZyYmImV4cGFuZCJpbiBnKXtmPWcuZXhwYW5kKGYpLGRlbGV0ZSBhW2RdO2ZvcihjIGluIGYpYyBpbiBhfHwoYVtjXT1mW2NdLGJbY109ZSl9ZWxzZSBiW2RdPWV9ZnVuY3Rpb24ga2IoYSxiLGMpe3ZhciBkLGUsZj0wLGc9ZGIubGVuZ3RoLGg9bS5EZWZlcnJlZCgpLmFsd2F5cyhmdW5jdGlvbigpe2RlbGV0ZSBpLmVsZW19KSxpPWZ1bmN0aW9uKCl7aWYoZSlyZXR1cm4hMTtmb3IodmFyIGI9JGF8fGZiKCksYz1NYXRoLm1heCgwLGouc3RhcnRUaW1lK2ouZHVyYXRpb24tYiksZD1jL2ouZHVyYXRpb258fDAsZj0xLWQsZz0wLGk9ai50d2VlbnMubGVuZ3RoO2k+ZztnKyspai50d2VlbnNbZ10ucnVuKGYpO3JldHVybiBoLm5vdGlmeVdpdGgoYSxbaixmLGNdKSwxPmYmJmk/YzooaC5yZXNvbHZlV2l0aChhLFtqXSksITEpfSxqPWgucHJvbWlzZSh7ZWxlbTphLHByb3BzOm0uZXh0ZW5kKHt9LGIpLG9wdHM6bS5leHRlbmQoITAse3NwZWNpYWxFYXNpbmc6e319LGMpLG9yaWdpbmFsUHJvcGVydGllczpiLG9yaWdpbmFsT3B0aW9uczpjLHN0YXJ0VGltZTokYXx8ZmIoKSxkdXJhdGlvbjpjLmR1cmF0aW9uLHR3ZWVuczpbXSxjcmVhdGVUd2VlbjpmdW5jdGlvbihiLGMpe3ZhciBkPW0uVHdlZW4oYSxqLm9wdHMsYixjLGoub3B0cy5zcGVjaWFsRWFzaW5nW2JdfHxqLm9wdHMuZWFzaW5nKTtyZXR1cm4gai50d2VlbnMucHVzaChkKSxkfSxzdG9wOmZ1bmN0aW9uKGIpe3ZhciBjPTAsZD1iP2oudHdlZW5zLmxlbmd0aDowO2lmKGUpcmV0dXJuIHRoaXM7Zm9yKGU9ITA7ZD5jO2MrKylqLnR3ZWVuc1tjXS5ydW4oMSk7cmV0dXJuIGI/aC5yZXNvbHZlV2l0aChhLFtqLGJdKTpoLnJlamVjdFdpdGgoYSxbaixiXSksdGhpc319KSxrPWoucHJvcHM7Zm9yKGpiKGssai5vcHRzLnNwZWNpYWxFYXNpbmcpO2c+ZjtmKyspaWYoZD1kYltmXS5jYWxsKGosYSxrLGoub3B0cykpcmV0dXJuIGQ7cmV0dXJuIG0ubWFwKGssaGIsaiksbS5pc0Z1bmN0aW9uKGoub3B0cy5zdGFydCkmJmoub3B0cy5zdGFydC5jYWxsKGEsaiksbS5meC50aW1lcihtLmV4dGVuZChpLHtlbGVtOmEsYW5pbTpqLHF1ZXVlOmoub3B0cy5xdWV1ZX0pKSxqLnByb2dyZXNzKGoub3B0cy5wcm9ncmVzcykuZG9uZShqLm9wdHMuZG9uZSxqLm9wdHMuY29tcGxldGUpLmZhaWwoai5vcHRzLmZhaWwpLmFsd2F5cyhqLm9wdHMuYWx3YXlzKX1tLkFuaW1hdGlvbj1tLmV4dGVuZChrYix7dHdlZW5lcjpmdW5jdGlvbihhLGIpe20uaXNGdW5jdGlvbihhKT8oYj1hLGE9WyIqIl0pOmE9YS5zcGxpdCgiICIpO2Zvcih2YXIgYyxkPTAsZT1hLmxlbmd0aDtlPmQ7ZCsrKWM9YVtkXSxlYltjXT1lYltjXXx8W10sZWJbY10udW5zaGlmdChiKX0scHJlZmlsdGVyOmZ1bmN0aW9uKGEsYil7Yj9kYi51bnNoaWZ0KGEpOmRiLnB1c2goYSl9fSksbS5zcGVlZD1mdW5jdGlvbihhLGIsYyl7dmFyIGQ9YSYmIm9iamVjdCI9PXR5cGVvZiBhP20uZXh0ZW5kKHt9LGEpOntjb21wbGV0ZTpjfHwhYyYmYnx8bS5pc0Z1bmN0aW9uKGEpJiZhLGR1cmF0aW9uOmEsZWFzaW5nOmMmJmJ8fGImJiFtLmlzRnVuY3Rpb24oYikmJmJ9O3JldHVybiBkLmR1cmF0aW9uPW0uZngub2ZmPzA6Im51bWJlciI9PXR5cGVvZiBkLmR1cmF0aW9uP2QuZHVyYXRpb246ZC5kdXJhdGlvbiBpbiBtLmZ4LnNwZWVkcz9tLmZ4LnNwZWVkc1tkLmR1cmF0aW9uXTptLmZ4LnNwZWVkcy5fZGVmYXVsdCwobnVsbD09ZC5xdWV1ZXx8ZC5xdWV1ZT09PSEwKSYmKGQucXVldWU9ImZ4IiksZC5vbGQ9ZC5jb21wbGV0ZSxkLmNvbXBsZXRlPWZ1bmN0aW9uKCl7bS5pc0Z1bmN0aW9uKGQub2xkKSYmZC5vbGQuY2FsbCh0aGlzKSxkLnF1ZXVlJiZtLmRlcXVldWUodGhpcyxkLnF1ZXVlKX0sZH0sbS5mbi5leHRlbmQoe2ZhZGVUbzpmdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4gdGhpcy5maWx0ZXIoVSkuY3NzKCJvcGFjaXR5IiwwKS5zaG93KCkuZW5kKCkuYW5pbWF0ZSh7b3BhY2l0eTpifSxhLGMsZCl9LGFuaW1hdGU6ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGU9bS5pc0VtcHR5T2JqZWN0KGEpLGY9bS5zcGVlZChiLGMsZCksZz1mdW5jdGlvbigpe3ZhciBiPWtiKHRoaXMsbS5leHRlbmQoe30sYSksZik7KGV8fG0uX2RhdGEodGhpcywiZmluaXNoIikpJiZiLnN0b3AoITApfTtyZXR1cm4gZy5maW5pc2g9ZyxlfHxmLnF1ZXVlPT09ITE/dGhpcy5lYWNoKGcpOnRoaXMucXVldWUoZi5xdWV1ZSxnKX0sc3RvcDpmdW5jdGlvbihhLGIsYyl7dmFyIGQ9ZnVuY3Rpb24oYSl7dmFyIGI9YS5zdG9wO2RlbGV0ZSBhLnN0b3AsYihjKX07cmV0dXJuInN0cmluZyIhPXR5cGVvZiBhJiYoYz1iLGI9YSxhPXZvaWQgMCksYiYmYSE9PSExJiZ0aGlzLnF1ZXVlKGF8fCJmeCIsW10pLHRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBiPSEwLGU9bnVsbCE9YSYmYSsicXVldWVIb29rcyIsZj1tLnRpbWVycyxnPW0uX2RhdGEodGhpcyk7aWYoZSlnW2VdJiZnW2VdLnN0b3AmJmQoZ1tlXSk7ZWxzZSBmb3IoZSBpbiBnKWdbZV0mJmdbZV0uc3RvcCYmY2IudGVzdChlKSYmZChnW2VdKTtmb3IoZT1mLmxlbmd0aDtlLS07KWZbZV0uZWxlbSE9PXRoaXN8fG51bGwhPWEmJmZbZV0ucXVldWUhPT1hfHwoZltlXS5hbmltLnN0b3AoYyksYj0hMSxmLnNwbGljZShlLDEpKTsoYnx8IWMpJiZtLmRlcXVldWUodGhpcyxhKX0pfSxmaW5pc2g6ZnVuY3Rpb24oYSl7cmV0dXJuIGEhPT0hMSYmKGE9YXx8ImZ4IiksdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGIsYz1tLl9kYXRhKHRoaXMpLGQ9Y1thKyJxdWV1ZSJdLGU9Y1thKyJxdWV1ZUhvb2tzIl0sZj1tLnRpbWVycyxnPWQ/ZC5sZW5ndGg6MDtmb3IoYy5maW5pc2g9ITAsbS5xdWV1ZSh0aGlzLGEsW10pLGUmJmUuc3RvcCYmZS5zdG9wLmNhbGwodGhpcywhMCksYj1mLmxlbmd0aDtiLS07KWZbYl0uZWxlbT09PXRoaXMmJmZbYl0ucXVldWU9PT1hJiYoZltiXS5hbmltLnN0b3AoITApLGYuc3BsaWNlKGIsMSkpO2ZvcihiPTA7Zz5iO2IrKylkW2JdJiZkW2JdLmZpbmlzaCYmZFtiXS5maW5pc2guY2FsbCh0aGlzKTtkZWxldGUgYy5maW5pc2h9KX19KSxtLmVhY2goWyJ0b2dnbGUiLCJzaG93IiwiaGlkZSJdLGZ1bmN0aW9uKGEsYil7dmFyIGM9bS5mbltiXTttLmZuW2JdPWZ1bmN0aW9uKGEsZCxlKXtyZXR1cm4gbnVsbD09YXx8ImJvb2xlYW4iPT10eXBlb2YgYT9jLmFwcGx5KHRoaXMsYXJndW1lbnRzKTp0aGlzLmFuaW1hdGUoZ2IoYiwhMCksYSxkLGUpfX0pLG0uZWFjaCh7c2xpZGVEb3duOmdiKCJzaG93Iiksc2xpZGVVcDpnYigiaGlkZSIpLHNsaWRlVG9nZ2xlOmdiKCJ0b2dnbGUiKSxmYWRlSW46e29wYWNpdHk6InNob3cifSxmYWRlT3V0OntvcGFjaXR5OiJoaWRlIn0sZmFkZVRvZ2dsZTp7b3BhY2l0eToidG9nZ2xlIn19LGZ1bmN0aW9uKGEsYil7bS5mblthXT1mdW5jdGlvbihhLGMsZCl7cmV0dXJuIHRoaXMuYW5pbWF0ZShiLGEsYyxkKX19KSxtLnRpbWVycz1bXSxtLmZ4LnRpY2s9ZnVuY3Rpb24oKXt2YXIgYSxiPW0udGltZXJzLGM9MDtmb3IoJGE9bS5ub3coKTtjPGIubGVuZ3RoO2MrKylhPWJbY10sYSgpfHxiW2NdIT09YXx8Yi5zcGxpY2UoYy0tLDEpO2IubGVuZ3RofHxtLmZ4LnN0b3AoKSwkYT12b2lkIDB9LG0uZngudGltZXI9ZnVuY3Rpb24oYSl7bS50aW1lcnMucHVzaChhKSxhKCk/bS5meC5zdGFydCgpOm0udGltZXJzLnBvcCgpfSxtLmZ4LmludGVydmFsPTEzLG0uZnguc3RhcnQ9ZnVuY3Rpb24oKXtfYXx8KF9hPXNldEludGVydmFsKG0uZngudGljayxtLmZ4LmludGVydmFsKSl9LG0uZnguc3RvcD1mdW5jdGlvbigpe2NsZWFySW50ZXJ2YWwoX2EpLF9hPW51bGx9LG0uZnguc3BlZWRzPXtzbG93OjYwMCxmYXN0OjIwMCxfZGVmYXVsdDo0MDB9LG0uZm4uZGVsYXk9ZnVuY3Rpb24oYSxiKXtyZXR1cm4gYT1tLmZ4P20uZnguc3BlZWRzW2FdfHxhOmEsYj1ifHwiZngiLHRoaXMucXVldWUoYixmdW5jdGlvbihiLGMpe3ZhciBkPXNldFRpbWVvdXQoYixhKTtjLnN0b3A9ZnVuY3Rpb24oKXtjbGVhclRpbWVvdXQoZCl9fSl9LGZ1bmN0aW9uKCl7dmFyIGEsYixjLGQsZTtiPXkuY3JlYXRlRWxlbWVudCgiZGl2IiksYi5zZXRBdHRyaWJ1dGUoImNsYXNzTmFtZSIsInQiKSxiLmlubmVySFRNTD0iICA8bGluay8+PHRhYmxlPjwvdGFibGU+PGEgaHJlZj0nL2EnPmE8L2E+PGlucHV0IHR5cGU9J2NoZWNrYm94Jy8+IixkPWIuZ2V0RWxlbWVudHNCeVRhZ05hbWUoImEiKVswXSxjPXkuY3JlYXRlRWxlbWVudCgic2VsZWN0IiksZT1jLmFwcGVuZENoaWxkKHkuY3JlYXRlRWxlbWVudCgib3B0aW9uIikpLGE9Yi5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaW5wdXQiKVswXSxkLnN0eWxlLmNzc1RleHQ9InRvcDoxcHgiLGsuZ2V0U2V0QXR0cmlidXRlPSJ0IiE9PWIuY2xhc3NOYW1lLGsuc3R5bGU9L3RvcC8udGVzdChkLmdldEF0dHJpYnV0ZSgic3R5bGUiKSksay5ocmVmTm9ybWFsaXplZD0iL2EiPT09ZC5nZXRBdHRyaWJ1dGUoImhyZWYiKSxrLmNoZWNrT249ISFhLnZhbHVlLGsub3B0U2VsZWN0ZWQ9ZS5zZWxlY3RlZCxrLmVuY3R5cGU9ISF5LmNyZWF0ZUVsZW1lbnQoImZvcm0iKS5lbmN0eXBlLGMuZGlzYWJsZWQ9ITAsay5vcHREaXNhYmxlZD0hZS5kaXNhYmxlZCxhPXkuY3JlYXRlRWxlbWVudCgiaW5wdXQiKSxhLnNldEF0dHJpYnV0ZSgidmFsdWUiLCIiKSxrLmlucHV0PSIiPT09YS5nZXRBdHRyaWJ1dGUoInZhbHVlIiksYS52YWx1ZT0idCIsYS5zZXRBdHRyaWJ1dGUoInR5cGUiLCJyYWRpbyIpLGsucmFkaW9WYWx1ZT0idCI9PT1hLnZhbHVlfSgpO3ZhciBsYj0vXHIvZzttLmZuLmV4dGVuZCh7dmFsOmZ1bmN0aW9uKGEpe3ZhciBiLGMsZCxlPXRoaXNbMF07e2lmKGFyZ3VtZW50cy5sZW5ndGgpcmV0dXJuIGQ9bS5pc0Z1bmN0aW9uKGEpLHRoaXMuZWFjaChmdW5jdGlvbihjKXt2YXIgZTsxPT09dGhpcy5ub2RlVHlwZSYmKGU9ZD9hLmNhbGwodGhpcyxjLG0odGhpcykudmFsKCkpOmEsbnVsbD09ZT9lPSIiOiJudW1iZXIiPT10eXBlb2YgZT9lKz0iIjptLmlzQXJyYXkoZSkmJihlPW0ubWFwKGUsZnVuY3Rpb24oYSl7cmV0dXJuIG51bGw9PWE/IiI6YSsiIn0pKSxiPW0udmFsSG9va3NbdGhpcy50eXBlXXx8bS52YWxIb29rc1t0aGlzLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCldLGImJiJzZXQiaW4gYiYmdm9pZCAwIT09Yi5zZXQodGhpcyxlLCJ2YWx1ZSIpfHwodGhpcy52YWx1ZT1lKSl9KTtpZihlKXJldHVybiBiPW0udmFsSG9va3NbZS50eXBlXXx8bS52YWxIb29rc1tlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCldLGImJiJnZXQiaW4gYiYmdm9pZCAwIT09KGM9Yi5nZXQoZSwidmFsdWUiKSk/YzooYz1lLnZhbHVlLCJzdHJpbmciPT10eXBlb2YgYz9jLnJlcGxhY2UobGIsIiIpOm51bGw9PWM/IiI6Yyl9fX0pLG0uZXh0ZW5kKHt2YWxIb29rczp7b3B0aW9uOntnZXQ6ZnVuY3Rpb24oYSl7dmFyIGI9bS5maW5kLmF0dHIoYSwidmFsdWUiKTtyZXR1cm4gbnVsbCE9Yj9iOm0udHJpbShtLnRleHQoYSkpfX0sc2VsZWN0OntnZXQ6ZnVuY3Rpb24oYSl7Zm9yKHZhciBiLGMsZD1hLm9wdGlvbnMsZT1hLnNlbGVjdGVkSW5kZXgsZj0ic2VsZWN0LW9uZSI9PT1hLnR5cGV8fDA+ZSxnPWY/bnVsbDpbXSxoPWY/ZSsxOmQubGVuZ3RoLGk9MD5lP2g6Zj9lOjA7aD5pO2krKylpZihjPWRbaV0sISghYy5zZWxlY3RlZCYmaSE9PWV8fChrLm9wdERpc2FibGVkP2MuZGlzYWJsZWQ6bnVsbCE9PWMuZ2V0QXR0cmlidXRlKCJkaXNhYmxlZCIpKXx8Yy5wYXJlbnROb2RlLmRpc2FibGVkJiZtLm5vZGVOYW1lKGMucGFyZW50Tm9kZSwib3B0Z3JvdXAiKSkpe2lmKGI9bShjKS52YWwoKSxmKXJldHVybiBiO2cucHVzaChiKX1yZXR1cm4gZ30sc2V0OmZ1bmN0aW9uKGEsYil7dmFyIGMsZCxlPWEub3B0aW9ucyxmPW0ubWFrZUFycmF5KGIpLGc9ZS5sZW5ndGg7d2hpbGUoZy0tKWlmKGQ9ZVtnXSxtLmluQXJyYXkobS52YWxIb29rcy5vcHRpb24uZ2V0KGQpLGYpPj0wKXRyeXtkLnNlbGVjdGVkPWM9ITB9Y2F0Y2goaCl7ZC5zY3JvbGxIZWlnaHR9ZWxzZSBkLnNlbGVjdGVkPSExO3JldHVybiBjfHwoYS5zZWxlY3RlZEluZGV4PS0xKSxlfX19fSksbS5lYWNoKFsicmFkaW8iLCJjaGVja2JveCJdLGZ1bmN0aW9uKCl7bS52YWxIb29rc1t0aGlzXT17c2V0OmZ1bmN0aW9uKGEsYil7cmV0dXJuIG0uaXNBcnJheShiKT9hLmNoZWNrZWQ9bS5pbkFycmF5KG0oYSkudmFsKCksYik+PTA6dm9pZCAwfX0say5jaGVja09ufHwobS52YWxIb29rc1t0aGlzXS5nZXQ9ZnVuY3Rpb24oYSl7cmV0dXJuIG51bGw9PT1hLmdldEF0dHJpYnV0ZSgidmFsdWUiKT8ib24iOmEudmFsdWV9KX0pO3ZhciBtYixuYixvYj1tLmV4cHIuYXR0ckhhbmRsZSxwYj0vXig/OmNoZWNrZWR8c2VsZWN0ZWQpJC9pLHFiPWsuZ2V0U2V0QXR0cmlidXRlLHJiPWsuaW5wdXQ7bS5mbi5leHRlbmQoe2F0dHI6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gVih0aGlzLG0uYXR0cixhLGIsYXJndW1lbnRzLmxlbmd0aD4xKX0scmVtb3ZlQXR0cjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7bS5yZW1vdmVBdHRyKHRoaXMsYSl9KX19KSxtLmV4dGVuZCh7YXR0cjpmdW5jdGlvbihhLGIsYyl7dmFyIGQsZSxmPWEubm9kZVR5cGU7aWYoYSYmMyE9PWYmJjghPT1mJiYyIT09ZilyZXR1cm4gdHlwZW9mIGEuZ2V0QXR0cmlidXRlPT09Sz9tLnByb3AoYSxiLGMpOigxPT09ZiYmbS5pc1hNTERvYyhhKXx8KGI9Yi50b0xvd2VyQ2FzZSgpLGQ9bS5hdHRySG9va3NbYl18fChtLmV4cHIubWF0Y2guYm9vbC50ZXN0KGIpP25iOm1iKSksdm9pZCAwPT09Yz9kJiYiZ2V0ImluIGQmJm51bGwhPT0oZT1kLmdldChhLGIpKT9lOihlPW0uZmluZC5hdHRyKGEsYiksbnVsbD09ZT92b2lkIDA6ZSk6bnVsbCE9PWM/ZCYmInNldCJpbiBkJiZ2b2lkIDAhPT0oZT1kLnNldChhLGMsYikpP2U6KGEuc2V0QXR0cmlidXRlKGIsYysiIiksYyk6dm9pZCBtLnJlbW92ZUF0dHIoYSxiKSl9LHJlbW92ZUF0dHI6ZnVuY3Rpb24oYSxiKXt2YXIgYyxkLGU9MCxmPWImJmIubWF0Y2goRSk7aWYoZiYmMT09PWEubm9kZVR5cGUpd2hpbGUoYz1mW2UrK10pZD1tLnByb3BGaXhbY118fGMsbS5leHByLm1hdGNoLmJvb2wudGVzdChjKT9yYiYmcWJ8fCFwYi50ZXN0KGMpP2FbZF09ITE6YVttLmNhbWVsQ2FzZSgiZGVmYXVsdC0iK2MpXT1hW2RdPSExOm0uYXR0cihhLGMsIiIpLGEucmVtb3ZlQXR0cmlidXRlKHFiP2M6ZCl9LGF0dHJIb29rczp7dHlwZTp7c2V0OmZ1bmN0aW9uKGEsYil7aWYoIWsucmFkaW9WYWx1ZSYmInJhZGlvIj09PWImJm0ubm9kZU5hbWUoYSwiaW5wdXQiKSl7dmFyIGM9YS52YWx1ZTtyZXR1cm4gYS5zZXRBdHRyaWJ1dGUoInR5cGUiLGIpLGMmJihhLnZhbHVlPWMpLGJ9fX19fSksbmI9e3NldDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGI9PT0hMT9tLnJlbW92ZUF0dHIoYSxjKTpyYiYmcWJ8fCFwYi50ZXN0KGMpP2Euc2V0QXR0cmlidXRlKCFxYiYmbS5wcm9wRml4W2NdfHxjLGMpOmFbbS5jYW1lbENhc2UoImRlZmF1bHQtIitjKV09YVtjXT0hMCxjfX0sbS5lYWNoKG0uZXhwci5tYXRjaC5ib29sLnNvdXJjZS5tYXRjaCgvXHcrL2cpLGZ1bmN0aW9uKGEsYil7dmFyIGM9b2JbYl18fG0uZmluZC5hdHRyO29iW2JdPXJiJiZxYnx8IXBiLnRlc3QoYik/ZnVuY3Rpb24oYSxiLGQpe3ZhciBlLGY7cmV0dXJuIGR8fChmPW9iW2JdLG9iW2JdPWUsZT1udWxsIT1jKGEsYixkKT9iLnRvTG93ZXJDYXNlKCk6bnVsbCxvYltiXT1mKSxlfTpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIGM/dm9pZCAwOmFbbS5jYW1lbENhc2UoImRlZmF1bHQtIitiKV0/Yi50b0xvd2VyQ2FzZSgpOm51bGx9fSkscmImJnFifHwobS5hdHRySG9va3MudmFsdWU9e3NldDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIG0ubm9kZU5hbWUoYSwiaW5wdXQiKT92b2lkKGEuZGVmYXVsdFZhbHVlPWIpOm1iJiZtYi5zZXQoYSxiLGMpfX0pLHFifHwobWI9e3NldDpmdW5jdGlvbihhLGIsYyl7dmFyIGQ9YS5nZXRBdHRyaWJ1dGVOb2RlKGMpO3JldHVybiBkfHxhLnNldEF0dHJpYnV0ZU5vZGUoZD1hLm93bmVyRG9jdW1lbnQuY3JlYXRlQXR0cmlidXRlKGMpKSxkLnZhbHVlPWIrPSIiLCJ2YWx1ZSI9PT1jfHxiPT09YS5nZXRBdHRyaWJ1dGUoYyk/Yjp2b2lkIDB9fSxvYi5pZD1vYi5uYW1lPW9iLmNvb3Jkcz1mdW5jdGlvbihhLGIsYyl7dmFyIGQ7cmV0dXJuIGM/dm9pZCAwOihkPWEuZ2V0QXR0cmlidXRlTm9kZShiKSkmJiIiIT09ZC52YWx1ZT9kLnZhbHVlOm51bGx9LG0udmFsSG9va3MuYnV0dG9uPXtnZXQ6ZnVuY3Rpb24oYSxiKXt2YXIgYz1hLmdldEF0dHJpYnV0ZU5vZGUoYik7cmV0dXJuIGMmJmMuc3BlY2lmaWVkP2MudmFsdWU6dm9pZCAwfSxzZXQ6bWIuc2V0fSxtLmF0dHJIb29rcy5jb250ZW50ZWRpdGFibGU9e3NldDpmdW5jdGlvbihhLGIsYyl7bWIuc2V0KGEsIiI9PT1iPyExOmIsYyl9fSxtLmVhY2goWyJ3aWR0aCIsImhlaWdodCJdLGZ1bmN0aW9uKGEsYil7bS5hdHRySG9va3NbYl09e3NldDpmdW5jdGlvbihhLGMpe3JldHVybiIiPT09Yz8oYS5zZXRBdHRyaWJ1dGUoYiwiYXV0byIpLGMpOnZvaWQgMH19fSkpLGsuc3R5bGV8fChtLmF0dHJIb29rcy5zdHlsZT17Z2V0OmZ1bmN0aW9uKGEpe3JldHVybiBhLnN0eWxlLmNzc1RleHR8fHZvaWQgMH0sc2V0OmZ1bmN0aW9uKGEsYil7cmV0dXJuIGEuc3R5bGUuY3NzVGV4dD1iKyIifX0pO3ZhciBzYj0vXig/OmlucHV0fHNlbGVjdHx0ZXh0YXJlYXxidXR0b258b2JqZWN0KSQvaSx0Yj0vXig/OmF8YXJlYSkkL2k7bS5mbi5leHRlbmQoe3Byb3A6ZnVuY3Rpb24oYSxiKXtyZXR1cm4gVih0aGlzLG0ucHJvcCxhLGIsYXJndW1lbnRzLmxlbmd0aD4xKX0scmVtb3ZlUHJvcDpmdW5jdGlvbihhKXtyZXR1cm4gYT1tLnByb3BGaXhbYV18fGEsdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dHJ5e3RoaXNbYV09dm9pZCAwLGRlbGV0ZSB0aGlzW2FdfWNhdGNoKGIpe319KX19KSxtLmV4dGVuZCh7cHJvcEZpeDp7ImZvciI6Imh0bWxGb3IiLCJjbGFzcyI6ImNsYXNzTmFtZSJ9LHByb3A6ZnVuY3Rpb24oYSxiLGMpe3ZhciBkLGUsZixnPWEubm9kZVR5cGU7aWYoYSYmMyE9PWcmJjghPT1nJiYyIT09ZylyZXR1cm4gZj0xIT09Z3x8IW0uaXNYTUxEb2MoYSksZiYmKGI9bS5wcm9wRml4W2JdfHxiLGU9bS5wcm9wSG9va3NbYl0pLHZvaWQgMCE9PWM/ZSYmInNldCJpbiBlJiZ2b2lkIDAhPT0oZD1lLnNldChhLGMsYikpP2Q6YVtiXT1jOmUmJiJnZXQiaW4gZSYmbnVsbCE9PShkPWUuZ2V0KGEsYikpP2Q6YVtiXX0scHJvcEhvb2tzOnt0YWJJbmRleDp7Z2V0OmZ1bmN0aW9uKGEpe3ZhciBiPW0uZmluZC5hdHRyKGEsInRhYmluZGV4Iik7cmV0dXJuIGI/cGFyc2VJbnQoYiwxMCk6c2IudGVzdChhLm5vZGVOYW1lKXx8dGIudGVzdChhLm5vZGVOYW1lKSYmYS5ocmVmPzA6LTF9fX19KSxrLmhyZWZOb3JtYWxpemVkfHxtLmVhY2goWyJocmVmIiwic3JjIl0sZnVuY3Rpb24oYSxiKXttLnByb3BIb29rc1tiXT17Z2V0OmZ1bmN0aW9uKGEpe3JldHVybiBhLmdldEF0dHJpYnV0ZShiLDQpfX19KSxrLm9wdFNlbGVjdGVkfHwobS5wcm9wSG9va3Muc2VsZWN0ZWQ9e2dldDpmdW5jdGlvbihhKXt2YXIgYj1hLnBhcmVudE5vZGU7cmV0dXJuIGImJihiLnNlbGVjdGVkSW5kZXgsYi5wYXJlbnROb2RlJiZiLnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleCksbnVsbH19KSxtLmVhY2goWyJ0YWJJbmRleCIsInJlYWRPbmx5IiwibWF4TGVuZ3RoIiwiY2VsbFNwYWNpbmciLCJjZWxsUGFkZGluZyIsInJvd1NwYW4iLCJjb2xTcGFuIiwidXNlTWFwIiwiZnJhbWVCb3JkZXIiLCJjb250ZW50RWRpdGFibGUiXSxmdW5jdGlvbigpe20ucHJvcEZpeFt0aGlzLnRvTG93ZXJDYXNlKCldPXRoaXN9KSxrLmVuY3R5cGV8fChtLnByb3BGaXguZW5jdHlwZT0iZW5jb2RpbmciKTt2YXIgdWI9L1tcdFxyXG5cZl0vZzttLmZuLmV4dGVuZCh7YWRkQ2xhc3M6ZnVuY3Rpb24oYSl7dmFyIGIsYyxkLGUsZixnLGg9MCxpPXRoaXMubGVuZ3RoLGo9InN0cmluZyI9PXR5cGVvZiBhJiZhO2lmKG0uaXNGdW5jdGlvbihhKSlyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKGIpe20odGhpcykuYWRkQ2xhc3MoYS5jYWxsKHRoaXMsYix0aGlzLmNsYXNzTmFtZSkpfSk7aWYoailmb3IoYj0oYXx8IiIpLm1hdGNoKEUpfHxbXTtpPmg7aCsrKWlmKGM9dGhpc1toXSxkPTE9PT1jLm5vZGVUeXBlJiYoYy5jbGFzc05hbWU/KCIgIitjLmNsYXNzTmFtZSsiICIpLnJlcGxhY2UodWIsIiAiKToiICIpKXtmPTA7d2hpbGUoZT1iW2YrK10pZC5pbmRleE9mKCIgIitlKyIgIik8MCYmKGQrPWUrIiAiKTtnPW0udHJpbShkKSxjLmNsYXNzTmFtZSE9PWcmJihjLmNsYXNzTmFtZT1nKX1yZXR1cm4gdGhpc30scmVtb3ZlQ2xhc3M6ZnVuY3Rpb24oYSl7dmFyIGIsYyxkLGUsZixnLGg9MCxpPXRoaXMubGVuZ3RoLGo9MD09PWFyZ3VtZW50cy5sZW5ndGh8fCJzdHJpbmciPT10eXBlb2YgYSYmYTtpZihtLmlzRnVuY3Rpb24oYSkpcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbihiKXttKHRoaXMpLnJlbW92ZUNsYXNzKGEuY2FsbCh0aGlzLGIsdGhpcy5jbGFzc05hbWUpKX0pO2lmKGopZm9yKGI9KGF8fCIiKS5tYXRjaChFKXx8W107aT5oO2grKylpZihjPXRoaXNbaF0sZD0xPT09Yy5ub2RlVHlwZSYmKGMuY2xhc3NOYW1lPygiICIrYy5jbGFzc05hbWUrIiAiKS5yZXBsYWNlKHViLCIgIik6IiIpKXtmPTA7d2hpbGUoZT1iW2YrK10pd2hpbGUoZC5pbmRleE9mKCIgIitlKyIgIik+PTApZD1kLnJlcGxhY2UoIiAiK2UrIiAiLCIgIik7Zz1hP20udHJpbShkKToiIixjLmNsYXNzTmFtZSE9PWcmJihjLmNsYXNzTmFtZT1nKX1yZXR1cm4gdGhpc30sdG9nZ2xlQ2xhc3M6ZnVuY3Rpb24oYSxiKXt2YXIgYz10eXBlb2YgYTtyZXR1cm4iYm9vbGVhbiI9PXR5cGVvZiBiJiYic3RyaW5nIj09PWM/Yj90aGlzLmFkZENsYXNzKGEpOnRoaXMucmVtb3ZlQ2xhc3MoYSk6dGhpcy5lYWNoKG0uaXNGdW5jdGlvbihhKT9mdW5jdGlvbihjKXttKHRoaXMpLnRvZ2dsZUNsYXNzKGEuY2FsbCh0aGlzLGMsdGhpcy5jbGFzc05hbWUsYiksYil9OmZ1bmN0aW9uKCl7aWYoInN0cmluZyI9PT1jKXt2YXIgYixkPTAsZT1tKHRoaXMpLGY9YS5tYXRjaChFKXx8W107d2hpbGUoYj1mW2QrK10pZS5oYXNDbGFzcyhiKT9lLnJlbW92ZUNsYXNzKGIpOmUuYWRkQ2xhc3MoYil9ZWxzZShjPT09S3x8ImJvb2xlYW4iPT09YykmJih0aGlzLmNsYXNzTmFtZSYmbS5fZGF0YSh0aGlzLCJfX2NsYXNzTmFtZV9fIix0aGlzLmNsYXNzTmFtZSksdGhpcy5jbGFzc05hbWU9dGhpcy5jbGFzc05hbWV8fGE9PT0hMT8iIjptLl9kYXRhKHRoaXMsIl9fY2xhc3NOYW1lX18iKXx8IiIpfSl9LGhhc0NsYXNzOmZ1bmN0aW9uKGEpe2Zvcih2YXIgYj0iICIrYSsiICIsYz0wLGQ9dGhpcy5sZW5ndGg7ZD5jO2MrKylpZigxPT09dGhpc1tjXS5ub2RlVHlwZSYmKCIgIit0aGlzW2NdLmNsYXNzTmFtZSsiICIpLnJlcGxhY2UodWIsIiAiKS5pbmRleE9mKGIpPj0wKXJldHVybiEwO3JldHVybiExfX0pLG0uZWFjaCgiYmx1ciBmb2N1cyBmb2N1c2luIGZvY3Vzb3V0IGxvYWQgcmVzaXplIHNjcm9sbCB1bmxvYWQgY2xpY2sgZGJsY2xpY2sgbW91c2Vkb3duIG1vdXNldXAgbW91c2Vtb3ZlIG1vdXNlb3ZlciBtb3VzZW91dCBtb3VzZWVudGVyIG1vdXNlbGVhdmUgY2hhbmdlIHNlbGVjdCBzdWJtaXQga2V5ZG93biBrZXlwcmVzcyBrZXl1cCBlcnJvciBjb250ZXh0bWVudSIuc3BsaXQoIiAiKSxmdW5jdGlvbihhLGIpe20uZm5bYl09ZnVuY3Rpb24oYSxjKXtyZXR1cm4gYXJndW1lbnRzLmxlbmd0aD4wP3RoaXMub24oYixudWxsLGEsYyk6dGhpcy50cmlnZ2VyKGIpfX0pLG0uZm4uZXh0ZW5kKHtob3ZlcjpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLm1vdXNlZW50ZXIoYSkubW91c2VsZWF2ZShifHxhKX0sYmluZDpmdW5jdGlvbihhLGIsYyl7cmV0dXJuIHRoaXMub24oYSxudWxsLGIsYyl9LHVuYmluZDpmdW5jdGlvbihhLGIpe3JldHVybiB0aGlzLm9mZihhLG51bGwsYil9LGRlbGVnYXRlOmZ1bmN0aW9uKGEsYixjLGQpe3JldHVybiB0aGlzLm9uKGIsYSxjLGQpfSx1bmRlbGVnYXRlOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gMT09PWFyZ3VtZW50cy5sZW5ndGg/dGhpcy5vZmYoYSwiKioiKTp0aGlzLm9mZihiLGF8fCIqKiIsYyl9fSk7dmFyIHZiPW0ubm93KCksd2I9L1w/Lyx4Yj0vKCwpfChcW3x7KXwofXxdKXwiKD86W14iXFxcclxuXXxcXFsiXFxcL2JmbnJ0XXxcXHVbXGRhLWZBLUZdezR9KSoiXHMqOj98dHJ1ZXxmYWxzZXxudWxsfC0/KD8hMFxkKVxkKyg/OlwuXGQrfCkoPzpbZUVdWystXT9cZCt8KS9nO20ucGFyc2VKU09OPWZ1bmN0aW9uKGIpe2lmKGEuSlNPTiYmYS5KU09OLnBhcnNlKXJldHVybiBhLkpTT04ucGFyc2UoYisiIik7dmFyIGMsZD1udWxsLGU9bS50cmltKGIrIiIpO3JldHVybiBlJiYhbS50cmltKGUucmVwbGFjZSh4YixmdW5jdGlvbihhLGIsZSxmKXtyZXR1cm4gYyYmYiYmKGQ9MCksMD09PWQ/YTooYz1lfHxiLGQrPSFmLSFlLCIiKX0pKT9GdW5jdGlvbigicmV0dXJuICIrZSkoKTptLmVycm9yKCJJbnZhbGlkIEpTT046ICIrYil9LG0ucGFyc2VYTUw9ZnVuY3Rpb24oYil7dmFyIGMsZDtpZighYnx8InN0cmluZyIhPXR5cGVvZiBiKXJldHVybiBudWxsO3RyeXthLkRPTVBhcnNlcj8oZD1uZXcgRE9NUGFyc2VyLGM9ZC5wYXJzZUZyb21TdHJpbmcoYiwidGV4dC94bWwiKSk6KGM9bmV3IEFjdGl2ZVhPYmplY3QoIk1pY3Jvc29mdC5YTUxET00iKSxjLmFzeW5jPSJmYWxzZSIsYy5sb2FkWE1MKGIpKX1jYXRjaChlKXtjPXZvaWQgMH1yZXR1cm4gYyYmYy5kb2N1bWVudEVsZW1lbnQmJiFjLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJwYXJzZXJlcnJvciIpLmxlbmd0aHx8bS5lcnJvcigiSW52YWxpZCBYTUw6ICIrYiksY307dmFyIHliLHpiLEFiPS8jLiokLyxCYj0vKFs/Jl0pXz1bXiZdKi8sQ2I9L14oLio/KTpbIFx0XSooW15cclxuXSopXHI/JC9nbSxEYj0vXig/OmFib3V0fGFwcHxhcHAtc3RvcmFnZXwuKy1leHRlbnNpb258ZmlsZXxyZXN8d2lkZ2V0KTokLyxFYj0vXig/OkdFVHxIRUFEKSQvLEZiPS9eXC9cLy8sR2I9L14oW1x3ListXSs6KSg/OlwvXC8oPzpbXlwvPyNdKkB8KShbXlwvPyM6XSopKD86OihcZCspfCl8KS8sSGI9e30sSWI9e30sSmI9IiovIi5jb25jYXQoIioiKTt0cnl7emI9bG9jYXRpb24uaHJlZn1jYXRjaChLYil7emI9eS5jcmVhdGVFbGVtZW50KCJhIiksemIuaHJlZj0iIix6Yj16Yi5ocmVmfXliPUdiLmV4ZWMoemIudG9Mb3dlckNhc2UoKSl8fFtdO2Z1bmN0aW9uIExiKGEpe3JldHVybiBmdW5jdGlvbihiLGMpeyJzdHJpbmciIT10eXBlb2YgYiYmKGM9YixiPSIqIik7dmFyIGQsZT0wLGY9Yi50b0xvd2VyQ2FzZSgpLm1hdGNoKEUpfHxbXTtpZihtLmlzRnVuY3Rpb24oYykpd2hpbGUoZD1mW2UrK10pIisiPT09ZC5jaGFyQXQoMCk/KGQ9ZC5zbGljZSgxKXx8IioiLChhW2RdPWFbZF18fFtdKS51bnNoaWZ0KGMpKTooYVtkXT1hW2RdfHxbXSkucHVzaChjKX19ZnVuY3Rpb24gTWIoYSxiLGMsZCl7dmFyIGU9e30sZj1hPT09SWI7ZnVuY3Rpb24gZyhoKXt2YXIgaTtyZXR1cm4gZVtoXT0hMCxtLmVhY2goYVtoXXx8W10sZnVuY3Rpb24oYSxoKXt2YXIgaj1oKGIsYyxkKTtyZXR1cm4ic3RyaW5nIiE9dHlwZW9mIGp8fGZ8fGVbal0/Zj8hKGk9aik6dm9pZCAwOihiLmRhdGFUeXBlcy51bnNoaWZ0KGopLGcoaiksITEpfSksaX1yZXR1cm4gZyhiLmRhdGFUeXBlc1swXSl8fCFlWyIqIl0mJmcoIioiKX1mdW5jdGlvbiBOYihhLGIpe3ZhciBjLGQsZT1tLmFqYXhTZXR0aW5ncy5mbGF0T3B0aW9uc3x8e307Zm9yKGQgaW4gYil2b2lkIDAhPT1iW2RdJiYoKGVbZF0/YTpjfHwoYz17fSkpW2RdPWJbZF0pO3JldHVybiBjJiZtLmV4dGVuZCghMCxhLGMpLGF9ZnVuY3Rpb24gT2IoYSxiLGMpe3ZhciBkLGUsZixnLGg9YS5jb250ZW50cyxpPWEuZGF0YVR5cGVzO3doaWxlKCIqIj09PWlbMF0paS5zaGlmdCgpLHZvaWQgMD09PWUmJihlPWEubWltZVR5cGV8fGIuZ2V0UmVzcG9uc2VIZWFkZXIoIkNvbnRlbnQtVHlwZSIpKTtpZihlKWZvcihnIGluIGgpaWYoaFtnXSYmaFtnXS50ZXN0KGUpKXtpLnVuc2hpZnQoZyk7YnJlYWt9aWYoaVswXWluIGMpZj1pWzBdO2Vsc2V7Zm9yKGcgaW4gYyl7aWYoIWlbMF18fGEuY29udmVydGVyc1tnKyIgIitpWzBdXSl7Zj1nO2JyZWFrfWR8fChkPWcpfWY9Znx8ZH1yZXR1cm4gZj8oZiE9PWlbMF0mJmkudW5zaGlmdChmKSxjW2ZdKTp2b2lkIDB9ZnVuY3Rpb24gUGIoYSxiLGMsZCl7dmFyIGUsZixnLGgsaSxqPXt9LGs9YS5kYXRhVHlwZXMuc2xpY2UoKTtpZihrWzFdKWZvcihnIGluIGEuY29udmVydGVycylqW2cudG9Mb3dlckNhc2UoKV09YS5jb252ZXJ0ZXJzW2ddO2Y9ay5zaGlmdCgpO3doaWxlKGYpaWYoYS5yZXNwb25zZUZpZWxkc1tmXSYmKGNbYS5yZXNwb25zZUZpZWxkc1tmXV09YiksIWkmJmQmJmEuZGF0YUZpbHRlciYmKGI9YS5kYXRhRmlsdGVyKGIsYS5kYXRhVHlwZSkpLGk9ZixmPWsuc2hpZnQoKSlpZigiKiI9PT1mKWY9aTtlbHNlIGlmKCIqIiE9PWkmJmkhPT1mKXtpZihnPWpbaSsiICIrZl18fGpbIiogIitmXSwhZylmb3IoZSBpbiBqKWlmKGg9ZS5zcGxpdCgiICIpLGhbMV09PT1mJiYoZz1qW2krIiAiK2hbMF1dfHxqWyIqICIraFswXV0pKXtnPT09ITA/Zz1qW2VdOmpbZV0hPT0hMCYmKGY9aFswXSxrLnVuc2hpZnQoaFsxXSkpO2JyZWFrfWlmKGchPT0hMClpZihnJiZhWyJ0aHJvd3MiXSliPWcoYik7ZWxzZSB0cnl7Yj1nKGIpfWNhdGNoKGwpe3JldHVybntzdGF0ZToicGFyc2VyZXJyb3IiLGVycm9yOmc/bDoiTm8gY29udmVyc2lvbiBmcm9tICIraSsiIHRvICIrZn19fXJldHVybntzdGF0ZToic3VjY2VzcyIsZGF0YTpifX1tLmV4dGVuZCh7YWN0aXZlOjAsbGFzdE1vZGlmaWVkOnt9LGV0YWc6e30sYWpheFNldHRpbmdzOnt1cmw6emIsdHlwZToiR0VUIixpc0xvY2FsOkRiLnRlc3QoeWJbMV0pLGdsb2JhbDohMCxwcm9jZXNzRGF0YTohMCxhc3luYzohMCxjb250ZW50VHlwZToiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkOyBjaGFyc2V0PVVURi04IixhY2NlcHRzOnsiKiI6SmIsdGV4dDoidGV4dC9wbGFpbiIsaHRtbDoidGV4dC9odG1sIix4bWw6ImFwcGxpY2F0aW9uL3htbCwgdGV4dC94bWwiLGpzb246ImFwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2YXNjcmlwdCJ9LGNvbnRlbnRzOnt4bWw6L3htbC8saHRtbDovaHRtbC8sanNvbjovanNvbi99LHJlc3BvbnNlRmllbGRzOnt4bWw6InJlc3BvbnNlWE1MIix0ZXh0OiJyZXNwb25zZVRleHQiLGpzb246InJlc3BvbnNlSlNPTiJ9LGNvbnZlcnRlcnM6eyIqIHRleHQiOlN0cmluZywidGV4dCBodG1sIjohMCwidGV4dCBqc29uIjptLnBhcnNlSlNPTiwidGV4dCB4bWwiOm0ucGFyc2VYTUx9LGZsYXRPcHRpb25zOnt1cmw6ITAsY29udGV4dDohMH19LGFqYXhTZXR1cDpmdW5jdGlvbihhLGIpe3JldHVybiBiP05iKE5iKGEsbS5hamF4U2V0dGluZ3MpLGIpOk5iKG0uYWpheFNldHRpbmdzLGEpfSxhamF4UHJlZmlsdGVyOkxiKEhiKSxhamF4VHJhbnNwb3J0OkxiKEliKSxhamF4OmZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBhJiYoYj1hLGE9dm9pZCAwKSxiPWJ8fHt9O3ZhciBjLGQsZSxmLGcsaCxpLGosaz1tLmFqYXhTZXR1cCh7fSxiKSxsPWsuY29udGV4dHx8ayxuPWsuY29udGV4dCYmKGwubm9kZVR5cGV8fGwuanF1ZXJ5KT9tKGwpOm0uZXZlbnQsbz1tLkRlZmVycmVkKCkscD1tLkNhbGxiYWNrcygib25jZSBtZW1vcnkiKSxxPWsuc3RhdHVzQ29kZXx8e30scj17fSxzPXt9LHQ9MCx1PSJjYW5jZWxlZCIsdj17cmVhZHlTdGF0ZTowLGdldFJlc3BvbnNlSGVhZGVyOmZ1bmN0aW9uKGEpe3ZhciBiO2lmKDI9PT10KXtpZighail7aj17fTt3aGlsZShiPUNiLmV4ZWMoZikpaltiWzFdLnRvTG93ZXJDYXNlKCldPWJbMl19Yj1qW2EudG9Mb3dlckNhc2UoKV19cmV0dXJuIG51bGw9PWI/bnVsbDpifSxnZXRBbGxSZXNwb25zZUhlYWRlcnM6ZnVuY3Rpb24oKXtyZXR1cm4gMj09PXQ/ZjpudWxsfSxzZXRSZXF1ZXN0SGVhZGVyOmZ1bmN0aW9uKGEsYil7dmFyIGM9YS50b0xvd2VyQ2FzZSgpO3JldHVybiB0fHwoYT1zW2NdPXNbY118fGEsclthXT1iKSx0aGlzfSxvdmVycmlkZU1pbWVUeXBlOmZ1bmN0aW9uKGEpe3JldHVybiB0fHwoay5taW1lVHlwZT1hKSx0aGlzfSxzdGF0dXNDb2RlOmZ1bmN0aW9uKGEpe3ZhciBiO2lmKGEpaWYoMj50KWZvcihiIGluIGEpcVtiXT1bcVtiXSxhW2JdXTtlbHNlIHYuYWx3YXlzKGFbdi5zdGF0dXNdKTtyZXR1cm4gdGhpc30sYWJvcnQ6ZnVuY3Rpb24oYSl7dmFyIGI9YXx8dTtyZXR1cm4gaSYmaS5hYm9ydChiKSx4KDAsYiksdGhpc319O2lmKG8ucHJvbWlzZSh2KS5jb21wbGV0ZT1wLmFkZCx2LnN1Y2Nlc3M9di5kb25lLHYuZXJyb3I9di5mYWlsLGsudXJsPSgoYXx8ay51cmx8fHpiKSsiIikucmVwbGFjZShBYiwiIikucmVwbGFjZShGYix5YlsxXSsiLy8iKSxrLnR5cGU9Yi5tZXRob2R8fGIudHlwZXx8ay5tZXRob2R8fGsudHlwZSxrLmRhdGFUeXBlcz1tLnRyaW0oay5kYXRhVHlwZXx8IioiKS50b0xvd2VyQ2FzZSgpLm1hdGNoKEUpfHxbIiJdLG51bGw9PWsuY3Jvc3NEb21haW4mJihjPUdiLmV4ZWMoay51cmwudG9Mb3dlckNhc2UoKSksay5jcm9zc0RvbWFpbj0hKCFjfHxjWzFdPT09eWJbMV0mJmNbMl09PT15YlsyXSYmKGNbM118fCgiaHR0cDoiPT09Y1sxXT8iODAiOiI0NDMiKSk9PT0oeWJbM118fCgiaHR0cDoiPT09eWJbMV0/IjgwIjoiNDQzIikpKSksay5kYXRhJiZrLnByb2Nlc3NEYXRhJiYic3RyaW5nIiE9dHlwZW9mIGsuZGF0YSYmKGsuZGF0YT1tLnBhcmFtKGsuZGF0YSxrLnRyYWRpdGlvbmFsKSksTWIoSGIsayxiLHYpLDI9PT10KXJldHVybiB2O2g9bS5ldmVudCYmay5nbG9iYWwsaCYmMD09PW0uYWN0aXZlKysmJm0uZXZlbnQudHJpZ2dlcigiYWpheFN0YXJ0Iiksay50eXBlPWsudHlwZS50b1VwcGVyQ2FzZSgpLGsuaGFzQ29udGVudD0hRWIudGVzdChrLnR5cGUpLGU9ay51cmwsay5oYXNDb250ZW50fHwoay5kYXRhJiYoZT1rLnVybCs9KHdiLnRlc3QoZSk/IiYiOiI/Iikray5kYXRhLGRlbGV0ZSBrLmRhdGEpLGsuY2FjaGU9PT0hMSYmKGsudXJsPUJiLnRlc3QoZSk/ZS5yZXBsYWNlKEJiLCIkMV89Iit2YisrKTplKyh3Yi50ZXN0KGUpPyImIjoiPyIpKyJfPSIrdmIrKykpLGsuaWZNb2RpZmllZCYmKG0ubGFzdE1vZGlmaWVkW2VdJiZ2LnNldFJlcXVlc3RIZWFkZXIoIklmLU1vZGlmaWVkLVNpbmNlIixtLmxhc3RNb2RpZmllZFtlXSksbS5ldGFnW2VdJiZ2LnNldFJlcXVlc3RIZWFkZXIoIklmLU5vbmUtTWF0Y2giLG0uZXRhZ1tlXSkpLChrLmRhdGEmJmsuaGFzQ29udGVudCYmay5jb250ZW50VHlwZSE9PSExfHxiLmNvbnRlbnRUeXBlKSYmdi5zZXRSZXF1ZXN0SGVhZGVyKCJDb250ZW50LVR5cGUiLGsuY29udGVudFR5cGUpLHYuc2V0UmVxdWVzdEhlYWRlcigiQWNjZXB0IixrLmRhdGFUeXBlc1swXSYmay5hY2NlcHRzW2suZGF0YVR5cGVzWzBdXT9rLmFjY2VwdHNbay5kYXRhVHlwZXNbMF1dKygiKiIhPT1rLmRhdGFUeXBlc1swXT8iLCAiK0piKyI7IHE9MC4wMSI6IiIpOmsuYWNjZXB0c1siKiJdKTtmb3IoZCBpbiBrLmhlYWRlcnMpdi5zZXRSZXF1ZXN0SGVhZGVyKGQsay5oZWFkZXJzW2RdKTtpZihrLmJlZm9yZVNlbmQmJihrLmJlZm9yZVNlbmQuY2FsbChsLHYsayk9PT0hMXx8Mj09PXQpKXJldHVybiB2LmFib3J0KCk7dT0iYWJvcnQiO2ZvcihkIGlue3N1Y2Nlc3M6MSxlcnJvcjoxLGNvbXBsZXRlOjF9KXZbZF0oa1tkXSk7aWYoaT1NYihJYixrLGIsdikpe3YucmVhZHlTdGF0ZT0xLGgmJm4udHJpZ2dlcigiYWpheFNlbmQiLFt2LGtdKSxrLmFzeW5jJiZrLnRpbWVvdXQ+MCYmKGc9c2V0VGltZW91dChmdW5jdGlvbigpe3YuYWJvcnQoInRpbWVvdXQiKX0say50aW1lb3V0KSk7dHJ5e3Q9MSxpLnNlbmQocix4KX1jYXRjaCh3KXtpZighKDI+dCkpdGhyb3cgdzt4KC0xLHcpfX1lbHNlIHgoLTEsIk5vIFRyYW5zcG9ydCIpO2Z1bmN0aW9uIHgoYSxiLGMsZCl7dmFyIGoscixzLHUsdyx4PWI7MiE9PXQmJih0PTIsZyYmY2xlYXJUaW1lb3V0KGcpLGk9dm9pZCAwLGY9ZHx8IiIsdi5yZWFkeVN0YXRlPWE+MD80OjAsaj1hPj0yMDAmJjMwMD5hfHwzMDQ9PT1hLGMmJih1PU9iKGssdixjKSksdT1QYihrLHUsdixqKSxqPyhrLmlmTW9kaWZpZWQmJih3PXYuZ2V0UmVzcG9uc2VIZWFkZXIoIkxhc3QtTW9kaWZpZWQiKSx3JiYobS5sYXN0TW9kaWZpZWRbZV09dyksdz12LmdldFJlc3BvbnNlSGVhZGVyKCJldGFnIiksdyYmKG0uZXRhZ1tlXT13KSksMjA0PT09YXx8IkhFQUQiPT09ay50eXBlP3g9Im5vY29udGVudCI6MzA0PT09YT94PSJub3Rtb2RpZmllZCI6KHg9dS5zdGF0ZSxyPXUuZGF0YSxzPXUuZXJyb3Isaj0hcykpOihzPXgsKGF8fCF4KSYmKHg9ImVycm9yIiwwPmEmJihhPTApKSksdi5zdGF0dXM9YSx2LnN0YXR1c1RleHQ9KGJ8fHgpKyIiLGo/by5yZXNvbHZlV2l0aChsLFtyLHgsdl0pOm8ucmVqZWN0V2l0aChsLFt2LHgsc10pLHYuc3RhdHVzQ29kZShxKSxxPXZvaWQgMCxoJiZuLnRyaWdnZXIoaj8iYWpheFN1Y2Nlc3MiOiJhamF4RXJyb3IiLFt2LGssaj9yOnNdKSxwLmZpcmVXaXRoKGwsW3YseF0pLGgmJihuLnRyaWdnZXIoImFqYXhDb21wbGV0ZSIsW3Ysa10pLC0tbS5hY3RpdmV8fG0uZXZlbnQudHJpZ2dlcigiYWpheFN0b3AiKSkpfXJldHVybiB2fSxnZXRKU09OOmZ1bmN0aW9uKGEsYixjKXtyZXR1cm4gbS5nZXQoYSxiLGMsImpzb24iKX0sZ2V0U2NyaXB0OmZ1bmN0aW9uKGEsYil7cmV0dXJuIG0uZ2V0KGEsdm9pZCAwLGIsInNjcmlwdCIpfX0pLG0uZWFjaChbImdldCIsInBvc3QiXSxmdW5jdGlvbihhLGIpe21bYl09ZnVuY3Rpb24oYSxjLGQsZSl7cmV0dXJuIG0uaXNGdW5jdGlvbihjKSYmKGU9ZXx8ZCxkPWMsYz12b2lkIDApLG0uYWpheCh7dXJsOmEsdHlwZTpiLGRhdGFUeXBlOmUsZGF0YTpjLHN1Y2Nlc3M6ZH0pfX0pLG0uX2V2YWxVcmw9ZnVuY3Rpb24oYSl7cmV0dXJuIG0uYWpheCh7dXJsOmEsdHlwZToiR0VUIixkYXRhVHlwZToic2NyaXB0Iixhc3luYzohMSxnbG9iYWw6ITEsInRocm93cyI6ITB9KX0sbS5mbi5leHRlbmQoe3dyYXBBbGw6ZnVuY3Rpb24oYSl7aWYobS5pc0Z1bmN0aW9uKGEpKXJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oYil7bSh0aGlzKS53cmFwQWxsKGEuY2FsbCh0aGlzLGIpKX0pO2lmKHRoaXNbMF0pe3ZhciBiPW0oYSx0aGlzWzBdLm93bmVyRG9jdW1lbnQpLmVxKDApLmNsb25lKCEwKTt0aGlzWzBdLnBhcmVudE5vZGUmJmIuaW5zZXJ0QmVmb3JlKHRoaXNbMF0pLGIubWFwKGZ1bmN0aW9uKCl7dmFyIGE9dGhpczt3aGlsZShhLmZpcnN0Q2hpbGQmJjE9PT1hLmZpcnN0Q2hpbGQubm9kZVR5cGUpYT1hLmZpcnN0Q2hpbGQ7cmV0dXJuIGF9KS5hcHBlbmQodGhpcyl9cmV0dXJuIHRoaXN9LHdyYXBJbm5lcjpmdW5jdGlvbihhKXtyZXR1cm4gdGhpcy5lYWNoKG0uaXNGdW5jdGlvbihhKT9mdW5jdGlvbihiKXttKHRoaXMpLndyYXBJbm5lcihhLmNhbGwodGhpcyxiKSl9OmZ1bmN0aW9uKCl7dmFyIGI9bSh0aGlzKSxjPWIuY29udGVudHMoKTtjLmxlbmd0aD9jLndyYXBBbGwoYSk6Yi5hcHBlbmQoYSl9KX0sd3JhcDpmdW5jdGlvbihhKXt2YXIgYj1tLmlzRnVuY3Rpb24oYSk7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbihjKXttKHRoaXMpLndyYXBBbGwoYj9hLmNhbGwodGhpcyxjKTphKX0pfSx1bndyYXA6ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5wYXJlbnQoKS5lYWNoKGZ1bmN0aW9uKCl7bS5ub2RlTmFtZSh0aGlzLCJib2R5Iil8fG0odGhpcykucmVwbGFjZVdpdGgodGhpcy5jaGlsZE5vZGVzKX0pLmVuZCgpfX0pLG0uZXhwci5maWx0ZXJzLmhpZGRlbj1mdW5jdGlvbihhKXtyZXR1cm4gYS5vZmZzZXRXaWR0aDw9MCYmYS5vZmZzZXRIZWlnaHQ8PTB8fCFrLnJlbGlhYmxlSGlkZGVuT2Zmc2V0cygpJiYibm9uZSI9PT0oYS5zdHlsZSYmYS5zdHlsZS5kaXNwbGF5fHxtLmNzcyhhLCJkaXNwbGF5IikpfSxtLmV4cHIuZmlsdGVycy52aXNpYmxlPWZ1bmN0aW9uKGEpe3JldHVybiFtLmV4cHIuZmlsdGVycy5oaWRkZW4oYSl9O3ZhciBRYj0vJTIwL2csUmI9L1xbXF0kLyxTYj0vXHI/XG4vZyxUYj0vXig/OnN1Ym1pdHxidXR0b258aW1hZ2V8cmVzZXR8ZmlsZSkkL2ksVWI9L14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8a2V5Z2VuKS9pO2Z1bmN0aW9uIFZiKGEsYixjLGQpe3ZhciBlO2lmKG0uaXNBcnJheShiKSltLmVhY2goYixmdW5jdGlvbihiLGUpe2N8fFJiLnRlc3QoYSk/ZChhLGUpOlZiKGErIlsiKygib2JqZWN0Ij09dHlwZW9mIGU/YjoiIikrIl0iLGUsYyxkKX0pO2Vsc2UgaWYoY3x8Im9iamVjdCIhPT1tLnR5cGUoYikpZChhLGIpO2Vsc2UgZm9yKGUgaW4gYilWYihhKyJbIitlKyJdIixiW2VdLGMsZCl9bS5wYXJhbT1mdW5jdGlvbihhLGIpe3ZhciBjLGQ9W10sZT1mdW5jdGlvbihhLGIpe2I9bS5pc0Z1bmN0aW9uKGIpP2IoKTpudWxsPT1iPyIiOmIsZFtkLmxlbmd0aF09ZW5jb2RlVVJJQ29tcG9uZW50KGEpKyI9IitlbmNvZGVVUklDb21wb25lbnQoYil9O2lmKHZvaWQgMD09PWImJihiPW0uYWpheFNldHRpbmdzJiZtLmFqYXhTZXR0aW5ncy50cmFkaXRpb25hbCksbS5pc0FycmF5KGEpfHxhLmpxdWVyeSYmIW0uaXNQbGFpbk9iamVjdChhKSltLmVhY2goYSxmdW5jdGlvbigpe2UodGhpcy5uYW1lLHRoaXMudmFsdWUpfSk7ZWxzZSBmb3IoYyBpbiBhKVZiKGMsYVtjXSxiLGUpO3JldHVybiBkLmpvaW4oIiYiKS5yZXBsYWNlKFFiLCIrIil9LG0uZm4uZXh0ZW5kKHtzZXJpYWxpemU6ZnVuY3Rpb24oKXtyZXR1cm4gbS5wYXJhbSh0aGlzLnNlcmlhbGl6ZUFycmF5KCkpfSxzZXJpYWxpemVBcnJheTpmdW5jdGlvbigpe3JldHVybiB0aGlzLm1hcChmdW5jdGlvbigpe3ZhciBhPW0ucHJvcCh0aGlzLCJlbGVtZW50cyIpO3JldHVybiBhP20ubWFrZUFycmF5KGEpOnRoaXN9KS5maWx0ZXIoZnVuY3Rpb24oKXt2YXIgYT10aGlzLnR5cGU7cmV0dXJuIHRoaXMubmFtZSYmIW0odGhpcykuaXMoIjpkaXNhYmxlZCIpJiZVYi50ZXN0KHRoaXMubm9kZU5hbWUpJiYhVGIudGVzdChhKSYmKHRoaXMuY2hlY2tlZHx8IVcudGVzdChhKSl9KS5tYXAoZnVuY3Rpb24oYSxiKXt2YXIgYz1tKHRoaXMpLnZhbCgpO3JldHVybiBudWxsPT1jP251bGw6bS5pc0FycmF5KGMpP20ubWFwKGMsZnVuY3Rpb24oYSl7cmV0dXJue25hbWU6Yi5uYW1lLHZhbHVlOmEucmVwbGFjZShTYiwiXHJcbiIpfX0pOntuYW1lOmIubmFtZSx2YWx1ZTpjLnJlcGxhY2UoU2IsIlxyXG4iKX19KS5nZXQoKX19KSxtLmFqYXhTZXR0aW5ncy54aHI9dm9pZCAwIT09YS5BY3RpdmVYT2JqZWN0P2Z1bmN0aW9uKCl7cmV0dXJuIXRoaXMuaXNMb2NhbCYmL14oZ2V0fHBvc3R8aGVhZHxwdXR8ZGVsZXRlfG9wdGlvbnMpJC9pLnRlc3QodGhpcy50eXBlKSYmWmIoKXx8JGIoKX06WmI7dmFyIFdiPTAsWGI9e30sWWI9bS5hamF4U2V0dGluZ3MueGhyKCk7YS5hdHRhY2hFdmVudCYmYS5hdHRhY2hFdmVudCgib251bmxvYWQiLGZ1bmN0aW9uKCl7Zm9yKHZhciBhIGluIFhiKVhiW2FdKHZvaWQgMCwhMCl9KSxrLmNvcnM9ISFZYiYmIndpdGhDcmVkZW50aWFscyJpbiBZYixZYj1rLmFqYXg9ISFZYixZYiYmbS5hamF4VHJhbnNwb3J0KGZ1bmN0aW9uKGEpe2lmKCFhLmNyb3NzRG9tYWlufHxrLmNvcnMpe3ZhciBiO3JldHVybntzZW5kOmZ1bmN0aW9uKGMsZCl7dmFyIGUsZj1hLnhocigpLGc9KytXYjtpZihmLm9wZW4oYS50eXBlLGEudXJsLGEuYXN5bmMsYS51c2VybmFtZSxhLnBhc3N3b3JkKSxhLnhockZpZWxkcylmb3IoZSBpbiBhLnhockZpZWxkcylmW2VdPWEueGhyRmllbGRzW2VdO2EubWltZVR5cGUmJmYub3ZlcnJpZGVNaW1lVHlwZSYmZi5vdmVycmlkZU1pbWVUeXBlKGEubWltZVR5cGUpLGEuY3Jvc3NEb21haW58fGNbIlgtUmVxdWVzdGVkLVdpdGgiXXx8KGNbIlgtUmVxdWVzdGVkLVdpdGgiXT0iWE1MSHR0cFJlcXVlc3QiKTtmb3IoZSBpbiBjKXZvaWQgMCE9PWNbZV0mJmYuc2V0UmVxdWVzdEhlYWRlcihlLGNbZV0rIiIpO2Yuc2VuZChhLmhhc0NvbnRlbnQmJmEuZGF0YXx8bnVsbCksYj1mdW5jdGlvbihjLGUpe3ZhciBoLGksajtpZihiJiYoZXx8ND09PWYucmVhZHlTdGF0ZSkpaWYoZGVsZXRlIFhiW2ddLGI9dm9pZCAwLGYub25yZWFkeXN0YXRlY2hhbmdlPW0ubm9vcCxlKTQhPT1mLnJlYWR5U3RhdGUmJmYuYWJvcnQoKTtlbHNle2o9e30saD1mLnN0YXR1cywic3RyaW5nIj09dHlwZW9mIGYucmVzcG9uc2VUZXh0JiYoai50ZXh0PWYucmVzcG9uc2VUZXh0KTt0cnl7aT1mLnN0YXR1c1RleHR9Y2F0Y2goayl7aT0iIn1ofHwhYS5pc0xvY2FsfHxhLmNyb3NzRG9tYWluPzEyMjM9PT1oJiYoaD0yMDQpOmg9ai50ZXh0PzIwMDo0MDR9aiYmZChoLGksaixmLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKX0sYS5hc3luYz80PT09Zi5yZWFkeVN0YXRlP3NldFRpbWVvdXQoYik6Zi5vbnJlYWR5c3RhdGVjaGFuZ2U9WGJbZ109YjpiKCl9LGFib3J0OmZ1bmN0aW9uKCl7YiYmYih2b2lkIDAsITApfX19fSk7ZnVuY3Rpb24gWmIoKXt0cnl7cmV0dXJuIG5ldyBhLlhNTEh0dHBSZXF1ZXN0fWNhdGNoKGIpe319ZnVuY3Rpb24gJGIoKXt0cnl7cmV0dXJuIG5ldyBhLkFjdGl2ZVhPYmplY3QoIk1pY3Jvc29mdC5YTUxIVFRQIil9Y2F0Y2goYil7fX1tLmFqYXhTZXR1cCh7YWNjZXB0czp7c2NyaXB0OiJ0ZXh0L2phdmFzY3JpcHQsIGFwcGxpY2F0aW9uL2phdmFzY3JpcHQsIGFwcGxpY2F0aW9uL2VjbWFzY3JpcHQsIGFwcGxpY2F0aW9uL3gtZWNtYXNjcmlwdCJ9LGNvbnRlbnRzOntzY3JpcHQ6Lyg/OmphdmF8ZWNtYSlzY3JpcHQvfSxjb252ZXJ0ZXJzOnsidGV4dCBzY3JpcHQiOmZ1bmN0aW9uKGEpe3JldHVybiBtLmdsb2JhbEV2YWwoYSksYX19fSksbS5hamF4UHJlZmlsdGVyKCJzY3JpcHQiLGZ1bmN0aW9uKGEpe3ZvaWQgMD09PWEuY2FjaGUmJihhLmNhY2hlPSExKSxhLmNyb3NzRG9tYWluJiYoYS50eXBlPSJHRVQiLGEuZ2xvYmFsPSExKX0pLG0uYWpheFRyYW5zcG9ydCgic2NyaXB0IixmdW5jdGlvbihhKXtpZihhLmNyb3NzRG9tYWluKXt2YXIgYixjPXkuaGVhZHx8bSgiaGVhZCIpWzBdfHx5LmRvY3VtZW50RWxlbWVudDtyZXR1cm57c2VuZDpmdW5jdGlvbihkLGUpe2I9eS5jcmVhdGVFbGVtZW50KCJzY3JpcHQiKSxiLmFzeW5jPSEwLGEuc2NyaXB0Q2hhcnNldCYmKGIuY2hhcnNldD1hLnNjcmlwdENoYXJzZXQpLGIuc3JjPWEudXJsLGIub25sb2FkPWIub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKGEsYyl7KGN8fCFiLnJlYWR5U3RhdGV8fC9sb2FkZWR8Y29tcGxldGUvLnRlc3QoYi5yZWFkeVN0YXRlKSkmJihiLm9ubG9hZD1iLm9ucmVhZHlzdGF0ZWNoYW5nZT1udWxsLGIucGFyZW50Tm9kZSYmYi5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGIpLGI9bnVsbCxjfHxlKDIwMCwic3VjY2VzcyIpKX0sYy5pbnNlcnRCZWZvcmUoYixjLmZpcnN0Q2hpbGQpfSxhYm9ydDpmdW5jdGlvbigpe2ImJmIub25sb2FkKHZvaWQgMCwhMCl9fX19KTt2YXIgX2I9W10sYWM9Lyg9KVw/KD89JnwkKXxcP1w/LzttLmFqYXhTZXR1cCh7anNvbnA6ImNhbGxiYWNrIixqc29ucENhbGxiYWNrOmZ1bmN0aW9uKCl7dmFyIGE9X2IucG9wKCl8fG0uZXhwYW5kbysiXyIrdmIrKztyZXR1cm4gdGhpc1thXT0hMCxhfX0pLG0uYWpheFByZWZpbHRlcigianNvbiBqc29ucCIsZnVuY3Rpb24oYixjLGQpe3ZhciBlLGYsZyxoPWIuanNvbnAhPT0hMSYmKGFjLnRlc3QoYi51cmwpPyJ1cmwiOiJzdHJpbmciPT10eXBlb2YgYi5kYXRhJiYhKGIuY29udGVudFR5cGV8fCIiKS5pbmRleE9mKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiKSYmYWMudGVzdChiLmRhdGEpJiYiZGF0YSIpO3JldHVybiBofHwianNvbnAiPT09Yi5kYXRhVHlwZXNbMF0/KGU9Yi5qc29ucENhbGxiYWNrPW0uaXNGdW5jdGlvbihiLmpzb25wQ2FsbGJhY2spP2IuanNvbnBDYWxsYmFjaygpOmIuanNvbnBDYWxsYmFjayxoP2JbaF09YltoXS5yZXBsYWNlKGFjLCIkMSIrZSk6Yi5qc29ucCE9PSExJiYoYi51cmwrPSh3Yi50ZXN0KGIudXJsKT8iJiI6Ij8iKStiLmpzb25wKyI9IitlKSxiLmNvbnZlcnRlcnNbInNjcmlwdCBqc29uIl09ZnVuY3Rpb24oKXtyZXR1cm4gZ3x8bS5lcnJvcihlKyIgd2FzIG5vdCBjYWxsZWQiKSxnWzBdfSxiLmRhdGFUeXBlc1swXT0ianNvbiIsZj1hW2VdLGFbZV09ZnVuY3Rpb24oKXtnPWFyZ3VtZW50c30sZC5hbHdheXMoZnVuY3Rpb24oKXthW2VdPWYsYltlXSYmKGIuanNvbnBDYWxsYmFjaz1jLmpzb25wQ2FsbGJhY2ssX2IucHVzaChlKSksZyYmbS5pc0Z1bmN0aW9uKGYpJiZmKGdbMF0pLGc9Zj12b2lkIDB9KSwic2NyaXB0Iik6dm9pZCAwfSksbS5wYXJzZUhUTUw9ZnVuY3Rpb24oYSxiLGMpe2lmKCFhfHwic3RyaW5nIiE9dHlwZW9mIGEpcmV0dXJuIG51bGw7ImJvb2xlYW4iPT10eXBlb2YgYiYmKGM9YixiPSExKSxiPWJ8fHk7dmFyIGQ9dS5leGVjKGEpLGU9IWMmJltdO3JldHVybiBkP1tiLmNyZWF0ZUVsZW1lbnQoZFsxXSldOihkPW0uYnVpbGRGcmFnbWVudChbYV0sYixlKSxlJiZlLmxlbmd0aCYmbShlKS5yZW1vdmUoKSxtLm1lcmdlKFtdLGQuY2hpbGROb2RlcykpfTt2YXIgYmM9bS5mbi5sb2FkO20uZm4ubG9hZD1mdW5jdGlvbihhLGIsYyl7aWYoInN0cmluZyIhPXR5cGVvZiBhJiZiYylyZXR1cm4gYmMuYXBwbHkodGhpcyxhcmd1bWVudHMpO3ZhciBkLGUsZixnPXRoaXMsaD1hLmluZGV4T2YoIiAiKTtyZXR1cm4gaD49MCYmKGQ9bS50cmltKGEuc2xpY2UoaCxhLmxlbmd0aCkpLGE9YS5zbGljZSgwLGgpKSxtLmlzRnVuY3Rpb24oYik/KGM9YixiPXZvaWQgMCk6YiYmIm9iamVjdCI9PXR5cGVvZiBiJiYoZj0iUE9TVCIpLGcubGVuZ3RoPjAmJm0uYWpheCh7dXJsOmEsdHlwZTpmLGRhdGFUeXBlOiJodG1sIixkYXRhOmJ9KS5kb25lKGZ1bmN0aW9uKGEpe2U9YXJndW1lbnRzLGcuaHRtbChkP20oIjxkaXY+IikuYXBwZW5kKG0ucGFyc2VIVE1MKGEpKS5maW5kKGQpOmEpfSkuY29tcGxldGUoYyYmZnVuY3Rpb24oYSxiKXtnLmVhY2goYyxlfHxbYS5yZXNwb25zZVRleHQsYixhXSl9KSx0aGlzfSxtLmVhY2goWyJhamF4U3RhcnQiLCJhamF4U3RvcCIsImFqYXhDb21wbGV0ZSIsImFqYXhFcnJvciIsImFqYXhTdWNjZXNzIiwiYWpheFNlbmQiXSxmdW5jdGlvbihhLGIpe20uZm5bYl09ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMub24oYixhKX19KSxtLmV4cHIuZmlsdGVycy5hbmltYXRlZD1mdW5jdGlvbihhKXtyZXR1cm4gbS5ncmVwKG0udGltZXJzLGZ1bmN0aW9uKGIpe3JldHVybiBhPT09Yi5lbGVtfSkubGVuZ3RofTt2YXIgY2M9YS5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7ZnVuY3Rpb24gZGMoYSl7cmV0dXJuIG0uaXNXaW5kb3coYSk/YTo5PT09YS5ub2RlVHlwZT9hLmRlZmF1bHRWaWV3fHxhLnBhcmVudFdpbmRvdzohMX1tLm9mZnNldD17c2V0T2Zmc2V0OmZ1bmN0aW9uKGEsYixjKXt2YXIgZCxlLGYsZyxoLGksaixrPW0uY3NzKGEsInBvc2l0aW9uIiksbD1tKGEpLG49e307InN0YXRpYyI9PT1rJiYoYS5zdHlsZS5wb3NpdGlvbj0icmVsYXRpdmUiKSxoPWwub2Zmc2V0KCksZj1tLmNzcyhhLCJ0b3AiKSxpPW0uY3NzKGEsImxlZnQiKSxqPSgiYWJzb2x1dGUiPT09a3x8ImZpeGVkIj09PWspJiZtLmluQXJyYXkoImF1dG8iLFtmLGldKT4tMSxqPyhkPWwucG9zaXRpb24oKSxnPWQudG9wLGU9ZC5sZWZ0KTooZz1wYXJzZUZsb2F0KGYpfHwwLGU9cGFyc2VGbG9hdChpKXx8MCksbS5pc0Z1bmN0aW9uKGIpJiYoYj1iLmNhbGwoYSxjLGgpKSxudWxsIT1iLnRvcCYmKG4udG9wPWIudG9wLWgudG9wK2cpLG51bGwhPWIubGVmdCYmKG4ubGVmdD1iLmxlZnQtaC5sZWZ0K2UpLCJ1c2luZyJpbiBiP2IudXNpbmcuY2FsbChhLG4pOmwuY3NzKG4pfX0sbS5mbi5leHRlbmQoe29mZnNldDpmdW5jdGlvbihhKXtpZihhcmd1bWVudHMubGVuZ3RoKXJldHVybiB2b2lkIDA9PT1hP3RoaXM6dGhpcy5lYWNoKGZ1bmN0aW9uKGIpe20ub2Zmc2V0LnNldE9mZnNldCh0aGlzLGEsYil9KTt2YXIgYixjLGQ9e3RvcDowLGxlZnQ6MH0sZT10aGlzWzBdLGY9ZSYmZS5vd25lckRvY3VtZW50O2lmKGYpcmV0dXJuIGI9Zi5kb2N1bWVudEVsZW1lbnQsbS5jb250YWlucyhiLGUpPyh0eXBlb2YgZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QhPT1LJiYoZD1lLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpKSxjPWRjKGYpLHt0b3A6ZC50b3ArKGMucGFnZVlPZmZzZXR8fGIuc2Nyb2xsVG9wKS0oYi5jbGllbnRUb3B8fDApLGxlZnQ6ZC5sZWZ0KyhjLnBhZ2VYT2Zmc2V0fHxiLnNjcm9sbExlZnQpLShiLmNsaWVudExlZnR8fDApfSk6ZH0scG9zaXRpb246ZnVuY3Rpb24oKXtpZih0aGlzWzBdKXt2YXIgYSxiLGM9e3RvcDowLGxlZnQ6MH0sZD10aGlzWzBdO3JldHVybiJmaXhlZCI9PT1tLmNzcyhkLCJwb3NpdGlvbiIpP2I9ZC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTooYT10aGlzLm9mZnNldFBhcmVudCgpLGI9dGhpcy5vZmZzZXQoKSxtLm5vZGVOYW1lKGFbMF0sImh0bWwiKXx8KGM9YS5vZmZzZXQoKSksYy50b3ArPW0uY3NzKGFbMF0sImJvcmRlclRvcFdpZHRoIiwhMCksYy5sZWZ0Kz1tLmNzcyhhWzBdLCJib3JkZXJMZWZ0V2lkdGgiLCEwKSkse3RvcDpiLnRvcC1jLnRvcC1tLmNzcyhkLCJtYXJnaW5Ub3AiLCEwKSxsZWZ0OmIubGVmdC1jLmxlZnQtbS5jc3MoZCwibWFyZ2luTGVmdCIsITApfX19LG9mZnNldFBhcmVudDpmdW5jdGlvbigpe3JldHVybiB0aGlzLm1hcChmdW5jdGlvbigpe3ZhciBhPXRoaXMub2Zmc2V0UGFyZW50fHxjYzt3aGlsZShhJiYhbS5ub2RlTmFtZShhLCJodG1sIikmJiJzdGF0aWMiPT09bS5jc3MoYSwicG9zaXRpb24iKSlhPWEub2Zmc2V0UGFyZW50O3JldHVybiBhfHxjY30pfX0pLG0uZWFjaCh7c2Nyb2xsTGVmdDoicGFnZVhPZmZzZXQiLHNjcm9sbFRvcDoicGFnZVlPZmZzZXQifSxmdW5jdGlvbihhLGIpe3ZhciBjPS9ZLy50ZXN0KGIpO20uZm5bYV09ZnVuY3Rpb24oZCl7cmV0dXJuIFYodGhpcyxmdW5jdGlvbihhLGQsZSl7dmFyIGY9ZGMoYSk7cmV0dXJuIHZvaWQgMD09PWU/Zj9iIGluIGY/ZltiXTpmLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudFtkXTphW2RdOnZvaWQoZj9mLnNjcm9sbFRvKGM/bShmKS5zY3JvbGxMZWZ0KCk6ZSxjP2U6bShmKS5zY3JvbGxUb3AoKSk6YVtkXT1lKX0sYSxkLGFyZ3VtZW50cy5sZW5ndGgsbnVsbCl9fSksbS5lYWNoKFsidG9wIiwibGVmdCJdLGZ1bmN0aW9uKGEsYil7bS5jc3NIb29rc1tiXT1MYShrLnBpeGVsUG9zaXRpb24sZnVuY3Rpb24oYSxjKXtyZXR1cm4gYz8oYz1KYShhLGIpLEhhLnRlc3QoYyk/bShhKS5wb3NpdGlvbigpW2JdKyJweCI6Yyk6dm9pZCAwfSl9KSxtLmVhY2goe0hlaWdodDoiaGVpZ2h0IixXaWR0aDoid2lkdGgifSxmdW5jdGlvbihhLGIpe20uZWFjaCh7cGFkZGluZzoiaW5uZXIiK2EsY29udGVudDpiLCIiOiJvdXRlciIrYX0sZnVuY3Rpb24oYyxkKXttLmZuW2RdPWZ1bmN0aW9uKGQsZSl7dmFyIGY9YXJndW1lbnRzLmxlbmd0aCYmKGN8fCJib29sZWFuIiE9dHlwZW9mIGQpLGc9Y3x8KGQ9PT0hMHx8ZT09PSEwPyJtYXJnaW4iOiJib3JkZXIiKTtyZXR1cm4gVih0aGlzLGZ1bmN0aW9uKGIsYyxkKXt2YXIgZTtyZXR1cm4gbS5pc1dpbmRvdyhiKT9iLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudFsiY2xpZW50IithXTo5PT09Yi5ub2RlVHlwZT8oZT1iLmRvY3VtZW50RWxlbWVudCxNYXRoLm1heChiLmJvZHlbInNjcm9sbCIrYV0sZVsic2Nyb2xsIithXSxiLmJvZHlbIm9mZnNldCIrYV0sZVsib2Zmc2V0IithXSxlWyJjbGllbnQiK2FdKSk6dm9pZCAwPT09ZD9tLmNzcyhiLGMsZyk6bS5zdHlsZShiLGMsZCxnKX0sYixmP2Q6dm9pZCAwLGYsbnVsbCl9fSl9KSxtLmZuLnNpemU9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5sZW5ndGh9LG0uZm4uYW5kU2VsZj1tLmZuLmFkZEJhY2ssImZ1bmN0aW9uIj09dHlwZW9mIGRlZmluZSYmZGVmaW5lLmFtZCYmZGVmaW5lKCJqcXVlcnkiLFtdLGZ1bmN0aW9uKCl7cmV0dXJuIG19KTt2YXIgZWM9YS5qUXVlcnksZmM9YS4kO3JldHVybiBtLm5vQ29uZmxpY3Q9ZnVuY3Rpb24oYil7cmV0dXJuIGEuJD09PW0mJihhLiQ9ZmMpLGImJmEualF1ZXJ5PT09bSYmKGEualF1ZXJ5PWVjKSxtfSx0eXBlb2YgYj09PUsmJihhLmpRdWVyeT1hLiQ9bSksbX0pOwo="></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="data:text/css;charset=utf-8,html%7Bfont%2Dfamily%3Asans%2Dserif%3B%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A100%25%3B%2Dms%2Dtext%2Dsize%2Dadjust%3A100%25%7Dbody%7Bmargin%3A0%7Darticle%2Caside%2Cdetails%2Cfigcaption%2Cfigure%2Cfooter%2Cheader%2Chgroup%2Cmain%2Cmenu%2Cnav%2Csection%2Csummary%7Bdisplay%3Ablock%7Daudio%2Ccanvas%2Cprogress%2Cvideo%7Bdisplay%3Ainline%2Dblock%3Bvertical%2Dalign%3Abaseline%7Daudio%3Anot%28%5Bcontrols%5D%29%7Bdisplay%3Anone%3Bheight%3A0%7D%5Bhidden%5D%2Ctemplate%7Bdisplay%3Anone%7Da%7Bbackground%2Dcolor%3Atransparent%7Da%3Aactive%2Ca%3Ahover%7Boutline%3A0%7Dabbr%5Btitle%5D%7Bborder%2Dbottom%3A1px%20dotted%7Db%2Cstrong%7Bfont%2Dweight%3A700%7Ddfn%7Bfont%2Dstyle%3Aitalic%7Dh1%7Bmargin%3A%2E67em%200%3Bfont%2Dsize%3A2em%7Dmark%7Bcolor%3A%23000%3Bbackground%3A%23ff0%7Dsmall%7Bfont%2Dsize%3A80%25%7Dsub%2Csup%7Bposition%3Arelative%3Bfont%2Dsize%3A75%25%3Bline%2Dheight%3A0%3Bvertical%2Dalign%3Abaseline%7Dsup%7Btop%3A%2D%2E5em%7Dsub%7Bbottom%3A%2D%2E25em%7Dimg%7Bborder%3A0%7Dsvg%3Anot%28%3Aroot%29%7Boverflow%3Ahidden%7Dfigure%7Bmargin%3A1em%2040px%7Dhr%7Bheight%3A0%3B%2Dwebkit%2Dbox%2Dsizing%3Acontent%2Dbox%3B%2Dmoz%2Dbox%2Dsizing%3Acontent%2Dbox%3Bbox%2Dsizing%3Acontent%2Dbox%7Dpre%7Boverflow%3Aauto%7Dcode%2Ckbd%2Cpre%2Csamp%7Bfont%2Dfamily%3Amonospace%2Cmonospace%3Bfont%2Dsize%3A1em%7Dbutton%2Cinput%2Coptgroup%2Cselect%2Ctextarea%7Bmargin%3A0%3Bfont%3Ainherit%3Bcolor%3Ainherit%7Dbutton%7Boverflow%3Avisible%7Dbutton%2Cselect%7Btext%2Dtransform%3Anone%7Dbutton%2Chtml%20input%5Btype%3Dbutton%5D%2Cinput%5Btype%3Dreset%5D%2Cinput%5Btype%3Dsubmit%5D%7B%2Dwebkit%2Dappearance%3Abutton%3Bcursor%3Apointer%7Dbutton%5Bdisabled%5D%2Chtml%20input%5Bdisabled%5D%7Bcursor%3Adefault%7Dbutton%3A%3A%2Dmoz%2Dfocus%2Dinner%2Cinput%3A%3A%2Dmoz%2Dfocus%2Dinner%7Bpadding%3A0%3Bborder%3A0%7Dinput%7Bline%2Dheight%3Anormal%7Dinput%5Btype%3Dcheckbox%5D%2Cinput%5Btype%3Dradio%5D%7B%2Dwebkit%2Dbox%2Dsizing%3Aborder%2Dbox%3B%2Dmoz%2Dbox%2Dsizing%3Aborder%2Dbox%3Bbox%2Dsizing%3Aborder%2Dbox%3Bpadding%3A0%7Dinput%5Btype%3Dnumber%5D%3A%3A%2Dwebkit%2Dinner%2Dspin%2Dbutton%2Cinput%5Btype%3Dnumber%5D%3A%3A%2Dwebkit%2Douter%2Dspin%2Dbutton%7Bheight%3Aauto%7Dinput%5Btype%3Dsearch%5D%7B%2Dwebkit%2Dbox%2Dsizing%3Acontent%2Dbox%3B%2Dmoz%2Dbox%2Dsizing%3Acontent%2Dbox%3Bbox%2Dsizing%3Acontent%2Dbox%3B%2Dwebkit%2Dappearance%3Atextfield%7Dinput%5Btype%3Dsearch%5D%3A%3A%2Dwebkit%2Dsearch%2Dcancel%2Dbutton%2Cinput%5Btype%3Dsearch%5D%3A%3A%2Dwebkit%2Dsearch%2Ddecoration%7B%2Dwebkit%2Dappearance%3Anone%7Dfieldset%7Bpadding%3A%2E35em%20%2E625em%20%2E75em%3Bmargin%3A0%202px%3Bborder%3A1px%20solid%20silver%7Dlegend%7Bpadding%3A0%3Bborder%3A0%7Dtextarea%7Boverflow%3Aauto%7Doptgroup%7Bfont%2Dweight%3A700%7Dtable%7Bborder%2Dspacing%3A0%3Bborder%2Dcollapse%3Acollapse%7Dtd%2Cth%7Bpadding%3A0%7D%40media%20print%7B%2A%2C%3Aafter%2C%3Abefore%7Bcolor%3A%23000%21important%3Btext%2Dshadow%3Anone%21important%3Bbackground%3A0%200%21important%3B%2Dwebkit%2Dbox%2Dshadow%3Anone%21important%3Bbox%2Dshadow%3Anone%21important%7Da%2Ca%3Avisited%7Btext%2Ddecoration%3Aunderline%7Da%5Bhref%5D%3Aafter%7Bcontent%3A%22%20%28%22%20attr%28href%29%20%22%29%22%7Dabbr%5Btitle%5D%3Aafter%7Bcontent%3A%22%20%28%22%20attr%28title%29%20%22%29%22%7Da%5Bhref%5E%3D%22javascript%3A%22%5D%3Aafter%2Ca%5Bhref%5E%3D%22%23%22%5D%3Aafter%7Bcontent%3A%22%22%7Dblockquote%2Cpre%7Bborder%3A1px%20solid%20%23999%3Bpage%2Dbreak%2Dinside%3Aavoid%7Dthead%7Bdisplay%3Atable%2Dheader%2Dgroup%7Dimg%2Ctr%7Bpage%2Dbreak%2Dinside%3Aavoid%7Dimg%7Bmax%2Dwidth%3A100%25%21important%7Dh2%2Ch3%2Cp%7Borphans%3A3%3Bwidows%3A3%7Dh2%2Ch3%7Bpage%2Dbreak%2Dafter%3Aavoid%7D%2Enavbar%7Bdisplay%3Anone%7D%2Ebtn%3E%2Ecaret%2C%2Edropup%3E%2Ebtn%3E%2Ecaret%7Bborder%2Dtop%2Dcolor%3A%23000%21important%7D%2Elabel%7Bborder%3A1px%20solid%20%23000%7D%2Etable%7Bborder%2Dcollapse%3Acollapse%21important%7D%2Etable%20td%2C%2Etable%20th%7Bbackground%2Dcolor%3A%23fff%21important%7D%2Etable%2Dbordered%20td%2C%2Etable%2Dbordered%20th%7Bborder%3A1px%20solid%20%23ddd%21important%7D%7D%40font%2Dface%7Bfont%2Dfamily%3A%27Glyphicons%20Halflings%27%3Bsrc%3Aurl%28data%3Aapplication%2Fvnd%2Ems%2Dfontobject%3Bbase64%2Cn04AAEFNAAACAAIABAAAAAAABQAAAAAAAAABAJABAAAEAExQAAAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAJxJ%2FLAAAAAAAAAAAAAAAAAAAAAAAACgARwBMAFkAUABIAEkAQwBPAE4AUwAgAEgAYQBsAGYAbABpAG4AZwBzAAAADgBSAGUAZwB1AGwAYQByAAAAeABWAGUAcgBzAGkAbwBuACAAMQAuADAAMAA5ADsAUABTACAAMAAwADEALgAwADAAOQA7AGgAbwB0AGMAbwBuAHYAIAAxAC4AMAAuADcAMAA7AG0AYQBrAGUAbwB0AGYALgBsAGkAYgAyAC4ANQAuADUAOAAzADIAOQAAADgARwBMAFkAUABIAEkAQwBPAE4AUwAgAEgAYQBsAGYAbABpAG4AZwBzACAAUgBlAGcAdQBsAGEAcgAAAAAAQlNHUAAAAAAAAAAAAAAAAAAAAAADAKncAE0TAE0ZAEbuFM3pjM%2FSEdmjKHUbyow8ATBE40IvWA3vTu8LiABDQ%2BpexwUMcm1SMnNryctQSiI1K5ZnbOlXKmnVV5YvRe6RnNMFNCOs1KNVpn6yZhCJkRtVRNzEufeIq7HgSrcx4S8h%2Fv4vnrrKc6oCNxmSk2uKlZQHBii6iKFoH0746ThvkO1kJHlxjrkxs%2BLWORaDQBEtiYJIR5IB9Bi1UyL4Rmr0BNigNkMzlKQmnofBHviqVzUxwdMb3NdCn69hy%2BpRYVKGVS%2F1tnsqv4LL7wCCPZZAZPT4aCShHjHJVNuXbmMrY5LeQaGnvAkXlVrJgKRAUdFjrWEah9XebPeQMj7KS7DIBAFt8ycgC5PLGUOHSE3ErGZCiViNLL5ZARfywnCoZaKQCu6NuFX42AEeKtKUGnr%2FCm2Cy8tpFhBPMW5Fxi4Qm4TkDWh4IWFDClhU2hRWosUWqcKLlgyXB%2BlSHaWaHiWlBAR8SeSgSPCQxdVQgzUixWKSTrIQEbU94viDctkvX%2BVSjJuUmV8L4CXShI11esnp0pjWNZIyxKHS4wVQ2ime1P4RnhvGw0aDN1OLAXGERsB7buFpFGGBAre4QEQR0HOIO5oYH305G%2BKspT%2FFupEGGafCCwxSe6ZUa%2B073rXHnNdVXE6eWvibUS27XtRzkH838mYLMBmYysZTM0EM3A1fbpCBYFccN1B%2FEnCYu%2FTgCGmr7bMh8GfYL%2BBfcLvB0gRagC09w9elfldaIy%2FhNCBLRgBgtCC7jAF63wLSMAfbfAlEggYU0bUA7ACCJmTDpEmJtI78w4%2FBO7dN7JR7J7ZvbYaUbaILSQsRBiF3HGk5fEg6p9unwLvn98r%2BvnsV%2B372uf1xBLq4qU%2F45fTuqaAP%2BpssmCCCTF0mhEow8ZXZOS8D7Q85JsxZ%2BAzok7B7O%2Ff6J8AzYBySZQB%2FQHYUSA%2BEeQhEWiS6AIQzgcsDiER4MjgMBAWDV4AgQ3g1eBgIdweCQmCjJEMkJ%2BPKRWyFHHmg1Wi%2F6xzUgA0LREoKJChwnQa9B%2B5RQZRB3IlBlkAnxyQNaANwHMowzlYSMCBgnbpzvqpl0iTJNCQidDI9ZrSYNIRBhHtUa5YHMHxyGEik9hDE0AKj72AbTCaxtHPUaKZdAZSnQTyjGqGLsmBStCejApUhg4uBMU6mATujEl%2BKdDPbI6Ag4vLr%2BhjY6lbjBeoLKnZl0UZgRX8gTySOeynZVz1wOq7e1hFGYIq%2BMhrGxDLak0PrwYzSXtcuyhXEhwOYofiW%2BEcI%2Fjw8P6IY6ed%2BetAbuqKp5QIapT77LnAe505lMuqL79a0ut4rWexzFttsOsLDy7zvtQzcq3U1qabe7tB0wHWVXji%2BzDbo8x8HyIRUbXnwUcklFv51fvTymiV%2BMXLSmGH9d9%2BaXpD5X6lao41anWGig7IwIdnoBY2ht%2FpO9mClLo4NdXHAsefqWUKlXJkbqPOFhMoR4aiA1BXqhRNbB2Xwi%2B7u%2FjpAoOpKJ0UX24EsrzMfHXViakCNcKjBxuQX8BO0ZqjJ3xXzf%2B61t2VXOSgJ8xu65QKgtN6FibPmPYsXbJRHHqbgATcSZxBqGiDiU4NNNsYBsKD0MIP%2FOfKnlk%2FLkaid%2FO2NbKeuQrwOB2Gq3YHyr6ALgzym5wIBnsdC1ZkoBFZSQXChZvlesPqvK2c5oHHT3Q65jYpNxnQcGF0EHbvYqoFw60WNlXIHQF2HQB7zD6lWjZ9rVqUKBXUT6hrkZOle0RFYII0V5ZYGl1JAP0Ud1fZZMvSomBzJ710j4Me8mjQDwEre5Uv2wQfk1ifDwb5ksuJQQ3xt423lbuQjvoIQByQrNDh1JxGFkOdlJvu%2FgFtuW0wR4cgd%2BZKesSV7QkNE2kw6AV4hoIuC02LGmTomyf8PiO6CZzOTLTPQ%2BHW06H%2Btx%2BbQ8LmDYg1pTFrp2oJXgkZTyeRJZM0C8aE2LpFrNVDuhARsN543%2FFV6klQ6Tv1OoZGXLv0igKrl%2FCmJxRmX7JJbJ998VSIPQRyDBICzl4JJlYHbdql30NvYcOuZ7a10uWRrgoieOdgIm4rlq6vNOQBuqESLbXG5lzdJGHw2m0sDYmODXbYGTfSTGRKpssTO95fothJCjUGQgEL4yKoGAF%2F0SrpUDNn8CBgBcSDQByAeNkCXp4S4Ro2Xh4OeaGRgR66PVOsU8bc6TR5%2FxTcn4IVMLOkXSWiXxkZQCbvKfmoAvQaKjO3EDKwkwqHChCDEM5loQRPd5ACBki1TjF772oaQhQbQ5C0lcWXPFOzrfsDGUXGrpxasbG4iab6eByaQkQfm0VFlP0ZsDkvvqCL6QXMUwCjdMx1ZOyKhTJ7a1GWAdOUcJ8RSejxNVyGs31OKMyRyBVoZFjqIkmKlLQ5eHMeEL4MkUf23cQ%2F1SgRCJ1dk4UdBT7OoyuNgLs0oCd8RnrEIb6QdMxT2QjD4zMrJkfgx5aDMcA4orsTtKCqWb%2FVeyceqa5OGSmB28YwH4rFbkQaLoUN8OQQYnD3w2eXpI4ScQfbCUZiJ4yMOIKLyyTc7BQ4uXUw6Ee6%2FxM%2B4Y67ngNBknxIPwuppgIhFcwJyr6EIj%2BLzNj%2FmfR2vhhRlx0BILZoAYruF0caWQ7YxO66UmeguDREAFHYuC7HJviRgVO6ruJH59h%2FC%2FPkgSle8xNzZJULLWq9JMDTE2fjGE146a1Us6PZDGYle6ldWRqn%2FpdpgHKNGrGIdkRK%2BKPETT9nKT6kLyDI8xd9A1FgWmXWRAIHwZ37WyZHOVyCadJEmMVz0MadMjDrPho%2BEIochkVC2xgGiwwsQ6DMv2P7UXqT4x7CdcYGId2BJQQa85EQKmCmwcRejQ9Bm4oATENFPkxPXILHpMPUyWTI5rjNOsIlmEeMbcOCEqInpXACYQ9DDxmFo9vcmsDblcMtg4tqBerNngkIKaFJmrQAPnq1dEzsMXcwjcHdfdCibcAxxA%2Bq%2Fj9m3LM%2FO7WJka4tSidVCjsvo2lQ%2F2ewyoYyXwAYyr2PlRoR5MpgVmSUIrM3PQxXPbgjBOaDQFIyFMJvx3Pc5RSYj12ySVF9fwFPQu2e2KWVoL9q3Ayv3IzpGHUdvdPdrNUdicjsTQ2ISy7QU3DrEytIjvbzJnAkmANXjAFERA0MUoPF3%2F5KFmW14bBNOhwircYgMqoDpUMcDtCmBE82QM2YtdjVLB4kBuKho%2FbcwQdeboqfQartuU3CsCf%2BcXkgYAqp%2F0Ee3RorAZt0AvvOCSI4JICIlGlsV0bsSid%2FNIEALAAzb6HAgyWHBps6xAOwkJIGcB82CxRQq4sJf3FzA70A%2BTRqcqjEMETCoez3mkPcpnoALs0ugJY8kQwrC%2BJE5ik3w9rzrvDRjAQnqgEVvdGrNwlanR0SOKWzxOJOvLJhcd8Cl4AshACUkv9czdMkJCVQSQhp6kp7StAlpVRpK0t0SW6LHeBJnE2QchB5Ccu8kxRghZXGIgZIiSj7gEKMJDClcnX6hgoqJMwiQDigIXg3ioFLCgDgjPtYHYpsF5EiA4kcnN18MZtOrY866dEQAb0FB34OGKHGZQjwW%2FWDHA60cYFaI%2FPjpzquUqdaYGcIq%2BmLez3WLFFCtNBN2QJcrlcoELgiPku5R5dSlJFaCEqEZle1AQzAKC%2B1SotMcBNyQUFuRHRF6OlimSBgjZeTBCwLyc6A%2BP%2FoFRchXTz5ADknYJHxzrJ5pGuIKRQISU6WyKTBBjD8WozmVYWIsto1AS5rxzKlvJu4E%2FvwOiKxRtCWsDM%2BeTHUrmwrCK5BIfMzGkD%2B0Fk5LzBs0jMYXktNDblB06LMNJ09U8pzSLmo14MS0OMjcdrZ31pyQqxJJpRImlSvfYAK8inkYU52QY2FPEVsjoWewpwhRp5yAuNpkqhdb7ku9Seefl2D0B8SMTFD90xi4CSOwwZy9IKkpMtI3FmFUg3%2FkFutpQGNc3pCR7gvC4sgwbupDu3DyEN%2BW6YGLNM21jpB49irxy9BSlHrVDlnihGKHwPrbVFtc%2Bh1rVQKZduxIyojccZIIcOCmhEnC7UkY68WXKQgLi2JCDQkQWJRQuk60hZp0D3rtCTINSeY9Ej2kIKYfGxwOs4j9qMM7fYZiipzgcf7TamnehqdhsiMiCawXnz4xAbyCkLAx5EGbo3Ax1u3dUIKnTxIaxwQTHehPl3V491H0%2BbC5zgpGz7Io%2BmjdhKlPJ01EeMpM7UsRJMi1nGjmJg35i6bQBAAxjO%2FENJubU2mg3ONySEoWklCwdABETcs7ck3jgiuU9pcKKpbgn%2B3YlzV1FzIkB6pmEDOSSyDfPPlQskznctFji0kpgZjW5RZe6x9kYT4KJcXg0bNiCyif%2BpZACCyRMmYsfiKmN9tSO65F0R2OO6ytlEhY5Sj6uRKfFxw0ijJaAx%2Fk3QgnAFSq27%2F2i4GEBA%2BUvTJKK%2F9eISNvG46Em5RZfjTYLdeD8kdXHyrwId%2FDQZUaMCY4gGbke2C8vfjgV%2FY9kkRQOJIn%2FxM9INZSpiBnqX0Q9GlQPpPKAyO5y%2BW5NMPSRdBCUlmuxl40ZfMCnf2Cp044uI9WLFtCi4YVxKjuRCOBWIb4XbIsGdbo4qtMQnNOQz4XDSui7W%2FN6l54qOynCqD3DpWQ%2BmpD7C40D8BZEWGJX3tlAaZBMj1yjvDYKwCJBa201u6nBKE5UE%2B7QSEhCwrXfbRZylAaAkplhBWX50dumrElePyNMRYUrC99UmcSSNgImhFhDI4BXjMtiqkgizUGCrZ8iwFxU6fQ8GEHCFdLewwxYWxgScAYMdMLmcZR6b7rZl95eQVDGVoUKcRMM1ixXQtXNkBETZkVVPg8LoSrdetHzkuM7DjZRHP02tCxA1fmkXKF3VzfN1pc1cv%2F8lbTIkkYpqKM9VOhp65ktYk%2BQ46myFWBapDfyWUCnsnI00QTBQmuFjMZTcd0V2NQ768Fhpby04k2IzNR1wKabuGJqYWwSly6ocMFGTeeI%2BejsWDYgEvr66QgqdcIbFYDNgsm0x9UHY6SCd5%2B7tpsLpKdvhahIDyYmEJQCqMqtCF6UlrE5GXRmbu%2Bvtm3BFSxI6ND6UxIE7GsGMgWqghXxSnaRJuGFveTcK5ZVSPJyjUxe1dKgI6kNF7EZhIZs8y8FVqwEfbM0Xk2ltORVDKZZM40SD3qQoQe0orJEKwPfZwm3YPqwixhUMOndis6MhbmfvLBKjC8sKKIZKbJk8L11oNkCQzCgvjhyyEiQSuJcgCQSG4Mocfgc0Hkwcjal1UNgP0CBPikYqBIk9tONv4kLtBswH07vUCjEaHiFGlLf8MgXKzSgjp2HolRRccAOh0ILHz9qlGgIFkwAnzHJRjWFhlA7ROwINyB5HFj59PRZHFor6voq7l23EPNRwdWhgawqbivLSjRA4htEYUFkjESu67icTg5S0aW1sOkCiIysfJ9UnIWevOOLGpepcBxy1wEhd2WI3AZg7sr9WBmHWyasxMcvY%2FiOmsLtHSWNUWEGk9hScMPShasUA1AcHOtRZlqMeQ0OzYS9vQvYUjOLrzP07BUAFikcJNMi7gIxEw4pL1G54TcmmmoAQ5s7TGWErJZ2Io4yQ0ljRYhL8H5e62oDtLF8aDpnIvZ5R3GWJyAugdiiJW9hQAVTsnCBHhwu7rkBlBX6r3b7ejEY0k5GGeyKv66v%2B6dg7mcJTrWHbtMywbedYqCQ0FPwoytmSWsL8WTtChZCKKzEF7vP6De4x2BJkkniMgSdWhbeBSLtJZR9CTHetK1xb34AYIJ37OegYIoPVbXgJ%2FqDQK%2BbfCtxQRVKQu77WzOoM6SGL7MaZwCGJVk46aImai9fmam%2BWpHG%2B0BtQPWUgZ7RIAlPq6lkECUhZQ2gqWkMYKcYMYaIc4gYCDFHYa2d1nzp3%2BJ1eCBay8IYZ0wQRKGAqvCuZ%2FUgbQPyllosq%2BXtfKIZOzmeJqRazpmmoP%2F76YfkjzV2NlXTDSBYB04SVlNQsFTbGPk1t%2FI4Jktu0XSgifO2ozFOiwd%2F0SssJDn0dn4xqk4GDTTKX73%2FwQyBLdqgJ%2BWx6AQaba3BA9CKEzjtQYIfAsiYamapq80LAamYjinlKXUkxdpIDk0puXUEYzSalfRibAeDAKpNiqQ0FTwoxuGYzRnisyTotdVTclis1LHRQCy%2FqqL8oUaQzWRxilq5Mi0IJGtMY02cGLD69vGjkj3p6pGePKI8bkBv5evq8SjjyU04vJR2cQXQwSJyoinDsUJHCQ50jrFTT7yRdbdYQMB3MYCb6uBzJ9ewhXYPAIZSXfeEQBZZ3GPN3Nbhh%2FwkvAJLXnQMdi5NYYZ5GHE400GS5rXkOZSQsdZgIbzRnF9ueLnsfQ47wHAsirITnTlkCcuWWIUhJSbpM3wWhXNHvt2xUsKKMpdBSbJnBMcihkoDqAd1Zml%2FR4yrzow1Q2A5G%2Bkzo%2FRhRxQS2lCSDRV8LlYLBOOoo1bF4jwJAwKMK1tWLHlu9i0j4Ig8qVm6wE1DxXwAwQwsaBWUg2pOOol2dHxyt6npwJEdLDDVYyRc2D0HbcbLUJQj8gPevQBUBOUHXPrsAPBERICpnYESeu2OHotpXQxRGlCCtLdIsu23MhZVEoJg8Qumj%2FUMMc34IBqTKLDTp76WzL%2FdMjCxK7MjhiGjeYAC%2Fkj%2FjY%2FRde7hpSM1xChrog6yZ7OWTuD56xBJnGFE%2BpT2ElSyCnJcwVzCjkqeNLfMEJqKW0G7OFIp0G%2B9mh50I9o8k1tpCY0xYqFNIALgIfc2me4n1bmJnRZ89oepgLPT0NTMLNZsvSCZAc3TXaNB07vail36%2FdBySis4m9%2FDR8izaLJW6bWCkVgm5T%2Bius3ZXq4xI%2BGnbveLbdRwF2mNtsrE0JjYc1AXknCOrLSu7Te%2Fr4dPYMCl5qtiHNTn%2BTPbh1jCBHH%2BdMJNhwNgs3nT%2BOhQoQ0vYif56BMG6WowAcHR3DjQolxLzyVekHj00PBAaW7IIAF1EF%2BuRIWyXjQMAs2chdpaKPNaB%2BkSezYt0%2BCA04sOg5vx8Fr7Ofa9sUv87h7SLAUFSzbetCCZ9pmyLt6l6%2FTzoA1%2FZBG9bIUVHLAbi%2FkdBFgYGyGwRQGBpkqCEg2ah9UD6EedEcEL3j4y0BQQCiExEnocA3SZboh%2Bepgd3YsOkHskZwPuQ5OoyA0fTA5AXrHcUOQF%2BzkJHIA7PwCDk1gGVmGUZSSoPhNf%2BTklauz98QofOlCIQ%2FtCD4dosHYPqtPCXB3agggQQIqQJsSkB%2Bqn0rkQ1toJjON%2FOtCIB9RYv3PqRA4C4U68ZMlZn6BdgEvi2ziU%2BTQ6NIw3ej%2BAtDwMGEZk7e2IjxUWKdAxyaw9OCwSmeADTPPleyk6UhGDNXQb%2B%2BW6Uk4q6F7%2Frg6WVTo82IoCxSIsFDrav4EPHphD3u4hR53WKVvYZUwNCCeM4PMBWzK%2BEfIthZOkuAwPo5C5jgoZgn6dUdvx5rIDmd58cXXdKNfw3l%2BwM2UjgrDJeQHhbD7HW2QDoZMCujgIUkk5Fg8VCsdyjOtnGRx8wgKRPZN5dR0zPUyfGZFVihbFRniXZFOZGKPnEQzU3AnD1KfR6weHW2XS6KbPJxUkOTZsAB9vTVp3Le1F8q5l%2BDMcLiIq78jxAImD2pGFw0VHfRatScGlK6SMu8leTmhUSMy8Uhdd6xBiH3Gdman4tjQGLboJfqz6fL2WKHTmrfsKZRYX6BTDjDldKMosaSTLdQS7oDisJNqAUhw1PfTlnacCO8vl8706Km1FROgLDmudzxg%2BEWTiArtHgLsRrAXYWdB0NmToNCJdKm0KWycZQqb%2BMw76Qy29iQ5up%2FX7oyw8QZ75kP5F6iJAJz6KCmqxz8fEa%2FxnsMYcIO%2FvEkGRuMckhr4rIeLrKaXnmIzlNLxbFspOphkcnJdnz%2FChp%2FVlpj2P7jJQmQRwGnltkTV5dbF9fE3%2FfxoSqTROgq9wFUlbuYzYcasE0ouzBo%2BdDCDzxKAfhbAZYxQiHrLzV2iVexnDX%2FQnT1fsT%2Fxuhu1ui5qIytgbGmRoQkeQooO8eJNNZsf0iALur8QxZFH0nCMnjerYQqG1pIfjyVZWxhVRznmmfLG00BcBWJE6hzQWRyFknuJnXuk8A5FRDCulwrWASSNoBtR%2BCtGdkPwYN2o7DOw%2FVGlCZPusRBFXODQdUM5zeHDIVuAJBLqbO%2Ff9Qua%2BpDqEPk230Sob9lEZ8BHiCorjVghuI0lI4JDgHGRDD%2FprQ84B1pVGkIpVUAHCG%2Biz3Bn3qm2AVrYcYWhock4jso5%2BJ7HfHVj4WMIQdGctq3psBCVVzupQOEioBGA2Bk%2BUILT7%2BVoX5mdxxA5fS42gISQVi%2FHTzrgMxu0fY6hE1ocUwwbsbWcezrY2n6S8%2F6cxXkOH4prpmPuFoikTzY7T85C4T2XYlbxLglSv2uLCgFv8Quk%2FwdesUdWPeHYIH0R729JIisN9Apdd4eB10aqwXrPt%2BSu9mA8k8n1sjMwnfsfF2j3jMUzXepSHmZ%2FBfqXvzgUNQQWOXO8YEuFBh4QTYCkOAPxywpYu1VxiDyJmKVcmJPGWk%2Fgc3Pov02StyYDahwmzw3E1gYC9wkupyWfDqDSUMpCTH5e5N8B%2F%2FlHiMuIkTNw4USHrJU67bjXGqNav6PBuQSoqTxc8avHoGmvqNtXzIaoyMIQIiiUHIM64cXieouplhNYln7qgc4wBVAYR104kO%2BCvKqsg4yIUlFNThVUAKZxZt1XA34h3TCUUiXVkZ0w8Hh2R0Z5L0b4LZvPd%2Fp1gi%2F07h8qfwHrByuSxglc9cI4QIg2oqvC%2Fqm0i7tjPLTgDhoWTAKDO2ONW5oe%2B%2FeKB9vZB8K6C25yCZ9RFVMnb6NRdRjyVK57CHHSkJBfnM2%2Fj4ODUwRkqrtBBCrDsDpt8jhZdXoy%2F1BCqw3sSGhgGGy0a5Jw6BP%2FTExoCmNFYjZl248A0osgPyGEmRA%2BfAsqPVaNAfytu0vuQJ7rk3J4kTDTR2AlCHJ5cls26opZM4w3jMULh2YXKpcqGBtuleAlOZnaZGbD6DHzMd6i2oFeJ8z9XYmalg1Szd%2FocZDc1C7Y6vcALJz2lYnTXiWEr2wawtoR4g3jvWUU2Ngjd1cewtFzEvM1NiHZPeLlIXFbBPawxNgMwwAlyNSuGF3zizVeOoC9bag1qRAQKQE%2FEZBWC2J8mnXAN2aTBboZ7HewnObE8CwROudZHmUM5oZ%2FUgd%2FJZQK8lvAm43uDRAbyW8gZ%2BZGq0EVerVGUKUSm%2FIdn8AQHdR4m7bue88WBwft9mSCeMOt1ncBwziOmJYI2ZR7ewNMPiCugmSsE4EyQ%2BQATJG6qORMGd4snEzc6B4shPIo4G1T7PgSm8PY5eUkPdF8JZ0VBtadbHXoJgnEhZQaODPj2gpODKJY5Yp4DOsLBFxWbvXN755KWylJm%2BoOd4zEL9Hpubuy2gyyfxh8oEfFutnYWdfB8PdESLWYvSqbElP9qo3u6KTmkhoacDauMNNjj0oy40DFV7Ql0aZj77xfGl7TJNHnIwgqOkenruYYNo6h724%2BzUQ7%2BvkCpZB%2BpGA562hYQiDxHVWOq0oDQl%2FQsoiY%2BcuI7iWq%2FZIBtHcXJ7kks%2Bh2fCNUPA82BzjnqktNts%2BRLdk1VSu%2BtqEn7QZCCsvEqk6FkfiOYkrsw092J8jsfIuEKypNjLxrKA9kiA19mxBD2suxQKCzwXGws7kEJvlhUiV9tArLIdZW0IORcxEzdzKmjtFhsjKy%2F44XYXdI5noQoRcvjZ1RMPACRqYg2V1%2BOwOepcOknRLLFdYgTkT5UApt%2FJhLM3jeFYprZV%2BZow2g8fP%2BU68hkKFWJj2yBbKqsrp25xkZX1DAjUw52IMYWaOhab8Kp05VrdNftqwRrymWF4OQSjbdfzmRZirK8FMJELEgER2PHjEAN9pGfLhCUiTJFbd5LBkOBMaxLr%2FA1SY9dXFz4RjzoU9ExfJCmx%2FI9FKEGT3n2cmzl2X42L3Jh%2BAbQq6sA%2BSs1kitoa4TAYgKHaoybHUDJ51oETdeI%2F9ThSmjWGkyLi5QAGWhL0BG1UsTyRGRJOldKBrYJeB8ljLJHfATWTEQBXBDnQexOHTB%2BUn44zExFE4vLytcu5NwpWrUxO%2F0ZICUGM7hGABXym0V6ZvDST0E370St9MIWQOTWngeoQHUTdCJUP04spMBMS8LSker9cReVQkULFDIZDFPrhTzBl6sed9wcZQTbL%2BBDqMyaN3RJPh%2Fanbx%2BIv%2BqgQdAa3M9Z5JmvYlh4qop%2BHo1F1W5gbOE9YKLgAnWytXElU4G8GtW47lhgFE6gaSs%2Bgs37sFvi0PPVvA5dnCBgILTwoKd%2F%2BDoL9F6inlM7H4rOTzD79KJgKlZO%2FZgt22UsKhrAaXU5ZcLrAglTVKJEmNJvORGN1vqrcfSMizfpsgbIe9zno%2BgBoKVXgIL%2FVI8dB1O5o%2FR3Suez%2FgD7M781ShjKpIIORM%2FnxG%2BjjhhgPwsn2IoXsPGPqYHXA63zJ07M2GPEykQwJBYLK808qYxuIew4frk52nhCsnCYmXiR6CuapvE1IwRB4%2FQftDbEn%2BAucIr1oxrLabRj9q4ae0%2BfXkHnteAJwXRbVkR0mctVSwEbqhJiMSZUp9DNbEDMmjX22m3ABpkrPQQTP3S1sib5pD2VRKRd%2BeNAjLYyT0hGrdjWJZy24OYXRoWQAIhGBZRxuBFMjjZQhpgrWo8SiFYbojcHO8V5DyscJpLTHyx9Fimassyo5U6WNtquUMYgccaHY5amgR3PQzq3ToNM5ABnoB9kuxsebqmYZm0R9qxJbFXCQ1UPyFIbxoUraTJFDpCk0Wk9GaYJKz%2F6oHwEP0Q14lMtlddQsOAU9zlYdMVHiT7RQP3XCmWYDcHCGbVRHGnHuwzScA0BaSBOGkz3lM8CArjrBsyEoV6Ys4qgDK3ykQQPZ3hCRGNXQTNNXbEb6tDiTDLKOyMzRhCFT%2BmAUmiYbV3YQVqFVp9dorv%2BTsLeCykS2b5yyu8AV7IS9cxcL8z4Kfwp%2BxJyYLv1OsxQCZwTB4a8BZ%2F5EdxTBJthApqyfd9u3ifr%2FWILTqq5VqgwMT9SOxbSGWLQJUUWCVi4k9tho9nEsbUh7U6NUsLmkYFXOhZ0kmamaJLRNJzSj%2Fqn4Mso6zb6iLLBXoaZ6AqeWCjHQm2lztnejYYM2eubnpBdKVLORZhudH3JF1waBJKA9%2BW8EhMj3Kzf0L4vi4k6RoHh3Z5YgmSZmk6ns4fjScjAoL8GoOECgqgYEBYUGFVO4FUv4%2FYtowhEmTs0vrvlD%2FCrisnoBNDAcUi%2FteY7OctFlmARQzjOItrrlKuPO6E2Ox93L4O%2F4DcgV%2FdZ7qR3VBwVQxP1GCieA4RIpweYJ5FoYrHxqRBdJjnqbsikA2Ictbb8vE1GYIo9dacK0REgDX4smy6GAkxlH1yCGGsk%2BtgiDhNKuKu3yNrMdxafmKTF632F8Vx4BNK57GvlFisrkjN9WDAtjsWA0ENT2e2nETUb%2Fn7qwhvGnrHuf5bX6Vh%2Fn3xffU3PeHdR%2BFA92i6ufT3AlyAREoNDh6chiMWTvjKjHDeRhOa9YkOQRq1vQXEMppAQVwHCuIcV2g5rBn6GmZZpTR7vnSD6ZmhdSl176gqKTXu5E%2BYbfL0adwNtHP7dT7t7b46DVZIkzaRJOM%2BS6KcrzYVg%2BT3wSRFRQashjfU18NutrKa%2F7PXbtuJvpIjbgPeqd%2BpjmRw6YKpnANFSQcpzTZgpSNJ6J7uiagAbir%2F8tNXJ%2FOsOnRh6iuIexxrmkIneAgz8QoLmiaJ8sLQrELVK2yn3wOHp57BAZJhDZjTBzyoRAuuZ4eoxHruY1pSb7qq79cIeAdOwin4GdgMeIMHeG%2BFZWYaiUQQyC5b50zKjYw97dFjAeY2I4Bnl105Iku1y0lMA1ZHolLx19uZnRdILcXKlZGQx%2FGdEqSsMRU1BIrFqRcV1qQOOHyxOLXEGcbRtAEsuAC2V4K3p5mFJ22IDWaEkk9ttf5Izb2LkD1MnrSwztXmmD%2FQi%2FEmVEFBfiKGmftsPwVaIoZanlKndMZsIBOskFYpDOq3QUs9aSbAAtL5Dbokus2G4%2FasthNMK5UQKCOhU97oaOYNGsTah%2BjfCKsZnTRn5TbhFX8ghg8CBYt%2FBjeYYYUrtUZ5jVij%2Fop7V5SsbA4mYTOwZ46hqdpbB6Qvq3AS2HHNkC15pTDIcDNGsMPXaBidXYPHc6PJAkRh29Vx8KcgX46LoUQBhRM%2B3SW6Opll%2FwgxxsPgKJKzr5QCmwkUxNbeg6Wj34SUnEzOemSuvS2OetRCO8Tyy%2BQbSKVJcqkia%2BGvDefFwMOmgnD7h81TUtMn%2BmRpyJJ349HhAnoWFTejhpYTL9G8N2nVg1qkXBeoS9Nw2fB27t7trm7d%2FQK7Cr4uoCeOQ7%2F8JfKT77KiDzLImESHw%2F0wf73QeHu74hxv7uihi4fTX%2BXEwAyQG3264dwv17aJ5N335Vt9sdrAXhPOAv8JFvzqyYXwfx8WYJaef1gMl98JRFyl5Mv5Uo%2FoVH5ww5OzLFsiTPDns7fS6EURSSWd%2F92BxMYQ8sBaH%2Bj%2BwthQPdVgDGpTfi%2BJQIWMD8xKqULliRH01rTeyF8x8q%2FGBEEEBrAJMPf25UQwi0b8tmqRXY7kIvNkzrkvRWLnxoGYEJsz8u4oOyMp8cHyaybb1HdMCaLApUE%2B%2F7xLIZGP6H9xuSEXp1zLIdjk5nBaMuV%2FyTDRRP8Y2ww5RO6d2D94o%2B6ucWIqUAvgHIHXhZsmDhjVLczmZ3ca0Cb3PpKwt2UtHVQ0BgFJsqqTsnzZPlKahRUkEu4qmkJt%2Bkqdae76ViWe3STan69yaF9%2BfESD2lcQshLHWVu4ovItXxO69bqC5p1nZLvI8NdQB9s9UNaJGlQ5mG947ipdDA0eTIw%2FA1zEdjWquIsQXXGIVEH0thC5M%2BW9pZe7IhAVnPJkYCCXN5a32HjN6nsvokEqRS44tGIs7s2LVTvcrHAF%2BRVmI8L4HUYk4x%2B67AxSMJKqCg8zrGOgvK9kNMdDrNiUtSWuHFpC8%2Fp5qIQrEo%2FH%2B1l%2F0cAwQ2nKmpWxKcMIuHY44Y6DlkpO48tRuUGBWT0FyHwSKO72Ud%2BtJUfdaZ4CWNijzZtlRa8%2BCkmO%2FEwHYfPZFU%2FhzjFWH7vnzHRMo%2BaF9u8qHSAiEkA2HjoNQPEwHsDKOt6hOoK3Ce%2F%2B%2F9boMWDa44I6FrQhdgS7OnNaSzwxWKZMcyHi6LN4WC6sSj0qm2PSOGBTvDs%2FGWJS6SwEN%2FULwpb4LQo9fYjUfSXRwZkynUazlSpvX9e%2BG2zor8l%2BYaMxSEomDdLHGcD6YVQPegTaA74H8%2BV4WvJkFUrjMLGLlvSZQWvi8%2FQA7yzQ8GPno%2F%2F5SJHRP%2FOqKObPCo81s%2F%2B6WgLqykYpGAgQZhVDEBPXWgU%2FWzFZjKUhSFInufPRiMAUULC6T11yL45ZrRoB4DzOyJShKXaAJIBS9wzLYIoCEcJKQW8GVCx4fihqJ6mshBUXSw3wWVj3grrHQlGNGhIDNNzsxQ3M%2BGWn6ASobIWC%2BLbYOC6UpahVO13Zs2zOzZC8z7FmA05JhUGyBsF4tsG0drcggIFzgg%2Fkpf3%2BCnAXKiMgIE8Jk%2FMhpkc8DUJEUzDSnWlQFme3d0sHZDrg7LavtsEX3cHwjCYA17pMTfx8Ajw9hHscN67hyo%2BRJQ4458RmPywXykkVcW688oVUrQhahpPRvTWPnuI0B%2BSkQu7dCyvLRyFYlC1LG1gRCIvn3rwQeINzZQC2KXq31FaR9UmVV2QeGVqBHjmE%2BVMd3b1fhCynD0pQNhCG6%2FWCDbKPyE7NRQzL3BzQAJ0g09aUzcQA6mUp9iZFK6Sbp%2FYbHjo%2B%2B7%2FWj8S4YNa%2BZdqAw1hDrKWFXv9%2BzaXpf8ZTDSbiqsxnwN%2FCzK5tPkOr4tRh2kY3Bn9JtalbIOI4b3F7F1vPQMfoDcdxMS8CW9m%2FNCW%2FHILTUVWQIPiD0j1A6bo8vsv6P1hCESl2abrSJWDrq5sSzUpwoxaCU9FtJyYH4QFMxDBpkkBR6kn0LMPO%2B5EJ7Z6bCiRoPedRZ%2FP0SSdii7ZnPAtVwwHUidcdyspwncz5uq6vvm4IEDbJVLUFCn%2FLvIHfooUBTkFO130FC7CmmcrKdgDJcid9mvVzsDSibOoXtIf9k6ABle3PmIxejodc4aob0QKS432srrCMndbfD454q52V01G4q913mC5HOsTzWF4h2No1av1VbcUgWAqyoZl%2B11PoFYnNv2HwAODeNRkHj%2B8SF1fcvVBu6MrehHAZK1Gm69ICcTKizykHgGFx7QdowTVAsYEF2tVc0Z6wLryz2FI1sc5By2znJAAmINndoJiB4sfPdPrTC8RnkW7KRCwxC6YvXg5ahMlQuMpoCSXjOlBy0Kij%2BbsCYPbGp8BdCBiLmLSAkEQRaieWo1SYvZIKJGj9Ur%2FeWHjiB7SOVdqMAVmpBvfRiebsFjger7DC%2B8kRFGtNrTrnnGD2GAJb8rQCWkUPYHhwXsjNBSkE6lGWUj5QNhK0DMNM2l%2BkXRZ0KLZaGsFSIdQz%2FHXDxf3%2FTE30%2BDgBKWGWdxElyLccJfEpjsnszECNoDGZpdwdRgCixeg9L4EPhH%2BRptvRMVRaahu4cySjS3P5wxAUCPkmn%2BrhyASpmiTaiDeggaIxYBmtLZDDhiWIJaBgzfCsAGUF1Q1SFZYyXDt9skCaxJsxK2Ms65dmdp5WAZyxik%2FzbrTQk5KmgxCg%2Ff45L0jywebOWUYFJQAJia7XzCV0x89rpp%2Ff3AVWhSPyTanqmik2SkD8A3Ml4NhIGLAjBXtPShwKYfi2eXtrDuKLk4QlSyTw1ftXgwqA2jUuopDl%2B5tfUWZNwBpEPXghzbBggYCw%2Fdhy0ntds2yeHCDKkF%2FYxQjNIL%2FF%2F37jLPHCKBO9ibwYCmuxImIo0ijV2Wbg3kSN2psoe8IsABv3RNFaF9uMyCtCYtqcD%2BqNOhwMlfARQUdJ2tUX%2BMNJqOwIciWalZsmEjt07tfa8ma4cji9sqz%2BQ9hWfmMoKEbIHPOQORbhQRHIsrTYlnVTNvcq1imqmmPDdVDkJgRcTgB8Sb6epCQVmFZe%2BjGDiNJQLWnfx%2BdrTKYjm0G8yH0ZAGMWzEJhUEQ4Maimgf%2Fbkvo8PLVBsZl152y5S8%2BHRDfZIMCbYZ1WDp4yrdchOJw8k6R%2B%2F2pHmydK4NIK2PHdFPHtoLmHxRDwLFb7eB%2BM4zNZcB9NrAgjVyzLM7xyYSY13ykWfIEEd2n5%2FiYp3ZdrCf7fL%2Ben%2BsIJu2W7E30MrAgZBD1rAAbZHPgeAMtKCg3NpSpYQUDWJu9bT3V7tOKv%2BNRiJc8JAKqqgCA%2FPNRBR7ChpiEulyQApMK1AyqcWnpSOmYh6yLiWkGJ2mklCSPIqN7UypWj3dGi5MvsHQ87MrB4VFgypJaFriaHivwcHIpmyi5LhNqtem4q0n8awM19Qk8BOS0EsqGscuuydYsIGsbT5GHnERUiMpKJl4ON7qjB4fEqlGN%2FhCky89232UQCiaeWpDYCJINXjT6xl4Gc7DxRCtgV0i1ma4RgWLsNtnEBRQFqZggCLiuyEydmFd7WlogpkCw5G1x4ft2psm3KAREwVwr1Gzl6RT7FDAqpVal34ewVm3VH4qn5mjGj%2BbYL1NgfLNeXDwtmYSpwzbruDKpTjOdgiIHDVQSb5%2FzBgSMbHLkxWWgghIh9QTFSDILixVwg0Eg1puooBiHAt7DzwJ7m8i8%2Fi%2BjHvKf0QDnnHVkVTIqMvIQImOrzCJwhSR7qYB5gSwL6aWL9hERHCZc4G2%2BJrpgHNB8eCCmcIWIQ6rSdyPCyftXkDlErUkHafHRlkOIjxGbAktz75bnh50dU7YHk%2BMz7wwstg6RFZb%2BTZuSOx1qqP5C66c0mptQmzIC2dlpte7vZrauAMm%2F7RfBYkGtXWGiaWTtwvAQiq2oD4YixPLXE2khB2FRaNRDTk%2B9sZ6K74Ia9VntCpN4BhJGJMT4Z5c5FhSepRCRWmBXqx%2BwhVZC4me4saDs2iNqXMuCl6iAZflH8fscC1sTsy4PHeC%2BXYuqMBMUun5YezKbRKmEPwuK%2BCLzijPEQgfhahQswBBLfg%2FGBgBiI4QwAqzJkkyYAWtjzSg2ILgMAgqxYfwERRo3zruBL9WOryUArSD8sQOcD7fvIODJxKFS615KFPsb68USBEPPj1orNzFY2xoTtNBVTyzBhPbhFH0PI5AtlJBl2aSgNPYzxYLw7XTDBDinmVoENwiGzmngrMo8OmnRP0Z0i0Zrln9DDFcnmOoBZjABaQIbPOJYZGqX%2BRCMlDDbElcjaROLDoualmUIQ88Kekk3iM4OQrADcxi3rJguS4MOIBIgKgXrjd1WkbCdqxJk%2F4efRIFsavZA7KvvJQqp3Iid5Z0NFc5aiMRzGN3vrpBzaMy4JYde3wr96PjN90AYOIbyp6T4zj8LoE66OGcX1Ef4Z3KoWLAUF4BTg7ug%2FAbkG5UNQXAMkQezujSHeir2uTThgd3gpyzDrbnEdDRH2W7U6PeRvBX1ZFMP5RM%2BZu6UUZZD8hDPHldVWntTCNk7To8IeOW9yn2wx0gmurwqC60AOde4r3ETi5pVMSDK8wxhoGAoEX9NLWHIR33VbrbMveii2jAJlrxwytTHbWNu8Y4N8vCCyZjAX%2FpcsfwXbLze2%2BD%2Bu33OGBoJyAAL3jn3RuEcdp5If8O%2Ba4NKWvxOTyDltG0IWoHhwVGe7dKkCWFT%2B%2Btm%2BhaBCikRUUMrMhYKZJKYoVuv%2FbsJzO8DwfVIInQq3g3BYypiz8baogH3r3GwqCwFtZnz4xMjAVOYnyOi5HWbFA8n0qz1OjSpHWFzpQOpvkNETZBGpxN8ybhtqV%2FDMUxd9uFZmBfKXMCn%2FSqkWJyKPnT6lq%2B4zBZni6fYRByJn6OK%2BOgPBGRAJluwGSk4wxjOOzyce%2FPKODwRlsgrVkdcsEiYrqYdXo0Er2GXi2GQZd0tNJT6c9pK1EEJG1zgDJBoTVuCXGAU8BKTvCO%2FcEQ1Wjk3Zzuy90JX4m3O5IlxVFhYkSUwuQB2up7jhvkm%2BbddRQu5F9s0XftGEJ9JSuSk%2BZachCbdU45fEqbugzTIUokwoAKvpUQF%2FCvLbWW5BNQFqFkJg2f30E%2F48StNe5QwBg8zz3YAJ82FZoXBxXSv4QDooDo79NixyglO9AembuBcx5Re3CwOKTHebOPhkmFC7wNaWtoBhFuV4AkEuJ0J%2B1pT0tLkvFVZaNzfhs%2FKd3%2BA9YsImlO4XK4vpCo%2FelHQi%2F9gkFg07xxnuXLt21unCIpDV%2BbbRxb7FC6nWYTsMFF8%2B1LUg4JFjVt3vqbuhHmDKbgQ4e%2BRGizRiO8ky05LQGMdL2IKLSNar0kNG7lHJMaXr5mLdG3nykgj6vB%2FKVijd1ARWkFEf3yiUw1v%2FWaQivVUpIDdSNrrKbjO5NPnxz6qTTGgYg03HgPhDrCFyYZTi3XQw3HXCva39mpLNFtz8AiEhxAJHpWX13gCTAwgm9YTvMeiqetdNQv6IU0hH0G%2BZManTqDLPjyrOse7WiiwOJCG%2BJ0pZYULhN8NILulmYYvmVcV2MjAfA39sGKqGdjpiPo86fecg65UPyXDIAOyOkCx5NQsLeD4gGVjTVDwOHWkbbBW0GeNjDkcSOn2Nq4cEssP54t9D749A7M1AIOBl0Fi0sSO5v3P7LCBrM6ZwFY6kp2FX6AcbGUdybnfChHPyu6WlRZ2Fwv9YM0RMI7kISRgR8HpQSJJOyTfXj%2F6gQKuihPtiUtlCQVPohUgzfezTg8o1b3n9pNZeco1QucaoXe40Fa5JYhqdTspFmxGtW9h5ezLFZs3j%2FN46f%2BS2rjYNC2JySXrnSAFhvAkz9a5L3pza8eYKHNoPrvBRESpxYPJdKVUxBE39nJ1chrAFpy4MMkf0qKgYALctGg1DQI1kIymyeS2AJNT4X240d3IFQb%2F0jQbaHJ2YRK8A%2Bls6WMhWmpCXYG5jqapGs5%2FeOJErxi2%2F2KWVHiPellTgh%2FfNl%2F2KYPKb7DUcAg%2BmCOPQFCiU9Mq%2FWLcU1xxC8aLePFZZlE%2BPCLzf7ey46INWRw2kcXySR9FDgByXzfxiNKwDFbUSMMhALPFSedyjEVM5442GZ4hTrsAEvZxIieSHGSgkwFh%2FnFNdrrFD4tBH4Il7fW6ur4J8Xaz7RW9jgtuPEXQsYk7gcMs2neu3zJwTyUerHKSh1iTBkj2YJh1SSOZL5pLuQbFFAvyO4k1Hxg2h99MTC6cTUkbONQIAnEfGsGkNFWRbuRyyaEZInM5pij73EA9rPIUfU4XoqQpHT9THZkW%2BoKFLvpyvTBMM69tN1Ydwv1LIEhHsC%2BueVG%2Bw%2BkyCPsvV3erRikcscHjZCkccx6VrBkBRusTDDd8847GA7p2Ucy0y0HdSRN6YIBciYa4vuXcAZbQAuSEmzw%2BH%2FAuOx%2BaH%2BtBL88H57D0MsqyiZxhOEQkF%2F8DR1d2hSPMj%2FsNOa5rxcUnBgH8ictv2J%2Bcb4BA4v3MCShdZ2vtK30vAwkobnEWh7rsSyhmos3WC93Gn9C4nnAd%2FPjMMtQfyDNZsOPd6XcAsnBE%2FmRHtHEyJMzJfZFLE9OvQa0i9kUmToJ0ZxknTgdl%2FXPV8xoh0K7wNHHsnBdvFH3sv52lU7UFteseLG%2FVanIvcwycVA7%2BBE1Ulyb20BvwUWZcMTKhaCcmY3ROpvonVMV4N7yBXTL7IDtHzQ4CCcqF66LjF3xUqgErKzolLyCG6Kb7irP%2FMVTCCwGRxfrPGpMMGvPLgJ881PHMNMIO09T5ig7AzZTX%2F5PLlwnJLDAPfuHynSGhV4tPqR3gJ4kg4c06c%2FF1AcjGytKm2Yb5jwMotF7vro4YDLWlnMIpmPg36NgAZsGA0W1spfLSue4xxat0Gdwd0lqDBOgIaMANykwwDKejt5YaNtJYIkrSgu0KjIg0pznY0SCd1qlC6R19g97UrWDoYJGlrvCE05J%2F5wkjpkre727p5PTRX5FGrSBIfJqhJE%2FIS876PaHFkx9pGTH3oaY3jJRvLX9Iy3Edoar7cFvJqyUlOhAEiOSAyYgVEGkzHdug%2BoRHIEOXAExMiTSKU9A6nmRC8mp8iYhwWdP2U%2F5EkFAdPrZw03YA3gSyNUtMZeh7dDCu8pF5x0VORCTgKp07ehy7NZqKTpIC4UJJ89lnboyAfy5OyXzXtuDRbtAFjZRSyGFTpFrXwkpjSLIQIG3N0Vj4BtzK3wdlkBJrO18MNsgseR4BysJilI0wI6ZahLhBFA0XBmV8d4LUzEcNVb0xbLjLTETYN8OEVqNxkt10W614dd1FlFFVTIgB7%2FBQQp1sWlNolpIu4ekxUTBV7NmxOFKEBmmN%2BnA7pvF78%2FRII5ZHA09OAiE%2F66MF6HQ%2BqVEJCHxwymukkNvzqHEh52dULPbVasfQMgTDyBZzx4007YiKdBuUauQOt27Gmy8ISclPmEUCIcuLbkb1mzQSqIa3iE0PJh7UMYQbkpe%2BhXjTJKdldyt2mVPwywoODGJtBV1lJTgMsuSQBlDMwhEKIfrvsxGQjHPCEfNfMAY2oxvyKcKPUbQySkKG6tj9AQyEW3Q5rpaDJ5Sns9ScLKeizPRbvWYAw4bXkrZdmB7CQopCH8NAmqbuciZChHN8lVGaDbCnmddnqO1PQ4ieMYfcSiBE5zzMz%2BJV%2F4eyzrzTEShvqSGzgWimkNxLvUj86iAwcZuIkqdB0VaIB7wncLRmzHkiUQpPBIXbDDLHBlq7vp9xwuC9AiNkIptAYlG7Biyuk8ILdynuUM1cHWJgeB%2BK3wBP%2FineogxkvBNNQ4AkW0hvpBOQGFfeptF2YTR75MexYDUy7Q%2F9uocGsx41O4IZhViw%2F2FvAEuGO5g2kyXBUijAggWM08bRhXg5ijgMwDJy40QeY%2FcQpUDZiIzmvskQpO5G1zyGZA8WByjIQU4jRoFJt56behxtHUUE%2Fom7Rj2psYXGmq3llVOCgGYKNMo4pzwntITtapDqjvQtqpjaJwjHmDzSVGLxMt12gEXAdLi%2FcaHSM3FPRGRf7dB7YC%2BcD2ho6oL2zGDCkjlf%2FDFoQVl8GS%2F56wur3rdV6ggtzZW60MRB3g%2BU1W8o8cvqIpMkctiGVMzXUFI7FacFLrgtdz4mTEr4aRAaQ2AFQaNeG7GX0yOJgMRYFziXdJf24kg%2FgBQIZMG%2FYcPEllRTVNoDYR6oSJ8wQNLuihfw81UpiKPm714bZX1KYjcXJdfclCUOOpvTxr9AAJevTY4HK%2FG7F3mUc3GOAKqh60zM0v34v%2BELyhJZqhkaMA8UMMOU90f8RKEJFj7EqepBVwsRiLbwMo1J2zrE2UYJnsgIAscDmjPjnzI8a719Wxp757wqmSJBjXowhc46QN4RwKIxqEE6E5218OeK7RfcpGjWG1jD7qND%2B%2FGTk6M56Ig4yMsU6LUW1EWE%2BfIYycVV1thldSlbP6ltdC01y3KUfkobkt2q01YYMmxpKRvh1Z48uNKzP%2FIoRIZ%2FF6buOymSnW8gICitpJjKWBscSb9JJKaWkvEkqinAJ2kowKoqkqZftRqfRQlLtKoqvTRDi2vg%2FRrPD%2Fd3a09J8JhGZlEkOM6znTsoMCsuvTmywxTCDhw5dd0GJOHCMPbsj3QLkTE3MInsZsimDQ3HkvthT7U9VA4s6G07sID0FW4SHJmRGwCl%2BMu4xf0ezqeXD2PtPDnwMPo86sbwDV%2B9PWcgFcARUVYm3hrFQrHcgMElFGbSM2A1zUYA3baWfheJp2AINmTJLuoyYD%2FOwA4a6V0ChBN97E8YtDBerUECv0u0TlxR5yhJCXvJxgyM73Bb6pyq0jTFJDZ4p1Am1SA6sh8nADd1hAcGBMfq4d%2FUfwnmBqe0Jun1n1LzrgKuZMAnxA3NtCN7Klf4BH%2B14B7ibBmgt0TGUafVzI4uKlpF7v8NmgNjg90D6QE3tbx8AjSAC%2BOA1YJvclyPKgT27QpIEgVYpbPYGBsnyCNrGz9XUsCHkW1QAHgL2STZk12QGqmvAB0NFteERkvBIH7INDsNW9KKaAYyDMdBEMzJiWaJHZALqDxQDWRntumSDPcplyFiI1oDpT8wbwe01AHhW6%2BvAUUBoGhY3CT2tgwehdPqU%2F4Q7ZLYvhRl%2FogOvR9O2%2BwkkPKW5vCTjD2fHRYXONCoIl4Jh1bZY0ZE1O94mMGn%2FdFSWBWzQ%2FVYk%2BGezi46RgiDv3EshoTmMSlioUK6MQEN8qeyK6FRninyX8ZPeUWjjbMJChn0n%2FyJvrq5bh5UcCAcBYSafTFg7p0jDgrXo2QWLb3WpSOET%2FHh4oSadBTvyDo10IufLzxiMLAnbZ1vcUmj3w7BQuIXjEZXifwukVxrGa9j%2BDXfpi12m1RbzYLg9J2wFergEwOxFyD0%2FJstNK06ZN2XdZSGWxcJODpQHOq4iKqjqkJUmPu1VczL5xTGUfCgLEYyNBCCbMBFT%2FcUP6pE%2FmujnHsSDeWxMbhrNilS5MyYR0nJyzanWXBeVcEQrRIhQeJA6Xt4f2eQESNeLwmC10WJVHqwx8SSyrtAAjpGjidcj1E2FYN0LObUcFQhafUKTiGmHWRHGsFCB%2BHEXgrzJEB5bp0QiF8ZHh11nFX8AboTD0PS4O1LqF8XBks2MpjsQnwKHF6HgaKCVLJtcr0XjqFMRGfKv8tmmykhLRzu%2BvqQ02%2BKpJBjaLt9ye1Ab%2BBbEBhy4EVdIJDrL2naV0o4wU8YZ2Lq04FG1mWCKC%2BUwkXOoAjneU%2FxHplMQo2cXUlrVNqJYczgYlaOEczVCs%2FOCgkyvLmTmdaBJc1iBLuKwmr6qtRnhowngsDxhzKFAi02tf8bmET8BO27ovJKF1plJwm3b0JpMh38%2BxsrXXg7U74QUM8ZCIMOpXujHntKdaRtsgyEZl5MClMVMMMZkZLNxH9%2Bb8fH6%2Bb8Lev30A9TuEVj9CqAdmwAAHBPbfOBFEATAPZ2CS0OH1Pj%2F0Q7PFUcC8hDrxESWdfgFRm%2B7vvWbkEppHB4T%2F1ApWnlTIqQwjcPl0VgS1yHSmD0OdsCVST8CQVwuiew1Y%2Bg3QGFjNMzwRB2DSsAk26cmA8lp2wIU4p93AUBiUHFGOxOajAqD7Gm6NezNDjYzwLOaSXRBYcWipTSONHjUDXCY4mMI8XoVCR%2FRrs%2FJLKXgEx%2BqkmeDlFOD1%2FyTQNDClRuiUyKYCllfMiQiyFkmuTz2vLsBNyRW%2Bxz%2B5FElFxWB28VjYIGZ0Yd%2B5wIjkcoMaggxswbT0pCmckRAErbRlIlcOGdBo4djTNO8FAgQ%2BlT6vPS60BwTRSUAM3ddkEAZiwtEyArrkiDRnS7LJ%2B2hwbzd2YDQagSgACpsovmjil5wfPuXq3GuH0CyE7FK3M4FgRaFoIkaodORrPx1%2BJpI9psyNYIFuJogZa0%2F1AhOWdlHQxdAgbwacsHqPZo8u%2FngAH2GmaTdhYnBfSDbBfh8CHq6Bx5bttP2%2BRdM%2BMAaYaZ0Y%2FADkbNCZuAyAVQa2OcXOeICmDn9Q%2FeFkDeFQg5MgHEDXq%2FtVjj%2Bjtd26nhaaolWxs1ixSUgOBwrDhRIGOLyOVk2%2FBc0UxvseQCO2pQ2i%2BKrfhu%2FWeBovNb5dJxQtJRUDv2mCwYVpNl2efQM9xQHnK0JwLYt%2FU0Wf%2BphiA4uw8G91slC832pmOTCAoZXohg1fewCZqLBhkOUBofBWpMPsqg7XEXgPfAlDo2U5WXjtFdS87PIqClCK5nW6adCeXPkUiTGx0emOIDQqw1yFYGHEVx20xKjJVYe0O8iLmnQr3FA9nSIQilUKtJ4ZAdcTm7%2BExseJauyqo30hs%2B1qSW211A1SFAOUgDlCGq7eTIcMAeyZkV1SQJ4j%2Fe1Smbq4HcjqgFbLAGLyKxlMDMgZavK5NAYH19Olz3la%2FQCTiVelFnU6O%2FGCvykqS%2FwZJDhKN9gBtSOp%2F1SP5VRgJcoVj%2Bkmf2wBgv4gjrgARBWiURYx8xENV3bEVUAAWWD3dYDKAIWk5opaCFCMR5ZjJExiCAw7gYiSZ2rkyTce4eNMY3lfGn%2B8p6%2BvBckGlKEXnA6Eota69OxDO9oOsJoy28BXOR0UoXNRaJD5ceKdlWMJlOFzDdZNpc05tkMGQtqeNF2lttZqNco1VtwXgRstLSQ6tSPChgqtGV5h2DcDReIQadaNRR6AsAYKL5gSFsCJMgfsaZ7DpKh8mg8Wz8V7H%2BgDnLuMxaWEIUPevIbClgap4dqmVWSrPgVYCzAoZHIa5z2Ocx1D%2FGvDOEqMOKLrMefWIbSWHZ6jbgA8qVBhYNHpx0P%2BjAgN5TB3haSifDcApp6yymEi6Ij%2FGsEpDYUgcHATJUYDUAmC1SCkJ4cuZXSAP2DEpQsGUjQmKJfJOvlC2x%2FpChkOyLW7KEoMYc5FDC4v2FGqSoRWiLsbPCiyg1U5yiHZVm1XLkHMMZL11%2Fyxyw0UnGig3MFdZklN5FI%2FqiT65T%2BjOXOdO7XbgWurOAZR6Cv9uu1cm5LjkXX4xi6mWn5r5NjBS0gTliHhMZI2WNqSiSphEtiCAwnafS11JhseDGHYQ5%2BbqWiAYiAv6Jsf79%2FVUs4cIl%2Bn6%2BWOjcgB%2F2l5TreoAV2717JzZbQIR0W1cl%2FdEqCy5kJ3ZSIHuU0vBoHooEpiHeQWVkkkOqRX27eD1FWw4BfO9CJDdKoSogQi3hAAwsPRFrN5RbX7bqLdBJ9JYMohWrgJKHSjVl1sy2xAG0E3sNyO0oCbSGOxCNBRRXTXenYKuwAoDLfnDcQaCwehUOIDiHAu5m5hMpKeKM4sIo3vxACakIxKoH2YWF2QM84e6F5C5hJU4g8uxuFOlAYnqtwxmHyNEawLW%2FPhoawJDrGAP0JYWHgAVUByo%2FbGdiv2T2EMg8gsS14%2FrAdzlOYazFE7w4OzxeKiWdm3nSOnQRRKXSlVo8HEAbBfyJMKqoq%2BSCcTSx5NDtbFwNlh8VhjGGDu7JG5%2FTAGAvniQSSUog0pNzTim8Owc6QTuSKSTXlQqwV3eiEnklS3LeSXYPXGK2VgeZBqNcHG6tZHvA3vTINhV0ELuQdp3t1y9%2BogD8Kk%2FW7QoRN1UWPqM4%2BxdygkFDPLoTaumKReKiLWoPHOfY54m3qPx4c%2B4pgY3MRKKbljG8w4wvz8pxk3AqKsy4GMAkAtmRjRMsCxbb4Q2Ds0Ia9ci8cMT6DmsJG00XaHCIS%2Bo3F8YVVeikw13w%2BOEDaCYYhC0ZE54kA4jpjruBr5STWeqQG6M74HHL6TZ3lXrd99ZX%2B%2B7LhNatQaZosuxEf5yRA15S9gPeHskBIq3Gcw81AGb9%2FO53DYi%2F5CsQ51EmEh8Rkg4vOciClpy4d04eYsfr6fyQkBmtD%2BP8sNh6e%2BXYHJXT%2FlkXxT4KXU5F2sGxYyzfniMMQkb9OjDN2C8tRRgTyL7GwozH14PrEUZc6oz05Emne3Ts5EG7WolDmU8OB1LDG3VrpQxp%2BpT0KYV5dGtknU64JhabdqcVQbGZiAxQAnvN1u70y1AnmvOSPgLI6uB4AuDGhmAu3ATkJSw7OtS%2F2ToPjqkaq62%2F7WFG8advGlRRqxB9diP07JrXowKR9tpRa%2BjGJ91zxNTT1h8I2PcSfoUPtd7NejVoH03EUcqSBuFZPkMZhegHyo2ZAITovmm3zAIdGFWxoNNORiMRShgwdYwFzkPw5PA4a5MIIQpmq%2Bnsp3YMuXt%2FGkXxLx%2FP6%2BZJS0lFyz4MunC3eWSGE8xlCQrKvhKUPXr0hjpAN9ZK4PfEDrPMfMbGNWcHDzjA7ngMxTPnT7GMHar%2BgMQQ3NwHCv4zH4BIMYvzsdiERi6gebRmerTsVwZJTRsL8dkZgxgRxmpbgRcud%2BYlCIRpPwHShlUSwuipZnx9QCsEWziVazdDeKSYU5CF7UVPAhLer3CgJOQXl%2Fzh575R5rsrmRnKAzq4POFdgbYBuEviM4%2BLVC15ssLNFghbTtHWerS1hDt5s4qkLUha%2FqpZXhWh1C6lTQAqCNQnaDjS7UGFBC6wTu8yFnKJnExCnAs3Ok9yj5KpfZESQ4lTy5pTGTnkAUpxI%2ByjEldJfSo4y0QhG4i4IwkRFGcjWY8%2BEzgYYJUK7BXQksLxAww%2FYYWBMhJILB9e8ePEJ4OP7z%2B4%2FwOQDl64iOYDp26DaONPxpKtBxq%2FaTzRGarm3VkPYTLJKx6Z%2FMw2YbBGseJhPMwhhNswrIkyvV2BYzrvZbxLpKwcWJhYmFtVZ%2BlPEq91FzVp1HlQY1bZVLqeNR9SAUn6n0E28k%2FUuGkNpP1DBI5ch%2FEehZfjUQ9aE41NhETExoPT2gGQz0IhWJbEOvTQ4wgcXCHHFBhewYUiFHuhRSAUVmEHeCRQHQkXGFwkAgyzREJCVN7TRnTon36Zw3tPhx4EALwNdwDv%2BJ41YSP4B2CQqz0EFgARZ4ESgBHQgROwAVn9GTI%2BHYexTUevLUeta4%2FDqKrbMVS%2BYqb8hUwYCrlgKtmAq1YCrFgKrd4qpXiqZcKn1oqdWipjYKpWwVPVYqW6xUpVipKqFR3QKjagVEtAqHpxUMTitsnFaJOKx2cVhswq35RVpyiq9lFVNIKnOQVMkgqtYxVNxiqQjFS7GKlSIVIsQqPIhUWwioigFQ%2B%2BKkN8VHr49HDw9Ebo9EDo9DTo9Crg9BDg9%2FWx7gWx7YWwlobYrOGxWPNisAaAHEyALpkAVDIAeWAArsABVXACYuAD5cAF6wAKFQAQqgAbVAAsoAAlQAUaYAfkwAvogBWQACOgAD9AAHSAAKT4GUdMiOvFngBTwCn2AZ7Dv6B6k%2F90B8%2ByRnkV144AIBoAMTQATGgAjNAA4YABgwABZgB%2FmQCwyAVlwCguASlwCEuAQFwB4uAMlwBYuAJlQAUVAAhUD2KgdpUDaJgaRMDFJgX5MC1JgWJEAokQCWRAHxEAWkQBMRADpEAMkQAYROAEecC484DRpwBDTnwNOdw05tjTmiNOYwtswhYFwLA7BYG4LA2BYGOLAwRYFuLAsxYFQJAohIEyJAMwkAwiQC0JAJgkAeiQBkJAFokAPCQA0JABwcD4Dgc4cDdDgaYcDIDgYgUC6CgWgUClCgUYUAVBQBOFAEYMALgwAgDA9QYAdIn8AZzeBB2L5EcWrenUT1KXienEsuJJ7x5U8XlTjc1NVzUyXFTGb1LlpUtWlTDIjqwE4LsagowoCi2gJLKAkpoBgJQNpAIhNqaEoneI6kiiqQ6Go%2Fn6j0cS%2Ba2gEU8gIHJ%2BBwfgZX4GL%2BBd%2FgW34FZ%2BBS%2FgUH4FN6BTegTvoEv6BJegRnYEF2A79gOvYDl2BdEjCkqkGtwXp0LNToIskOTXzh%2FF062yJ7AAAAEDAWAAABWhJ%2BKPEIJgBFxMVP7w2QJBGHASQnOBKXKFIdUK4igKA9IEaYJg%29%3Bsrc%3Aurl%28data%3Aapplication%2Fvnd%2Ems%2Dfontobject%3Bbase64%2Cn04AAEFNAAACAAIABAAAAAAABQAAAAAAAAABAJABAAAEAExQAAAAAAAAAAIAAAAAAAAAAAEAAAAAAAAAJxJ%2FLAAAAAAAAAAAAAAAAAAAAAAAACgARwBMAFkAUABIAEkAQwBPAE4AUwAgAEgAYQBsAGYAbABpAG4AZwBzAAAADgBSAGUAZwB1AGwAYQByAAAAeABWAGUAcgBzAGkAbwBuACAAMQAuADAAMAA5ADsAUABTACAAMAAwADEALgAwADAAOQA7AGgAbwB0AGMAbwBuAHYAIAAxAC4AMAAuADcAMAA7AG0AYQBrAGUAbwB0AGYALgBsAGkAYgAyAC4ANQAuADUAOAAzADIAOQAAADgARwBMAFkAUABIAEkAQwBPAE4AUwAgAEgAYQBsAGYAbABpAG4AZwBzACAAUgBlAGcAdQBsAGEAcgAAAAAAQlNHUAAAAAAAAAAAAAAAAAAAAAADAKncAE0TAE0ZAEbuFM3pjM%2FSEdmjKHUbyow8ATBE40IvWA3vTu8LiABDQ%2BpexwUMcm1SMnNryctQSiI1K5ZnbOlXKmnVV5YvRe6RnNMFNCOs1KNVpn6yZhCJkRtVRNzEufeIq7HgSrcx4S8h%2Fv4vnrrKc6oCNxmSk2uKlZQHBii6iKFoH0746ThvkO1kJHlxjrkxs%2BLWORaDQBEtiYJIR5IB9Bi1UyL4Rmr0BNigNkMzlKQmnofBHviqVzUxwdMb3NdCn69hy%2BpRYVKGVS%2F1tnsqv4LL7wCCPZZAZPT4aCShHjHJVNuXbmMrY5LeQaGnvAkXlVrJgKRAUdFjrWEah9XebPeQMj7KS7DIBAFt8ycgC5PLGUOHSE3ErGZCiViNLL5ZARfywnCoZaKQCu6NuFX42AEeKtKUGnr%2FCm2Cy8tpFhBPMW5Fxi4Qm4TkDWh4IWFDClhU2hRWosUWqcKLlgyXB%2BlSHaWaHiWlBAR8SeSgSPCQxdVQgzUixWKSTrIQEbU94viDctkvX%2BVSjJuUmV8L4CXShI11esnp0pjWNZIyxKHS4wVQ2ime1P4RnhvGw0aDN1OLAXGERsB7buFpFGGBAre4QEQR0HOIO5oYH305G%2BKspT%2FFupEGGafCCwxSe6ZUa%2B073rXHnNdVXE6eWvibUS27XtRzkH838mYLMBmYysZTM0EM3A1fbpCBYFccN1B%2FEnCYu%2FTgCGmr7bMh8GfYL%2BBfcLvB0gRagC09w9elfldaIy%2FhNCBLRgBgtCC7jAF63wLSMAfbfAlEggYU0bUA7ACCJmTDpEmJtI78w4%2FBO7dN7JR7J7ZvbYaUbaILSQsRBiF3HGk5fEg6p9unwLvn98r%2BvnsV%2B372uf1xBLq4qU%2F45fTuqaAP%2BpssmCCCTF0mhEow8ZXZOS8D7Q85JsxZ%2BAzok7B7O%2Ff6J8AzYBySZQB%2FQHYUSA%2BEeQhEWiS6AIQzgcsDiER4MjgMBAWDV4AgQ3g1eBgIdweCQmCjJEMkJ%2BPKRWyFHHmg1Wi%2F6xzUgA0LREoKJChwnQa9B%2B5RQZRB3IlBlkAnxyQNaANwHMowzlYSMCBgnbpzvqpl0iTJNCQidDI9ZrSYNIRBhHtUa5YHMHxyGEik9hDE0AKj72AbTCaxtHPUaKZdAZSnQTyjGqGLsmBStCejApUhg4uBMU6mATujEl%2BKdDPbI6Ag4vLr%2BhjY6lbjBeoLKnZl0UZgRX8gTySOeynZVz1wOq7e1hFGYIq%2BMhrGxDLak0PrwYzSXtcuyhXEhwOYofiW%2BEcI%2Fjw8P6IY6ed%2BetAbuqKp5QIapT77LnAe505lMuqL79a0ut4rWexzFttsOsLDy7zvtQzcq3U1qabe7tB0wHWVXji%2BzDbo8x8HyIRUbXnwUcklFv51fvTymiV%2BMXLSmGH9d9%2BaXpD5X6lao41anWGig7IwIdnoBY2ht%2FpO9mClLo4NdXHAsefqWUKlXJkbqPOFhMoR4aiA1BXqhRNbB2Xwi%2B7u%2FjpAoOpKJ0UX24EsrzMfHXViakCNcKjBxuQX8BO0ZqjJ3xXzf%2B61t2VXOSgJ8xu65QKgtN6FibPmPYsXbJRHHqbgATcSZxBqGiDiU4NNNsYBsKD0MIP%2FOfKnlk%2FLkaid%2FO2NbKeuQrwOB2Gq3YHyr6ALgzym5wIBnsdC1ZkoBFZSQXChZvlesPqvK2c5oHHT3Q65jYpNxnQcGF0EHbvYqoFw60WNlXIHQF2HQB7zD6lWjZ9rVqUKBXUT6hrkZOle0RFYII0V5ZYGl1JAP0Ud1fZZMvSomBzJ710j4Me8mjQDwEre5Uv2wQfk1ifDwb5ksuJQQ3xt423lbuQjvoIQByQrNDh1JxGFkOdlJvu%2FgFtuW0wR4cgd%2BZKesSV7QkNE2kw6AV4hoIuC02LGmTomyf8PiO6CZzOTLTPQ%2BHW06H%2Btx%2BbQ8LmDYg1pTFrp2oJXgkZTyeRJZM0C8aE2LpFrNVDuhARsN543%2FFV6klQ6Tv1OoZGXLv0igKrl%2FCmJxRmX7JJbJ998VSIPQRyDBICzl4JJlYHbdql30NvYcOuZ7a10uWRrgoieOdgIm4rlq6vNOQBuqESLbXG5lzdJGHw2m0sDYmODXbYGTfSTGRKpssTO95fothJCjUGQgEL4yKoGAF%2F0SrpUDNn8CBgBcSDQByAeNkCXp4S4Ro2Xh4OeaGRgR66PVOsU8bc6TR5%2FxTcn4IVMLOkXSWiXxkZQCbvKfmoAvQaKjO3EDKwkwqHChCDEM5loQRPd5ACBki1TjF772oaQhQbQ5C0lcWXPFOzrfsDGUXGrpxasbG4iab6eByaQkQfm0VFlP0ZsDkvvqCL6QXMUwCjdMx1ZOyKhTJ7a1GWAdOUcJ8RSejxNVyGs31OKMyRyBVoZFjqIkmKlLQ5eHMeEL4MkUf23cQ%2F1SgRCJ1dk4UdBT7OoyuNgLs0oCd8RnrEIb6QdMxT2QjD4zMrJkfgx5aDMcA4orsTtKCqWb%2FVeyceqa5OGSmB28YwH4rFbkQaLoUN8OQQYnD3w2eXpI4ScQfbCUZiJ4yMOIKLyyTc7BQ4uXUw6Ee6%2FxM%2B4Y67ngNBknxIPwuppgIhFcwJyr6EIj%2BLzNj%2FmfR2vhhRlx0BILZoAYruF0caWQ7YxO66UmeguDREAFHYuC7HJviRgVO6ruJH59h%2FC%2FPkgSle8xNzZJULLWq9JMDTE2fjGE146a1Us6PZDGYle6ldWRqn%2FpdpgHKNGrGIdkRK%2BKPETT9nKT6kLyDI8xd9A1FgWmXWRAIHwZ37WyZHOVyCadJEmMVz0MadMjDrPho%2BEIochkVC2xgGiwwsQ6DMv2P7UXqT4x7CdcYGId2BJQQa85EQKmCmwcRejQ9Bm4oATENFPkxPXILHpMPUyWTI5rjNOsIlmEeMbcOCEqInpXACYQ9DDxmFo9vcmsDblcMtg4tqBerNngkIKaFJmrQAPnq1dEzsMXcwjcHdfdCibcAxxA%2Bq%2Fj9m3LM%2FO7WJka4tSidVCjsvo2lQ%2F2ewyoYyXwAYyr2PlRoR5MpgVmSUIrM3PQxXPbgjBOaDQFIyFMJvx3Pc5RSYj12ySVF9fwFPQu2e2KWVoL9q3Ayv3IzpGHUdvdPdrNUdicjsTQ2ISy7QU3DrEytIjvbzJnAkmANXjAFERA0MUoPF3%2F5KFmW14bBNOhwircYgMqoDpUMcDtCmBE82QM2YtdjVLB4kBuKho%2FbcwQdeboqfQartuU3CsCf%2BcXkgYAqp%2F0Ee3RorAZt0AvvOCSI4JICIlGlsV0bsSid%2FNIEALAAzb6HAgyWHBps6xAOwkJIGcB82CxRQq4sJf3FzA70A%2BTRqcqjEMETCoez3mkPcpnoALs0ugJY8kQwrC%2BJE5ik3w9rzrvDRjAQnqgEVvdGrNwlanR0SOKWzxOJOvLJhcd8Cl4AshACUkv9czdMkJCVQSQhp6kp7StAlpVRpK0t0SW6LHeBJnE2QchB5Ccu8kxRghZXGIgZIiSj7gEKMJDClcnX6hgoqJMwiQDigIXg3ioFLCgDgjPtYHYpsF5EiA4kcnN18MZtOrY866dEQAb0FB34OGKHGZQjwW%2FWDHA60cYFaI%2FPjpzquUqdaYGcIq%2BmLez3WLFFCtNBN2QJcrlcoELgiPku5R5dSlJFaCEqEZle1AQzAKC%2B1SotMcBNyQUFuRHRF6OlimSBgjZeTBCwLyc6A%2BP%2FoFRchXTz5ADknYJHxzrJ5pGuIKRQISU6WyKTBBjD8WozmVYWIsto1AS5rxzKlvJu4E%2FvwOiKxRtCWsDM%2BeTHUrmwrCK5BIfMzGkD%2B0Fk5LzBs0jMYXktNDblB06LMNJ09U8pzSLmo14MS0OMjcdrZ31pyQqxJJpRImlSvfYAK8inkYU52QY2FPEVsjoWewpwhRp5yAuNpkqhdb7ku9Seefl2D0B8SMTFD90xi4CSOwwZy9IKkpMtI3FmFUg3%2FkFutpQGNc3pCR7gvC4sgwbupDu3DyEN%2BW6YGLNM21jpB49irxy9BSlHrVDlnihGKHwPrbVFtc%2Bh1rVQKZduxIyojccZIIcOCmhEnC7UkY68WXKQgLi2JCDQkQWJRQuk60hZp0D3rtCTINSeY9Ej2kIKYfGxwOs4j9qMM7fYZiipzgcf7TamnehqdhsiMiCawXnz4xAbyCkLAx5EGbo3Ax1u3dUIKnTxIaxwQTHehPl3V491H0%2BbC5zgpGz7Io%2BmjdhKlPJ01EeMpM7UsRJMi1nGjmJg35i6bQBAAxjO%2FENJubU2mg3ONySEoWklCwdABETcs7ck3jgiuU9pcKKpbgn%2B3YlzV1FzIkB6pmEDOSSyDfPPlQskznctFji0kpgZjW5RZe6x9kYT4KJcXg0bNiCyif%2BpZACCyRMmYsfiKmN9tSO65F0R2OO6ytlEhY5Sj6uRKfFxw0ijJaAx%2Fk3QgnAFSq27%2F2i4GEBA%2BUvTJKK%2F9eISNvG46Em5RZfjTYLdeD8kdXHyrwId%2FDQZUaMCY4gGbke2C8vfjgV%2FY9kkRQOJIn%2FxM9INZSpiBnqX0Q9GlQPpPKAyO5y%2BW5NMPSRdBCUlmuxl40ZfMCnf2Cp044uI9WLFtCi4YVxKjuRCOBWIb4XbIsGdbo4qtMQnNOQz4XDSui7W%2FN6l54qOynCqD3DpWQ%2BmpD7C40D8BZEWGJX3tlAaZBMj1yjvDYKwCJBa201u6nBKE5UE%2B7QSEhCwrXfbRZylAaAkplhBWX50dumrElePyNMRYUrC99UmcSSNgImhFhDI4BXjMtiqkgizUGCrZ8iwFxU6fQ8GEHCFdLewwxYWxgScAYMdMLmcZR6b7rZl95eQVDGVoUKcRMM1ixXQtXNkBETZkVVPg8LoSrdetHzkuM7DjZRHP02tCxA1fmkXKF3VzfN1pc1cv%2F8lbTIkkYpqKM9VOhp65ktYk%2BQ46myFWBapDfyWUCnsnI00QTBQmuFjMZTcd0V2NQ768Fhpby04k2IzNR1wKabuGJqYWwSly6ocMFGTeeI%2BejsWDYgEvr66QgqdcIbFYDNgsm0x9UHY6SCd5%2B7tpsLpKdvhahIDyYmEJQCqMqtCF6UlrE5GXRmbu%2Bvtm3BFSxI6ND6UxIE7GsGMgWqghXxSnaRJuGFveTcK5ZVSPJyjUxe1dKgI6kNF7EZhIZs8y8FVqwEfbM0Xk2ltORVDKZZM40SD3qQoQe0orJEKwPfZwm3YPqwixhUMOndis6MhbmfvLBKjC8sKKIZKbJk8L11oNkCQzCgvjhyyEiQSuJcgCQSG4Mocfgc0Hkwcjal1UNgP0CBPikYqBIk9tONv4kLtBswH07vUCjEaHiFGlLf8MgXKzSgjp2HolRRccAOh0ILHz9qlGgIFkwAnzHJRjWFhlA7ROwINyB5HFj59PRZHFor6voq7l23EPNRwdWhgawqbivLSjRA4htEYUFkjESu67icTg5S0aW1sOkCiIysfJ9UnIWevOOLGpepcBxy1wEhd2WI3AZg7sr9WBmHWyasxMcvY%2FiOmsLtHSWNUWEGk9hScMPShasUA1AcHOtRZlqMeQ0OzYS9vQvYUjOLrzP07BUAFikcJNMi7gIxEw4pL1G54TcmmmoAQ5s7TGWErJZ2Io4yQ0ljRYhL8H5e62oDtLF8aDpnIvZ5R3GWJyAugdiiJW9hQAVTsnCBHhwu7rkBlBX6r3b7ejEY0k5GGeyKv66v%2B6dg7mcJTrWHbtMywbedYqCQ0FPwoytmSWsL8WTtChZCKKzEF7vP6De4x2BJkkniMgSdWhbeBSLtJZR9CTHetK1xb34AYIJ37OegYIoPVbXgJ%2FqDQK%2BbfCtxQRVKQu77WzOoM6SGL7MaZwCGJVk46aImai9fmam%2BWpHG%2B0BtQPWUgZ7RIAlPq6lkECUhZQ2gqWkMYKcYMYaIc4gYCDFHYa2d1nzp3%2BJ1eCBay8IYZ0wQRKGAqvCuZ%2FUgbQPyllosq%2BXtfKIZOzmeJqRazpmmoP%2F76YfkjzV2NlXTDSBYB04SVlNQsFTbGPk1t%2FI4Jktu0XSgifO2ozFOiwd%2F0SssJDn0dn4xqk4GDTTKX73%2FwQyBLdqgJ%2BWx6AQaba3BA9CKEzjtQYIfAsiYamapq80LAamYjinlKXUkxdpIDk0puXUEYzSalfRibAeDAKpNiqQ0FTwoxuGYzRnisyTotdVTclis1LHRQCy%2FqqL8oUaQzWRxilq5Mi0IJGtMY02cGLD69vGjkj3p6pGePKI8bkBv5evq8SjjyU04vJR2cQXQwSJyoinDsUJHCQ50jrFTT7yRdbdYQMB3MYCb6uBzJ9ewhXYPAIZSXfeEQBZZ3GPN3Nbhh%2FwkvAJLXnQMdi5NYYZ5GHE400GS5rXkOZSQsdZgIbzRnF9ueLnsfQ47wHAsirITnTlkCcuWWIUhJSbpM3wWhXNHvt2xUsKKMpdBSbJnBMcihkoDqAd1Zml%2FR4yrzow1Q2A5G%2Bkzo%2FRhRxQS2lCSDRV8LlYLBOOoo1bF4jwJAwKMK1tWLHlu9i0j4Ig8qVm6wE1DxXwAwQwsaBWUg2pOOol2dHxyt6npwJEdLDDVYyRc2D0HbcbLUJQj8gPevQBUBOUHXPrsAPBERICpnYESeu2OHotpXQxRGlCCtLdIsu23MhZVEoJg8Qumj%2FUMMc34IBqTKLDTp76WzL%2FdMjCxK7MjhiGjeYAC%2Fkj%2FjY%2FRde7hpSM1xChrog6yZ7OWTuD56xBJnGFE%2BpT2ElSyCnJcwVzCjkqeNLfMEJqKW0G7OFIp0G%2B9mh50I9o8k1tpCY0xYqFNIALgIfc2me4n1bmJnRZ89oepgLPT0NTMLNZsvSCZAc3TXaNB07vail36%2FdBySis4m9%2FDR8izaLJW6bWCkVgm5T%2Bius3ZXq4xI%2BGnbveLbdRwF2mNtsrE0JjYc1AXknCOrLSu7Te%2Fr4dPYMCl5qtiHNTn%2BTPbh1jCBHH%2BdMJNhwNgs3nT%2BOhQoQ0vYif56BMG6WowAcHR3DjQolxLzyVekHj00PBAaW7IIAF1EF%2BuRIWyXjQMAs2chdpaKPNaB%2BkSezYt0%2BCA04sOg5vx8Fr7Ofa9sUv87h7SLAUFSzbetCCZ9pmyLt6l6%2FTzoA1%2FZBG9bIUVHLAbi%2FkdBFgYGyGwRQGBpkqCEg2ah9UD6EedEcEL3j4y0BQQCiExEnocA3SZboh%2Bepgd3YsOkHskZwPuQ5OoyA0fTA5AXrHcUOQF%2BzkJHIA7PwCDk1gGVmGUZSSoPhNf%2BTklauz98QofOlCIQ%2FtCD4dosHYPqtPCXB3agggQQIqQJsSkB%2Bqn0rkQ1toJjON%2FOtCIB9RYv3PqRA4C4U68ZMlZn6BdgEvi2ziU%2BTQ6NIw3ej%2BAtDwMGEZk7e2IjxUWKdAxyaw9OCwSmeADTPPleyk6UhGDNXQb%2B%2BW6Uk4q6F7%2Frg6WVTo82IoCxSIsFDrav4EPHphD3u4hR53WKVvYZUwNCCeM4PMBWzK%2BEfIthZOkuAwPo5C5jgoZgn6dUdvx5rIDmd58cXXdKNfw3l%2BwM2UjgrDJeQHhbD7HW2QDoZMCujgIUkk5Fg8VCsdyjOtnGRx8wgKRPZN5dR0zPUyfGZFVihbFRniXZFOZGKPnEQzU3AnD1KfR6weHW2XS6KbPJxUkOTZsAB9vTVp3Le1F8q5l%2BDMcLiIq78jxAImD2pGFw0VHfRatScGlK6SMu8leTmhUSMy8Uhdd6xBiH3Gdman4tjQGLboJfqz6fL2WKHTmrfsKZRYX6BTDjDldKMosaSTLdQS7oDisJNqAUhw1PfTlnacCO8vl8706Km1FROgLDmudzxg%2BEWTiArtHgLsRrAXYWdB0NmToNCJdKm0KWycZQqb%2BMw76Qy29iQ5up%2FX7oyw8QZ75kP5F6iJAJz6KCmqxz8fEa%2FxnsMYcIO%2FvEkGRuMckhr4rIeLrKaXnmIzlNLxbFspOphkcnJdnz%2FChp%2FVlpj2P7jJQmQRwGnltkTV5dbF9fE3%2FfxoSqTROgq9wFUlbuYzYcasE0ouzBo%2BdDCDzxKAfhbAZYxQiHrLzV2iVexnDX%2FQnT1fsT%2Fxuhu1ui5qIytgbGmRoQkeQooO8eJNNZsf0iALur8QxZFH0nCMnjerYQqG1pIfjyVZWxhVRznmmfLG00BcBWJE6hzQWRyFknuJnXuk8A5FRDCulwrWASSNoBtR%2BCtGdkPwYN2o7DOw%2FVGlCZPusRBFXODQdUM5zeHDIVuAJBLqbO%2Ff9Qua%2BpDqEPk230Sob9lEZ8BHiCorjVghuI0lI4JDgHGRDD%2FprQ84B1pVGkIpVUAHCG%2Biz3Bn3qm2AVrYcYWhock4jso5%2BJ7HfHVj4WMIQdGctq3psBCVVzupQOEioBGA2Bk%2BUILT7%2BVoX5mdxxA5fS42gISQVi%2FHTzrgMxu0fY6hE1ocUwwbsbWcezrY2n6S8%2F6cxXkOH4prpmPuFoikTzY7T85C4T2XYlbxLglSv2uLCgFv8Quk%2FwdesUdWPeHYIH0R729JIisN9Apdd4eB10aqwXrPt%2BSu9mA8k8n1sjMwnfsfF2j3jMUzXepSHmZ%2FBfqXvzgUNQQWOXO8YEuFBh4QTYCkOAPxywpYu1VxiDyJmKVcmJPGWk%2Fgc3Pov02StyYDahwmzw3E1gYC9wkupyWfDqDSUMpCTH5e5N8B%2F%2FlHiMuIkTNw4USHrJU67bjXGqNav6PBuQSoqTxc8avHoGmvqNtXzIaoyMIQIiiUHIM64cXieouplhNYln7qgc4wBVAYR104kO%2BCvKqsg4yIUlFNThVUAKZxZt1XA34h3TCUUiXVkZ0w8Hh2R0Z5L0b4LZvPd%2Fp1gi%2F07h8qfwHrByuSxglc9cI4QIg2oqvC%2Fqm0i7tjPLTgDhoWTAKDO2ONW5oe%2B%2FeKB9vZB8K6C25yCZ9RFVMnb6NRdRjyVK57CHHSkJBfnM2%2Fj4ODUwRkqrtBBCrDsDpt8jhZdXoy%2F1BCqw3sSGhgGGy0a5Jw6BP%2FTExoCmNFYjZl248A0osgPyGEmRA%2BfAsqPVaNAfytu0vuQJ7rk3J4kTDTR2AlCHJ5cls26opZM4w3jMULh2YXKpcqGBtuleAlOZnaZGbD6DHzMd6i2oFeJ8z9XYmalg1Szd%2FocZDc1C7Y6vcALJz2lYnTXiWEr2wawtoR4g3jvWUU2Ngjd1cewtFzEvM1NiHZPeLlIXFbBPawxNgMwwAlyNSuGF3zizVeOoC9bag1qRAQKQE%2FEZBWC2J8mnXAN2aTBboZ7HewnObE8CwROudZHmUM5oZ%2FUgd%2FJZQK8lvAm43uDRAbyW8gZ%2BZGq0EVerVGUKUSm%2FIdn8AQHdR4m7bue88WBwft9mSCeMOt1ncBwziOmJYI2ZR7ewNMPiCugmSsE4EyQ%2BQATJG6qORMGd4snEzc6B4shPIo4G1T7PgSm8PY5eUkPdF8JZ0VBtadbHXoJgnEhZQaODPj2gpODKJY5Yp4DOsLBFxWbvXN755KWylJm%2BoOd4zEL9Hpubuy2gyyfxh8oEfFutnYWdfB8PdESLWYvSqbElP9qo3u6KTmkhoacDauMNNjj0oy40DFV7Ql0aZj77xfGl7TJNHnIwgqOkenruYYNo6h724%2BzUQ7%2BvkCpZB%2BpGA562hYQiDxHVWOq0oDQl%2FQsoiY%2BcuI7iWq%2FZIBtHcXJ7kks%2Bh2fCNUPA82BzjnqktNts%2BRLdk1VSu%2BtqEn7QZCCsvEqk6FkfiOYkrsw092J8jsfIuEKypNjLxrKA9kiA19mxBD2suxQKCzwXGws7kEJvlhUiV9tArLIdZW0IORcxEzdzKmjtFhsjKy%2F44XYXdI5noQoRcvjZ1RMPACRqYg2V1%2BOwOepcOknRLLFdYgTkT5UApt%2FJhLM3jeFYprZV%2BZow2g8fP%2BU68hkKFWJj2yBbKqsrp25xkZX1DAjUw52IMYWaOhab8Kp05VrdNftqwRrymWF4OQSjbdfzmRZirK8FMJELEgER2PHjEAN9pGfLhCUiTJFbd5LBkOBMaxLr%2FA1SY9dXFz4RjzoU9ExfJCmx%2FI9FKEGT3n2cmzl2X42L3Jh%2BAbQq6sA%2BSs1kitoa4TAYgKHaoybHUDJ51oETdeI%2F9ThSmjWGkyLi5QAGWhL0BG1UsTyRGRJOldKBrYJeB8ljLJHfATWTEQBXBDnQexOHTB%2BUn44zExFE4vLytcu5NwpWrUxO%2F0ZICUGM7hGABXym0V6ZvDST0E370St9MIWQOTWngeoQHUTdCJUP04spMBMS8LSker9cReVQkULFDIZDFPrhTzBl6sed9wcZQTbL%2BBDqMyaN3RJPh%2Fanbx%2BIv%2BqgQdAa3M9Z5JmvYlh4qop%2BHo1F1W5gbOE9YKLgAnWytXElU4G8GtW47lhgFE6gaSs%2Bgs37sFvi0PPVvA5dnCBgILTwoKd%2F%2BDoL9F6inlM7H4rOTzD79KJgKlZO%2FZgt22UsKhrAaXU5ZcLrAglTVKJEmNJvORGN1vqrcfSMizfpsgbIe9zno%2BgBoKVXgIL%2FVI8dB1O5o%2FR3Suez%2FgD7M781ShjKpIIORM%2FnxG%2BjjhhgPwsn2IoXsPGPqYHXA63zJ07M2GPEykQwJBYLK808qYxuIew4frk52nhCsnCYmXiR6CuapvE1IwRB4%2FQftDbEn%2BAucIr1oxrLabRj9q4ae0%2BfXkHnteAJwXRbVkR0mctVSwEbqhJiMSZUp9DNbEDMmjX22m3ABpkrPQQTP3S1sib5pD2VRKRd%2BeNAjLYyT0hGrdjWJZy24OYXRoWQAIhGBZRxuBFMjjZQhpgrWo8SiFYbojcHO8V5DyscJpLTHyx9Fimassyo5U6WNtquUMYgccaHY5amgR3PQzq3ToNM5ABnoB9kuxsebqmYZm0R9qxJbFXCQ1UPyFIbxoUraTJFDpCk0Wk9GaYJKz%2F6oHwEP0Q14lMtlddQsOAU9zlYdMVHiT7RQP3XCmWYDcHCGbVRHGnHuwzScA0BaSBOGkz3lM8CArjrBsyEoV6Ys4qgDK3ykQQPZ3hCRGNXQTNNXbEb6tDiTDLKOyMzRhCFT%2BmAUmiYbV3YQVqFVp9dorv%2BTsLeCykS2b5yyu8AV7IS9cxcL8z4Kfwp%2BxJyYLv1OsxQCZwTB4a8BZ%2F5EdxTBJthApqyfd9u3ifr%2FWILTqq5VqgwMT9SOxbSGWLQJUUWCVi4k9tho9nEsbUh7U6NUsLmkYFXOhZ0kmamaJLRNJzSj%2Fqn4Mso6zb6iLLBXoaZ6AqeWCjHQm2lztnejYYM2eubnpBdKVLORZhudH3JF1waBJKA9%2BW8EhMj3Kzf0L4vi4k6RoHh3Z5YgmSZmk6ns4fjScjAoL8GoOECgqgYEBYUGFVO4FUv4%2FYtowhEmTs0vrvlD%2FCrisnoBNDAcUi%2FteY7OctFlmARQzjOItrrlKuPO6E2Ox93L4O%2F4DcgV%2FdZ7qR3VBwVQxP1GCieA4RIpweYJ5FoYrHxqRBdJjnqbsikA2Ictbb8vE1GYIo9dacK0REgDX4smy6GAkxlH1yCGGsk%2BtgiDhNKuKu3yNrMdxafmKTF632F8Vx4BNK57GvlFisrkjN9WDAtjsWA0ENT2e2nETUb%2Fn7qwhvGnrHuf5bX6Vh%2Fn3xffU3PeHdR%2BFA92i6ufT3AlyAREoNDh6chiMWTvjKjHDeRhOa9YkOQRq1vQXEMppAQVwHCuIcV2g5rBn6GmZZpTR7vnSD6ZmhdSl176gqKTXu5E%2BYbfL0adwNtHP7dT7t7b46DVZIkzaRJOM%2BS6KcrzYVg%2BT3wSRFRQashjfU18NutrKa%2F7PXbtuJvpIjbgPeqd%2BpjmRw6YKpnANFSQcpzTZgpSNJ6J7uiagAbir%2F8tNXJ%2FOsOnRh6iuIexxrmkIneAgz8QoLmiaJ8sLQrELVK2yn3wOHp57BAZJhDZjTBzyoRAuuZ4eoxHruY1pSb7qq79cIeAdOwin4GdgMeIMHeG%2BFZWYaiUQQyC5b50zKjYw97dFjAeY2I4Bnl105Iku1y0lMA1ZHolLx19uZnRdILcXKlZGQx%2FGdEqSsMRU1BIrFqRcV1qQOOHyxOLXEGcbRtAEsuAC2V4K3p5mFJ22IDWaEkk9ttf5Izb2LkD1MnrSwztXmmD%2FQi%2FEmVEFBfiKGmftsPwVaIoZanlKndMZsIBOskFYpDOq3QUs9aSbAAtL5Dbokus2G4%2FasthNMK5UQKCOhU97oaOYNGsTah%2BjfCKsZnTRn5TbhFX8ghg8CBYt%2FBjeYYYUrtUZ5jVij%2Fop7V5SsbA4mYTOwZ46hqdpbB6Qvq3AS2HHNkC15pTDIcDNGsMPXaBidXYPHc6PJAkRh29Vx8KcgX46LoUQBhRM%2B3SW6Opll%2FwgxxsPgKJKzr5QCmwkUxNbeg6Wj34SUnEzOemSuvS2OetRCO8Tyy%2BQbSKVJcqkia%2BGvDefFwMOmgnD7h81TUtMn%2BmRpyJJ349HhAnoWFTejhpYTL9G8N2nVg1qkXBeoS9Nw2fB27t7trm7d%2FQK7Cr4uoCeOQ7%2F8JfKT77KiDzLImESHw%2F0wf73QeHu74hxv7uihi4fTX%2BXEwAyQG3264dwv17aJ5N335Vt9sdrAXhPOAv8JFvzqyYXwfx8WYJaef1gMl98JRFyl5Mv5Uo%2FoVH5ww5OzLFsiTPDns7fS6EURSSWd%2F92BxMYQ8sBaH%2Bj%2BwthQPdVgDGpTfi%2BJQIWMD8xKqULliRH01rTeyF8x8q%2FGBEEEBrAJMPf25UQwi0b8tmqRXY7kIvNkzrkvRWLnxoGYEJsz8u4oOyMp8cHyaybb1HdMCaLApUE%2B%2F7xLIZGP6H9xuSEXp1zLIdjk5nBaMuV%2FyTDRRP8Y2ww5RO6d2D94o%2B6ucWIqUAvgHIHXhZsmDhjVLczmZ3ca0Cb3PpKwt2UtHVQ0BgFJsqqTsnzZPlKahRUkEu4qmkJt%2Bkqdae76ViWe3STan69yaF9%2BfESD2lcQshLHWVu4ovItXxO69bqC5p1nZLvI8NdQB9s9UNaJGlQ5mG947ipdDA0eTIw%2FA1zEdjWquIsQXXGIVEH0thC5M%2BW9pZe7IhAVnPJkYCCXN5a32HjN6nsvokEqRS44tGIs7s2LVTvcrHAF%2BRVmI8L4HUYk4x%2B67AxSMJKqCg8zrGOgvK9kNMdDrNiUtSWuHFpC8%2Fp5qIQrEo%2FH%2B1l%2F0cAwQ2nKmpWxKcMIuHY44Y6DlkpO48tRuUGBWT0FyHwSKO72Ud%2BtJUfdaZ4CWNijzZtlRa8%2BCkmO%2FEwHYfPZFU%2FhzjFWH7vnzHRMo%2BaF9u8qHSAiEkA2HjoNQPEwHsDKOt6hOoK3Ce%2F%2B%2F9boMWDa44I6FrQhdgS7OnNaSzwxWKZMcyHi6LN4WC6sSj0qm2PSOGBTvDs%2FGWJS6SwEN%2FULwpb4LQo9fYjUfSXRwZkynUazlSpvX9e%2BG2zor8l%2BYaMxSEomDdLHGcD6YVQPegTaA74H8%2BV4WvJkFUrjMLGLlvSZQWvi8%2FQA7yzQ8GPno%2F%2F5SJHRP%2FOqKObPCo81s%2F%2B6WgLqykYpGAgQZhVDEBPXWgU%2FWzFZjKUhSFInufPRiMAUULC6T11yL45ZrRoB4DzOyJShKXaAJIBS9wzLYIoCEcJKQW8GVCx4fihqJ6mshBUXSw3wWVj3grrHQlGNGhIDNNzsxQ3M%2BGWn6ASobIWC%2BLbYOC6UpahVO13Zs2zOzZC8z7FmA05JhUGyBsF4tsG0drcggIFzgg%2Fkpf3%2BCnAXKiMgIE8Jk%2FMhpkc8DUJEUzDSnWlQFme3d0sHZDrg7LavtsEX3cHwjCYA17pMTfx8Ajw9hHscN67hyo%2BRJQ4458RmPywXykkVcW688oVUrQhahpPRvTWPnuI0B%2BSkQu7dCyvLRyFYlC1LG1gRCIvn3rwQeINzZQC2KXq31FaR9UmVV2QeGVqBHjmE%2BVMd3b1fhCynD0pQNhCG6%2FWCDbKPyE7NRQzL3BzQAJ0g09aUzcQA6mUp9iZFK6Sbp%2FYbHjo%2B%2B7%2FWj8S4YNa%2BZdqAw1hDrKWFXv9%2BzaXpf8ZTDSbiqsxnwN%2FCzK5tPkOr4tRh2kY3Bn9JtalbIOI4b3F7F1vPQMfoDcdxMS8CW9m%2FNCW%2FHILTUVWQIPiD0j1A6bo8vsv6P1hCESl2abrSJWDrq5sSzUpwoxaCU9FtJyYH4QFMxDBpkkBR6kn0LMPO%2B5EJ7Z6bCiRoPedRZ%2FP0SSdii7ZnPAtVwwHUidcdyspwncz5uq6vvm4IEDbJVLUFCn%2FLvIHfooUBTkFO130FC7CmmcrKdgDJcid9mvVzsDSibOoXtIf9k6ABle3PmIxejodc4aob0QKS432srrCMndbfD454q52V01G4q913mC5HOsTzWF4h2No1av1VbcUgWAqyoZl%2B11PoFYnNv2HwAODeNRkHj%2B8SF1fcvVBu6MrehHAZK1Gm69ICcTKizykHgGFx7QdowTVAsYEF2tVc0Z6wLryz2FI1sc5By2znJAAmINndoJiB4sfPdPrTC8RnkW7KRCwxC6YvXg5ahMlQuMpoCSXjOlBy0Kij%2BbsCYPbGp8BdCBiLmLSAkEQRaieWo1SYvZIKJGj9Ur%2FeWHjiB7SOVdqMAVmpBvfRiebsFjger7DC%2B8kRFGtNrTrnnGD2GAJb8rQCWkUPYHhwXsjNBSkE6lGWUj5QNhK0DMNM2l%2BkXRZ0KLZaGsFSIdQz%2FHXDxf3%2FTE30%2BDgBKWGWdxElyLccJfEpjsnszECNoDGZpdwdRgCixeg9L4EPhH%2BRptvRMVRaahu4cySjS3P5wxAUCPkmn%2BrhyASpmiTaiDeggaIxYBmtLZDDhiWIJaBgzfCsAGUF1Q1SFZYyXDt9skCaxJsxK2Ms65dmdp5WAZyxik%2FzbrTQk5KmgxCg%2Ff45L0jywebOWUYFJQAJia7XzCV0x89rpp%2Ff3AVWhSPyTanqmik2SkD8A3Ml4NhIGLAjBXtPShwKYfi2eXtrDuKLk4QlSyTw1ftXgwqA2jUuopDl%2B5tfUWZNwBpEPXghzbBggYCw%2Fdhy0ntds2yeHCDKkF%2FYxQjNIL%2FF%2F37jLPHCKBO9ibwYCmuxImIo0ijV2Wbg3kSN2psoe8IsABv3RNFaF9uMyCtCYtqcD%2BqNOhwMlfARQUdJ2tUX%2BMNJqOwIciWalZsmEjt07tfa8ma4cji9sqz%2BQ9hWfmMoKEbIHPOQORbhQRHIsrTYlnVTNvcq1imqmmPDdVDkJgRcTgB8Sb6epCQVmFZe%2BjGDiNJQLWnfx%2BdrTKYjm0G8yH0ZAGMWzEJhUEQ4Maimgf%2Fbkvo8PLVBsZl152y5S8%2BHRDfZIMCbYZ1WDp4yrdchOJw8k6R%2B%2F2pHmydK4NIK2PHdFPHtoLmHxRDwLFb7eB%2BM4zNZcB9NrAgjVyzLM7xyYSY13ykWfIEEd2n5%2FiYp3ZdrCf7fL%2Ben%2BsIJu2W7E30MrAgZBD1rAAbZHPgeAMtKCg3NpSpYQUDWJu9bT3V7tOKv%2BNRiJc8JAKqqgCA%2FPNRBR7ChpiEulyQApMK1AyqcWnpSOmYh6yLiWkGJ2mklCSPIqN7UypWj3dGi5MvsHQ87MrB4VFgypJaFriaHivwcHIpmyi5LhNqtem4q0n8awM19Qk8BOS0EsqGscuuydYsIGsbT5GHnERUiMpKJl4ON7qjB4fEqlGN%2FhCky89232UQCiaeWpDYCJINXjT6xl4Gc7DxRCtgV0i1ma4RgWLsNtnEBRQFqZggCLiuyEydmFd7WlogpkCw5G1x4ft2psm3KAREwVwr1Gzl6RT7FDAqpVal34ewVm3VH4qn5mjGj%2BbYL1NgfLNeXDwtmYSpwzbruDKpTjOdgiIHDVQSb5%2FzBgSMbHLkxWWgghIh9QTFSDILixVwg0Eg1puooBiHAt7DzwJ7m8i8%2Fi%2BjHvKf0QDnnHVkVTIqMvIQImOrzCJwhSR7qYB5gSwL6aWL9hERHCZc4G2%2BJrpgHNB8eCCmcIWIQ6rSdyPCyftXkDlErUkHafHRlkOIjxGbAktz75bnh50dU7YHk%2BMz7wwstg6RFZb%2BTZuSOx1qqP5C66c0mptQmzIC2dlpte7vZrauAMm%2F7RfBYkGtXWGiaWTtwvAQiq2oD4YixPLXE2khB2FRaNRDTk%2B9sZ6K74Ia9VntCpN4BhJGJMT4Z5c5FhSepRCRWmBXqx%2BwhVZC4me4saDs2iNqXMuCl6iAZflH8fscC1sTsy4PHeC%2BXYuqMBMUun5YezKbRKmEPwuK%2BCLzijPEQgfhahQswBBLfg%2FGBgBiI4QwAqzJkkyYAWtjzSg2ILgMAgqxYfwERRo3zruBL9WOryUArSD8sQOcD7fvIODJxKFS615KFPsb68USBEPPj1orNzFY2xoTtNBVTyzBhPbhFH0PI5AtlJBl2aSgNPYzxYLw7XTDBDinmVoENwiGzmngrMo8OmnRP0Z0i0Zrln9DDFcnmOoBZjABaQIbPOJYZGqX%2BRCMlDDbElcjaROLDoualmUIQ88Kekk3iM4OQrADcxi3rJguS4MOIBIgKgXrjd1WkbCdqxJk%2F4efRIFsavZA7KvvJQqp3Iid5Z0NFc5aiMRzGN3vrpBzaMy4JYde3wr96PjN90AYOIbyp6T4zj8LoE66OGcX1Ef4Z3KoWLAUF4BTg7ug%2FAbkG5UNQXAMkQezujSHeir2uTThgd3gpyzDrbnEdDRH2W7U6PeRvBX1ZFMP5RM%2BZu6UUZZD8hDPHldVWntTCNk7To8IeOW9yn2wx0gmurwqC60AOde4r3ETi5pVMSDK8wxhoGAoEX9NLWHIR33VbrbMveii2jAJlrxwytTHbWNu8Y4N8vCCyZjAX%2FpcsfwXbLze2%2BD%2Bu33OGBoJyAAL3jn3RuEcdp5If8O%2Ba4NKWvxOTyDltG0IWoHhwVGe7dKkCWFT%2B%2Btm%2BhaBCikRUUMrMhYKZJKYoVuv%2FbsJzO8DwfVIInQq3g3BYypiz8baogH3r3GwqCwFtZnz4xMjAVOYnyOi5HWbFA8n0qz1OjSpHWFzpQOpvkNETZBGpxN8ybhtqV%2FDMUxd9uFZmBfKXMCn%2FSqkWJyKPnT6lq%2B4zBZni6fYRByJn6OK%2BOgPBGRAJluwGSk4wxjOOzyce%2FPKODwRlsgrVkdcsEiYrqYdXo0Er2GXi2GQZd0tNJT6c9pK1EEJG1zgDJBoTVuCXGAU8BKTvCO%2FcEQ1Wjk3Zzuy90JX4m3O5IlxVFhYkSUwuQB2up7jhvkm%2BbddRQu5F9s0XftGEJ9JSuSk%2BZachCbdU45fEqbugzTIUokwoAKvpUQF%2FCvLbWW5BNQFqFkJg2f30E%2F48StNe5QwBg8zz3YAJ82FZoXBxXSv4QDooDo79NixyglO9AembuBcx5Re3CwOKTHebOPhkmFC7wNaWtoBhFuV4AkEuJ0J%2B1pT0tLkvFVZaNzfhs%2FKd3%2BA9YsImlO4XK4vpCo%2FelHQi%2F9gkFg07xxnuXLt21unCIpDV%2BbbRxb7FC6nWYTsMFF8%2B1LUg4JFjVt3vqbuhHmDKbgQ4e%2BRGizRiO8ky05LQGMdL2IKLSNar0kNG7lHJMaXr5mLdG3nykgj6vB%2FKVijd1ARWkFEf3yiUw1v%2FWaQivVUpIDdSNrrKbjO5NPnxz6qTTGgYg03HgPhDrCFyYZTi3XQw3HXCva39mpLNFtz8AiEhxAJHpWX13gCTAwgm9YTvMeiqetdNQv6IU0hH0G%2BZManTqDLPjyrOse7WiiwOJCG%2BJ0pZYULhN8NILulmYYvmVcV2MjAfA39sGKqGdjpiPo86fecg65UPyXDIAOyOkCx5NQsLeD4gGVjTVDwOHWkbbBW0GeNjDkcSOn2Nq4cEssP54t9D749A7M1AIOBl0Fi0sSO5v3P7LCBrM6ZwFY6kp2FX6AcbGUdybnfChHPyu6WlRZ2Fwv9YM0RMI7kISRgR8HpQSJJOyTfXj%2F6gQKuihPtiUtlCQVPohUgzfezTg8o1b3n9pNZeco1QucaoXe40Fa5JYhqdTspFmxGtW9h5ezLFZs3j%2FN46f%2BS2rjYNC2JySXrnSAFhvAkz9a5L3pza8eYKHNoPrvBRESpxYPJdKVUxBE39nJ1chrAFpy4MMkf0qKgYALctGg1DQI1kIymyeS2AJNT4X240d3IFQb%2F0jQbaHJ2YRK8A%2Bls6WMhWmpCXYG5jqapGs5%2FeOJErxi2%2F2KWVHiPellTgh%2FfNl%2F2KYPKb7DUcAg%2BmCOPQFCiU9Mq%2FWLcU1xxC8aLePFZZlE%2BPCLzf7ey46INWRw2kcXySR9FDgByXzfxiNKwDFbUSMMhALPFSedyjEVM5442GZ4hTrsAEvZxIieSHGSgkwFh%2FnFNdrrFD4tBH4Il7fW6ur4J8Xaz7RW9jgtuPEXQsYk7gcMs2neu3zJwTyUerHKSh1iTBkj2YJh1SSOZL5pLuQbFFAvyO4k1Hxg2h99MTC6cTUkbONQIAnEfGsGkNFWRbuRyyaEZInM5pij73EA9rPIUfU4XoqQpHT9THZkW%2BoKFLvpyvTBMM69tN1Ydwv1LIEhHsC%2BueVG%2Bw%2BkyCPsvV3erRikcscHjZCkccx6VrBkBRusTDDd8847GA7p2Ucy0y0HdSRN6YIBciYa4vuXcAZbQAuSEmzw%2BH%2FAuOx%2BaH%2BtBL88H57D0MsqyiZxhOEQkF%2F8DR1d2hSPMj%2FsNOa5rxcUnBgH8ictv2J%2Bcb4BA4v3MCShdZ2vtK30vAwkobnEWh7rsSyhmos3WC93Gn9C4nnAd%2FPjMMtQfyDNZsOPd6XcAsnBE%2FmRHtHEyJMzJfZFLE9OvQa0i9kUmToJ0ZxknTgdl%2FXPV8xoh0K7wNHHsnBdvFH3sv52lU7UFteseLG%2FVanIvcwycVA7%2BBE1Ulyb20BvwUWZcMTKhaCcmY3ROpvonVMV4N7yBXTL7IDtHzQ4CCcqF66LjF3xUqgErKzolLyCG6Kb7irP%2FMVTCCwGRxfrPGpMMGvPLgJ881PHMNMIO09T5ig7AzZTX%2F5PLlwnJLDAPfuHynSGhV4tPqR3gJ4kg4c06c%2FF1AcjGytKm2Yb5jwMotF7vro4YDLWlnMIpmPg36NgAZsGA0W1spfLSue4xxat0Gdwd0lqDBOgIaMANykwwDKejt5YaNtJYIkrSgu0KjIg0pznY0SCd1qlC6R19g97UrWDoYJGlrvCE05J%2F5wkjpkre727p5PTRX5FGrSBIfJqhJE%2FIS876PaHFkx9pGTH3oaY3jJRvLX9Iy3Edoar7cFvJqyUlOhAEiOSAyYgVEGkzHdug%2BoRHIEOXAExMiTSKU9A6nmRC8mp8iYhwWdP2U%2F5EkFAdPrZw03YA3gSyNUtMZeh7dDCu8pF5x0VORCTgKp07ehy7NZqKTpIC4UJJ89lnboyAfy5OyXzXtuDRbtAFjZRSyGFTpFrXwkpjSLIQIG3N0Vj4BtzK3wdlkBJrO18MNsgseR4BysJilI0wI6ZahLhBFA0XBmV8d4LUzEcNVb0xbLjLTETYN8OEVqNxkt10W614dd1FlFFVTIgB7%2FBQQp1sWlNolpIu4ekxUTBV7NmxOFKEBmmN%2BnA7pvF78%2FRII5ZHA09OAiE%2F66MF6HQ%2BqVEJCHxwymukkNvzqHEh52dULPbVasfQMgTDyBZzx4007YiKdBuUauQOt27Gmy8ISclPmEUCIcuLbkb1mzQSqIa3iE0PJh7UMYQbkpe%2BhXjTJKdldyt2mVPwywoODGJtBV1lJTgMsuSQBlDMwhEKIfrvsxGQjHPCEfNfMAY2oxvyKcKPUbQySkKG6tj9AQyEW3Q5rpaDJ5Sns9ScLKeizPRbvWYAw4bXkrZdmB7CQopCH8NAmqbuciZChHN8lVGaDbCnmddnqO1PQ4ieMYfcSiBE5zzMz%2BJV%2F4eyzrzTEShvqSGzgWimkNxLvUj86iAwcZuIkqdB0VaIB7wncLRmzHkiUQpPBIXbDDLHBlq7vp9xwuC9AiNkIptAYlG7Biyuk8ILdynuUM1cHWJgeB%2BK3wBP%2FineogxkvBNNQ4AkW0hvpBOQGFfeptF2YTR75MexYDUy7Q%2F9uocGsx41O4IZhViw%2F2FvAEuGO5g2kyXBUijAggWM08bRhXg5ijgMwDJy40QeY%2FcQpUDZiIzmvskQpO5G1zyGZA8WByjIQU4jRoFJt56behxtHUUE%2Fom7Rj2psYXGmq3llVOCgGYKNMo4pzwntITtapDqjvQtqpjaJwjHmDzSVGLxMt12gEXAdLi%2FcaHSM3FPRGRf7dB7YC%2BcD2ho6oL2zGDCkjlf%2FDFoQVl8GS%2F56wur3rdV6ggtzZW60MRB3g%2BU1W8o8cvqIpMkctiGVMzXUFI7FacFLrgtdz4mTEr4aRAaQ2AFQaNeG7GX0yOJgMRYFziXdJf24kg%2FgBQIZMG%2FYcPEllRTVNoDYR6oSJ8wQNLuihfw81UpiKPm714bZX1KYjcXJdfclCUOOpvTxr9AAJevTY4HK%2FG7F3mUc3GOAKqh60zM0v34v%2BELyhJZqhkaMA8UMMOU90f8RKEJFj7EqepBVwsRiLbwMo1J2zrE2UYJnsgIAscDmjPjnzI8a719Wxp757wqmSJBjXowhc46QN4RwKIxqEE6E5218OeK7RfcpGjWG1jD7qND%2B%2FGTk6M56Ig4yMsU6LUW1EWE%2BfIYycVV1thldSlbP6ltdC01y3KUfkobkt2q01YYMmxpKRvh1Z48uNKzP%2FIoRIZ%2FF6buOymSnW8gICitpJjKWBscSb9JJKaWkvEkqinAJ2kowKoqkqZftRqfRQlLtKoqvTRDi2vg%2FRrPD%2Fd3a09J8JhGZlEkOM6znTsoMCsuvTmywxTCDhw5dd0GJOHCMPbsj3QLkTE3MInsZsimDQ3HkvthT7U9VA4s6G07sID0FW4SHJmRGwCl%2BMu4xf0ezqeXD2PtPDnwMPo86sbwDV%2B9PWcgFcARUVYm3hrFQrHcgMElFGbSM2A1zUYA3baWfheJp2AINmTJLuoyYD%2FOwA4a6V0ChBN97E8YtDBerUECv0u0TlxR5yhJCXvJxgyM73Bb6pyq0jTFJDZ4p1Am1SA6sh8nADd1hAcGBMfq4d%2FUfwnmBqe0Jun1n1LzrgKuZMAnxA3NtCN7Klf4BH%2B14B7ibBmgt0TGUafVzI4uKlpF7v8NmgNjg90D6QE3tbx8AjSAC%2BOA1YJvclyPKgT27QpIEgVYpbPYGBsnyCNrGz9XUsCHkW1QAHgL2STZk12QGqmvAB0NFteERkvBIH7INDsNW9KKaAYyDMdBEMzJiWaJHZALqDxQDWRntumSDPcplyFiI1oDpT8wbwe01AHhW6%2BvAUUBoGhY3CT2tgwehdPqU%2F4Q7ZLYvhRl%2FogOvR9O2%2BwkkPKW5vCTjD2fHRYXONCoIl4Jh1bZY0ZE1O94mMGn%2FdFSWBWzQ%2FVYk%2BGezi46RgiDv3EshoTmMSlioUK6MQEN8qeyK6FRninyX8ZPeUWjjbMJChn0n%2FyJvrq5bh5UcCAcBYSafTFg7p0jDgrXo2QWLb3WpSOET%2FHh4oSadBTvyDo10IufLzxiMLAnbZ1vcUmj3w7BQuIXjEZXifwukVxrGa9j%2BDXfpi12m1RbzYLg9J2wFergEwOxFyD0%2FJstNK06ZN2XdZSGWxcJODpQHOq4iKqjqkJUmPu1VczL5xTGUfCgLEYyNBCCbMBFT%2FcUP6pE%2FmujnHsSDeWxMbhrNilS5MyYR0nJyzanWXBeVcEQrRIhQeJA6Xt4f2eQESNeLwmC10WJVHqwx8SSyrtAAjpGjidcj1E2FYN0LObUcFQhafUKTiGmHWRHGsFCB%2BHEXgrzJEB5bp0QiF8ZHh11nFX8AboTD0PS4O1LqF8XBks2MpjsQnwKHF6HgaKCVLJtcr0XjqFMRGfKv8tmmykhLRzu%2BvqQ02%2BKpJBjaLt9ye1Ab%2BBbEBhy4EVdIJDrL2naV0o4wU8YZ2Lq04FG1mWCKC%2BUwkXOoAjneU%2FxHplMQo2cXUlrVNqJYczgYlaOEczVCs%2FOCgkyvLmTmdaBJc1iBLuKwmr6qtRnhowngsDxhzKFAi02tf8bmET8BO27ovJKF1plJwm3b0JpMh38%2BxsrXXg7U74QUM8ZCIMOpXujHntKdaRtsgyEZl5MClMVMMMZkZLNxH9%2Bb8fH6%2Bb8Lev30A9TuEVj9CqAdmwAAHBPbfOBFEATAPZ2CS0OH1Pj%2F0Q7PFUcC8hDrxESWdfgFRm%2B7vvWbkEppHB4T%2F1ApWnlTIqQwjcPl0VgS1yHSmD0OdsCVST8CQVwuiew1Y%2Bg3QGFjNMzwRB2DSsAk26cmA8lp2wIU4p93AUBiUHFGOxOajAqD7Gm6NezNDjYzwLOaSXRBYcWipTSONHjUDXCY4mMI8XoVCR%2FRrs%2FJLKXgEx%2BqkmeDlFOD1%2FyTQNDClRuiUyKYCllfMiQiyFkmuTz2vLsBNyRW%2Bxz%2B5FElFxWB28VjYIGZ0Yd%2B5wIjkcoMaggxswbT0pCmckRAErbRlIlcOGdBo4djTNO8FAgQ%2BlT6vPS60BwTRSUAM3ddkEAZiwtEyArrkiDRnS7LJ%2B2hwbzd2YDQagSgACpsovmjil5wfPuXq3GuH0CyE7FK3M4FgRaFoIkaodORrPx1%2BJpI9psyNYIFuJogZa0%2F1AhOWdlHQxdAgbwacsHqPZo8u%2FngAH2GmaTdhYnBfSDbBfh8CHq6Bx5bttP2%2BRdM%2BMAaYaZ0Y%2FADkbNCZuAyAVQa2OcXOeICmDn9Q%2FeFkDeFQg5MgHEDXq%2FtVjj%2Bjtd26nhaaolWxs1ixSUgOBwrDhRIGOLyOVk2%2FBc0UxvseQCO2pQ2i%2BKrfhu%2FWeBovNb5dJxQtJRUDv2mCwYVpNl2efQM9xQHnK0JwLYt%2FU0Wf%2BphiA4uw8G91slC832pmOTCAoZXohg1fewCZqLBhkOUBofBWpMPsqg7XEXgPfAlDo2U5WXjtFdS87PIqClCK5nW6adCeXPkUiTGx0emOIDQqw1yFYGHEVx20xKjJVYe0O8iLmnQr3FA9nSIQilUKtJ4ZAdcTm7%2BExseJauyqo30hs%2B1qSW211A1SFAOUgDlCGq7eTIcMAeyZkV1SQJ4j%2Fe1Smbq4HcjqgFbLAGLyKxlMDMgZavK5NAYH19Olz3la%2FQCTiVelFnU6O%2FGCvykqS%2FwZJDhKN9gBtSOp%2F1SP5VRgJcoVj%2Bkmf2wBgv4gjrgARBWiURYx8xENV3bEVUAAWWD3dYDKAIWk5opaCFCMR5ZjJExiCAw7gYiSZ2rkyTce4eNMY3lfGn%2B8p6%2BvBckGlKEXnA6Eota69OxDO9oOsJoy28BXOR0UoXNRaJD5ceKdlWMJlOFzDdZNpc05tkMGQtqeNF2lttZqNco1VtwXgRstLSQ6tSPChgqtGV5h2DcDReIQadaNRR6AsAYKL5gSFsCJMgfsaZ7DpKh8mg8Wz8V7H%2BgDnLuMxaWEIUPevIbClgap4dqmVWSrPgVYCzAoZHIa5z2Ocx1D%2FGvDOEqMOKLrMefWIbSWHZ6jbgA8qVBhYNHpx0P%2BjAgN5TB3haSifDcApp6yymEi6Ij%2FGsEpDYUgcHATJUYDUAmC1SCkJ4cuZXSAP2DEpQsGUjQmKJfJOvlC2x%2FpChkOyLW7KEoMYc5FDC4v2FGqSoRWiLsbPCiyg1U5yiHZVm1XLkHMMZL11%2Fyxyw0UnGig3MFdZklN5FI%2FqiT65T%2BjOXOdO7XbgWurOAZR6Cv9uu1cm5LjkXX4xi6mWn5r5NjBS0gTliHhMZI2WNqSiSphEtiCAwnafS11JhseDGHYQ5%2BbqWiAYiAv6Jsf79%2FVUs4cIl%2Bn6%2BWOjcgB%2F2l5TreoAV2717JzZbQIR0W1cl%2FdEqCy5kJ3ZSIHuU0vBoHooEpiHeQWVkkkOqRX27eD1FWw4BfO9CJDdKoSogQi3hAAwsPRFrN5RbX7bqLdBJ9JYMohWrgJKHSjVl1sy2xAG0E3sNyO0oCbSGOxCNBRRXTXenYKuwAoDLfnDcQaCwehUOIDiHAu5m5hMpKeKM4sIo3vxACakIxKoH2YWF2QM84e6F5C5hJU4g8uxuFOlAYnqtwxmHyNEawLW%2FPhoawJDrGAP0JYWHgAVUByo%2FbGdiv2T2EMg8gsS14%2FrAdzlOYazFE7w4OzxeKiWdm3nSOnQRRKXSlVo8HEAbBfyJMKqoq%2BSCcTSx5NDtbFwNlh8VhjGGDu7JG5%2FTAGAvniQSSUog0pNzTim8Owc6QTuSKSTXlQqwV3eiEnklS3LeSXYPXGK2VgeZBqNcHG6tZHvA3vTINhV0ELuQdp3t1y9%2BogD8Kk%2FW7QoRN1UWPqM4%2BxdygkFDPLoTaumKReKiLWoPHOfY54m3qPx4c%2B4pgY3MRKKbljG8w4wvz8pxk3AqKsy4GMAkAtmRjRMsCxbb4Q2Ds0Ia9ci8cMT6DmsJG00XaHCIS%2Bo3F8YVVeikw13w%2BOEDaCYYhC0ZE54kA4jpjruBr5STWeqQG6M74HHL6TZ3lXrd99ZX%2B%2B7LhNatQaZosuxEf5yRA15S9gPeHskBIq3Gcw81AGb9%2FO53DYi%2F5CsQ51EmEh8Rkg4vOciClpy4d04eYsfr6fyQkBmtD%2BP8sNh6e%2BXYHJXT%2FlkXxT4KXU5F2sGxYyzfniMMQkb9OjDN2C8tRRgTyL7GwozH14PrEUZc6oz05Emne3Ts5EG7WolDmU8OB1LDG3VrpQxp%2BpT0KYV5dGtknU64JhabdqcVQbGZiAxQAnvN1u70y1AnmvOSPgLI6uB4AuDGhmAu3ATkJSw7OtS%2F2ToPjqkaq62%2F7WFG8advGlRRqxB9diP07JrXowKR9tpRa%2BjGJ91zxNTT1h8I2PcSfoUPtd7NejVoH03EUcqSBuFZPkMZhegHyo2ZAITovmm3zAIdGFWxoNNORiMRShgwdYwFzkPw5PA4a5MIIQpmq%2Bnsp3YMuXt%2FGkXxLx%2FP6%2BZJS0lFyz4MunC3eWSGE8xlCQrKvhKUPXr0hjpAN9ZK4PfEDrPMfMbGNWcHDzjA7ngMxTPnT7GMHar%2BgMQQ3NwHCv4zH4BIMYvzsdiERi6gebRmerTsVwZJTRsL8dkZgxgRxmpbgRcud%2BYlCIRpPwHShlUSwuipZnx9QCsEWziVazdDeKSYU5CF7UVPAhLer3CgJOQXl%2Fzh575R5rsrmRnKAzq4POFdgbYBuEviM4%2BLVC15ssLNFghbTtHWerS1hDt5s4qkLUha%2FqpZXhWh1C6lTQAqCNQnaDjS7UGFBC6wTu8yFnKJnExCnAs3Ok9yj5KpfZESQ4lTy5pTGTnkAUpxI%2ByjEldJfSo4y0QhG4i4IwkRFGcjWY8%2BEzgYYJUK7BXQksLxAww%2FYYWBMhJILB9e8ePEJ4OP7z%2B4%2FwOQDl64iOYDp26DaONPxpKtBxq%2FaTzRGarm3VkPYTLJKx6Z%2FMw2YbBGseJhPMwhhNswrIkyvV2BYzrvZbxLpKwcWJhYmFtVZ%2BlPEq91FzVp1HlQY1bZVLqeNR9SAUn6n0E28k%2FUuGkNpP1DBI5ch%2FEehZfjUQ9aE41NhETExoPT2gGQz0IhWJbEOvTQ4wgcXCHHFBhewYUiFHuhRSAUVmEHeCRQHQkXGFwkAgyzREJCVN7TRnTon36Zw3tPhx4EALwNdwDv%2BJ41YSP4B2CQqz0EFgARZ4ESgBHQgROwAVn9GTI%2BHYexTUevLUeta4%2FDqKrbMVS%2BYqb8hUwYCrlgKtmAq1YCrFgKrd4qpXiqZcKn1oqdWipjYKpWwVPVYqW6xUpVipKqFR3QKjagVEtAqHpxUMTitsnFaJOKx2cVhswq35RVpyiq9lFVNIKnOQVMkgqtYxVNxiqQjFS7GKlSIVIsQqPIhUWwioigFQ%2B%2BKkN8VHr49HDw9Ebo9EDo9DTo9Crg9BDg9%2FWx7gWx7YWwlobYrOGxWPNisAaAHEyALpkAVDIAeWAArsABVXACYuAD5cAF6wAKFQAQqgAbVAAsoAAlQAUaYAfkwAvogBWQACOgAD9AAHSAAKT4GUdMiOvFngBTwCn2AZ7Dv6B6k%2F90B8%2ByRnkV144AIBoAMTQATGgAjNAA4YABgwABZgB%2FmQCwyAVlwCguASlwCEuAQFwB4uAMlwBYuAJlQAUVAAhUD2KgdpUDaJgaRMDFJgX5MC1JgWJEAokQCWRAHxEAWkQBMRADpEAMkQAYROAEecC484DRpwBDTnwNOdw05tjTmiNOYwtswhYFwLA7BYG4LA2BYGOLAwRYFuLAsxYFQJAohIEyJAMwkAwiQC0JAJgkAeiQBkJAFokAPCQA0JABwcD4Dgc4cDdDgaYcDIDgYgUC6CgWgUClCgUYUAVBQBOFAEYMALgwAgDA9QYAdIn8AZzeBB2L5EcWrenUT1KXienEsuJJ7x5U8XlTjc1NVzUyXFTGb1LlpUtWlTDIjqwE4LsagowoCi2gJLKAkpoBgJQNpAIhNqaEoneI6kiiqQ6Go%2Fn6j0cS%2Ba2gEU8gIHJ%2BBwfgZX4GL%2BBd%2FgW34FZ%2BBS%2FgUH4FN6BTegTvoEv6BJegRnYEF2A79gOvYDl2BdEjCkqkGtwXp0LNToIskOTXzh%2FF062yJ7AAAAEDAWAAABWhJ%2BKPEIJgBFxMVP7w2QJBGHASQnOBKXKFIdUK4igKA9IEaYJg%29%20format%28%27embedded%2Dopentype%27%29%2Curl%28data%3Aapplication%2Fx%2Dfont%2Dwoff%3Bbase64%2Cd09GRgABAAAAAFuAAA8AAAAAsVwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABWAAAABwAAAAcbSqX3EdERUYAAAF0AAAAHwAAACABRAAET1MvMgAAAZQAAABFAAAAYGe5a4ljbWFwAAAB3AAAAsAAAAZy2q3jgWN2dCAAAAScAAAABAAAAAQAKAL4Z2FzcAAABKAAAAAIAAAACP%2F%2FAANnbHlmAAAEqAAATRcAAJSkfV3Cb2hlYWQAAFHAAAAANAAAADYFTS%2FYaGhlYQAAUfQAAAAcAAAAJApEBBFobXR4AABSEAAAAU8AAAN00scgYGxvY2EAAFNgAAACJwAAAjBv%2B5XObWF4cAAAVYgAAAAgAAAAIAFqANhuYW1lAABVqAAAAZ4AAAOisyygm3Bvc3QAAFdIAAAELQAACtG6o%2BU1d2ViZgAAW3gAAAAGAAAABsMYVFAAAAABAAAAAMw9os8AAAAA0HaBdQAAAADQdnOXeNpjYGRgYOADYgkGEGBiYGRgZBQDkixgHgMABUgASgB42mNgZulmnMDAysDCzMN0gYGBIQpCMy5hMGLaAeQDpRCACYkd6h3ux%2BDAoPD%2FP%2FOB%2FwJAdSIM1UBhRiQlCgyMADGWCwwAAAB42u2UP2hTQRzHf5ekaVPExv6JjW3fvTQ0sa3QLA5xylBLgyBx0gzSWEUaXbIoBBQyCQGHLqXUqYNdtIIgIg5FHJxEtwqtpbnfaV1E1KFaSvX5vVwGEbW6OPngk8%2FvvXfv7pt3v4SImojIDw6BViKxRgIVBaZwVdSv%2BxvXA%2BIuzqcog2cOkkvDNE8Lbqs74k64i%2B5Sf3u8Z2AnIRLbyVCyTflVSEXVoEqrrMqrgiqqsqqqWQ5xlAc5zWOc5TwXucxVnuE5HdQhHdFRHdNJndZZndeFLc%2FzsKJLQ%2FWV6BcrCdWkwspVKZVROaw0qUqqoqZZcJhdTnGGxznHBS5xhad5VhNWCuturBTXKZ3RObuS98pb9c57k6ql9rp2v1as5deb1r6s9q1GV2IrHSt73T631424YXzjgPwqt%2BRn%2BVG%2BlRvyirwsS%2FKCPCfPytPypDwhj8mjctRZd9acF86y89x55jxxHjkPnXstXfbt%2FpNjj%2FnwXW%2BcHa6%2FSYvZ7yEwbDYazDcIgoUGzY3h2HtqgUcs1AFPWKgTXrRQF7xkoQhRf7uF9hPFeyzUTTSwY6EoUUJY6AC8bSGMS4Ys1Au3WaiPSGGsMtkdGH2rzJgYHAaYjxIwQqtB1CnYkEZ9BM6ALOpROAfyqI%2FDBQudgidBETXuqRIooz4DV0AV9UV4GsyivkTEyMMmw1UYGdhkuAYjA5sMGMvIwCbDDRgZeAz1TXgcmDy3YeRhk%2BcOjCxsMjyAkYFNhscwMrDJ8BQ2886gXoaRhedQvyTSkDZ7uA6HLLQBI5vGntAbGHugTc53cMxC7%2BE4SKL%2BACOzNpk3YWTWJid%2BiRo5NXIKM3fBItAPW55FdJLY3FeHBDr90606JCIU9Jk%2BMs3%2FY%2F8L8jUq3y79bJ%2F0%2F%2BROoP4v9v%2F4%2Fmj%2Bi7HBXUd0%2FelU6IHfHt8Aj9EPGAAoAvgAAAAB%2F%2F8AAnjaxb0JfBvVtTA%2BdxaN1hltI1m2ZVuSJVneLVlSHCdy9oTEWchqtrBEJRAgCYEsQNhC2EsbWmpI2dqkQBoSYgKlpaQthVL0yusrpW77aEubfq%2Fly%2BujvJampSTW5Dvnzmi1E%2Bjr%2F%2F3%2BXmbu3Llz77nnbuece865DMu0MAy5jGtiOEZkOp8lTNeUwyLP%2FDH%2BrEH41ZTDHAtB5lkOowWMPiwayNiUwwTjE46AI5xwhFrINPXYn%2F7ENY0dbWHfZAiTZbL8ID%2FInAd5xz2NpIH4STpDGonHIJNE3OP1KG4ISaSNeBuITAyRLgIxoiEUhFAnmUpEiXSRSGqAQEw0kuyFUIb0k2gnGSApyBFi0il2SI5YLGb5MdFjXCey4mNHzQ7WwLGEdZiPPgYR64we8THZHAt%2BwnT84D%2Fx8YTpGPgheKH4CMEDVF9xBOIeP3EbQgGH29BGgpGkIxCMTCW9qUTA0Zsir%2BQUP1mt%2BP2KusevwIO6Bx%2FIaj8%2FOD5O0VNrZW2EsqZBWbO1skRiEKE0DdlKKaSVO5VAuRpqk8VQJAqY7ydxaK44YJvrO2EWjOoDBoFYzQbDNkON%2BUbiKoRkywMWWf1j4bEY2iIY1AeMgvmEz%2FkVo9v4FSc%2FaMZMrFbjl4zWLL0%2BY5FlyzNlEVYDudJohg8gPUP7kcB%2Fmn%2BG6cd%2B5PV4Q72dXCgocWJADBgUuDTwiXiGSyZo14HOEQ2lE6k0XDIEusexDzZOMXwt1Dutz%2BtqmxTvlskNWXXUQIbhaurum9GrePqm9Yaeabjkiqf%2BbUvzDOvb2Y1E%2BEX2DnemcTP%2FzLcuu7xjQXdAtjR0Lo5n4%2FHs%2FGtntMlysHt%2B29NXbH6se%2F%2FWbFcyu%2Br28H0MwzI30DYeYTLMXIA2EG8QlHpAsyS0EfEToR0a3utIxFPJ3kiIHCCrZ66b0e2xEmL1dM9YN%2FMwS5p01N5jMX%2FBLKt%2F1R83l0LyC29M6%2BiYxo%2FUNg%2FEF7c2WyyW5tYl8WnhWg2%2FhyySbD5UhnDyS7OcU0dnrFw%2BDfGdI7v4QfYIIzOMq9hFtY55gmvC7jZ2FK7sEdrn6IXBuucYhjsGdQ8z0yEbWkkczjjsE5hNAIZrPx2zOLZDmKNXcXtg7EMqidAEEWg%2BSJCBBNwxvxJfc%2FbZa%2BKKf%2BxoKZybnq5vaqpPTye7CiF%2BZFjxZ8%2F7Qij0hfOG%2FcowPA1rT1l4ymWnrKmxxqfErTVrpgwPlz1kC%2BOy8NMDz6c%2BIO38K%2Fx0xkPnLW8Kx6qGAoQdL%2BTD9V9rb%2B%2Fctn%2F%2Ftrxz8dUrZrD%2Fzk%2FferF0cNt1BzctmX2FZPXt%2FjnFCQNz4Ah%2FiKllGiCMs1w5Lkg0kiEwj6VTXCDKsX9rMpnvIj9pcDecXAIXMnqn2dTUbN6w0XQ9ue6FV%2FnnXCH7S3lPWGltVcLsH75ub3ab7A8M28caNrIeOr3o5Q0yFsYL80xaa0EY%2FUEczV7icUMY5pnelAkmUAXmHYjvFWFGxuqlSaow3OM%2B%2FiYY7%2Fl%2FhVELF4EjRqNR%2FbvRbOY%2BDUGzGR%2FOh3EqmE%2FugIQQguGt%2FeMYz%2F%2BL0cimjeZfQDI3phXMbMQsqH%2BCjwVz%2Fhf4idHovgVmB8gLvjbicDcC%2FNypP536E%2F9N%2FpuMibExdohBmNwyiaZdJGoigos7GpF222xrfnZhML%2F7Z%2BylaqP63Hr%2Bm7bdUkQ6%2F2cXqdfmvwixY%2Bs2ksXFeXcE%2BiX0Z%2BIow76DBNgjJ7TOdUK18iPsPflfQD%2BDPsZG2Aj9VmKMMJ4fYRrhIaxhTDR0Elh2vA6h%2FAE6xUb29mj3sjmL72petXjejPy%2Boel60M99tFduCI59N3221xe7apOvxs6aHs7vab1IqY2tv7q2xsHeHGml%2FcV06u%2F8S%2FxTjJ%2BJYc0bWEX0ukW6YmIbGkJRMdjJ9mYIH5QIdJF4hvRGyK7cC7ctImQRcUET99fGXOoft35GYLMQu%2Bg2smnkgZUrH8AL%2F9Si217IssJ916nv14ZrJrvdxLkQvrvtBcjgPC0NXOicO8Qf4mcxPqh3hgUw3DDfdvLJXngg7N3dN2zbPJSaed3OfZnMU7dvmznp3C3bruO%2BNmue0LFsy7S%2B6265%2BfCKFYdvvuW6vmlblnUI8xCXp37CrOZv4B9gauDBlYp7adcUXB5DNCwYImlXOJJKkAdvExXxVvKEYnCo%2B3eIskP9qrrfIYs71CccBjfXRC52udTHHdaP1A1ui%2FVvH1otbrLrpNXBsGX5B89QghDyimlvNB2KfkxZ5C9%2Fem3%2Bd1%2Bd%2F%2FIfFp2%2B2Oxn%2Fs%2B9n%2F79p39S3s8idN6g0yZObwJOgKUpNB3GyU0Ls0PbRzIRq4lcarLKOJBkLRzJQD4j2090XrbA7DW8K3jNF5hlGS5e4V2D17zgss4T20egOJte5iD0bReM9yjTxnQxCRj3c5kFzGJmGbNKmwGw39IJDJcXJZGMkaAB4jyJAKw0jt5IAuIE%2BA%2BU3cVAZZrq9zhDyBrU8oosuxcGNTzCKJfla7JjNVmuSb%2F%2BtuzN2H%2BX4vlB%2BPpdfMXXmuVsNiub1T34SFbjYw5itEvVi0K0Nt9pNJUMI7SLGRhf2xipfCYf8z5OdlGKayOucFeVPeS%2Fdbo3lBrbSMmwUiQN5%2Fed7g0Ds1s17IuZC5kNzM3MZ6EWCa0DtekdJfAxz%2BR%2FOX28sND7yRMTBcf%2B%2Bs8mQCQWHya4qBv%2FufeMoWyslPA9DtMxUknxkH%2FyfTnm2CMYzs%2BCq3r7PxY%2FMXomrvTEsRpfEGHa%2BWN8E1AHjElb7d06ddA7oK%2F%2B5Mdsv9EtPms0jv0Z5kf1FqPxWdFtfFr0kHfgDX0Y%2B5PRSG7RUj0tQr7rmfX8DH4G5W28kKeJLtmQsQkuwMP1pk16EV4sl7vrMJATfyUWo%2FGwEco4rh4XFQgaiUX9qxZHrMQqKnz%2Fc2d8b9TysYrAuXpP%2FRf%2FGr8b1qwwc5a%2BeuLa6S6sneNXToG2XrEJi4R5SGs8Sq2S3d97bsfCRaTdaLwKClRHt37mkudvXbjwVrLhuYeGhh56bvfQkHpk2CwvwClqgWwuBfndC3c8dwmstj81KkagcUgbfPY8Zje0W%2F82VPWJHmSq6pP8hPWpotc%2FEexDOK3qU%2BwngPhOCiO9MJRm8TJefjelrzoKnG2Bn%2B1NCUmPE4gHFmBN9jrTigRIpsACrc9Gstg58ULkp9467%2BGf%2FeFnD5%2F31lNrt2967dhrm7bzI%2BVT5m%2BfzKhvf2MzpICEm79Bopkn07lt1762adNr127LwVqQLdJ5%2BlpQDcvHPQtVY5knhYrK6q8%2FJsiP6EuhGZdFdaNszjvpqvc%2BPI0CdjN0AXsFOC3ZfALDJwr4q2Xq%2BGF%2BGNbsxUg5NLLIEXi8otcDQcUts0D8eQ1iVDRAMBTsYiNdRIxE09EIBJO9A2xqgERTaW86BUFn0OD2xFO97FAgFhF6OoQ7prYt4XwSeUgQHiJyDbeke9IdQntciLQ1FlJMaYcUNvZBg%2BFB1ubjlnRNvl3o6IEU2w7fdNPhm%2Fhh%2BFLysUu6%2B%2BDLHkOkrSHYEjH0tEPe7WdD3uyDgvAgK%2Fm4szFFR7ch0toUgBTdWHr7EpaWru6%2B6dmbbnqWEbV2EtxAsXiZAPTtGPSbHsotI2leoM8TePEqgSQprs7AGFf8kuOkPdZPXGb55POAW1d%2FjLST9v5YflasP6v%2FCO7%2BGNAPC2BMZWmsOjp2NNbfHwMCJD%2BLPVL%2BD%2FOYlWEEI%2F9jpPddOFkB5d1GSuKZYggmCCd7JUxD7EXAzxyirYnNDLdDZoFdx14kivkvGc3579Jm36reTTvDgBnaO6vzyQ6chQmlsMoIkIQ2%2BbBDWBud1Va4pcCn8CPqxlh%2FfgtG8IPaPH8C5wk6%2FnZDv69jurV5QhtwE0x2iqOsj9Mx8B9%2F0EaUdiPfOYYDCi%2Fq9jhWRuupMDEU0%2BCtX0sDFxv07T%2FK5niBPqN9%2BtQjgEc31NGCXFeMcCEuQBIc%2FBK4CO78u7EPYvl3yaEfK3vcb6qP1R2tI7vUjVDDUdKubsSrNjYKY1qBEa2P50SJoaXiksIoLiCwnxS6EBuBde87botNfdEWwYvF%2FR0%2Fu5yCqhGeEOR2ynSeyXjt6ka7neyye8kryBSWE52y%2BRBgogrXPZ8E1yIHoHIFUM%2BAbJhE7lbMtt8ApL%2BxmZW7PwbjAO0fAVoXQOuiSP%2FksIVdFZ0aulsamKUzwPZ%2FNYDMJRBPCxsBqLzqHyneXF6Ej9HlIFo7%2Bpg%2BjUb3unRmGpstGkm6etOuDBGA5wCMefp1gTHcdZlvPBXlOslvYTp1cd8UjYLVd%2FJ5awNrIOKLnIt9MD9qdrKrWCvA6ALm3QV9VrsPm60Q7%2BRHJHP%2B2hqfugo%2FMvI2H%2Fmqr4b9tFnKSRY1Y5Ek80Nm%2FWIhr1ikKnxGz9TWXrokf9xwujfvcOTtNTWnxd0F37Y2W79tteBqZ4G5qLCuomw%2BnSr28QESCRVLTyYKILGJOPfcnaIFOsewhRdvv%2BrWa%2FWih0vlbX6Zb75T5C0qNKVFvH1QL%2FvazSWgC2s6oWXXIuUxQelKiJbowuJDQViatLmLijg9CQBMg8WiPgiw3LEeYRmm5f%2BXdnvkDnxLLjMLxtvX74C3OlwPQqx4xwIdpPx38LrlDphiyWUWHWKAzzxurS%2FxTo%2BP5wGFak62ap1PVFFN4v%2Fy%2BxuR39WnIO7lsWfwgVsK17wxrs9K8ltIKuhkw7f%2F6dhK6gQokFKhWX3urrjk%2FrnI0pgfpGMeuQIUaEM7%2BGF5q2iMkCaMQwxxOzcvU0eXbsnS9XknXvP7Gtw5dwPXlFu2ecvSHEZgNDsU6x%2FGdXBYXyOQjzZReSedeEPY6nEv9gJR4oBQJtFO6Kd0fwC6BO4LNHDeBujB6dSNcUQC9zIv2LnAzGk99bUDrdFY%2B9yGFQtEo0GQPNv6vS2drj4%2B1jHbv3aJSMUWP%2BQTZrmbNTjU8wyG%2FiXNNpskybLcJ3CiTF5Ir%2BJYzmJwE0mSVhlxbtbmvweB3ulB6Til5UuUZydpgiFVeobhU0WaBqpJ198d%2B%2FXeNRTZ9%2F1OPfG7%2B2hwzd5W3D%2BhmyjsRcUg%2F%2BCavb%2B%2BVh2ls3L7zT%2FetOnHNxeerv313vzLVqPai4nJv%2BK1FC6040%2F4udw7sAb3laSg0XCkAAs0npBO6VJabS4Elk%2FU%2BD4gTXW%2Bj0wnrMlqNamq4tMIYB87tE10i0FR3LZNhJsb7%2FR561btmes8YBCRkhYNByRtKd55mqTas9FYhJnbRGHuOh3M4QTdgQSqmgRxuzGdSvZGcbMxNQGk5C3ebLjoXIOFM4l%2BWKHmLTJwRv9E8GWJ6dYvf%2FFmEyEGr%2Bgyrr1p5zrgkz0Cw2j94Hv8Jdx7dIVegBSNtgsqGsRQEYiIBoXwD0LNvQ5d7s5Z00QzwNhqZA0b%2BtMG1tQq5nd84uq8R0zPvX35G8uRaze4jcOHzz0w1%2BQ2BIRvf6J6Kgatnrbiem%2BCFvAxfkrndzD9MFPP1GWTUHclpASUkCNAQkpCCcCgDSUDAhDZ%2BCuEkgn8J7i9nMA7pA4lISappxILKfAeSAbIcSDuN2bJcfZILqeO5rLs0MnngSHYRdrHjmaz7JEsEPw51ZqDJDmUIOZIe34WaQeegNsJn1qz8AIpT3yCjyEih%2FxELkuJ0lEMYTLVCiWpo5oYMleMH6USyYJcD%2BuOe%2BkWKpn1Qns34iyYDjkSLvgnZXcgVQNeqINXr48m3iS7cjm8tedyY0f1QvTnHHdsrKby%2F%2BSSbPY8%2FNH6vpl%2FEsq3Ae4ZU1HC44KFiI9o7CEgab%2FRqHbj7s5KAg06s39ZP%2FzxI%2FmVuF%2FTbTSy%2B3Fb8If9%2Fcv7%2Bwt91yy8RfP1QXtW5RzQn7qIiZyuFM5QfJ5E9uVnqT85TanFx0lkP3ukBAMprvsRyi%2FC8NAJL1xbIIirSvnSj4O5netb4JxmNANHPssHAcHMHsFRgEug816gDBeMbdfiuRcghqYcm0%2BXxx%2F5IAEtN3fqFF3LzAXqwoT0PN0OVTNqxo8sxMkd5Ig6k79Zk7VxxX6gMLOZFQgvpW2RrMW1D0BDihaXQ9wVRoBxPLfpknmkeMtoB%2FqM9cRc9IqmMD2XUmdZ7GSRKPUZvChf8BoykriM2MnKYbOHX8R7cLdNCxSFFVQqoYswnlWtlFS2mNkhswVpZiQW1J%2FUKFfipHGlUkM6UKBhMz1istELIHJLMSctu3ugzfaVSOjKvUgc%2FTHK4Sdg2Wscz69leKIkkrwuuWiOe9yGYKQXRumkC3qbRcMwrvhjNXgdZk3RxAUEhuSPvn3nnd%2B%2BU%2F3vlVOmrJzCD8JLxV1OHRjrZifbcFDOuRNTGqdgQm1tSNJ2OcQ04YiEXuxtII1ECSQRoQGYioEsgCfchB4ghAtw7FfJre4WZ9hkVi9MtjuWqtdNDlpMrfEG9fOT6q21okg%2Be4As38MfGquNt7oUws6Ysarj1%2FefE%2Byst86YUVNvDdts3Pv5c8m%2FaP0C%2Bf8%2FQb%2BIMnGq09BgwN01oIOAnAdagI8mBSrqk1gxTDUBOtk2ousEtBH2z4Ir2d3f6k8PXXVlt2qN9RODxRuoJT%2Fv27wm09jRYVc%2Fe%2B%2Biyx2tyzJb%2Fn3J0htXP87eSsQaf2Ly0s6Zmxela88REy1cf4273mI3iXNJ7KxrZibOm9xm6rl4fqy%2Ft27smU8tOfdW2ucBzg2UfmOIVyLIl3kpYlwphDISTXJXsctmiDtN7fNV6zelgxwnWxsVr83Aj%2FS5ki1jL%2Fa0GC6%2B2L6Um%2BaoddlNFuj%2BbJ8mH%2FiaLh8I0%2FU51NspIEfq0dohwyFXKgm4NggwQ4rRhCOUFtxxo8XnitT4cnGfT93IS8FaT85XE3H5LMY4zIEPL1hw443wz%2B1UmhTJyJGxZzw%2BwsKkKZgUiVtKOKMEb2AKHTv61FNc01PQFwKnvsZ%2F9pPA4RKTASWahmh%2B8MxwzHxKy74IRn5LGRjsPUUwTu64UYNY38caqd7HKucZ%2FtHnODtENw%2F2UfHRMaq1UUPDJQ0OKkWCeet5fYOhII1VRz8%2B%2FElg5j4Gxur3J8o2PJ4rg%2B2d08T%2FfwEzSVbyZ9XPro95T477lRKqUSRXQnauHNsISAl27oWi6Fv9z48JMv8r%2FaMMj8onCP%2FDuDZOuN%2BGPPr%2F%2Bp7bx%2B7JlbYdppcNhzKU%2F1Px5aiaGDn%2Fs1iGMaBcleKUo%2Fv9rcxkZj7DBEKOfrayytXNLYiUdBY%2BpleQXdnscKlQcpzuWluxsieeyuXIK6SdxozitWyGOV3vOHHjguyCQ6fpIYy2JwvrQEF%2FQa9Pdf%2FQqOSqCiE%2FEE1%2FXIVKTc2tzWbHnimrEd%2BVyz311Ml3P0GVTj7PD5aDnsvCvH36alEaPMePcMegXs7x8igTu4B9v7G9vTHvhCu%2FkzIdx%2BBxC0ay9zRSvoS0F2lIxI%2BX7klU63I40gLQ3w5ep5na%2BSFnba3z5D64zv%2BQtM4n4ffG3tq4aNHGRfxgrXPMim%2B5487abL7xhdseIRn1KDl%2B7aINixdv0OD%2BJSPwKf5%2BxoP6aiTeQIDVlIhMcL1H5R9PYXvprs3fv2bO7MOplCmweuiq2JRZ1zz%2B9a%2Fv2PH1Hfz9236w%2BZrPXvWfAxlj4NLLHpq3c%2FPQ3uvmvbrjG7fe%2Bo2y%2FcLdtE6VUlXi0ASb1VLUBVSUWSU4HdvAraTyS8xzM8NxvxFkXV6pUVRiJwcgC5zEeht4rwcp7ki0k41G0qlQhG1Vzlq8alEmnFi58caB5Q9vn988MLhqyVlHvLEWjtQFeupdiocF%2FtkkOGPW2ibWaBTkeZ%2FdvPWazXfOnnvL6jkRXpi85sFzZt%2B55ZptW3bl1cCCHZPD06MhySha7UFzjcjbp8fOecFCirzAG%2FyVjBX6OFIaadSjQq1nNhyIe8tVbaaSdHlXIWKacMeuZA1uxS95zILhyrxAdsXTL6m7kNQlx2P9uZf2qhufePFFbpI6%2FOU0WcP99RrCsrwseVot5mtytpf6Y0gm9sdeyKnPQ7onyK4nXlR%2Frg7H95M1upzu89DH6pgUcikoiihJ6NJKmRxV1x%2BMJiOA3YwhDRQrWU0u%2F0rvq0VYXnyCwsLeTJYBq3dAtJDavuzyoVpzZ99Z0%2Ba0uoiFH%2FxcqgDR7rUFeOrUn6Cywb8ZeNMbhLV5ugP9l0zv9UN5b5mFkjzxUcpPJCn3V402pRxtJd2GrnLdhtVk9ZSZh9W91fCSH5B7ofxPiWL%2Bj3D%2FuwhBRdyAyozeZwvQzs79soi%2BBKSnafLviZCcfrpBpLyimfLfTyJtbyruIQKD01tUwJyKEo%2FybaxkSNFUMdMkhQoJyRBQFhnUkDQSXhTM%2B3NmY0EDM7ffLIjqWEGt8lCO6mLia3PukFnghosJD5p5SIho%2FVDkzQfLE%2BIrYoJXkD19pdP7OwG%2FvoIUtagiWiZ4PAFTHHlTVhRZ7dYmPar%2BNJ%2B8JhmR6DFK5DV1foHoLNO%2FpHrvZfmWZ15RQlwvoVDKhCWNK3CCch9lfFBuAqUgpFSShmNaPj%2Bi5%2B%2BWZfKeViJfW5HnUakVL4UCNVkA4%2BETfIqx4B5xSaP2L1yn0zn2ltPn4%2BOqZGmwwEVCaCSqG53ldtL1oLGAhdMLd09MpCCF6tD6ZnAZBY9hDaYsP0jzZ0j5ZjKsF4i1UmLuhbJMCnYJPt5VwFNvmZawXjEvLJqIH8STonZjq7BZ8gKgR20C9MDFqJAX1H64QW2NEup6qgzLP8cvppL%2FNNTOBTCJABOHeWoXzLhw4Wuy7gaBtjKr9kgKq8ZlRYBS32Lpxc8vIhpNDTfyNXWybMJbn2RyQ5EmWc2QF9wmSZ0KYCE%2BcPuYO6b15Uotj2Kd4MItLS7gtFbkTdrFND6pvEZqv5Yv7jXAus7Pg7avo7KDot50NX3CPkP%2BKps8J9%2F3mGQIteY%2FLGPC%2BL7872SPR2br5fy8MtKBMHedGuM28%2FMZmPJMrGgi3Gb1S%2BSi1%2FL%2FzrZwO9XH1ce%2Fz7ZQ1WSoY%2F%2BpMb5FT4ua0Wm%2BJf%2F298nFmChEQ%2BTi71est4mq9VYI6RsymoRJKYidElT2FGnDTZvqtfhGAFTbeqEw68GqtfmbVa%2F1IFO1%2FjdWr%2F8BDRRtQh9XNjubEm4aWVpVonpTGR7PVGc%2BKJNoBIWF7kYi4gUV3r1U6723i6TxUl3n3%2FtM27aZfKb7THiHW9VzFSwHJ05VfK6Ar7kaB0XgPPE0BSkSFKsBUpaLihEWoA9wBt8qirh2VSOkZwXEwyrxZ5jyt2rJmSo9gX7cg6jsEUGJU9z9xJPOEM3uQQxKgkh35DNATnVyrmJ3mbCNyIB%2Fyox4wH1bg2DwN7q9kov4pFqny8oSm3RQbGgJ1QQTs6ZMLilOVYJ9v6Wha3HcJ9jddsXp9YhGUXLXt%2FqMDnvLpPNTXfNa60z5%2FyjXQOMq%2BlNmwh5egpYrdfZQZV9rI47xlRkuyTjpzsmCBSWNkAXVoK8sgYWqQJWbo1RLo6QH0YW6pxqfCnRgkd%2BRiFjUQUQ7poIaYoakgXxwFd9BuuI38H1xBxXSFb%2FpBDIKQFn7YB3dB36l7sG1FLaKiBdp1KxLvfswap%2F30lnVESgNnvjbUoT6w9N%2BXoio0qcYOIM%2Bheg940YimsucQVvli9NEcft2UZwGQwLuilj1fFr1i3NP94X%2BPE7Hpvtj6lBJfJ4R6NvWiaL6MgzWHxiN66DExa%2BdAdAbMYX6HVF8A%2B7rjEZIXAVbDe7PVI9rmN69JOLV1DOSvRPxWNPZBZf%2FNf%2BNy65BhYxxxV%2B77XJ2wfQ389%2FIQPgajXbwMsuAz%2F0IaQcXJavKbRqR2IqyZruXjVC2%2Bhdee%2F5vdnYOedpmVtR3NGXldxSzDSIiBVpkGb9by89UpEPKrSLZmyFDzMab%2FwXl2CNe7s%2FqCtTvWgG5kpBmCBlSzDS%2Fr8N4uwBwohRW63JTS1y32f0TQsPfXVGEHQrV8%2FNCfiOUVirYcBbIeA2%2BiF68rQIo3B%2FS628vYESr79ehzS7Q9LEL9UXmik9XVHb1yBO3Ngvt5935%2Bk1efkV51mzzrM0LL3%2F20avnwMeKuWyOUZg2TasSqZ%2BKcZQiOn1Iu2Vh497ALUVZiCKt%2Fgh6IvTIj1ZLRjWAkpHKOKovNwp00eqPROiAbiNEKieXwMLcXhVJ1%2FuzmLP4tfxaHR59cBdJVG1kTAgl9ze9QKUEQ946Hkb%2BokJ5JRDyf54Axur1D%2BWS49cLr0tTPEu7UmXrxcSr3XNvumv4yXzInXKH4F7Tc7p17Zt%2Bt%2FqW2%2B93k063X7VW6lALxTY7i1nBXMxcxmzQbabxz%2BtJo%2BwijYaIGMNS8AoSMgAPt84DdHOoMPfjXhF%2BkuH1tZvuFQrRCN07xGcXRX9MYxYchDe5BcHj%2BZ4i%2B42WyPc8Xofi7bbZJN5nJLJ5qr6IqRtzqNlM17SpFsnkEyTWoABEjz4JXOQvzWYuwdnV5LNGOwTM5v9r4RpQ8ZXsYodks3o31JBlzbYtNotisnm22MxiwGFXam5oN1n0TA%2FhRvshvTSDwHff4nNzRo9Dum6PaJbMXzDz%2Bx%2BFkj4L4bFNBb1asqsgH7Dyh4DvbkPtf5yMDKzEwyoaESMSNS9P9gJVA3%2FRTlwoMwZvxECFWxIPNw9gi01nOHjP32esZTtmXHnxvZd8ZtakqQ7ekajbXetpNa6ocTVxJtY%2BuSe69OLz77zh5bDR3xjZMzUz6fxrz1nqrZGcHQHfPVefN%2BfiK86LeXj%2BSc5lPKy%2Bk%2FvCUI%2FDaLFYCWHr6nbXuILTIsb5imNKY%2FrCm28fSMxPhkN1XbNMNZGuqwOBhtTSxWuTk6bw0ZaG86b1hKddePOKuBvmiguYBn4T%2FyOqOyGRBt7bKUI1GjioBC8aUKwF7Q319UgcmtFGIzCJGBqwQij0ynDsfdFGc3TS3BlNfJ25xmzniMkpXXTPvCaD3ZaZvyzjmZdudBostmhb0ORZNN2sJBeed1HXkrUsywueQH%2BL0eCPxmsa5ZpgRJSDZ11yDv%2Bjmbd86vxZfc1WcZJ3UkMq1BOOOVtvu%2F%2BpB%2Ben186d3GTwWAw2jheaJs09%2F%2BLNfZft37DALyrNj1wABMuUKbODyTVnT%2FKYbJ3Tpq8IrNh92dkxOj5P%2FYpZx4%2FycyiVcDYdn4JbEoKdQi9054iBKsygLW46FRGxAb0NPNCm8BSNCPjoKcj6EAus4SuP3rB%2BcV99%2FeTF6294dA8%2BTK6v74MHVpYNRt%2FI30e8QGTOOdfGWzzxcy%2B87a7bLjw37rHw1nPzp0KyyRSeZO%2BQQhInt3dYgvycjrPOv%2BT8s1rptaP84VeywdWX2T4ysr0%2F7TLIs6%2Bx9zib56ye1dM9e%2FXsZmePY3NDs9zlnNVt4%2BWgHJbbz3Livg4P9WWgviOMm4kCRT6I8vw0NbUUEnFvOuFKoxQW1gTsvFirsF5pb7qTUCx4i7VmtToveaDxvK9uOaedVvPRpVOnNz0Q6bry7uiSdQ8t7Vy4JQKVS%2BXPplV2ts4bvCwZu%2BKzgITtxepaPRzWdpv74muvv6RO0SorX6cu%2FdqKn%2FXWnrtp%2FZragz13DUCl5myiFW2Ycvb0PtsXnU%2Btx8pvLFbUspLX68mdegwmOif%2FNPDONajTGoUh6tU56HBJCTBASVvNUB5VIiKpc9kd7kludodSFz7xQbiOmMk5dOYk56gzL6uaf7N8a6MQOHm0ae6snZpFDfuT3%2FjdYzjzwkXXIVHoXNuCfQslQZqBZjTsoHMqrkE4jaYdgkGz2ATOgB3cPkSukD01DnV3ttb1wx%2B6arPqbkcNAHoFPzKUUQ%2BqL0k97pjbZv1I%2FegC9zTFbrrlFpNdmea%2BgIgfWW3wqkcis8ky5FAcRd1If5nNZrl2FFpungc8wpoCl1BpQV%2FScS%2BzjlASyUTVv%2FAJ46gkJI4bHX4lTnloctxPZE1ckS3%2BjG2fKIjkQFyzuo8jvYQG1OrGvJPSTu%2FnSp9PHNTl4z5hK%2F8gtXVKF6gEKiglgcKiRlCESsQCV5QIlKWKpr34lt%2FwkSx%2FJCmP5%2FcBKQfl%2F5gd%2BrOS%2F%2Bp91%2F%2BYCg5CXK2W4M9fu%2B%2F6xxX%2BvnelVuldIDCG0VQTpU9Dw4pRfei%2B6zWx0MLie0gPbyrkmRU7OwT16JGeyXLHqOLqAfVN1GPlBzWtFNzj0TRTCjogtP1NjIvu5habN5Aoa1k66wGpqriVetJgiGdwDZtKhnN0y4n9sXYnsqGmZfDSR15%2B5NLBlhoDaedEm7sxmpqRija6ZEEg2EAnTiAC8IrmFbGz1q08P9PSkjl%2F5bqzYqT9hMmptEXDgTqP3Wiye%2BsD4Wir4jCeoHbbp5hRfpB7BakUIppIlPCD30dR1GtslDz8OsqbXmejFC%2Fv8wu5X2myq7SJ8Avzv9DFUJySf5uNvq4%2BTi7W9D%2FOZrLChdwxmPNiBRqVjnpK%2FaGxRCDspVYKAW9AN1JANoo8wP4BJUlGqdgw6m1qPQ2QW3%2BOfU5%2FieLS%2FNuKpDU3uf8bcAXyBal5jMR2NEAbPAZt0K3hvxHBEDlUxfIGcD%2BN2gNSNx36nfqlAYow0puatNpRz0e4W2oahKzQHsjf2c16ad%2F3t2KTtPobnX6D8C8pd0MDP%2BKx7wnXqGGlLQcvikMErm6TmfsuxJXbSAxqNjOogJLQBLiKEHAE%2BJGTS3JoEhTrz8%2FCB%2B5YlupJ58aOat8Kv4JvregxwcU5Cp8GFAFm1FyOfto6GS2m1NGTS6CPNKkbsTdCBlnN9onMho55BX8IJZtEQ35lk%2BhtwN5A0V3RCPoD%2FyXAcv6pAtbZczRUA64JmcUf4q7Q89ZHLeJVZ5D1Ps%2Ft%2B0iCT3AHVtZC7JDCXfR7OSb%2FXja5H3zQbZL1B%2BULX1BMTEk3AseSpmnKEK4T9ekMIidUCRQFfcbj7z8gNLvzF7mbhQN8h6ZbRset%2BnQWdS%2FZX3k7WpS8P9sfo0iGS64wV516pOhjI6TZ2dApgI5%2BLhxywYoWxKUrykKJsIoDsR4mSrCTg0egMPnLW%2F3Q5Nn8BZEuzqEI7HK3n0%2BzFmuO3TtWQ5WJoG9YqCD6Gc32SxnbnVPfsxvrFXK2dILl7bLthDp6glhcsfp4bYvbSmj%2FmQ94uBTw0E73x2jbNRCvC6VL6GCFDwU7eWQDcC5FY5s0slieRDwtAbRsbLXbaXAuu14e2OJw1dc6jQ3ZdY8v7rv2%2FBWZLqvFWVvvcmwZkK9f5jS4muO9yR5res4kfkRxhV03L1RfPOiPtYi8pd7jNEsOpyTwxpaY%2FyCZu%2FAmd5Or9uS3DYaeqVOhH7gZN%2F8I%2Fwi1fEuLXvyNivibjuKvN%2B1Nc01HF%2F3h%2Bef%2FsOhox8MPd5SFucPjorQwXT%2BytA8EmA5mamHNFDVhBI5pjZbQpugBNkO8MvRub8KVDKST1Wag7D3xlin1ZF7LFP%2F79nbvCXFOY%2BPUjrT7%2FotsPXXZ4exdPzuhZuL5LUXVAn7k7PbhG89uz3b41X01gbjP1xwlu5rrvvf9%2Bpbs6E%2FVu7Nk642%2FPYRaAiUBdrmO6CDTBLPQFA1ur0uXoBR1INDMkypKpoTqnSMx5GiEdTEaSHLs0Alvu%2F19%2F5QW9Rv1U1ridT22i%2B53pzumbs%2BXFFXYC%2B%2BCGsTj5JUT%2FGCgRt3n78i2n71FHG4%2Fu6X%2B%2B9%2Braya7os3ZbDmgWfXun44e%2Bu2NZKuGZ0HiF8M4TlMPR%2BEU6rPKRJ8wOU2RFUFLex3egEsz3YqEAq0cqhAAW19dBZIlVzR61tuIdTnpXH7l%2BuXrbjPUyep%2B8cl6aXKWhPHpDcXl9KiTWDNr4mBQc8Tq%2BNzK%2FOKSbsfl79o9G20R%2BbrBXYvUg0rLHhtrc4TN81TTOWSZ0gL1ZVlOYH2ery%2F7XVUjFMbzYpg7UswcqJPQwBd0LKLabJ8IaCr2otcjSkIrGwootKECaUd4XH1%2BSdazRrfddkBU98t1htvWrbjqSqjaCguxrffM%2F5zDCpBALUycmajhd%2BR6ww4SWafuZ5eU%2BtPid4lgd3gt%2Bb%2FY9rQoZNmiXYPXyRHbRs8zX%2Ff4WIFjWZJtUdSD55AP3xtXH%2BZipC0EqdBGDA4CoYEU6gRLGPU11QhkLTBiEYPiqOeQgwTCl9aok1Qr5pFf71qEeNxjy%2F8F0GoqYPv75Yh9j3x4DuJ%2BuEzHRpAq2lMqb%2BqfTdiq6kGtzfOWsv0c7lSeMXDHBDe1MT%2BLUgx0Pg%2Fp87u2UicdIvqQi8DkxhcUwUXCedMpb4NQjwY3npTmgsURJavLwCRyEcN2HfWsDVGfv%2Fu9ZUWUx%2BPYFueUKwaNvbtu%2BXps3eVWbN1GcgVrdMnWJ7WmJz9SD66EBidag0NF1Ukep0t5A7sFCWdhzvYwHv6L%2FBehXuHqfaBwBEU7hfVLcXvS4VQv%2BT%2FvaSIl7cbeMc7ekv9i8S3e1L5xxpvMGcu1EYPbKyCiijjGXcDKckm43PqU2qNWlXusZMiqF82cuVzolUHN9NNR0HZPxFPV9V0wLtvq%2Bk4DqOwVWDlzuQLVdqFiP08cRX7aRlBVfR8cb55bWe5LExnlcsDp1vAP8Q9BucPMk1Ulh4GnN0SAdxcNHv3q9ohx1Ati4S%2FtkWjIDe3hQdkUGrGRaFBiUdiTSkI41UkMuuQHP%2BEaSQYlPQTFWJF03BNPpTu5KFAdkWgDukzsZKMG0Q1TAQQglScOaP%2FdsZ8%2BfP75D%2F9Uu5Gs3FY%2F2SxPld0DHOciXI9gqjcEidXjE%2B3BLosy0OcX3T7O5g65ROGyzQ2BZs7WbZVnO5ydLe32hMwTQ4wnnKXW6XW5LAa7oaXOIHoUl0FgLQLH2by8wSTWeAx2Y5PDazK3BqZbeJZwXGPaYhX87ZNszoDdaRxotXO1nNlpdvAPFWHDm8PqEE0sZxDEqGzxisFNnuCWetPcGrObN0p23tTZwMuRVodSV8%2BLTrOV3eRvzjQZiSjaLYS1WEJe0kNsJlZu9LFun7%2B%2BwW4gRDRbaxw2nrOGm%2BxOj9cmtbp9ZqeTM1m8UXfQQCSTVSQox6pvtjot%2FFpHvIUjJovFEoYvHYV9C5Y%2FxN9OfcalvII37UEhTbTg%2FAQIaPb4Vz6j5u8%2FaViycMod%2FfkDcpu8QZbZoeBi%2FvbzP3XPsZvOubMtaPHkD9jt6%2BU2O7vqU%2F9C9SMvgrXpQNG%2FE0oJxun%2BCiElUa0IKQSUwERxOntKSV7ekcuh9VBZBBo3VUcB58ofKBHCwLyf9qFosz9Ibf8dGqwaBMjRig4SGOZ2UkWI7UiO9OfUPdxOYFApUZyfpY7mgEc5rtNGGk2H1lPhAk1Hp%2FVAMqQEHEUfEYkkUQq1JMdzsX7kklRrTrUi1wMcDjmu1YYfATj7Y%2BpGpPEBXuoQIj8rR9mgCl4C9yqmF7xnVWxGVniNqtpVmXBvQ6iwni5YQ8a1jYrXtc2J13HvgkvqWxuva1sbr%2BP2S5ceKGyBwDv2DbrToe1u6BkAJV7xnVLUaq0sJB8pFqcUIPi3yuwxi4JuLr%2BP30f3OkPQ72aO0xYo3%2FEsmO3QO5qEF8S0qQH0UsKXv0brnl9%2B8M7jF174%2BDsfvPOl1au%2FRL5%2F9DsbNnwHL2pHR1NTRxMZhJtHktOOxLxErPF6YlLvpC9YP73x%2B4ofw%2B3xVdrHcDE0dQQCmCRgvt9b35xINDf1CDcRSfJ%2BpYl%2BSf8YcurfmXP5F%2Fkj6J82jNsrkWiEuhVlgFfyNkB3S5MUzLhoNiwSCYcxQ7Ui4J0Xh7fmqRbaPa1tzujxkBRlsEHy0%2FOM4pYLPb7g9O6BQJN6l9zQ0OGyCaZz0vMTbHOzXfQ7a2tsterTcqxeInODoemdktw%2B1SbVhKwtW9ffe8VKadK0OVuC3bWzyKm5LeddsWTeorWyY9IMtUFutdu5g%2BRn533qkocdvLs2HmhU75br%2FMmWtD8zA3OP2t1ea636jEzqYxJZGAwFiDEd61oTsrRuW3%2F3pYNi3bS%2BRd%2BGjOfVpAPNd6y64Gsz1GaZleWIPoYL%2Fv9mTeQBENVEguiF1aC4YeXxFETw6QyPfn0m9g8IrMFAvKM1EI11DARnbqibHk%2FIojy5rSdgCyZi06y8sS024PeuO4MfwQ5Y9yKRZCqyYaF30vzeHlmUprR21tR0t0yz8KZY66zWuGvxVQB%2F36kP%2BK38t2Hu6NQ9SFJfw0AdpqPEK2qTMpf2VCqJwqPoJezTL824b8akoL%2Bx03nhh%2BoNo5e77psxg9Q5LzebIKD%2BfsY34f2MtB9fk9v5b8PT6tYrgv4kRPwd0q9z3gdJSJ0653KjCYPwCaR5aUY63eW48O%2Fkdo33yxX9wCiMv2QTrk8eGSI6Ag6moG9t2P%2FF7GRNlDjl0gw7pJ5aOXXqyqn8SENnXBmbSwUYLyqJjv3UmY1nKr4t80no0faXsaIEiF%2FBRaIBnItSce4OUif7W6Vm9T9H1X9Vj71BEm%2BRdmIJQST%2FZfVdudUvh9S%2FqqNvqT98g9SQ3lHibZY0mRVHooyDN%2FFHmTgzjdozKw28NwQ0hwN6BCoPKaEk3YtKwNhwRLXuk076CGoZNXDQcRwZvreTZY9EZi%2Bd0s4%2Bztv8iei04JQl6ZbDD2eHV7X4uHuFVfPrOmcs6m6Kr7hssr%2B1VZFcEZ%2FPdJkn1hOs8SXS%2FNFFgqt94PIZzZ3tdaL6Q5vo6piSzdy737pwsX1VyxUrF15iJ4uNkq%2Brbyg1Z%2BO8VsNC1UmcvORPRfxtPrfRwL2p%2FoA1eZp6Z%2FaGffoewaXcA%2FxBlKlQLfhQL%2FoPgBGP3qsA7IQS8qDVNswHKRSheDUvA3Q7MZoRcJMxlEygujn1QdyzfPfq3dEp%2FbXh5e5YXW2Ngfvza0ZF6UgFL%2FE0fTq4LBlvTE2qb%2FKuuzYSXVnjTfM1osvqMHVbm9950quIZlbqaL6YP7jk3kUtA0GnX2nvq53f3WoSsvEdDRnULgo2fN7lNZJgI8%2FVWi33c3bBZnGY05%2Bdm%2B3qc7fNmj4YGKLj2nfqFP%2Bg7jdDlxEV5XsJQZP6hYrS1l0VQr4c69Xueixp90gnZPmE5OF22j%2BSYEWHlZ0K%2FHgsh%2FZtsbh6h2DNRlvv6jJh9XaJaHCZDiUDKNTMkvb8vsqCyf3ZNdSmO0fa0Y4baJTtpbKzuVzeeSI7fCKr2Z0WypapnXJ4gnoWy3PoUIlIQ1TXdqhQJIXp9Wx5fYdpeWh2TY5D%2BYVyKd0jw3iumwi%2FBC3cEy4o83QlZnW79MrCgCjbhWXBlRZVVZZv4rIKpXC01HFlHdHLoeWVl6UVc%2FJ5uGm6CViW5mulYMk%2BHqNYr0AyUPivLg2oMs2MPqtuhHyRyiwvNJej1Br%2BfcLyoAyu8D9B7bgmzUqfFobF5nKnK4%2Bt8MPJkI%2FxHUNWk117jugWF%2BxazTAALQn6%2BUE9lhoI5ApGA%2FiuJOsrlNP28SVVuBVajXmircLel46w2bJS1Q0Ft0KDuikDFL%2F3pYrid1Q4FvofwRIo4R9h2ftSwc6jHAMqLcCql8YPHtlzGoByNXYN6v8hXnRaOhUvx0sVLCexwupGDR4NOYC7PePa5keIPACnuAdD7dEadRuTIiS6Lb7uskb381My5yjzF8lGCjBRqdwrWJCagfB3yCy7XT1i92hbcZ5Ci1FJkgYMDf6n%2BjspIsHFjJrTOdzSMuOa9DbDcj%2FnH9N9bIoGVgzHPWIQuFuYtaMRaq8eCKI0gEF6lPOZjBz3EEvaaxwSUT9U%2F8JbJZPJJLBLolH1La%2FRbF9AbC8JJjv%2FmMnssKjLRBJyqj9QXxNko0Ux%2FX79epfiXkm6fmKwF%2Fen1HLc6LxloXWKvGa5rVCVL83VuiPcDEX%2FK5pTXOxHfx6HHB0t2FI0qI2rCZFTrvPWU67zVuS%2FkTsLnc7IKhFg30e4FOkqNSfH5PtkmUy6Cpiv%2F36k2sbqCeCFNa%2BURpoY0sZoYmCgCr3qgZz6s8I0gP1bYiR%2BD79H56NOz0EVWCTy2%2FfffvSCCx59W7uRV9995eqrX8GLesOXNm360iZ%2BT%2FEl3uZqL%2BFyzSZ8XxpTiI%2FG0nkT4zznFZ0t4ipMz5v4q9ssqbdKUZt6u82knPCrt6PZwsnn0XySVnyPR1ZXAn72yx48bWJsu7apnI3Hy8bygUK5Js32qcytapqgmn95uexccj205vGgJ%2BeuOeG2SORmKZr%2FqKzcx9SFctMJdwMUFZDJITs7dnOp1EKZCxg304Cevyfya%2BvlKqv6aXK1qIj3imL%2BL6hL%2ByvUlFfE0VKZ7E8gBY3M%2F8VoJCFgizH1W6VyC76nH6b7jiibYVxUmVIEspry%2FLgZIlCeP11Z4zs%2FAwvVwtGFEut5S1JY4lfyT0N%2FevOLo%2BrUEgjcqc9IkGpQbv3iW7Co5b%2BKgjvpzYdH85PLcc4X21ouwEGl%2FS4qnUAvoSlXUUhR1eKr2VWFTB%2BGMl6FsiQsVD1R3urlAAIoSn7JQkmiVVCHSpCwDH%2FqPepXQ0Db77CJOAImohB%2BRPWr31ev5g%2FkE%2BzTa4lbvZo8xdWPffQu9yJTPCNB66s%2BzXoJt%2F0L6hSoCuBIoK8fnBGG87OoRckJpLqyWe4YbpGi50g0%2B3I3UD85Oa0fzubfoXxPLbW3FDWzigmyJeM0tQkax7PqTy80%2BUxfUHPlBZIRVNQ%2Bv0xRm8REKPoLmNr0%2BUo48v9GFbXPKylqQ2IKm00QddgyWGMROCTxdLB9nCY8P7j2DjlsV%2F%2Bmfr0C0r%2FNkeXbbpPlOTBBwT0mVz1zx9S%2FwJecBF9Wgv3p032iP2v4VSgfgW2G%2BHUEdEXU6iq4CtpLJfIN9XQG8dwa1VoO8XC2SrPDDyCOQptXgbcPvlAgBfxBoGwftQKeKFrNTASPt3pGGqDt%2FQRasn2kri%2BH6L80MJRsmVYJrAKyDItpJUy3%2F15WYIJqcJ9Q5N%2FLFJ4c3dc1URpWl9hW6mu50MUIelg4ucTPf15zs5DFo1c0VSp1tKB9jkwIyuM45kb%2BIP8gHed%2B6jO3v0KbIknzLy636E8KPTdCuUpB0wLo9JKnAO6pv0vS31EtBha%2FfJemkgLVVnd8KCk4qBTpQ5m7FbifBKrPJcq0pZAFVG%2FXbOFz%2BTcq2MLrcmV28Nmi%2FOHskh82bau0k8eWCaPijQPWQ5lUvslwVCfHkXBMIehqUgtDNLeauH1huvZTbYmw%2BluPjyWoNGEuxRLR7LK5fSyXFUyK7PURQv2v8D3XOt2NJ6liBbmPGOsakw1kbeOs%2B31Wm5qpH%2BiJWSzqdPr2O7zc2TmtnrzCig6bBd%2FvgQmzOlz0STWIlmZEQfupogOZFHUZ7EkUnMn0RrpIMqAgHRJAOjIJ3yGw1I%2FMAp9q9S3Q%2FclADNm1wEeO%2Bxbwg5OIYHZLY3ehG5lJk2xhco%2B6JWybpEVz2wrR6hZyD0QXZbeDVB%2BonmlimpkWprdAs4WEZDSQppsDlcdCBJJESIYFuAtUnC4GIF2C3Uu2Kv7L1bdz6FxtqxpG4TqQOqOUNAJ2HLvPWA2GgDy4O4vaDrtyl6P%2B1fAll%2BSyFcQ28GHqh7fvvf37udylf0fNwhzgz87Y%2Bcf5x9GnF6ygHu18sAbipWeF0YPBgp2GaKeQduxxdEr3SgbH1kvH7tvqSLhedomOvZyts2dw8acu3dY%2Ff%2BucuMtCuP%2Fe4zC4XnH3OLZ8ZuxTWxy8dJfU5dhDeKPSlJy5pn%2F%2B7u3XrJhmr9C5CuleGflGQocKnlAUaRKp0BAHV0ZwUt9VCqk6zYOgRIuMfePJzdmBdpPJ7%2F6B23%2Bf%2Bsp9NMDZevovvfYHG5dGPISQq1DojqNckchVrCcCYz%2FQ0hI0m3NKDRfkgsrnamo%2Bp0CAq1FyvC3a3Nak%2Fs5VX282x9Ufy3E39VAx6o7LpCvO2wK%2Bch9jNqpJCutcIOooKnYWtDK8gTRVYygRQfwgzKM5%2BjP2jOZdx3r32Py7rQUPOzAnoRs95NvRAR0qLGU11Taqu1bUYSzMcWjMEir067JQQHfIrLBHsrgv00%2FWavd8HRLMEEYFSW3HCSNQehnrHztKqHcDyo4VfZ6gPKCR%2BgufwA8GegxUEo4A%2Bgd0BASHiH6jYMLIsUdQJTs%2FC641KN4oCHWolCMLlMfIdtWKScjx7SM5LD9HnfmhrGI0S139UWfUnxgOXdJFW%2BAMcGjKr6eHAttHF5sUoeArYKDcxMSYcKA%2FxUDhPiEOEAPafSIUFArN0r24ynI91EPARDXvIDYyvqZaWeroBOUABQA%2FE%2BDXC7PWafDLQY2oiwpUEyj4RQtVlUp1GrM7In2p2A7VuiOW6otMiGOo5Mrp05ejVuTy6dNX%2Fk%2F7mybZQ0nUmfrbx3U4KueDnlHm5wdh8FFeKnoaKKh%2FTK18StOPhwG9Xo5mqXAxvw%2F79YQwwDR%2BnAKQQ4izVXioB84qcppWB7IqjU45z4CE17OvF1Dw%2BoTFqxtz8dxwtogBnF9MjIl%2Fin%2BK8s3hM9laIn0TiCbTAXL0T798bPXqx36p3chrv0O%2BGC9Xaj48Ecv8U8UEeBvUEsDlTepiU5OvlpeNGvpnKF0RvUooWhIjnx6GeBapXCQYTw9DNg6%2FOC3gZjp76oNTj9Kz6Jqobxb9NDqc08vcKReOpcsQV2K8InXFaXW3aI6Ofr1k48rp7CX7rx%2Bv1UKPsfvzQU0Kc83i2VdILmd2%2FyX55zT9luN2%2BCu4nKfwPcK%2FCvDVU%2BpHh8%2BLaldIf1fA5h3ndT6Fln9%2FW%2F9Ce1vndfvJtnPVO2xhm3qbafHVCN1X363UXHq9xuVD8OSD29Z8pZ5cZrern9cAdGW%2Fuib%2Fud%2BVK0L9a42r6C90kL8KzxwLQw9NkIQJL0ASU8M%2BVG0KsUdgdvpgP%2F6NqqP0%2FgHZFUfGEijZLHpiIgvV5%2FBltrj8Qd7XQd5p4P%2B7tJo30NMO6VGBwahSPMYiaaBYoLY6uEnciyhhh1Z%2FvvacG%2Frjpsvnpzs0B1Id6fmX8119l88XnOxe%2FuGrzzHcdu7UtY3%2B2vmXN5zUyj3ZcPl8p1sZSs6%2FnGXtwrV7Ka0XZdz83fwjjINpZWYw85lL8BRK4nGyIir2RiOsEyipuEcIakpGjWgBjLiHWOgj0Yi34gW1kKPxHt2Na5q%2Blwg1RdRSpFDNzosb44YJXnAfoEOpZW%2F%2F6u1lhYA6leevezbI26zNHO811M2dc5HFxpk4i1jPC0s21%2FBWW5DnPQbn2X1WK43%2FaM2n18DfSoybbNHijFpamzXI31eRibGUOxSu%2FlT96YZlq1Yt20DaSBuG6knw2eusHs5EPBfNmVvHKdaQzcDfz9ZsXmLDWGXy2U5OsYSsIn8CS12jQIyD12KKqZrLPy7mSPdICmd6WGHG8NDZkkHuE4h9TU8FpmUO%2FVjC%2FEinToFyoNDz2p9XD6g78WgQdPG7Z3R0T%2FZ5dTM9lsL8Ktek7szl2L%2BgQwGgwkZHc2g5Su7NvVqwGy2Ua4KSXUwt1X4PaM5paaEu6jQ5zVFyNabxvUksVt2T%2F4VeamYPlLtffdQsk%2B2sUTY%2FzDXl%2F05W53%2FBz9UK3p7LjapZ2ZxOm%2BUlZXrL3HHGqO8%2BwVroDaCTTnTxitMxmiAAYQzVJQH%2Bnj3oIHnPaN6Zq6sNSLjBl8tKgVr2mj%2F9CWi9dnKca8rBQBsd5R1tzVlgrl5pbnPw6kZclCr2CHxMnHohLz%2B3KRQokzALyeIKFU1TNCiayJdoHvDYe7K6mZLm8S3uJ9dojuaJ62%2FqN%2FtjQxnSnhnKPw%2BLNrLi8ZKyJ3x1YhiI1aNAtP6NzCGzYv3DmaGh%2FLvQZnt0evgIhTFV0kE%2FPYxAnOHhCQUZdCWY5JWJwMzlAGl1mpNbDU7yyGnhRMILsYhH3VRAijrPcBU8%2FCj1Y9NY6cnGVW0CjTLaz7E3epvaT%2FLtTV72Rs%2B0WVVmd0dz%2FMGTI5F0OsIviaqDlbbO5X6xT3PeXbXHRtf%2Fz%2Bfdka%2BeKPr8KF7IF4vBsT9MFPuPJMBTBMq9hQxXelQ%2Bbewnf18ap4Ib%2BmSMrtDU5zqlD8QANa5MBGh%2FOwOvSDfcV2d66mfEWsbGWmIz6nsyZDWQSmqmxDneYyvjHPmRXHZxeueyRGLZzvRioKnGto9nIPkibAJA16adcOZRQr1iAP3bUyBR7T4RgAWTKxhkCYFwshq%2B7iV9r0whk50cmRcTg4fy5x4OmmNkHndIA2%2BYuMbmE9dwGYB4KFTsvnDE6Ah47r%2FfE3AYI%2BoXADpkdlENcZ8OZEEf8FFGZNxMs6ZLpG3SUFLL7Q2kcFU%2FA%2FJsw%2BvWDa%2F7emewLaoeibaF1B9qUNnuqWK3%2BUfXYVL1v%2FomD15xxeDkPnXTOKSVcCbDGtOu0YQNpGAP7U1HU58UrqGu8xIbHtkQ3LVhb7Dx46ET3Ffcm1q0YcOizNmf3bC3VjWfAcpSv3MyTlgJ23FHQgmgvk%2Bgk8pL0mcCDOn08MDAQlf%2B%2FSlTZ1z12fnqntOhbOTL9%2FZdevbAPN%2Byby1f%2FuUtC%2Fixm8ZBo59LTXEW060hGrTDplNprWd58fwB%2Fb%2FE27BdS%2Fs7U%2BrGVCeQ46nzaw9QccnmZerGZZs3Yw9aVHt%2BKh6HN4ti6lxIhT%2FwahnZtWwzlY9QHQ2c79C%2BdxzvVDKy8GqKWQERO9YAKbpsDUTLdWV5dE8PVPjvj9pqw7ah%2FPFVtkit7aj6G5xY9mfJrCz1j1e0BcnPol4UjtrCdbahIVtd2HaURujnFJR8CuOuUUfhrGhgKKgjCYNSvCc1WKlEp8wHUaAYynFNyzZn%2B2MnYv36dbMDBTonl%2FT%2Fma5IKAyEGz%2B4eRnVtaX6tss2o34u8mWorFtuFgm4A6qK%2Fyp%2FgLEBVat5WnPDdKA574ubuFJ%2FIUfZ%2FY2Nt6mN%2BZNNTSTaeI56gKwkXerTe9DDHUw8%2FH35FY3nNN7GGuBKWhrV9ep%2B0k1WjNWVaHkW1yA%2BQHWNu8rtBw2a5YXuE40rs7%2FGA%2Bj09V3hA98yRnFPOGr8ltGlsFdD%2F7tRce3LH6Trcneuiy7K7J3khKu%2B3qUaXPWaX7T6%2FKfj9BX2eZq2XAcZT79u1ClJzUtHUqfqSMWBcZS43Ena0cUGLgpkKxB1QM%2B0Fxz10wgg6r5rltnFpH05pepUq3Y2HfYqeKRntmUFNz%2BXmcOs1H31U6cC6RTVLfCg7RNBF1UF2%2FwBgu0fFQtPEU1sSg3VcNsR7dWq3af87tUFn1l3ltXpaJxpNvtcZkH2WmMst3JqRpxUH%2BWC0E1qOGtP66s1MYv%2BVLu8%2FXFXvV%2FZbunYYBeVN64ls0ur6NzpV9xzlmQwB5qC4Tq70WC0tk8dWJXeHvkD0h9zJOM0vD86%2F1NJMaIAolctvlByferCsqOKDKceOfUu1PsmoFCamV5mCrMUOCi6V6FJosMF22AcrKJgQDVhfYh6tepp%2FlYgvnCEAbJQ1L0rOpajEmRcasMiPfxhgGoVo4rwreQpV6fUJHH2e8fa1s2c13Apl1b89a58ozdoap2sjgLN9uISl7P1DrulyeIkt0zr6JjWocoPOZsaXPb6jtqBblsgsaRre2xHi4nELm0MhG1%2Bx1SXwLpFi53b%2BaHRYo%2FIrbZtuWAKu5cSEXfybnnmUCaXGTpQr0xK2O2WWY76f%2BnAjNVf7nCZHU5XqIkTnpt6VtvsFlPXg1031g%2FVRdpkkyVpD7jnmax88QwDvg%2F66NnMRdRXTcGTmQc3cuINwN5IQqi0yzb%2BYFVHuVqI5s4ADfg5oE4ybDLd28mFSFmYvRoomsWXEdLU2Wl3GJy93ZNb%2Fd5gqmNaqJZSO1l6PVRy0nZIj%2F45EetjLguh1rLqR%2BSK0hO6NrsqcNX8zoUdjQYDJ7tb4os6%2Bi%2BY0qpY2AWlnLRDWdGFTfGY1gV0zNAtJ7pdo24se0D88AwLY%2FgZmE9iuP4V5v7CSR%2FRThaHLh%2BUeBkXwU6BC7lGOevK65udTv%2BtS%2FPfW7qj3ljTcj3b9OkbV85t8xsMj7Ddj7DGpthZKwKPvso%2Fc%2F1K9aLE12fMWLV1y1D9ua8lyJdWXr%2FbG%2BnoCFutf%2FmLILe39ITUV4igr3876fpX5g2zeB52sWnIL4fXHlgeUzOx5QfIvJQyrKQE9wHUqVq%2BPEaOrz0wVvNbJZVSfsuMzxN4l9PkedFzw9V5Dj%2BnzpgoT4ZxCxJfC5RWLc74YVHxKlExCYt0JAOMatREhHBSCAtSfod6x6Ls8HCWECLwXZ9nd5Dz1T24JUdWs6fU3%2B%2BfcnT49Qe%2BkBs%2BwdsMZgPXMp3U5S958snPP%2FEE7bvkOPCuTUDTUQ%2FUzirLhML9yPahoe1D5Fj5jWsaoveyP00PehdUAHk%2FseDVWsvDWXXXsyn%2F4wfpXc2V3%2FQxli3jl%2F5hj%2F83avSCfpTNxOEKLmTjxOEKuxgNlsQn0xgct724mhynupNW1Ph6o3RYS3%2F%2B2TJrzLlkFz%2Bip3qCHKf6eqW02QJLjBYuuj4sobhCWqa%2FYHGEHpcnumuWSOhxeaL7sOakNR6vvmo%2BYcfFA8UFXEPZf9UjyudIOyNwx%2Fi90DdsujS%2FFX2UAwvWSVK4NxaMhAGw3oowp%2Fuc8CTi7D2rBgZWwb%2F60faR7SPsEbjkXy4G0XaqhXPwe2cePjxjxuHD6ssQuR1fq6PF0E%2Bo2t1nePTn8TUmxz%2FA3crMoCc7egESuoTHYc7mYdg6etORoOhR7BBGD%2BqJopELrl4S6cJNRtEAsLP%2FOdvnJq0Wo0GolY2Et9VFB2Kf%2B4bZvVyxfOMz3WdFfSIryj6DwWghre7aQbdiDrkTL3A3vNDuDpk93HqXwam%2BbWmUJZfNn5ozKV5Pmmq8PF%2FjVY%2B2Tlk2M2RzSXKjmbQ4RZcQavEYrN%2F9rlXwtIQqzxQNMzPPfHYLvuPoO9TbT8bpGw5CQPGd%2BSyX%2FCyf0Vxjd2R9NmsunnXYa8xGHzn%2BsSfM5J0y0DZEXWWxkXjcR75KBLNLHi7XvX2G8VOrf4Ykg0AMdBESIpo7MgAfyakA6rkqpI6UjNs0px7cMV%2BD5BF49Tez1VGnYmq0WIijp985m4Sn2gJR9b07riPPFo97OYbUZbxJCpot7H%2FlpZBicglCPN7WOfJkcHqc3ElWqvvz%2F1E6bIQrG%2Btz6WkM1SM9FBTR7FSs8KyBBytSmNEoquJNFN5EQyTiCrnKDx1h58yxCepPHU5nxGoxEQeeOZi2m80DxNxncVhr6BmEfUarxejw%2BWSiHhWk19bSY7aKR5MsteblJpfTLtjimBouXsm3d3djjYM%2BwEW0El9dM%2FueVRWIsXwe43R7SgbVZqrnqoJ1X%2FkuF7pcgf8duv4q6vayV5U9zMV91GxO59UUjW8rHV6u799WzKMT7umRCXbYUKM%2BfoaCcwgaoqZUtmodV3p%2BX7akb4dnU9B9La38RPFUG2SCC90tVA4XwEFhyOpZZrUCsgWYHsczLFBBVGNtstoN1bw0Z%2BO4fYIbvZVt4EUcJEKOhHeincWqONw%2Bq6w5Go%2BWGOSR7LhKV%2BKBqbBPpfUvOf9QqkpDyVhBeyyZQGMsdA5FBUqvFMtUyGq9vjnsAJU4UcrxldP1CCaofyDkSAifoP5QwWx%2BSyUGxp75BzGAvtG7uQ38LehlyEQMeh0TeE6Bm7tYdXqdkt0uOb3kfYlNwmOdDyacOq%2FqlFo1v%2BPTmTi3E%2FglC9W11b34A22zmLzvb231Q0L2Bgg60OTW4YdstO%2BYOJnO38TtpH7zy9ymokWyA79qlVSn38HtpFlImFnhu3b4boNWXklOXV0Iwo7lQ1hrZyPFcwtjwFP7iEKSHSSJw509kh8kj6pr%2BH1jR7km9vcvqN9657vffefkv%2BfKxge1X%2B7RdjYUPIESN7gTvRkB%2FRMYtEkaVkdHApmdBPpnKmz0n1xSWFOyVIuLrinZwpoCRe6kyiVZoHX088F%2BUX4%2BWKS4iBTP0IWxGtZgOdMaV4KTayqHQF%2FVihBwTbgDXTCmKoOBJeNhwJMzEVjtjIFLuU38fPR7hqNG1JS7g%2FqRCuy3vmQ3W9Vu8qbVbP%2BSzazGRJH83MzP90Ck2m31mMjP8TiLn5uwD2Ugr2PFvPQjB5BnSJvQxGQZZEB%2BLopqzGzDbMmbkAPkZVJjeO5FzOSBKCgJze2ZS4Gemc9twrwY6u9H61iUQTcRvtdT9RW3tRxAWwFs2tcuJRnI6xjmBdWjbgFNRHMHiF1uHYBfUR%2Fut5Ug2jXAaT96%2B9RH%2FFToRwIzGbKmVJ1AZQnoabSB1yyIg7ByAridHApPMjyw0OiV6RjSbCuzwLAvFizBliWJua1tsuAgvNPbmljYbpt8lkWam7b3XZiOiKJskMOtmfScnsbPW208knwjuXrXK4Q1iKIgNyYXXDVT9C2Ye%2F78GQ5BEEXfFdde2RwauOysdJNL5AzCy84ard%2FnGAVN8alecnFdgu5Gbd5DJTL%2BhHZK0vApVy3OfU8XTSJg1TlssivsPYUlIqvn66PzrVTymCc4wgF6SDNR0pDf%2B9Gp%2BVnsUH5WtpHYsuhOaey8zdwLN47V8MTbm78g687%2BP3cx6tcAeNpjYGRgYGBk8s0%2FzBIfz2%2FzlUGeZQNQhOFCWfF0GP0%2F8P8c1jusIkAuBwMTSBQAYwQM6HjaY2BkYGAV%2Bd8KJgP%2FXWG9wwAUQQGLAYqPBl942n1TvUoDQRCe1VM8kWARjNrZGIurBAsRBIuA2vkAFsJiKTYW4guIjT5ARMgTxCLoA1hcb5OgDyGHrY7f7M65e8fpLF%2B%2B2W%2FnZ2eTmGfaIJi5I0qGDlZZcD51QzTTJirZPAI9JIwVA%2BwT8L5nOdMaV0AuMJ%2BicRHq8of6LSD18fzq8ds7xjpwBnQiSI9V5QVl6NwPvgM15NXn%2FAtWZyj3W0HjEXitOc%2FdIdbetPdFTZ%2BP6t%2BX7xU0%2Fk6GJtOe1%2FB3arN0%2Fpmz1J4UZc%2BD6ExwjD7vioeGd5HvhvU%2BR%2BDZcGZ6YBPNfAi0G97iBPwFXqph2cW8%2BD7kjMfwtinHb6kLb6Wygk3cZytSEoptGrlScdHtLPeri1JKueACMZfU1ViJG1Sq5E43dIt7SZZFl1zuRhb%2FGOs44xFVDbrJzB5tYs35OmaXTrEmkv0DajnMWQB42mNgYNCCwk0MLxheMPrhgUuY2JiUmOqY2pjWMD1hdmPOY%2B5hPsLCwWLEksSyiOUOawzrLrYiti%2FsCuxJ7Kc45DiSOPZxmnG2cG7jvMelweXDNYXrEbcBdxf3KR4OngheLd443g18fHwZfFv4NfiX8T8TEBIIEZggsEpQS7BMcJsQl5CFUI3QAWEp4RLhCyJaIldEbURXiJ4RYxEzE0sQ2yD2TzxIfJkEk4SeRJbENIkNEg8k%2FklqSGZITpE8InlL8p2UmVSG1A6pb9Jx0ltkjGSmyDySlZF1kc2RnSK7R%2FaZnJ5cmdwB%2BST5SwpuCvsUjRTLFHcoOShNU9qhzKespGyhXKV8SPmBCpOKgUqcyjSVR6omqgmqe9RE1OrUnqkHqO9R%2F6FholGgsUZzgeYZLTUtL60WbS7tKh0OnQydXTpvdGV0O3S%2F6Gnopekt0ruhz6fvpl%2Bnv0n%2Fh4GdQYvBJUMhwwTDdYYvjFSM4oxmGd0zVjK2M84w3mYiYZJgssLkkqmO6TzTF2Z2ZjVmd8ylzP3MJ5lfsRCwcLJoszhhyWXpZdlhecZKxirHapbVPesF1ndsJGwCbBbZ%2FLA1sn1jZ2XXY3fFXsM%2Bz36V%2FS8HD4cGh2OOTI51ThJOK5zeOUs4OzmXOS9wPuUi4JLgss7lm2uU6zY3NrcSty1u39zN3Mvct7l%2F8xDzMPLw88jyaPM44ynkaeEZ59niucqLyUvPKwgAn3OqOQAAAQAAARcApwARAAAAAAACAAAAAQABAAAAQAAuAAAAAHjarZK9TgJBEMf%2Fd6CRaAyRhMLqCgsbL4ciglTGRPEjSiSKlnLycXJ86CEniU%2FhM9jYWPgIFkYfwd6nsDD%2Bd1mBIIUx3mZnfzs3MzszuwDCeIYG8UUwQxmAFgxxPeeuyxrmcaNYxzTuFAewi0fFQSTxqXgM11pC8TgS2oPiCUS1d8Uh8ofiSczpYcVT5LjiCPlY8Qui%2BncOr7D02y6%2FBTCrP%2Fm%2Bb5bdTrPi2I26Z9qNGtbRQBMdXMJBGRW0YOCecxEWYoiTCvxrYBunqHPdoX2bLOyrMKlZg8thDETw5K7Itci1TXlGy0124QRZZLDFU%2FexhxztMozlosTpMH6ZPge0L%2BOKGnFKjJ4WRwppHPL0PP3SI2P9jLQwFOu3GRhDfkeyDo%2F%2FG7IHgzllZQxLdquvrdCyBVvat3seJlYo06gxapUxhU2JWnFygR03sSxnEkvcpf5Y5eibGq315TDp7fKWm8zbUVl71Aqq%2FZtNnlkWmLnQtno9ycvXYbA6W2pF3aKfCayyC0Ja7Fr%2FPW70%2FHO4YM0OKxFvzf0C1MyPjwAAeNpt1VWUU2cYRuHsgxenQt1d8%2F3JOUnqAyR1d%2FcCLQVKO22pu7tQd3d3d3d3d3cXmGzumrWy3pWLs%2FNdPDMpZaWu1783l1Lpf14MnfzO6FbqVupfGkD30iR60JNe9KYP09CXfvRnAAMZxGCGMG3pW6ZjemZgKDMyEzMzC7MyG7MzB3MyF3MzD%2FMyH%2FOzAAuyEAuzCIuyGIuzBGWCRIUqOQU16jRYkqVYmmVYluVYng6GMZwRNGmxAiuyEiuzCquyGquzBmuyFmuzDuuyHuuzARuyERuzCZuyGZuzBVuyFVuzDduyHdszklGMZgd2ZAw7MZZxjGdnJrALu9LJbuzOHkxkT%2FZib%2FZhX%2FZjfw7gQA7iYA7hUA7jcI7gSI7iaI7hWI7jeE7gRE7iZE5hEqdyGqdzBmdyFmdzDudyHudzARdyERdzCZdyGZdzBVdyFVdzDddyHddzAzdyEzdzC7dyG7dzB3dyF3dzD%2FdyH%2FfzAA%2FyEA%2FzCI%2FyGI%2FzBE%2FyFE%2FzDM%2FyHM%2FzAi%2FyEi%2FzCq%2FyGq%2FzBm%2FyFm%2FzDu%2FyHu%2FzAR%2FyER%2FzCZ%2FyGZ%2FzBV%2FyFV%2FzDd%2FyHd%2FzAz%2FyEz%2FzC7%2FyG7%2FzB3%2FyF3%2FzD%2F9mpYwsy7pl3bMeWc%2BsV9Y765NNk%2FXN%2BmX9swHZwGxQNjgb0nPkmInjR0V7Uq%2FOsaPL5Y7ylE3l8tQNN7kVt%2BrmbuHW3LrbcDvam1rtzVvdm50TxrU%2FDBvRtZUY1rV5a3jXFn550Wo%2FXDNWK3dFmh7X9LimxzU9qulRTY9qelTTo5rlKLt2wk7YiaprL%2ByFvbAX9pK9ZC%2FZS%2FaSvWQv2Uv2kr1kr2KvYq9ir2KvYq9ir2KvYq9ir2Kvaq9qr2qvaq9qr2qvaq9qr2qvai%2B3l9vL7eX2cnu5vdxebi%2B3l9sr7BV2CjuFncJOYaewU9gp7NTs1LyrZq9mr2avZq9mr2avZq9mr26vbq9ur26vbq9ur26vbq9ur26vYa9hr2GvYa9hr2GvYa%2FR7oXuQ%2Feh%2B2j%2FUU7e3C3cqc%2FV3fYdof%2FQf%2Bg%2F9B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6D92H7kP3ofvQfeg%2BdB%2B6D92H7kP3ofvQfRT29B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6D%2F2H%2FkP%2Fof%2FQf%2Bg%2F9B%2F6j6nuG3Ya7U5q%2F0hN3nCTW3Grbu4Wrs%2FrP%2Bk%2F6T%2FpP%2Bk%2F6T%2FpP%2Bk%2B6T7pPek86TzpPOk86TzpOuk66TrpOuk66TrpOlWmPu%2F36zrpOuk66TrpOuk66TrpOvl%2FPek76TvpO%2Bk76TvpO%2Bk76TvpO%2Bk76TvpO7V9t%2BqtVs%2FOaOURU6bo6PgPt6rZbwAAAAABVFDDFwAA%29%20format%28%27woff%27%29%2Curl%28data%3Aapplication%2Fx%2Dfont%2Dtruetype%3Bbase64%2CAAEAAAAPAIAAAwBwRkZUTW0ql9wAAAD8AAAAHEdERUYBRAAEAAABGAAAACBPUy8yZ7lriQAAATgAAABgY21hcNqt44EAAAGYAAAGcmN2dCAAKAL4AAAIDAAAAARnYXNw%2F%2F8AAwAACBAAAAAIZ2x5Zn1dwm8AAAgYAACUpGhlYWQFTS%2FYAACcvAAAADZoaGVhCkQEEQAAnPQAAAAkaG10eNLHIGAAAJ0YAAADdGxvY2Fv%2B5XOAACgjAAAAjBtYXhwAWoA2AAAorwAAAAgbmFtZbMsoJsAAKLcAAADonBvc3S6o%2BU1AACmgAAACtF3ZWJmwxhUUAAAsVQAAAAGAAAAAQAAAADMPaLPAAAAANB2gXUAAAAA0HZzlwABAAAADgAAABgAAAAAAAIAAQABARYAAQAEAAAAAgAAAAMEiwGQAAUABAMMAtAAAABaAwwC0AAAAaQAMgK4AAAAAAUAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAFVLV04AQAAg%2F%2F8DwP8QAAAFFAB7AAAAAQAAAAAAAAAAAAAAIAABAAAABQAAAAMAAAAsAAAACgAAAdwAAQAAAAAEaAADAAEAAAAsAAMACgAAAdwABAGwAAAAaABAAAUAKAAgACsAoAClIAogLyBfIKwgvSISIxsl%2FCYBJvonCScP4APgCeAZ4CngOeBJ4FngYOBp4HngieCX4QnhGeEp4TnhRuFJ4VnhaeF54YnhleGZ4gbiCeIW4hniIeIn4jniSeJZ4mD4%2F%2F%2F%2FAAAAIAAqAKAApSAAIC8gXyCsIL0iEiMbJfwmASb6JwknD%2BAB4AXgEOAg4DDgQOBQ4GDgYuBw4IDgkOEB4RDhIOEw4UDhSOFQ4WDhcOGA4ZDhl%2BIA4gniEOIY4iHiI%2BIw4kDiUOJg%2BP%2F%2F%2F%2F%2Fj%2F9r%2FZv9i4Ajf5N%2B132nfWd4F3P3aHdoZ2SHZE9kOIB0gHCAWIBAgCiAEH%2F4f%2BB%2F3H%2FEf6x%2FlH3wfdh9wH2ofZB9jH10fVx9RH0sfRR9EHt4e3B7WHtUezh7NHsUevx65HrMIFQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAACjAAAAAAAAAA1AAAAIAAAACAAAAADAAAAKgAAACsAAAAEAAAAoAAAAKAAAAAGAAAApQAAAKUAAAAHAAAgAAAAIAoAAAAIAAAgLwAAIC8AAAATAAAgXwAAIF8AAAAUAAAgrAAAIKwAAAAVAAAgvQAAIL0AAAAWAAAiEgAAIhIAAAAXAAAjGwAAIxsAAAAYAAAl%2FAAAJfwAAAAZAAAmAQAAJgEAAAAaAAAm%2BgAAJvoAAAAbAAAnCQAAJwkAAAAcAAAnDwAAJw8AAAAdAADgAQAA4AMAAAAeAADgBQAA4AkAAAAhAADgEAAA4BkAAAAmAADgIAAA4CkAAAAwAADgMAAA4DkAAAA6AADgQAAA4EkAAABEAADgUAAA4FkAAABOAADgYAAA4GAAAABYAADgYgAA4GkAAABZAADgcAAA4HkAAABhAADggAAA4IkAAABrAADgkAAA4JcAAAB1AADhAQAA4QkAAAB9AADhEAAA4RkAAACGAADhIAAA4SkAAACQAADhMAAA4TkAAACaAADhQAAA4UYAAACkAADhSAAA4UkAAACrAADhUAAA4VkAAACtAADhYAAA4WkAAAC3AADhcAAA4XkAAADBAADhgAAA4YkAAADLAADhkAAA4ZUAAADVAADhlwAA4ZkAAADbAADiAAAA4gYAAADeAADiCQAA4gkAAADlAADiEAAA4hYAAADmAADiGAAA4hkAAADtAADiIQAA4iEAAADvAADiIwAA4icAAADwAADiMAAA4jkAAAD1AADiQAAA4kkAAAD%2FAADiUAAA4lkAAAEJAADiYAAA4mAAAAETAAD4%2FwAA%2BP8AAAEUAAH1EQAB9REAAAEVAAH2qgAB9qoAAAEWAAYCCgAAAAABAAABAAAAAAAAAAAAAAAAAAAAAQACAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAEAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAL4AAAAAf%2F%2FAAIAAgAoAAABaAMgAAMABwAusQEALzyyBwQA7TKxBgXcPLIDAgDtMgCxAwAvPLIFBADtMrIHBgH8PLIBAgDtMjMRIRElMxEjKAFA%2Fujw8AMg%2FOAoAtAAAQBkAGQETARMAFsAAAEyFh8BHgEdATc%2BAR8BFgYPATMyFhcWFRQGDwEOASsBFx4BDwEGJi8BFRQGBwYjIiYvAS4BPQEHDgEvASY2PwEjIiYnJjU0Nj8BPgE7AScuAT8BNhYfATU0Njc2AlgPJgsLCg%2BeBxYIagcCB57gChECBgMCAQIRCuCeBwIHaggWB54PCikiDyYLCwoPngcWCGoHAgee4AoRAgYDAgECEQrgngcCB2oIFgeeDwopBEwDAgECEQrgngcCB2oIFgeeDwopIg8mCwsKD54HFghqBwIHnuAKEQIGAwIBAhEK4J4HAgdqCBYHng8KKSIPJgsLCg%2BeBxYIagcCB57gChECBgAAAAABAAAAAARMBEwAIwAAATMyFhURITIWHQEUBiMhERQGKwEiJjURISImPQE0NjMhETQ2AcLIFR0BXhUdHRX%2Boh0VyBUd%2FqIVHR0VAV4dBEwdFf6iHRXIFR3%2BohUdHRUBXh0VyBUdAV4VHQAAAAABAHAAAARABEwARQAAATMyFgcBBgchMhYPAQ4BKwEVITIWDwEOASsBFRQGKwEiJj0BISImPwE%2BATsBNSEiJj8BPgE7ASYnASY2OwEyHwEWMj8BNgM5%2BgoFCP6UBgUBDAoGBngGGAp9ARMKBgZ4BhgKfQ8LlAsP%2Fu0KBgZ4BhgKff7tCgYGeAYYCnYFBv6UCAUK%2BhkSpAgUCKQSBEwKCP6UBgwMCKAIDGQMCKAIDK4LDw8LrgwIoAgMZAwIoAgMDAYBbAgKEqQICKQSAAABAGQABQSMBK4AOwAAATIXFhcjNC4DIyIOAwchByEGFSEHIR4EMzI%2BAzUzBgcGIyInLgEnIzczNjcjNzM%2BATc2AujycDwGtSM0QDkXEys4MjAPAXtk%2FtQGAZZk%2FtQJMDlCNBUWOUA0I64eYmunznYkQgzZZHABBdpkhhQ%2BH3UErr1oaS1LMCEPCx4uTzJkMjJkSnRCKw8PIjBKK6trdZ4wqndkLzVkV4UljQAAAgB7AAAETASwAD4ARwAAASEyHgUVHAEVFA4FKwEHITIWDwEOASsBFRQGKwEiJj0BISImPwE%2BATsBNSEiJj8BPgE7ARE0NhcRMzI2NTQmIwGsAV5DakIwFgwBAQwWMEJqQ7ICASAKBgZ4BhgKigsKlQoP%2FvUKBgZ4BhgKdf71CgYGeAYYCnUPtstALS1ABLAaJD8yTyokCwsLJCpQMkAlGmQMCKAIDK8LDg8KrwwIoAgMZAwIoAgMAdsKD8j%2B1EJWVEAAAAEAyAGQBEwCvAAPAAATITIWHQEUBiMhIiY9ATQ2%2BgMgFR0dFfzgFR0dArwdFcgVHR0VyBUdAAAAAgDIAAAD6ASwACUAQQAAARUUBisBFRQGBx4BHQEzMhYdASE1NDY7ATU0NjcuAT0BIyImPQEXFRQWFx4BFAYHDgEdASE1NCYnLgE0Njc%2BAT0BA%2BgdFTJjUVFjMhUd%2FOAdFTJjUVFjMhUdyEE3HCAgHDdBAZBBNxwgIBw3QQSwlhUdZFuVIyOVW5YdFZaWFR2WW5UjI5VbZB0VlshkPGMYDDI8MgwYYzyWljxjGAwyPDIMGGM8ZAAAAAEAAAAAAAAAAAAAAAAxAAAB%2F%2FIBLATCBEEAFgAAATIWFzYzMhYVFAYjISImNTQ2NyY1NDYB9261LCwueKqqeP0ST3FVQgLYBEF3YQ6teHmtclBFaw4MGZnXAAAAAgAAAGQEsASvABoAHgAAAB4BDwEBMzIWHQEhNTQ2OwEBJyY%2BARYfATc2AyEnAwL2IAkKiAHTHhQe%2B1AeFB4B1IcKCSAkCm9wCXoBebbDBLMTIxC7%2FRYlFSoqFSUC6rcQJBQJEJSWEPwecAIWAAAAAAQAAABkBLAETAALABcAIwA3AAATITIWBwEGIicBJjYXARYUBwEGJjURNDYJATYWFREUBicBJjQHARYGIyEiJjcBNjIfARYyPwE2MhkEfgoFCP3MCBQI%2FcwIBQMBCAgI%2FvgICgoDjAEICAoKCP74CFwBbAgFCvuCCgUIAWwIFAikCBQIpAgUBEwKCP3JCAgCNwgK2v74CBQI%2FvgIBQoCJgoF%2FvABCAgFCv3aCgUIAQgIFID%2BlAgKCggBbAgIpAgIpAgAAAAD%2F%2FD%2F8AS6BLoACQANABAAAAAyHwEWFA8BJzcTAScJAQUTA%2BAmDpkNDWPWXyL9mdYCZv4f%2FrNuBLoNmQ4mDlzWYP50%2FZrWAmb8anABTwAAAAEAAAAABLAEsAAPAAABETMyFh0BITU0NjsBEQEhArz6FR384B0V%2Bv4MBLACiv3aHRUyMhUdAiYCJgAAAAEADgAIBEwEnAAfAAABJTYWFREUBgcGLgE2NzYXEQURFAYHBi4BNjc2FxE0NgFwAoUnMFNGT4gkV09IQv2oWEFPiCRXT0hCHQP5ow8eIvzBN1EXGSltchkYEAIJm%2F2iKmAVGilucRoYEQJ%2FJioAAAACAAn%2F%2BAS7BKcAHQApAAAAMh4CFQcXFAcBFgYPAQYiJwEGIycHIi4CND4BBCIOARQeATI%2BATQmAZDItoNOAQFOARMXARY7GikT%2Fu13jgUCZLaDTk6DAXKwlFZWlLCUVlYEp06DtmQCBY15%2Fu4aJRg6FBQBEk0BAU6Dtsi2g1tWlLCUVlaUsJQAAQBkAFgErwREABkAAAE%2BAh4CFRQOAwcuBDU0PgIeAQKJMHt4dVg2Q3mEqD4%2Bp4V4Qzhadnh5A7VESAUtU3ZAOXmAf7JVVbJ%2FgHk5QHZTLQVIAAAAAf%2FTAF4EewSUABgAAAETNjIXEyEyFgcFExYGJyUFBiY3EyUmNjMBl4MHFQeBAaUVBhH%2BqoIHDxH%2Bqf6qEQ8Hgv6lEQYUAyABYRMT%2Fp8RDPn%2BbxQLDPb3DAsUAZD7DBEAAv%2FTAF4EewSUABgAIgAAARM2MhcTITIWBwUTFgYnJQUGJjcTJSY2MwUjFwc3Fyc3IycBl4MHFQeBAaUVBhH%2BqoIHDxH%2Bqf6qEQ8Hgv6lEQYUAfPwxUrBw0rA6k4DIAFhExP%2BnxEM%2Bf5vFAsM9vcMCxQBkPsMEWSO4ouM5YzTAAABAAAAAASwBLAAJgAAATIWHQEUBiMVFBYXBR4BHQEUBiMhIiY9ATQ2NyU%2BAT0BIiY9ATQ2Alh8sD4mDAkBZgkMDwr7ggoPDAkBZgkMJj6wBLCwfPouaEsKFwbmBRcKXQoPDwpdChcF5gYXCktoLvp8sAAAAA0AAAAABLAETAAPABMAIwAnACsALwAzADcARwBLAE8AUwBXAAATITIWFREUBiMhIiY1ETQ2FxUzNSkBIgYVERQWMyEyNjURNCYzFTM1BRUzNSEVMzUFFTM1IRUzNQchIgYVERQWMyEyNjURNCYFFTM1IRUzNQUVMzUhFTM1GQR%2BCg8PCvuCCg8PVWQCo%2F3aCg8PCgImCg8Pc2T8GGQDIGT8GGQDIGTh%2FdoKDw8KAiYKDw%2F872QDIGT8GGQDIGQETA8K%2B%2BYKDw8KBBoKD2RkZA8K%2FqIKDw8KAV4KD2RkyGRkZGTIZGRkZGQPCv6iCg8PCgFeCg9kZGRkZMhkZGRkAAAEAAAAAARMBEwADwAfAC8APwAAEyEyFhURFAYjISImNRE0NikBMhYVERQGIyEiJjURNDYBITIWFREUBiMhIiY1ETQ2KQEyFhURFAYjISImNRE0NjIBkBUdHRX%2BcBUdHQJtAZAVHR0V%2FnAVHR39vQGQFR0dFf5wFR0dAm0BkBUdHRX%2BcBUdHQRMHRX%2BcBUdHRUBkBUdHRX%2BcBUdHRUBkBUd%2FagdFf5wFR0dFQGQFR0dFf5wFR0dFQGQFR0AAAkAAAAABEwETAAPAB8ALwA%2FAE8AXwBvAH8AjwAAEzMyFh0BFAYrASImPQE0NiEzMhYdARQGKwEiJj0BNDYhMzIWHQEUBisBIiY9ATQ2ATMyFh0BFAYrASImPQE0NiEzMhYdARQGKwEiJj0BNDYhMzIWHQEUBisBIiY9ATQ2ATMyFh0BFAYrASImPQE0NiEzMhYdARQGKwEiJj0BNDYhMzIWHQEUBisBIiY9ATQ2MsgVHR0VyBUdHQGlyBUdHRXIFR0dAaXIFR0dFcgVHR389cgVHR0VyBUdHQGlyBUdHRXIFR0dAaXIFR0dFcgVHR389cgVHR0VyBUdHQGlyBUdHRXIFR0dAaXIFR0dFcgVHR0ETB0VyBUdHRXIFR0dFcgVHR0VyBUdHRXIFR0dFcgVHf5wHRXIFR0dFcgVHR0VyBUdHRXIFR0dFcgVHR0VyBUd%2FnAdFcgVHR0VyBUdHRXIFR0dFcgVHR0VyBUdHRXIFR0ABgAAAAAEsARMAA8AHwAvAD8ATwBfAAATMzIWHQEUBisBIiY9ATQ2KQEyFh0BFAYjISImPQE0NgEzMhYdARQGKwEiJj0BNDYpATIWHQEUBiMhIiY9ATQ2ATMyFh0BFAYrASImPQE0NikBMhYdARQGIyEiJj0BNDYyyBUdHRXIFR0dAaUCvBUdHRX9RBUdHf6FyBUdHRXIFR0dAaUCvBUdHRX9RBUdHf6FyBUdHRXIFR0dAaUCvBUdHRX9RBUdHQRMHRXIFR0dFcgVHR0VyBUdHRXIFR3%2BcB0VyBUdHRXIFR0dFcgVHR0VyBUd%2FnAdFcgVHR0VyBUdHRXIFR0dFcgVHQAAAAABACYALAToBCAAFwAACQE2Mh8BFhQHAQYiJwEmND8BNjIfARYyAdECOwgUB7EICPzxBxUH%2FoAICLEHFAirBxYB3QI7CAixBxQI%2FPAICAGACBQHsQgIqwcAAQBuAG4EQgRCACMAAAEXFhQHCQEWFA8BBiInCQEGIi8BJjQ3CQEmND8BNjIXCQE2MgOIsggI%2FvUBCwgIsggVB%2F70%2FvQHFQiyCAgBC%2F71CAiyCBUHAQwBDAcVBDuzCBUH%2FvT%2B9AcVCLIICAEL%2FvUICLIIFQcBDAEMBxUIsggI%2FvUBDAcAAwAX%2F%2BsExQSZABkAJQBJAAAAMh4CFRQHARYUDwEGIicBBiMiLgI0PgEEIg4BFB4BMj4BNCYFMzIWHQEzMhYdARQGKwEVFAYrASImPQEjIiY9ATQ2OwE1NDYBmcSzgk1OASwICG0HFQj%2B1HeOYrSBTU2BAW%2BzmFhYmLOZWFj%2BvJYKD0sKDw8KSw8KlgoPSwoPDwpLDwSZTYKzYo15%2FtUIFQhsCAgBK01NgbTEs4JNWJmzmFhYmLOZIw8KSw8KlgoPSwoPDwpLDwqWCg9LCg8AAAMAF%2F%2FrBMUEmQAZACUANQAAADIeAhUUBwEWFA8BBiInAQYjIi4CND4BBCIOARQeATI%2BATQmBSEyFh0BFAYjISImPQE0NgGZxLOCTU4BLAgIbQcVCP7Ud45itIFNTYEBb7OYWFiYs5lYWP5YAV4KDw8K%2FqIKDw8EmU2Cs2KNef7VCBUIbAgIAStNTYG0xLOCTViZs5hYWJizmYcPCpYKDw8KlgoPAAAAAAIAFwAXBJkEsAAPAC0AAAEzMhYVERQGKwEiJjURNDYFNRYSFRQOAiIuAjU0EjcVDgEVFB4BMj4BNTQmAiZkFR0dFWQVHR0BD6fSW5vW6tabW9KnZ3xyxejFcnwEsB0V%2FnAVHR0VAZAVHeGmPv7ZuHXWm1tbm9Z1uAEnPqY3yHh0xXJyxXR4yAAEAGQAAASwBLAADwAfAC8APwAAATMyFhURFAYrASImNRE0NgEzMhYVERQGKwEiJjURNDYBMzIWFREUBisBIiY1ETQ2BTMyFh0BFAYrASImPQE0NgQBlgoPDwqWCg8P%2Ft6WCg8PCpYKDw%2F%2B3pYKDw8KlgoPD%2F7elgoPDwqWCg8PBLAPCvuCCg8PCgR%2BCg%2F%2BcA8K%2FRIKDw8KAu4KD%2F7UDwr%2BPgoPDwoBwgoPyA8K%2BgoPDwr6Cg8AAAAAAgAaABsElgSWAEcATwAAATIfAhYfATcWFwcXFh8CFhUUDwIGDwEXBgcnBwYPAgYjIi8CJi8BByYnNycmLwImNTQ%2FAjY%2FASc2Nxc3Nj8CNhIiBhQWMjY0AlghKSYFMS0Fhj0rUAMZDgGYBQWYAQ8YA1AwOIYFLDIFJisfISkmBTEtBYY8LFADGQ0ClwYGlwINGQNQLzqFBS0xBSYreLJ%2BfrJ%2BBJYFmAEOGQJQMDmGBSwxBiYrHiIoJgYxLAWGPSxRAxkOApcFBZcCDhkDUTA5hgUtMAYmKiAhKCYGMC0Fhj0sUAIZDgGYBf6ZfrF%2BfrEABwBkAAAEsAUUABMAFwAhACUAKQAtADEAAAEhMhYdASEyFh0BITU0NjMhNTQ2FxUhNQERFAYjISImNREXETMRMxEzETMRMxEzETMRAfQBLCk7ARMKD%2Fu0DwoBEzspASwBLDsp%2FUQpO2RkZGRkZGRkBRQ7KWQPCktLCg9kKTtkZGT%2B1PzgKTs7KQMgZP1EArz9RAK8%2FUQCvP1EArwAAQAMAAAFCATRAB8AABMBNjIXARYGKwERFAYrASImNREhERQGKwEiJjURIyImEgJsCBUHAmAIBQqvDwr6Cg%2F%2B1A8K%2BgoPrwoFAmoCYAcH%2FaAICv3BCg8PCgF3%2FokKDw8KAj8KAAIAZAAAA%2BgEsAARABcAAAERFBYzIREUBiMhIiY1ETQ2MwEjIiY9AQJYOykBLB0V%2FOAVHR0VA1L6FR0EsP5wKTv9dhUdHRUETBUd%2FnAdFfoAAwAXABcEmQSZAA8AGwAwAAAAMh4CFA4CIi4CND4BBCIOARQeATI%2BATQmBTMyFhURMzIWHQEUBisBIiY1ETQ2AePq1ptbW5vW6tabW1ubAb%2FoxXJyxejFcnL%2BfDIKD68KDw8K%2BgoPDwSZW5vW6tabW1ub1urWmztyxejFcnLF6MUNDwr%2B7Q8KMgoPDwoBXgoPAAAAAAL%2FnAAABRQEsAALAA8AACkBAyMDIQEzAzMDMwEDMwMFFP3mKfIp%2FeYBr9EVohTQ%2Fp4b4BsBkP5wBLD%2B1AEs%2FnD%2B1AEsAAAAAAIAZAAABLAEsAAVAC8AAAEzMhYVETMyFgcBBiInASY2OwERNDYBMzIWFREUBiMhIiY1ETQ2OwEyFh0BITU0NgImyBUdvxQLDf65DSYN%2FrkNCxS%2FHQJUMgoPDwr75goPDwoyCg8DhA8EsB0V%2Fj4XEP5wEBABkBAXAcIVHfzgDwr%2BogoPDwoBXgoPDwqvrwoPAAMAFwAXBJkEmQAPABsAMQAAADIeAhQOAiIuAjQ%2BAQQiDgEUHgEyPgE0JgUzMhYVETMyFgcDBiInAyY2OwERNDYB4%2BrWm1tbm9bq1ptbW5sBv%2BjFcnLF6MVycv58lgoPiRUKDd8NJg3fDQoViQ8EmVub1urWm1tbm9bq1ps7csXoxXJyxejFDQ8K%2Fu0XEP7tEBABExAXARMKDwAAAAMAFwAXBJkEmQAPABsAMQAAADIeAhQOAiIuAjQ%2BAQQiDgEUHgEyPgE0JiUTFgYrAREUBisBIiY1ESMiJjcTNjIB4%2BrWm1tbm9bq1ptbW5sBv%2BjFcnLF6MVycv7n3w0KFYkPCpYKD4kVCg3fDSYEmVub1urWm1tbm9bq1ps7csXoxXJyxejFAf7tEBf%2B7QoPDwoBExcQARMQAAAAAAIAAAAABLAEsAAZADkAABMhMhYXExYVERQGBwYjISImJyY1EzQ3Ez4BBSEiBgcDBhY7ATIWHwEeATsBMjY%2FAT4BOwEyNicDLgHhAu4KEwO6BwgFDBn7tAweAgYBB7kDEwKX%2FdQKEgJXAgwKlgoTAiYCEwr6ChMCJgITCpYKDAJXAhIEsA4K%2FXQYGf5XDB4CBggEDRkBqRkYAowKDsgOC%2F4%2BCw4OCpgKDg4KmAoODgsBwgsOAAMAFwAXBJkEmQAPABsAJwAAADIeAhQOAiIuAjQ%2BAQQiDgEUHgEyPgE0JgUXFhQPAQYmNRE0NgHj6tabW1ub1urWm1tbmwG%2F6MVycsXoxXJy%2Fov9ERH9EBgYBJlbm9bq1ptbW5vW6tabO3LF6MVycsXoxV2%2BDCQMvgwLFQGQFQsAAQAXABcEmQSwACgAAAE3NhYVERQGIyEiJj8BJiMiDgEUHgEyPgE1MxQOAiIuAjQ%2BAjMyA7OHBwsPCv6WCwQHhW2BdMVycsXoxXKWW5vW6tabW1ub1nXABCSHBwQL%2FpYKDwsHhUxyxejFcnLFdHXWm1tbm9bq1ptbAAAAAAIAFwABBJkEsAAaADUAAAE3NhYVERQGIyEiJj8BJiMiDgEVIzQ%2BAjMyEzMUDgIjIicHBiY1ETQ2MyEyFg8BFjMyPgEDs4cHCw8L%2FpcLBAeGboF0xXKWW5vWdcDrllub1nXAnIYHCw8LAWgKBQiFboJ0xXIEJIcHBAv%2BlwsPCweGS3LFdHXWm1v9v3XWm1t2hggFCgFoCw8LB4VMcsUAAAAKAGQAAASwBLAADwAfAC8APwBPAF8AbwB%2FAI8AnwAAEyEyFhURFAYjISImNRE0NgUhIgYVERQWMyEyNjURNCYFMzIWHQEUBisBIiY9ATQ2MyEyFh0BFAYjISImPQE0NgczMhYdARQGKwEiJj0BNDYzITIWHQEUBiMhIiY9ATQ2BzMyFh0BFAYrASImPQE0NjMhMhYdARQGIyEiJj0BNDYHMzIWHQEUBisBIiY9ATQ2MyEyFh0BFAYjISImPQE0Nn0EGgoPDwr75goPDwPA%2FK4KDw8KA1IKDw%2F9CDIKDw8KMgoPD9IBwgoPDwr%2BPgoPD74yCg8PCjIKDw%2FSAcIKDw8K%2Fj4KDw%2B%2BMgoPDwoyCg8P0gHCCg8PCv4%2BCg8PvjIKDw8KMgoPD9IBwgoPDwr%2BPgoPDwSwDwr7ggoPDwoEfgoPyA8K%2FK4KDw8KA1IKD2QPCjIKDw8KMgoPDwoyCg8PCjIKD8gPCjIKDw8KMgoPDwoyCg8PCjIKD8gPCjIKDw8KMgoPDwoyCg8PCjIKD8gPCjIKDw8KMgoPDwoyCg8PCjIKDwAAAAACAAAAAARMBLAAGQAjAAABNTQmIyEiBh0BIyIGFREUFjMhMjY1ETQmIyE1NDY7ATIWHQEDhHVT%2FtRSdmQpOzspA4QpOzsp%2FageFMgUHgMgyFN1dlLIOyn9qCk7OykCWCk7lhUdHRWWAAIAZAAABEwETAAJADcAABMzMhYVESMRNDYFMhcWFREUBw4DIyIuAScuAiMiBwYjIicmNRE%2BATc2HgMXHgIzMjc2fTIKD2QPA8AEBRADIUNAMRwaPyonKSxHHlVLBwgGBQ4WeDsXKC4TOQQpLUUdZ1AHBEwPCvvNBDMKDzACBhH%2BWwYGO1AkDQ0ODg8PDzkFAwcPAbY3VwMCAwsGFAEODg5XCAAAAwAAAAAEsASXACEAMQBBAAAAMh4CFREUBisBIiY1ETQuASAOARURFAYrASImNRE0PgEDMzIWFREUBisBIiY1ETQ2ITMyFhURFAYrASImNRE0NgHk6N6jYw8KMgoPjeT%2B%2BuSNDwoyCg9joyqgCAwMCKAIDAwCYKAIDAwIoAgMDASXY6PedP7UCg8PCgEsf9FyctF%2F%2FtQKDw8KASx03qP9wAwI%2FjQIDAwIAcwIDAwI%2FjQIDAwIAcwIDAAAAAACAAAA0wRHA90AFQA5AAABJTYWFREUBiclJisBIiY1ETQ2OwEyBTc2Mh8BFhQPARcWFA8BBiIvAQcGIi8BJjQ%2FAScmND8BNjIXAUEBAgkMDAn%2B%2FhUZ%2BgoPDwr6GQJYeAcUByIHB3h4BwciBxQHeHgHFAciBwd3dwcHIgcUBwMurAYHCv0SCgcGrA4PCgFeCg%2BEeAcHIgcUB3h4BxQHIgcHd3cHByIHFAd4eAcUByIICAAAAAACAAAA0wNyA90AFQAvAAABJTYWFREUBiclJisBIiY1ETQ2OwEyJTMWFxYVFAcGDwEiLwEuATc2NTQnJjY%2FATYBQQECCQwMCf7%2BFRn6Cg8PCvoZAdIECgZgWgYLAwkHHQcDBkhOBgMIHQcDLqwGBwr9EgoHBqwODwoBXgoPZAEJgaGafwkBAQYXBxMIZ36EaggUBxYFAAAAAAMAAADEBGID7AAbADEASwAAATMWFxYVFAYHBgcjIi8BLgE3NjU0JicmNj8BNgUlNhYVERQGJyUmKwEiJjURNDY7ATIlMxYXFhUUBwYPASIvAS4BNzY1NCcmNj8BNgPHAwsGh0RABwoDCQcqCAIGbzs3BgIJKgf9ggECCQwMCf7%2BFRn6Cg8PCvoZAdIECgZgWgYLAwkHHQcDBkhOBgMIHQcD7AEJs9lpy1QJAQYiBhQIlrJarEcJFAYhBb6sBgcK%2FRIKBwasDg8KAV4KD2QBCYGhmn8JAQEGFwcTCGd%2BhGoIFQYWBQAAAAANAAAAAASwBLAACQAVABkAHQAhACUALQA7AD8AQwBHAEsATwAAATMVIxUhFSMRIQEjFTMVIREjESM1IQURIREhESERBSM1MwUjNTMBMxEhETM1MwEzFSMVIzUjNTM1IzUhBREhEQcjNTMFIzUzASM1MwUhNSEB9GRk%2FnBkAfQCvMjI%2FtTIZAJY%2B7QBLAGQASz84GRkArxkZP1EyP4MyGQB9MhkyGRkyAEs%2FUQBLGRkZAOEZGT%2BDGRkAfT%2B1AEsA4RkZGQCWP4MZMgBLAEsyGT%2B1AEs%2FtQBLMhkZGT%2BDP4MAfRk%2FtRkZGRkyGTI%2FtQBLMhkZGT%2B1GRkZAAAAAAJAAAAAASwBLAAAwAHAAsADwATABcAGwAfACMAADcjETMTIxEzASMRMxMjETMBIxEzASE1IRcjNTMXIzUzBSM1M2RkZMhkZAGQyMjIZGQBLMjI%2FOD%2B1AEsyGRkyGRkASzIyMgD6PwYA%2Bj8GAPo%2FBgD6PwYA%2Bj7UGRkW1tbW1sAAAIAAAAKBKYEsAANABUAAAkBFhQHAQYiJwETNDYzBCYiBhQWMjYB9AKqCAj%2BMAgUCP1WAQ8KAUM7Uzs7UzsEsP1WCBQI%2FjAICAKqAdsKD807O1Q7OwAAAAADAAAACgXSBLAADQAZACEAAAkBFhQHAQYiJwETNDYzIQEWFAcBBiIvAQkBBCYiBhQWMjYB9AKqCAj%2BMAgUCP1WAQ8KAwYCqggI%2FjAIFAg4Aaj9RP7TO1M7O1M7BLD9VggUCP4wCAgCqgHbCg%2F9VggUCP4wCAg4AaoCvM07O1Q7OwAAAAABAGQAAASwBLAAJgAAASEyFREUDwEGJjURNCYjISIPAQYWMyEyFhURFAYjISImNRE0PwE2ASwDOUsSQAgKDwr9RBkSQAgFCgK8Cg8PCvyuCg8SixIEsEv8fBkSQAgFCgO2Cg8SQAgKDwr8SgoPDwoDzxkSixIAAAABAMj%2F%2FwRMBLAACgAAEyEyFhURCQERNDb6AyAVHf4%2B%2Fj4dBLAdFfuCAbz%2BQwR%2FFR0AAAAAAwAAAAAEsASwABUARQBVAAABISIGBwMGHwEeATMhMjY%2FATYnAy4BASMiBg8BDgEjISImLwEuASsBIgYVERQWOwEyNj0BNDYzITIWHQEUFjsBMjY1ETQmASEiBg8BBhYzITI2LwEuAQM2%2FkQLEAFOBw45BhcKAcIKFwY%2BDgdTARABVpYKFgROBBYK%2FdoKFgROBBYKlgoPDwqWCg8PCgLuCg8PCpYKDw%2F%2Bsf4MChMCJgILCgJYCgsCJgITBLAPCv7TGBVsCQwMCWwVGAEtCg%2F%2BcA0JnAkNDQmcCQ0PCv12Cg8PCpYKDw8KlgoPDwoCigoP%2FagOCpgKDg4KmAoOAAAAAAQAAABkBLAETAAdACEAKQAxAAABMzIeAh8BMzIWFREUBiMhIiY1ETQ2OwE%2BBAEVMzUEIgYUFjI2NCQyFhQGIiY0AfTIOF00JAcGlik7Oyn8GCk7OymWAgknM10ByGT%2Bz76Hh76H%2Fu9WPDxWPARMKTs7FRQ7Kf2oKTs7KQJYKTsIG0U1K%2F7UZGRGh76Hh74IPFY8PFYAAAAAAgA1AAAEsASvACAAIwAACQEWFx4BHwEVITUyNi8BIQYHBh4CMxUhNTY3PgE%2FAQEDIQMCqQGBFCgSJQkK%2Fl81LBFS%2Fnk6IgsJKjIe%2FpM4HAwaBwcBj6wBVKIEr%2FwaMioTFQECQkJXLd6RWSIuHAxCQhgcDCUNDQPu%2FVoByQAAAAADAGQAAAPwBLAAJwAyADsAAAEeBhUUDgMjITU%2BATURNC4EJzUFMh4CFRQOAgclMzI2NTQuAisBETMyNjU0JisBAvEFEzUwOyodN1htbDD%2BDCk7AQYLFyEaAdc5dWM%2BHy0tEP6Pi05pESpTPnbYUFJ9Xp8CgQEHGB0zOlIuQ3VONxpZBzMoAzsYFBwLEAkHRwEpSXNDM1s6KwkxYUopOzQb%2FK5lUFqBAAABAMgAAANvBLAAGQAAARcOAQcDBhYXFSE1NjcTNjQuBCcmJzUDbQJTQgeECSxK%2Fgy6Dq0DAw8MHxUXDQYEsDkTNSj8uTEoBmFhEFIDQBEaExAJCwYHAwI5AAAAAAL%2FtQAABRQEsAAlAC8AAAEjNC4FKwERFBYfARUhNTI%2BAzURIyIOBRUjESEFIxEzByczESM3BRQyCAsZEyYYGcgyGRn%2BcAQOIhoWyBkYJhMZCwgyA%2Bj7m0tLfX1LS30DhBUgFQ4IAwH8rhYZAQJkZAEFCRUOA1IBAwgOFSAVASzI%2FOCnpwMgpwACACH%2FtQSPBLAAJQAvAAABIzQuBSsBERQWHwEVITUyPgM1ESMiDgUVIxEhEwc1IRUnNxUhNQRMMggLGRMmGBnIMhkZ%2FnAEDiIaFsgZGCYTGQsIMgPoQ6f84KenAyADhBUgFQ4IAwH9dhYZAQJkZAEFCRUOAooBAwgOFSAVASz7gn1LS319S0sABAAAAAAEsARMAA8AHwAvAD8AABMhMhYdARQGIyEiJj0BNDYTITIWHQEUBiMhIiY9ATQ2EyEyFh0BFAYjISImPQE0NhMhMhYdARQGIyEiJj0BNDYyAlgVHR0V%2FagVHR0VA%2BgVHR0V%2FBgVHR0VAyAVHR0V%2FOAVHR0VBEwVHR0V%2B7QVHR0ETB0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR0ABAAAAAAEsARMAA8AHwAvAD8AABMhMhYdARQGIyEiJj0BNDYDITIWHQEUBiMhIiY9ATQ2EyEyFh0BFAYjISImPQE0NgMhMhYdARQGIyEiJj0BNDb6ArwVHR0V%2FUQVHR2zBEwVHR0V%2B7QVHR3dArwVHR0V%2FUQVHR2zBEwVHR0V%2B7QVHR0ETB0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR0ABAAAAAAEsARMAA8AHwAvAD8AAAE1NDYzITIWHQEUBiMhIiYBNTQ2MyEyFh0BFAYjISImEzU0NjMhMhYdARQGIyEiJgE1NDYzITIWHQEUBiMhIiYB9B0VAlgVHR0V%2FagVHf5wHRUD6BUdHRX8GBUdyB0VAyAVHR0V%2FOAVHf7UHRUETBUdHRX7tBUdA7ZkFR0dFWQVHR3%2B6WQVHR0VZBUdHf7pZBUdHRVkFR0d%2FulkFR0dFWQVHR0AAAQAAAAABLAETAAPAB8ALwA%2FAAATITIWHQEUBiMhIiY9ATQ2EyEyFh0BFAYjISImPQE0NhMhMhYdARQGIyEiJj0BNDYTITIWHQEUBiMhIiY9ATQ2MgRMFR0dFfu0FR0dFQRMFR0dFfu0FR0dFQRMFR0dFfu0FR0dFQRMFR0dFfu0FR0dBEwdFWQVHR0VZBUd%2FtQdFWQVHR0VZBUd%2FtQdFWQVHR0VZBUd%2FtQdFWQVHR0VZBUdAAgAAAAABLAETAAPAB8ALwA%2FAE8AXwBvAH8AABMzMhYdARQGKwEiJj0BNDYpATIWHQEUBiMhIiY9ATQ2ATMyFh0BFAYrASImPQE0NikBMhYdARQGIyEiJj0BNDYBMzIWHQEUBisBIiY9ATQ2KQEyFh0BFAYjISImPQE0NgEzMhYdARQGKwEiJj0BNDYpATIWHQEUBiMhIiY9ATQ2MmQVHR0VZBUdHQFBAyAVHR0V%2FOAVHR3%2B6WQVHR0VZBUdHQFBAyAVHR0V%2FOAVHR3%2B6WQVHR0VZBUdHQFBAyAVHR0V%2FOAVHR3%2B6WQVHR0VZBUdHQFBAyAVHR0V%2FOAVHR0ETB0VZBUdHRVkFR0dFWQVHR0VZBUd%2FtQdFWQVHR0VZBUdHRVkFR0dFWQVHf7UHRVkFR0dFWQVHR0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR0dFWQVHR0VZBUdAAAG%2F5wAAASwBEwAAwATACMAKgA6AEoAACEjETsCMhYdARQGKwEiJj0BNDYTITIWHQEUBiMhIiY9ATQ2BQc1IzUzNQUhMhYdARQGIyEiJj0BNDYTITIWHQEUBiMhIiY9ATQ2AZBkZJZkFR0dFWQVHR0VAfQVHR0V%2FgwVHR3%2B%2BqfIyAHCASwVHR0V%2FtQVHR0VAlgVHR0V%2FagVHR0ETB0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR36fUtkS68dFWQVHR0VZBUd%2FtQdFWQVHR0VZBUdAAAABgAAAAAFFARMAA8AEwAjACoAOgBKAAATMzIWHQEUBisBIiY9ATQ2ASMRMwEhMhYdARQGIyEiJj0BNDYFMxUjFSc3BSEyFh0BFAYjISImPQE0NhMhMhYdARQGIyEiJj0BNDYyZBUdHRVkFR0dA2dkZPyuAfQVHR0V%2FgwVHR0EL8jIp6f75gEsFR0dFf7UFR0dFQJYFR0dFf2oFR0dBEwdFWQVHR0VZBUd%2B7QETP7UHRVkFR0dFWQVHchkS319rx0VZBUdHRVkFR3%2B1B0VZBUdHRVkFR0AAAAAAgAAAMgEsAPoAA8AEgAAEyEyFhURFAYjISImNRE0NgkCSwLuHywsH%2F0SHywsBIT%2B1AEsA%2BgsH%2F12HywsHwKKHyz9RAEsASwAAwAAAAAEsARMAA8AFwAfAAATITIWFREUBiMhIiY1ETQ2FxE3BScBExEEMhYUBiImNCwEWBIaGhL7qBIaGkr3ASpKASXs%2FNJwTk5wTgRMGhL8DBIaGhID9BIaZP0ftoOcAT7%2B4AH0dE5vT09vAAAAAAIA2wAFBDYEkQAWAB4AAAEyHgEVFAcOAQ8BLgQnJjU0PgIWIgYUFjI2NAKIdcZzRkWyNjYJIV5YbSk8RHOft7eCgreCBJF4ynVzj23pPz4IIWZomEiEdVijeUjDgriBgbgAAAACABcAFwSZBJkADwAXAAAAMh4CFA4CIi4CND4BAREiDgEUHgEB4%2BrWm1tbm9bq1ptbW5sBS3TFcnLFBJlbm9bq1ptbW5vW6tab%2FG8DVnLF6MVyAAACAHUAAwPfBQ8AGgA1AAABHgYVFA4DBy4DNTQ%2BBQMOAhceBBcWNj8BNiYnLgInJjc2IyYCKhVJT1dOPiUzVnB9P1SbfEokP0xXUEm8FykoAwEbITEcExUWAgYCCQkFEikMGiACCAgFD0iPdXdzdYdFR4BeRiYEBTpjl1lFh3ZzeHaQ%2Ff4hS4I6JUEnIw4IBwwQIgoYBwQQQSlZtgsBAAAAAwAAAAAEywRsAAwAKgAvAAABNz4CHgEXHgEPAiUhMhcHISIGFREUFjMhMjY9ATcRFAYjISImNRE0NgkBBzcBA%2BhsAgYUFR0OFgoFBmz9BQGQMje7%2FpApOzspAfQpO8i7o%2F5wpbm5Azj%2BlqE3AWMD9XMBAgIEDw4WKgsKc8gNuzsp%2FgwpOzsptsj%2BtKW5uaUBkKW5%2Ftf%2BljKqAWMAAgAAAAAEkwRMABsANgAAASEGByMiBhURFBYzITI2NTcVFAYjISImNRE0NgUBFhQHAQYmJzUmDgMHPgY3NT4BAV4BaaQ0wyk7OykB9Ck7yLml%2FnClubkCfwFTCAj%2BrAcLARo5ZFRYGgouOUlARioTAQsETJI2Oyn%2BDCk7OymZZ6W5uaUBkKW5G%2F7TBxUH%2Fs4GBAnLAQINFjAhO2JBNB0UBwHSCgUAAAAAAgAAAAAEnQRMAB0ANQAAASEyFwchIgYVERQWMyEyNj0BNxUUBiMhIiY1ETQ2CQE2Mh8BFhQHAQYiLwEmND8BNjIfARYyAV4BXjxDsv6jKTs7KQH0KTvIuaX%2BcKW5uQHKAYsHFQdlBwf97QcVB%2FgHB2UHFQdvCBQETBexOyn%2BDCk7OylFyNulubmlAZCluf4zAYsHB2UHFQf97AcH%2BAcVB2UHB28HAAAAAQAKAAoEpgSmADsAAAkBNjIXARYGKwEVMzU0NhcBFhQHAQYmPQEjFTMyFgcBBiInASY2OwE1IxUUBicBJjQ3ATYWHQEzNSMiJgE%2BAQgIFAgBBAcFCqrICggBCAgI%2FvgICsiqCgUH%2FvwIFAj%2B%2BAgFCq%2FICgj%2B%2BAgIAQgICsivCgUDlgEICAj%2B%2BAgKyK0KBAf%2B%2FAcVB%2F73BwQKrcgKCP74CAgBCAgKyK0KBAcBCQcVBwEEBwQKrcgKAAEAyAAAA4QETAAZAAATMzIWFREBNhYVERQGJwERFAYrASImNRE0NvpkFR0B0A8VFQ%2F%2BMB0VZBUdHQRMHRX%2BSgHFDggV%2FBgVCA4Bxf5KFR0dFQPoFR0AAAABAAAAAASwBEwAIwAAEzMyFhURATYWFREBNhYVERQGJwERFAYnAREUBisBIiY1ETQ2MmQVHQHQDxUB0A8VFQ%2F%2BMBUP%2FjAdFWQVHR0ETB0V%2FkoBxQ4IFf5KAcUOCBX8GBUIDgHF%2FkoVCA4Bxf5KFR0dFQPoFR0AAAABAJ0AGQSwBDMAFQAAAREUBicBERQGJwEmNDcBNhYVEQE2FgSwFQ%2F%2BMBUP%2FhQPDwHsDxUB0A8VBBr8GBUIDgHF%2FkoVCA4B4A4qDgHgDggV%2FkoBxQ4IAAAAAQDIABYEMwQ2AAsAABMBFhQHAQYmNRE0NvMDLhIS%2FNISGRkEMv4OCx4L%2Fg4LDhUD6BUOAAIAyABkA4QD6AAPAB8AABMzMhYVERQGKwEiJjURNDYhMzIWFREUBisBIiY1ETQ2%2BsgVHR0VyBUdHQGlyBUdHRXIFR0dA%2BgdFfzgFR0dFQMgFR0dFfzgFR0dFQMgFR0AAAEAyABkBEwD6AAPAAABERQGIyEiJjURNDYzITIWBEwdFfzgFR0dFQMgFR0DtvzgFR0dFQMgFR0dAAAAAAEAAAAZBBMEMwAVAAABETQ2FwEWFAcBBiY1EQEGJjURNDYXAfQVDwHsDw%2F%2BFA8V%2FjAPFRUPAmQBthUIDv4gDioO%2FiAOCBUBtv47DggVA%2BgVCA4AAAH%2F%2FgACBLMETwAjAAABNzIWFRMUBiMHIiY1AwEGJjUDAQYmNQM0NhcBAzQ2FwEDNDYEGGQUHgUdFWQVHQL%2BMQ4VAv4yDxUFFQ8B0gIVDwHSAh0ETgEdFfwYFR0BHRUBtf46DwkVAbX%2BOQ4JFAPoFQkP%2Fj4BthQJDv49AbYVHQAAAQEsAAAD6ARMABkAAAEzMhYVERQGKwEiJjURAQYmNRE0NhcBETQ2A1JkFR0dFWQVHf4wDxUVDwHQHQRMHRX8GBUdHRUBtv47DggVA%2BgVCA7%2BOwG2FR0AAAIAZADIBLAESAALABsAAAkBFgYjISImNwE2MgEhMhYdARQGIyEiJj0BNDYCrgH1DwkW%2B%2B4WCQ8B9Q8q%2FfcD6BUdHRX8GBUdHQQ5%2FeQPFhYPAhwP%2FUgdFWQVHR0VZBUdAAEAiP%2F8A3UESgAFAAAJAgcJAQN1%2FqABYMX92AIoA4T%2Bn%2F6fxgIoAiYAAAAAAQE7%2F%2FwEKARKAAUAAAkBJwkBNwQo%2FdnGAWH%2Bn8YCI%2F3ZxgFhAWHGAAIAFwAXBJkEmQAPADMAAAAyHgIUDgIiLgI0PgEFIyIGHQEjIgYdARQWOwEVFBY7ATI2PQEzMjY9ATQmKwE1NCYB4%2BrWm1tbm9bq1ptbW5sBfWQVHZYVHR0Vlh0VZBUdlhUdHRWWHQSZW5vW6tabW1ub1urWm7odFZYdFWQVHZYVHR0Vlh0VZBUdlhUdAAAAAAIAFwAXBJkEmQAPAB8AAAAyHgIUDgIiLgI0PgEBISIGHQEUFjMhMjY9ATQmAePq1ptbW5vW6tabW1ubAkX%2BDBUdHRUB9BUdHQSZW5vW6tabW1ub1urWm%2F5%2BHRVkFR0dFWQVHQACABcAFwSZBJkADwAzAAAAMh4CFA4CIi4CND4BBCIPAScmIg8BBhQfAQcGFB8BFjI%2FARcWMj8BNjQvATc2NC8BAePq1ptbW5vW6tabW1ubAeUZCXh4CRkJjQkJeHgJCY0JGQl4eAkZCY0JCXh4CQmNBJlbm9bq1ptbW5vW6tabrQl4eAkJjQkZCXh4CRkJjQkJeHgJCY0JGQl4eAkZCY0AAgAXABcEmQSZAA8AJAAAADIeAhQOAiIuAjQ%2BAQEnJiIPAQYUHwEWMjcBNjQvASYiBwHj6tabW1ub1urWm1tbmwEVVAcVCIsHB%2FIHFQcBdwcHiwcVBwSZW5vW6tabW1ub1urWm%2F4xVQcHiwgUCPEICAF3BxUIiwcHAAAAAAMAFwAXBJkEmQAPADsASwAAADIeAhQOAiIuAjQ%2BAQUiDgMVFDsBFjc%2BATMyFhUUBgciDgUHBhY7ATI%2BAzU0LgMTIyIGHQEUFjsBMjY9ATQmAePq1ptbW5vW6tabW1ubAT8dPEIyIRSDHgUGHR8UFw4TARkOGhITDAIBDQ6tBx4oIxgiM0Q8OpYKDw8KlgoPDwSZW5vW6tabW1ub1urWm5ELHi9PMhkFEBQQFRIXFgcIBw4UHCoZCBEQKDhcNi9IKhsJ%2FeMPCpYKDw8KlgoPAAADABcAFwSZBJkADwAfAD4AAAAyHgIUDgIiLgI0PgEFIyIGHQEUFjsBMjY9ATQmAyMiBh0BFBY7ARUjIgYdARQWMyEyNj0BNCYrARE0JgHj6tabW1ub1urWm1tbmwGWlgoPDwqWCg8PCvoKDw8KS0sKDw8KAV4KDw8KSw8EmVub1urWm1tbm9bq1ptWDwqWCg8PCpYKD%2F7UDwoyCg%2FIDwoyCg8PCjIKDwETCg8AAgAAAAAEsASwAC8AXwAAATMyFh0BHgEXMzIWHQEUBisBDgEHFRQGKwEiJj0BLgEnIyImPQE0NjsBPgE3NTQ2ExUUBisBIiY9AQ4BBzMyFh0BFAYrAR4BFzU0NjsBMhYdAT4BNyMiJj0BNDY7AS4BAg2WCg9nlxvCCg8PCsIbl2cPCpYKD2eXG8IKDw8KwhuXZw%2B5DwqWCg9EZheoCg8PCqgXZkQPCpYKD0RmF6gKDw8KqBdmBLAPCsIbl2cPCpYKD2eXG8IKDw8KwhuXZw8KlgoPZ5cbwgoP%2Fs2oCg8PCqgXZkQPCpYKD0RmF6gKDw8KqBdmRA8KlgoPRGYAAwAXABcEmQSZAA8AGwA%2FAAAAMh4CFA4CIi4CND4BBCIOARQeATI%2BATQmBxcWFA8BFxYUDwEGIi8BBwYiLwEmND8BJyY0PwE2Mh8BNzYyAePq1ptbW5vW6tabW1ubAb%2FoxXJyxejFcnKaQAcHfHwHB0AHFQd8fAcVB0AHB3x8BwdABxUHfHwHFQSZW5vW6tabW1ub1urWmztyxejFcnLF6MVaQAcVB3x8BxUHQAcHfHwHB0AHFQd8fAcVB0AHB3x8BwAAAAMAFwAXBJkEmQAPABsAMAAAADIeAhQOAiIuAjQ%2BAQQiDgEUHgEyPgE0JgcXFhQHAQYiLwEmND8BNjIfATc2MgHj6tabW1ub1urWm1tbmwG%2F6MVycsXoxXJyg2oHB%2F7ACBQIyggIagcVB0%2FFBxUEmVub1urWm1tbm9bq1ps7csXoxXJyxejFfWoHFQf%2BvwcHywcVB2oICE%2FFBwAAAAMAFwAXBJkEmQAPABgAIQAAADIeAhQOAiIuAjQ%2BAQUiDgEVFBcBJhcBFjMyPgE1NAHj6tabW1ub1urWm1tbmwFLdMVyQQJLafX9uGhzdMVyBJlbm9bq1ptbW5vW6tabO3LFdHhpAktB0P24PnLFdHMAAAAAAQAXAFMEsAP5ABUAABMBNhYVESEyFh0BFAYjIREUBicBJjQnAgoQFwImFR0dFf3aFxD99hACRgGrDQoV%2Ft0dFcgVHf7dFQoNAasNJgAAAAABAAAAUwSZA%2FkAFQAACQEWFAcBBiY1ESEiJj0BNDYzIRE0NgJ%2FAgoQEP32EBf92hUdHRUCJhcD8f5VDSYN%2FlUNChUBIx0VyBUdASMVCgAAAAEAtwAABF0EmQAVAAAJARYGIyERFAYrASImNREhIiY3ATYyAqoBqw0KFf7dHRXIFR3%2B3RUKDQGrDSYEif32EBf92hUdHRUCJhcQAgoQAAAAAQC3ABcEXQSwABUAAAEzMhYVESEyFgcBBiInASY2MyERNDYCJsgVHQEjFQoN%2FlUNJg3%2BVQ0KFQEjHQSwHRX92hcQ%2FfYQEAIKEBcCJhUdAAABAAAAtwSZBF0AFwAACQEWFAcBBiY1EQ4DBz4ENxE0NgJ%2FAgoQEP32EBdesKWBJAUsW4fHfhcEVf5VDSYN%2FlUNChUBIwIkRHVNabGdcUYHAQYVCgACAAAAAASwBLAAFQArAAABITIWFREUBi8BBwYiLwEmND8BJyY2ASEiJjURNDYfATc2Mh8BFhQPARcWBgNSASwVHRUOXvkIFAhqBwf5Xg4I%2FiH%2B1BUdFQ5e%2BQgUCGoHB%2FleDggEsB0V%2FtQVCA5e%2BQcHaggUCPleDhX7UB0VASwVCA5e%2BQcHaggUCPleDhUAAAACAEkASQRnBGcAFQArAAABFxYUDwEXFgYjISImNRE0Nh8BNzYyASEyFhURFAYvAQcGIi8BJjQ%2FAScmNgP2agcH%2BV4OCBX%2B1BUdFQ5e%2BQgU%2FQwBLBUdFQ5e%2BQgUCGoHB%2FleDggEYGoIFAj5Xg4VHRUBLBUIDl75B%2F3xHRX%2B1BUIDl75BwdqCBQI%2BV4OFQAAAAADABcAFwSZBJkADwAfAC8AAAAyHgIUDgIiLgI0PgEFIyIGFxMeATsBMjY3EzYmAyMiBh0BFBY7ATI2PQE0JgHj6tabW1ub1urWm1tbmwGz0BQYBDoEIxQ2FCMEOgQYMZYKDw8KlgoPDwSZW5vW6tabW1ub1urWm7odFP7SFB0dFAEuFB3%2BDA8KlgoPDwqWCg8AAAAABQAAAAAEsASwAEkAVQBhAGgAbwAAATIWHwEWHwEWFxY3Nj8BNjc2MzIWHwEWHwIeATsBMhYdARQGKwEiBh0BIREjESE1NCYrASImPQE0NjsBMjY1ND8BNjc%2BBAUHBhY7ATI2LwEuAQUnJgYPAQYWOwEyNhMhIiY1ESkBERQGIyERAQQJFAUFFhbEFQ8dCAsmxBYXERUXMA0NDgQZCAEPCj0KDw8KMgoP%2FnDI%2FnAPCjIKDw8KPQsOCRkFDgIGFRYfAp2mBwQK2woKAzMDEP41sQgQAzMDCgrnCwMe%2FokKDwGQAlgPCv6JBLAEAgIKDXYNCxUJDRZ2DQoHIREQFRh7LAkLDwoyCg8PCq8BLP7UrwoPDwoyCg8GBQQwgBkUAwgWEQ55ogcKDgqVCgSqnQcECo8KDgr8cg8KAXf%2BiQoPAZAAAAAAAgAAAAwErwSmACsASQAAATYWFQYCDgQuAScmByYOAQ8BBiY1NDc%2BATc%2BAScuAT4BNz4GFyYGBw4BDwEOBAcOARY2Nz4CNz4DNz4BBI0IGgItQmxhi2KORDg9EQQRMxuZGhYqCFUYEyADCQIQOjEnUmFch3vAJQgdHyaiPT44XHRZUhcYDhItIRmKcVtGYWtbKRYEBKYDEwiy%2Ft3IlVgxEQgLCwwBAQIbG5kYEyJAJghKFRE8Hzdff4U%2FM0o1JSMbL0QJGCYvcSEhHjZST2c1ODwEJygeW0AxJUBff1UyFAABAF0AHgRyBM8ATwAAAQ4BHgQXLgc%2BATceAwYHDgQHBicmNzY3PgQuAScWDgMmJy4BJyY%2BBDcGHgM3PgEuAicmPgMCjScfCic4R0IgBBsKGAoQAwEJEg5gikggBhANPkpTPhZINx8SBgsNJysiCRZOQQoVNU1bYC9QZwICBAUWITsoCAYdJzIYHw8YIiYHDyJJYlkEz0OAZVxEOSQMBzgXOB42IzElKRIqg5Gnl0o3Z0c6IAYWCwYNAwQFIDhHXGF1OWiqb0sdBxUknF0XNTQ8PEUiNWNROBYJDS5AQVUhVZloUSkAAAAAA%2F%2FcAGoE1ARGABsAPwBRAAAAMh4FFA4FIi4FND4EBSYGFxYVFAYiJjU0NzYmBwYHDgEXHgQyPgM3NiYnJgUHDgEXFhcWNj8BNiYnJicuAQIGpJ17bk85HBw6T257naKde25POhwcOU9uewIPDwYIGbD4sBcIBw5GWg0ECxYyWl%2BDiINfWjIWCwQMWv3%2FIw8JCSU4EC0OIw4DDywtCyIERi1JXGJcSSpJXGJcSS0tSVxiXEkqSVxiXEncDwYTOT58sLB8OzcTBg9FcxAxEiRGXkQxMEVeRSQSMRF1HiQPLxJEMA0EDyIPJQ8sSRIEAAAABP%2FcAAAE1ASwABQAJwA7AEwAACEjNy4ENTQ%2BBTMyFzczEzceARUUDgMHNz4BNzYmJyYlBgcOARceBBc3LgE1NDc2JhcHDgEXFhcWNj8CJyYnLgECUJQfW6l2WSwcOU9ue51SPUEglCYvbIknUGqYUi5NdiYLBAw2%2FVFGWg0ECxIqSExoNSlrjxcIB3wjDwkJJTgQLQ4MFgMsLQsieBRhdHpiGxVJXGJcSS0Pef5StVXWNBpacm5jGq0xiD8SMRFGckVzEDESHjxRQTkNmhKnbjs3EwZwJA8vEkQwDQQPC1YELEkSBAAAAAP%2FngAABRIEqwALABgAKAAAJwE2FhcBFgYjISImJSE1NDY7ATIWHQEhAQczMhYPAQ4BKwEiJi8BJjZaAoIUOBQCghUbJfryJRsBCgFZDwqWCg8BWf5DaNAUGAQ6BCMUNhQjBDoEGGQEKh8FIfvgIEdEhEsKDw8KSwLT3x0U%2FBQdHRT8FB0AAAABAGQAFQSwBLAAKAAAADIWFREBHgEdARQGJyURFh0BFAYvAQcGJj0BNDcRBQYmPQE0NjcBETQCTHxYAWsPFhgR%2FplkGhPNzRMaZP6ZERgWDwFrBLBYPv6t%2FrsOMRQpFA0M%2Bf75XRRAFRAJgIAJEBVAFF0BB%2FkMDRQpFDEOAUUBUz4AAAARAAAAAARMBLAAHQAnACsALwAzADcAOwA%2FAEMARwBLAE8AUwBXAFsAXwBjAAABMzIWHQEzMhYdASE1NDY7ATU0NjsBMhYdASE1NDYBERQGIyEiJjURFxUzNTMVMzUzFTM1MxUzNTMVMzUFFTM1MxUzNTMVMzUzFTM1MxUzNQUVMzUzFTM1MxUzNTMVMzUzFTM1A1JkFR0yFR37tB0VMh0VZBUdAfQdAQ8dFfwYFR1kZGRkZGRkZGRk%2FHxkZGRkZGRkZGT8fGRkZGRkZGRkZASwHRUyHRWWlhUdMhUdHRUyMhUd%2FnD9EhUdHRUC7shkZGRkZGRkZGRkyGRkZGRkZGRkZGTIZGRkZGRkZGRkZAAAAAMAAAAZBXcElwAZACUANwAAARcWFA8BBiY9ASMBISImPQE0NjsBATM1NDYBBycjIiY9ATQ2MyEBFxYUDwEGJj0BIyc3FzM1NDYEb%2FkPD%2FkOFZ%2F9qP7dFR0dFdECWPEV%2FamNetEVHR0VASMDGvkPD%2FkOFfG1jXqfFQSN5g4qDuYOCBWW%2FagdFWQVHQJYlhUI%2FpiNeh0VZBUd%2Fk3mDioO5g4IFZa1jXqWFQgAAAABAAAAAASwBEwAEgAAEyEyFhURFAYjIQERIyImNRE0NmQD6Ck7Oyn9rP7QZCk7OwRMOyn9qCk7%2FtQBLDspAlgpOwAAAAMAZAAABEwEsAAJABMAPwAAEzMyFh0BITU0NiEzMhYdASE1NDYBERQOBSIuBTURIRUUFRwBHgYyPgYmNTQ9AZbIFR3%2B1B0C0cgVHf7UHQEPBhgoTGacwJxmTCgYBgEsAwcNFB8nNkI2Jx8TDwUFAQSwHRX6%2BhUdHRX6%2BhUd%2FnD%2B1ClJalZcPigoPlxWakkpASz6CRIVKyclIRsWEAgJEBccISUnKhURCPoAAAAB%2F%2F8A1ARMA8IABQAAAQcJAScBBEzG%2Fp%2F%2Bn8UCJwGbxwFh%2Fp%2FHAicAAQAAAO4ETQPcAAUAAAkCNwkBBE392v3ZxgFhAWEDFf3ZAifH%2Fp8BYQAAAAAC%2F1EAZAVfA%2BgAFAApAAABITIWFREzMhYPAQYiLwEmNjsBESElFxYGKwERIRchIiY1ESMiJj8BNjIBlALqFR2WFQgO5g4qDuYOCBWW%2FoP%2BHOYOCBWWAYHX%2FRIVHZYVCA7mDioD6B0V%2FdkVDvkPD%2FkOFQGRuPkOFf5wyB0VAiYVDvkPAAABAAYAAASeBLAAMAAAEzMyFh8BITIWBwMOASMhFyEyFhQGKwEVFAYiJj0BIRUUBiImPQEjIiYvAQMjIiY0NjheERwEJgOAGB4FZAUsIf2HMAIXFR0dFTIdKh3%2B1B0qHR8SHQYFyTYUHh4EsBYQoiUY%2FiUVK8gdKh0yFR0dFTIyFR0dFTIUCQoDwR0qHQAAAAACAAAAAASwBEwACwAPAAABFSE1MzQ2MyEyFhUFIREhBLD7UMg7KQEsKTv9RASw%2B1AD6GRkKTs7Kcj84AACAAAAAAXcBEwADAAQAAATAxEzNDYzITIWFSEVBQEhAcjIyDspASwqOgH0ASz%2B1PtQASwDIP5wAlgpOzspyGT9RAK8AAEBRQAAA2sErwAbAAABFxYGKwERMzIWDwEGIi8BJjY7AREjIiY%2FATYyAnvmDggVlpYVCA7mDioO5g4IFZaWFQgO5g4qBKD5DhX9pxUO%2BQ8P%2BQ4VAlkVDvkPAAAAAQABAUQErwNrABsAAAEXFhQPAQYmPQEhFRQGLwEmND8BNhYdASE1NDYDqPkODvkPFf2oFQ%2F5Dg75DxUCWBUDYOUPKQ%2FlDwkUl5cUCQ%2FlDykP5Q8JFZWVFQkAAAAEAAAAAASwBLAACQAZAB0AIQAAAQMuASMhIgYHAwUhIgYdARQWMyEyNj0BNCYFNTMVMzUzFQSRrAUkFP1gFCQFrAQt%2FBgpOzspA%2BgpOzv%2Bq2RkZAGQAtwXLSgV%2FR1kOylkKTs7KWQpO8hkZGRkAAAAA%2F%2BcAGQEsARMAAsAIwAxAAAAMhYVERQGIiY1ETQDJSMTFgYjIisBIiYnAj0BNDU0PgE7ASUBFSIuAz0BND4CNwRpKh0dKh1k%2FV0mLwMRFQUCVBQdBDcCCwzIAqP8GAQOIhoWFR0dCwRMHRX8rhUdHRUDUhX8mcj%2B7BAIHBUBUQ76AgQQDw36%2FtT6AQsTKRwyGigUDAEAAAACAEoAAARmBLAALAA1AAABMzIWDwEeARcTFzMyFhQGBw4EIyIuBC8BLgE0NjsBNxM%2BATcnJjYDFjMyNw4BIiYCKV4UEgYSU3oPP3YRExwaEggeZGqfTzl0XFU%2BLwwLEhocExF2Pw96UxIGEyQyNDUxDDdGOASwFRMlE39N%2FrmtHSkoBwQLHBYSCg4REg4FBAgoKR2tAUdNfhQgExr7vgYGMT09AAEAFAAUBJwEnAAXAAABNwcXBxcHFycHJwcnBzcnNyc3Jxc3FzcDIOBO6rS06k7gLZubLeBO6rS06k7gLZubA7JO4C2bmy3gTuq0tOpO4C2bmy3gTuq0tAADAAAAZASwBLAAIQAtAD0AAAEzMhYdAQchMhYdARQHAw4BKwEiJi8BIyImNRE0PwI%2BARcPAREzFzMTNSE3NQEzMhYVERQGKwEiJjURNDYCijIoPBwBSCg8He4QLBf6B0YfHz0tNxSRYA0xG2SWZIjW%2Bv4%2BMv12ZBUdHRVkFR0dBLBRLJZ9USxkLR3%2BqBghMhkZJCcBkCQbxMYcKGTU1f6JZAF3feGv%2FtQdFf4MFR0dFQH0FR0AAAAAAwAAAAAEsARMACAAMAA8AAABMzIWFxMWHQEUBiMhFh0BFAYrASImLwImNRE0NjsBNgUzMhYVERQGKwEiJjURNDYhByMRHwEzNSchNQMCWPoXLBDuHTwo%2FrgcPCgyGzENYJEUNy09fP3pZBUdHRVkFR0dAl%2BIZJZkMjIBwvoETCEY%2FqgdLWQsUXYHlixRKBzGxBskAZAnJGRkHRX%2BDBUdHRUB9BUdZP6J1dSv4X0BdwADAAAAZAUOBE8AGwA3AEcAAAElNh8BHgEPASEyFhQGKwEDDgEjISImNRE0NjcXERchEz4BOwEyNiYjISoDLgQnJj8BJwUzMhYVERQGKwEiJjURNDYBZAFrHxZuDQEMVAEuVGxuVGqDBhsP%2FqoHphwOOmQBJYMGGw%2FLFRMSFv44AgoCCQMHAwUDAQwRklb9T2QVHR0VZBUdHQNp5hAWcA0mD3lMkE7%2BrRUoog0CDRElCkj%2BCVkBUxUoMjIBAgIDBQIZFrdT5B0V%2FgwVHR0VAfQVHQAAAAP%2FnABkBLAETwAdADYARgAAAQUeBBURFAYjISImJwMjIiY0NjMhJyY2PwE2BxcWBw4FKgIjIRUzMhYXEyE3ESUFMzIWFREUBisBIiY1ETQ2AdsBbgIIFBANrAf%2Bqg8bBoNqVW1sVAEuVQsBDW4WSpIRDAIDBQMHAwkDCgH%2BJd0PHAaCASZq%2FqoCUGQVHR0VZBUdHQRP5gEFEBEXC%2F3zDaIoFQFTTpBMeQ8mDXAWrrcWGQIFAwICAWQoFf6tWQH37OQdFf4MFR0dFQH0FR0AAAADAGEAAARMBQ4AGwA3AEcAAAAyFh0BBR4BFREUBiMhIiYvAQMmPwE%2BAR8BETQXNTQmBhURHAMOBAcGLwEHEyE3ESUuAQMhMhYdARQGIyEiJj0BNDYB3pBOAVMVKKIN%2FfMRJQoJ5hAWcA0mD3nGMjIBAgIDBQIZFrdT7AH3Wf6tFSiWAfQVHR0V%2FgwVHR0FDm5UaoMGGw%2F%2BqgemHA4OAWsfFm4NAQxUAS5U1ssVExIW%2FjgCCgIJAwcDBQMBDBGSVv6tZAElgwYb%2FQsdFWQVHR0VZBUdAAP%2F%2FQAGA%2BgFFAAPAC0ASQAAASEyNj0BNCYjISIGHQEUFgEVFAYiJjURBwYmLwEmNxM%2BBDMhMhYVERQGBwEDFzc2Fx4FHAIVERQWNj0BNDY3JREnAV4B9BUdHRX%2BDBUdHQEPTpBMeQ8mDXAWEOYBBRARFwsCDQ2iKBX9iexTtxYZAgUDAgIBMjIoFQFTWQRMHRVkFR0dFWQVHfzmalRubFQBLlQMAQ1uFh8BawIIEw8Mpgf%2Bqg8bBgHP%2Fq1WkhEMAQMFAwcDCQIKAv44FhITFcsPGwaDASVkAAIAFgAWBJoEmgAPACUAAAAyHgIUDgIiLgI0PgEBJSYGHQEhIgYdARQWMyEVFBY3JTY0AeLs1ptbW5vW7NabW1ubAob%2B7RAX%2Fu0KDw8KARMXEAETEASaW5vW7NabW1ub1uzWm%2F453w0KFYkPCpYKD4kVCg3fDSYAAAIAFgAWBJoEmgAPACUAAAAyHgIUDgIiLgI0PgENAQYUFwUWNj0BITI2PQE0JiMhNTQmAeLs1ptbW5vW7NabW1ubASX%2B7RAQARMQFwETCg8PCv7tFwSaW5vW7NabW1ub1uzWm%2BjfDSYN3w0KFYkPCpYKD4kVCgAAAAIAFgAWBJoEmgAPACUAAAAyHgIUDgIiLgI0PgEBAyYiBwMGFjsBERQWOwEyNjURMzI2AeLs1ptbW5vW7NabW1ubAkvfDSYN3w0KFYkPCpYKD4kVCgSaW5vW7NabW1ub1uzWm%2F5AARMQEP7tEBf%2B7QoPDwoBExcAAAIAFgAWBJoEmgAPACUAAAAyHgIUDgIiLgI0PgEFIyIGFREjIgYXExYyNxM2JisBETQmAeLs1ptbW5vW7NabW1ubAZeWCg%2BJFQoN3w0mDd8NChWJDwSaW5vW7NabW1ub1uzWm7sPCv7tFxD%2B7RAQARMQFwETCg8AAAMAGAAYBJgEmAAPAJYApgAAADIeAhQOAiIuAjQ%2BASUOAwcGJgcOAQcGFgcOAQcGFgcUFgcyHgEXHgIXHgI3Fg4BFx4CFxQGFBcWNz4CNy4BJy4BJyIOAgcGJyY2NS4BJzYuAQYHBicmNzY3HgIXHgMfAT4CJyY%2BATc%2BAzcmNzIWMjY3LgMnND4CJiceAT8BNi4CJwYHFB4BFS4CJz4BNxYyPgEB5OjVm1xcm9Xo1ZtcXJsBZA8rHDoKDz0PFD8DAxMBAzEFCRwGIgEMFhkHECIvCxU%2FOR0HFBkDDRQjEwcFaHUeISQDDTAMD0UREi4oLBAzDwQBBikEAQMLGhIXExMLBhAGKBsGBxYVEwYFAgsFAwMNFwQGCQcYFgYQCCARFwkKKiFBCwQCAQMDHzcLDAUdLDgNEiEQEgg%2FKhADGgMKEgoRBJhcm9Xo1ZtcXJvV6NWbEQwRBwkCAwYFBycPCxcHInIWInYcCUcYChQECA4QBAkuHgQPJioRFRscBAcSCgwCch0kPiAIAQcHEAsBAgsLIxcBMQENCQIPHxkCFBkdHB4QBgEBBwoMGBENBAMMJSAQEhYXDQ4qFBkKEhIDCQsXJxQiBgEOCQwHAQ0DBAUcJAwSCwRnETIoAwEJCwsLJQcKDBEAAAAAAQAAAAIErwSFABYAAAE2FwUXNxYGBw4BJwEGIi8BJjQ3ASY2AvSkjv79kfsGUE08hjv9rA8rD28PDwJYIk8EhVxliuh%2BWYcrIgsW%2FawQEG4PKxACV2XJAAYAAABgBLAErAAPABMAIwAnADcAOwAAEyEyFh0BFAYjISImPQE0NgUjFTMFITIWHQEUBiMhIiY9ATQ2BSEVIQUhMhYdARQGIyEiJj0BNDYFIRUhZAPoKTs7KfwYKTs7BBHIyPwYA%2BgpOzsp%2FBgpOzsEEf4MAfT8GAPoKTs7KfwYKTs7BBH%2B1AEsBKw7KWQpOzspZCk7ZGTIOylkKTs7KWQpO2RkyDspZCk7OylkKTtkZAAAAAIAZAAABEwEsAALABEAABMhMhYUBiMhIiY0NgERBxEBIZYDhBUdHRX8fBUdHQI7yP6iA4QEsB0qHR0qHf1E%2FtTIAfQB9AAAAAMAAABkBLAEsAAXABsAJQAAATMyFh0BITIWFREhNSMVIRE0NjMhNTQ2FxUzNQEVFAYjISImPQEB9MgpOwEsKTv%2BDMj%2BDDspASw7KcgB9Dsp%2FBgpOwSwOylkOyn%2BcGRkAZApO2QpO2RkZP1EyCk7OynIAAAABAAAAAAEsASwABUAKwBBAFcAABMhMhYPARcWFA8BBiIvAQcGJjURNDYpATIWFREUBi8BBwYiLwEmND8BJyY2ARcWFA8BFxYGIyEiJjURNDYfATc2MgU3NhYVERQGIyEiJj8BJyY0PwE2MhcyASwVCA5exwcHaggUCMdeDhUdAzUBLBUdFQ5exwgUCGoHB8deDgj%2BL2oHB8deDggV%2FtQVHRUOXscIFALLXg4VHRX%2B1BUIDl7HBwdqCBQIBLAVDl7HCBQIagcHx14OCBUBLBUdHRX%2B1BUIDl7HBwdqCBQIx14OFf0maggUCMdeDhUdFQEsFQgOXscHzl4OCBX%2B1BUdFQ5exwgUCGoHBwAAAAYAAAAABKgEqAAPABsAIwA7AEMASwAAADIeAhQOAiIuAjQ%2BAQQiDgEUHgEyPgE0JiQyFhQGIiY0JDIWFAYjIicHFhUUBiImNTQ2PwImNTQEMhYUBiImNCQyFhQGIiY0Advy3Z9fX5%2Fd8t2gXl6gAcbgv29vv%2BC%2Fb2%2F%2BLS0gIC0gAUwtICAWDg83ETNIMykfegEJ%2FoctICAtIAIdLSAgLSAEqF%2Bf3fLdoF5eoN3y3Z9Xb7%2Fgv29vv%2BC%2FBiAtISEtICAtIQqRFxwkMzMkIDEFfgEODhekIC0gIC0gIC0gIC0AAf%2FYAFoEuQS8AFsAACUBNjc2JicmIyIOAwcABw4EFx4BMzI3ATYnLgEjIgcGBwEOASY0NwA3PgEzMhceARcWBgcOBgcGIyImJyY2NwE2NzYzMhceARcWBgcBDgEnLgECIgHVWwgHdl8WGSJBMD8hIP6IDx4eLRMNBQlZN0ozAiQkEAcdEhoYDRr%2Bqw8pHA4BRyIjQS4ODyw9DQ4YIwwod26La1YOOEBGdiIwGkQB%2F0coW2tQSE5nDxE4Qv4eDyoQEAOtAdZbZWKbEQQUGjIhH%2F6JDxsdNSg3HT5CMwIkJCcQFBcMGv6uDwEcKQ4BTSIjIQEINykvYyMLKnhuiWZMBxtAOU6%2BRAH%2FSBg3ISSGV121Qv4kDwIPDyYAAAACAGQAWASvBEQAGQBEAAABPgIeAhUUDgMHLgQ1ND4CHgEFIg4DIi4DIyIGFRQeAhcWFx4EMj4DNzY3PgQ1NCYCiTB7eHVYNkN5hKg%2BPqeFeEM4WnZ4eQEjIT8yLSohJyktPyJDbxtBMjMPBw86KzEhDSIzKUAMBAgrKT8dF2oDtURIBS1TdkA5eYB%2FslVVsn%2BAeTlAdlMtBUgtJjY1JiY1NiZvTRc4SjQxDwcOPCouGBgwKEALBAkpKkQqMhNPbQACADn%2F8gR3BL4AFwAuAAAAMh8BFhUUBg8BJi8BNycBFwcvASY0NwEDNxYfARYUBwEGIi8BJjQ%2FARYfAQcXAQKru0KNQjgiHR8uEl%2F3%2FnvUaRONQkIBGxJpCgmNQkL%2B5UK6Qo1CQjcdLhJf9wGFBL5CjUJeKmsiHTUuEl%2F4%2FnvUahKNQrpCARv%2BRmkICY1CukL%2B5UJCjUK7Qjc3LxFf%2BAGFAAAAAAMAyAAAA%2BgEsAARABUAHQAAADIeAhURFAYjISImNRE0PgEHESERACIGFBYyNjQCBqqaZDo7Kf2oKTs8Zj4CWP7%2FVj09Vj0EsB4uMhX8Ryk7OykDuRUzLar9RAK8%2FRY9Vj09VgABAAAAAASwBLAAFgAACQEWFAYiLwEBEScBBRMBJyEBJyY0NjIDhgEbDx0qDiT%2B6dT%2BzP7oywEz0gEsAQsjDx0qBKH%2B5g8qHQ8j%2FvX%2B1NL%2BzcsBGAE01AEXJA4qHQAAAAADAScAEQQJBOAAMgBAAEsAAAEVHgQXIy4DJxEXHgQVFAYHFSM1JicuASczHgEXEScuBDU0PgI3NRkBDgMVFB4DFxYXET4ENC4CArwmRVI8LAKfBA0dMydAIjxQNyiym2SWVygZA4sFV0obLkJOMCAyVWg6HSoqFQ4TJhkZCWgWKTEiGBkzNwTgTgUTLD9pQiQuLBsH%2Fs0NBxMtPGQ%2Bi6oMTU8QVyhrVk1iEAFPCA4ZLzlYNkZwSCoGTf4SARIEDh02Jh0rGRQIBgPQ%2FsoCCRYgNEM0JRkAAAABAGQAZgOUBK0ASgAAATIeARUjNC4CIyIGBwYVFB4BFxYXMxUjFgYHBgc%2BATM2FjMyNxcOAyMiLgEHDgEPASc%2BBTc%2BAScjNTMmJy4CPgE3NgIxVJlemSc8OxolVBQpGxoYBgPxxQgVFS02ImIWIIwiUzUyHzY4HCAXanQmJ1YYFzcEGAcTDBEJMAwk3aYXFQcKAg4tJGEErVCLTig%2FIhIdFSw5GkowKgkFZDKCHj4yCg8BIh6TExcIASIfBAMaDAuRAxAFDQsRCjePR2QvORQrREFMIVgAAAACABn%2F%2FwSXBLAADwAfAAABMzIWDwEGIi8BJjY7AREzBRcWBisBESMRIyImPwE2MgGQlhUIDuYOKg7mDggVlsgCF%2BYOCBWWyJYVCA7mDioBLBYO%2Bg8P%2Bg4WA4QQ%2BQ4V%2FHwDhBUO%2BQ8AAAQAGf%2F%2FA%2BgEsAAHABcAGwAlAAABIzUjFSMRIQEzMhYPAQYiLwEmNjsBETMFFTM1EwczFSE1NyM1IQPoZGRkASz9qJYVCA7mDioO5g4IFZbIAZFkY8jI%2FtTIyAEsArxkZAH0%2FHwWDvoPD%2FoOFgOEZMjI%2FRL6ZJb6ZAAAAAAEABn%2F%2FwPoBLAADwAZACEAJQAAATMyFg8BBiIvASY2OwERMwUHMxUhNTcjNSERIzUjFSMRIQcVMzUBkJYVCA7mDioO5g4IFZbIAljIyP7UyMgBLGRkZAEsx2QBLBYO%2Bg8P%2Bg4WA4SW%2BmSW%2BmT7UGRkAfRkyMgAAAAEABn%2F%2FwRMBLAADwAVABsAHwAAATMyFg8BBiIvASY2OwERMwEjESM1MxMjNSMRIQcVMzUBkJYVCA7mDioO5g4IFZbIAlhkZMhkZMgBLMdkASwWDvoPD%2FoOFgOE%2FgwBkGT7UGQBkGTIyAAAAAAEABn%2F%2FwRMBLAADwAVABkAHwAAATMyFg8BBiIvASY2OwERMwEjNSMRIQcVMzUDIxEjNTMBkJYVCA7mDioO5g4IFZbIArxkyAEsx2QBZGTIASwWDvoPD%2FoOFgOE%2FgxkAZBkyMj7tAGQZAAAAAAFABn%2F%2FwSwBLAADwATABcAGwAfAAABMzIWDwEGIi8BJjY7AREzBSM1MxMhNSETITUhEyE1IQGQlhUIDuYOKg7mDggVlsgB9MjIZP7UASxk%2FnABkGT%2BDAH0ASwWDvoPD%2FoOFgOEyMj%2BDMj%2BDMj%2BDMgABQAZ%2F%2F8EsASwAA8AEwAXABsAHwAAATMyFg8BBiIvASY2OwERMwUhNSEDITUhAyE1IQMjNTMBkJYVCA7mDioO5g4IFZbIAyD%2BDAH0ZP5wAZBk%2FtQBLGTIyAEsFg76Dw%2F6DhYDhMjI%2FgzI%2FgzI%2FgzIAAIAAAAABEwETAAPAB8AAAEhMhYVERQGIyEiJjURNDYFISIGFREUFjMhMjY1ETQmAV4BkKK8u6P%2BcKW5uQJn%2FgwpOzspAfQpOzsETLuj%2FnClubmlAZClucg7Kf4MKTs7KQH0KTsAAAAAAwAAAAAETARMAA8AHwArAAABITIWFREUBiMhIiY1ETQ2BSEiBhURFBYzITI2NRE0JgUXFhQPAQYmNRE0NgFeAZClubml%2FnCju7wCZP4MKTs7KQH0KTs7%2Fm%2F9ERH9EBgYBEy5pf5wpbm5pQGQo7vIOyn%2BDCk7OykB9Ck7gr4MJAy%2BDAsVAZAVCwAAAAADAAAAAARMBEwADwAfACsAAAEhMhYVERQGIyEiJjURNDYFISIGFREUFjMhMjY1ETQmBSEyFg8BBiIvASY2AV4BkKO7uaX%2BcKW5uQJn%2FgwpOzspAfQpOzv%2BFQGQFQsMvgwkDL4MCwRMvKL%2BcKW5uaUBkKO7yDsp%2FgwpOzspAfQpO8gYEP0REf0QGAAAAAMAAAAABEwETAAPAB8AKwAAASEyFhURFAYjISImNRE0NgUhIgYVERQWMyEyNjURNCYFFxYGIyEiJj8BNjIBXgGQpbm5pf5wo7u5Amf%2BDCk7OykB9Ck7O%2F77vgwLFf5wFQsMvgwkBEy5pf5wo7u8ogGQpbnIOyn%2BDCk7OykB9Ck7z%2F0QGBgQ%2FREAAAAAAgAAAAAFFARMAB8ANQAAASEyFhURFAYjISImPQE0NjMhMjY1ETQmIyEiJj0BNDYHARYUBwEGJj0BIyImPQE0NjsBNTQ2AiYBkKW5uaX%2BcBUdHRUBwik7Oyn%2BPhUdHb8BRBAQ%2FrwQFvoVHR0V%2BhYETLml%2FnCluR0VZBUdOykB9Ck7HRVkFR3p%2FuQOJg7%2B5A4KFZYdFcgVHZYVCgAAAQDZAAID1wSeACMAAAEXFgcGAgclMhYHIggBBwYrAScmNz4BPwEhIicmNzYANjc2MwMZCQgDA5gCASwYEQ4B%2Fvf%2B8wQMDgkJCQUCUCcn%2FtIXCAoQSwENuwUJEASeCQoRC%2F5TBwEjEv7K%2FsUFDwgLFQnlbm4TFRRWAS%2FTBhAAAAACAAAAAAT%2BBEwAHwA1AAABITIWHQEUBiMhIgYVERQWMyEyFh0BFAYjISImNRE0NgUBFhQHAQYmPQEjIiY9ATQ2OwE1NDYBXgGQFR0dFf4%2BKTs7KQHCFR0dFf5wpbm5AvEBRBAQ%2FrwQFvoVHR0V%2BhYETB0VZBUdOyn%2BDCk7HRVkFR25pQGQpbnp%2FuQOJg7%2B5A4KFZYdFcgVHZYVCgACAAAAAASwBLAAFQAxAAABITIWFREUBi8BAQYiLwEmNDcBJyY2ASMiBhURFBYzITI2PQE3ERQGIyEiJjURNDYzIQLuAZAVHRUObf7IDykPjQ8PAThtDgj%2B75wpOzspAfQpO8i7o%2F5wpbm5pQEsBLAdFf5wFQgObf7IDw%2BNDykPAThtDhX%2B1Dsp%2FgwpOzsplMj%2B1qW5uaUBkKW5AAADAA4ADgSiBKIADwAbACMAAAAyHgIUDgIiLgI0PgEEIg4BFB4BMj4BNCYEMhYUBiImNAHh7tmdXV2d2e7ZnV1dnQHD5sJxccLmwnFx%2FnugcnKgcgSiXZ3Z7tmdXV2d2e7ZnUdxwubCcXHC5sJzcqBycqAAAAMAAAAABEwEsAAVAB8AIwAAATMyFhURMzIWBwEGIicBJjY7ARE0NgEhMhYdASE1NDYFFTM1AcLIFR31FAoO%2FoEOJw3%2BhQ0JFfod%2FoUD6BUd%2B7QdA2dkBLAdFf6iFg%2F%2BVg8PAaoPFgFeFR38fB0V%2BvoVHWQyMgAAAAMAAAAABEwErAAVAB8AIwAACQEWBisBFRQGKwEiJj0BIyImNwE%2BAQEhMhYdASE1NDYFFTM1AkcBeg4KFfQiFsgUGPoUCw4Bfw4n%2FfkD6BUd%2B7QdA2dkBJ7%2BTQ8g%2BhQeHRX6IQ8BrxAC%2FH8dFfr6FR1kMjIAAwAAAAAETARLABQAHgAiAAAJATYyHwEWFAcBBiInASY0PwE2MhcDITIWHQEhNTQ2BRUzNQGMAXEHFQeLBwf98wcVB%2F7cBweLCBUH1APoFR37tB0DZ2QC0wFxBweLCBUH%2FfMICAEjCBQIiwcH%2FdIdFfr6FR1kMjIABAAAAAAETASbAAkAGQAjACcAABM3NjIfAQcnJjQFNzYWFQMOASMFIiY%2FASc3ASEyFh0BITU0NgUVMzWHjg4qDk3UTQ4CFtIOFQIBHRX9qxUIDtCa1P49A%2BgVHfu0HQNnZAP%2Fjg4OTdRMDyqa0g4IFf2pFB4BFQ7Qm9T9Oh0V%2BvoVHWQyMgAAAAQAAAAABEwEsAAPABkAIwAnAAABBR4BFRMUBi8BByc3JyY2EwcGIi8BJjQ%2FAQEhMhYdASE1NDYFFTM1AV4CVxQeARUO0JvUm9IOCMNMDyoOjg4OTf76A%2BgVHfu0HQNnZASwAgEdFf2rFQgO0JrUmtIOFf1QTQ4Ojg4qDk3%2BWB0V%2BvoVHWQyMgACAAT%2F7ASwBK8ABQAIAAAlCQERIQkBFQEEsP4d%2Fsb%2BcQSs%2FTMCq2cBFP5xAacDHPz55gO5AAAAAAIAAABkBEwEsAAVABkAAAERFAYrAREhESMiJjURNDY7AREhETMHIzUzBEwdFZb9RJYVHR0V%2BgH0ZMhkZAPo%2FK4VHQGQ%2FnAdFQPoFB7%2B1AEsyMgAAAMAAABFBN0EsAAWABoALwAAAQcBJyYiDwEhESMiJjURNDY7AREhETMHIzUzARcWFAcBBiIvASY0PwE2Mh8BATYyBEwC%2FtVfCRkJlf7IlhUdHRX6AfRkyGRkAbBqBwf%2BXAgUCMoICGoHFQdPASkHFQPolf7VXwkJk%2F5wHRUD6BQe%2FtQBLMjI%2Fc5qBxUH%2FlsHB8sHFQdqCAhPASkHAAMAAAANBQcEsAAWABoAPgAAAREHJy4BBwEhESMiJjURNDY7AREhETMHIzUzARcWFA8BFxYUDwEGIi8BBwYiLwEmND8BJyY0PwE2Mh8BNzYyBExnhg8lEP72%2FreWFR0dFfoB9GTIZGQB9kYPD4ODDw9GDykPg4MPKQ9GDw%2BDgw8PRg8pD4ODDykD6P7zZ4YPAw7%2B9v5wHRUD6BQe%2FtQBLMjI%2FYxGDykPg4MPKQ9GDw%2BDgw8PRg8pD4ODDykPRg8Pg4MPAAADAAAAFQSXBLAAFQAZAC8AAAERISIGHQEhESMiJjURNDY7AREhETMHIzUzEzMyFh0BMzIWDwEGIi8BJjY7ATU0NgRM%2FqIVHf4MlhUdHRX6AfRkyGRklmQVHZYVCA7mDioO5g4IFZYdA%2Bj%2B1B0Vlv5wHRUD6BQe%2FtQBLMjI%2FagdFfoVDuYODuYOFfoVHQAAAAADAAAAAASXBLAAFQAZAC8AAAERJyYiBwEhESMiJjURNDY7AREhETMHIzUzExcWBisBFRQGKwEiJj0BIyImPwE2MgRMpQ4qDv75%2Fm6WFR0dFfoB9GTIZGTr5g4IFZYdFWQVHZYVCA7mDioD6P5wpQ8P%2Fvf%2BcB0VA%2BgUHv7UASzIyP2F5Q8V%2BhQeHhT6FQ%2FlDwADAAAAyASwBEwACQATABcAABMhMhYdASE1NDYBERQGIyEiJjURExUhNTIETBUd%2B1AdBJMdFfu0FR1kAZAETB0VlpYVHf7U%2FdoVHR0VAib%2B1MjIAAAGAAMAfQStBJcADwAZAB0ALQAxADsAAAEXFhQPAQYmPQEhNSE1NDYBIyImPQE0NjsBFyM1MwE3NhYdASEVIRUUBi8BJjQFIzU7AjIWHQEUBisBA6f4Dg74DhX%2BcAGQFf0vMhUdHRUyyGRk%2FoL3DhUBkP5wFQ73DwOBZGRkMxQdHRQzBI3mDioO5g4IFZbIlhUI%2FoUdFWQVHcjI%2FcvmDggVlsiWFQgO5g4qecgdFWQVHQAAAAACAGQAAASwBLAAFgBRAAABJTYWFREUBisBIiY1ES4ENRE0NiUyFh8BERQOAg8BERQGKwEiJjURLgQ1ETQ%2BAzMyFh8BETMRPAE%2BAjMyFh8BETMRND4DA14BFBklHRXIFR0EDiIaFiX%2B4RYZAgEVHR0LCh0VyBUdBA4iGhYBBwoTDRQZAgNkBQkVDxcZAQFkAQUJFQQxdBIUH%2FuuFR0dFQGNAQgbHzUeAWcfRJEZDA3%2BPhw%2FMSkLC%2F5BFR0dFQG%2FBA8uLkAcAcICBxENCxkMDf6iAV4CBxENCxkMDf6iAV4CBxENCwABAGQAAASwBEwAMwAAARUiDgMVERQWHwEVITUyNjURIREUFjMVITUyPgM1ETQmLwE1IRUiBhURIRE0JiM1BLAEDiIaFjIZGf5wSxn%2BDBlL%2FnAEDiIaFjIZGQGQSxkB9BlLBEw4AQUKFA78iBYZAQI4OA0lAYr%2BdiUNODgBBQoUDgN4FhkBAjg4DSX%2BdgGKJQ04AAAABgAAAAAETARMAAwAHAAgACQAKAA0AAABITIWHQEjBTUnITchBSEyFhURFAYjISImNRE0NhcVITUBBTUlBRUhNQUVFAYjIQchJyE3MwKjAXcVHWn%2B2cj%2BcGQBd%2F4lASwpOzsp%2FtQpOzspASwCvP5wAZD8GAEsArwdFf6JZP6JZAGQyGkD6B0VlmJiyGTIOyn%2BDCk7OykB9Ck7ZMjI%2FveFo4XGyMhm%2BBUdZGTIAAEAEAAQBJ8EnwAmAAATNzYWHwEWBg8BHgEXNz4BHwEeAQ8BBiIuBicuBTcRohEuDosOBhF3ZvyNdxEzE8ATBxGjAw0uMUxPZWZ4O0p3RjITCwED76IRBhPCFDERdo78ZXYRBA6IDi8RogEECBUgNUNjO0qZfHNVQBAAAAACAAAAAASwBEwAIwBBAAAAMh4EHwEVFAYvAS4BPQEmIAcVFAYPAQYmPQE%2BBRIyHgIfARUBHgEdARQGIyEiJj0BNDY3ATU0PgIB%2FLimdWQ%2FLAkJHRTKFB2N%2FsKNHRTKFB0DDTE7ZnTKcFImFgEBAW0OFR0V%2B7QVHRUOAW0CFiYETBUhKCgiCgrIFRgDIgMiFZIYGJIVIgMiAxgVyAQNJyQrIP7kExwcCgoy%2FtEPMhTUFR0dFdQUMg8BLzIEDSEZAAADAAAAAASwBLAADQAdACcAAAEHIScRMxUzNTMVMzUzASEyFhQGKwEXITcjIiY0NgMhMhYdASE1NDYETMj9qMjIyMjIyPyuArwVHR0VDIn8SokMFR0dswRMFR37UB0CvMjIAfTIyMjI%2FOAdKh1kZB0qHf7UHRUyMhUdAAAAAwBkAAAEsARMAAkAEwAdAAABIyIGFREhETQmASMiBhURIRE0JgEhETQ2OwEyFhUCvGQpOwEsOwFnZCk7ASw7%2FRv%2B1DspZCk7BEw7KfwYA%2BgpO%2F7UOyn9RAK8KTv84AGQKTs7KQAAAAAF%2F5wAAASwBEwADwATAB8AJQApAAATITIWFREUBiMhIiY1ETQ2FxEhEQUjFTMRITUzNSMRIQURByMRMwcRMxHIArx8sLB8%2FUR8sLAYA4T%2BDMjI%2FtTIyAEsAZBkyMhkZARMsHz%2BDHywsHwB9HywyP1EArzIZP7UZGQBLGT%2B1GQB9GT%2B1AEsAAAABf%2BcAAAEsARMAA8AEwAfACUAKQAAEyEyFhURFAYjISImNRE0NhcRIREBIzUjFSMRMxUzNTMFEQcjETMHETMRyAK8fLCwfP1EfLCwGAOE%2FgxkZGRkZGQBkGTIyGRkBEywfP4MfLCwfAH0fLDI%2FUQCvP2oyMgB9MjIZP7UZAH0ZP7UASwABP%2BcAAAEsARMAA8AEwAbACMAABMhMhYVERQGIyEiJjURNDYXESERBSMRMxUhESEFIxEzFSERIcgCvHywsHz9RHywsBgDhP4MyMj%2B1AEsAZDIyP7UASwETLB8%2Fgx8sLB8AfR8sMj9RAK8yP7UZAH0ZP7UZAH0AAAABP%2BcAAAEsARMAA8AEwAWABkAABMhMhYVERQGIyEiJjURNDYXESERAS0BDQERyAK8fLCwfP1EfLCwGAOE%2Fgz%2B1AEsAZD%2B1ARMsHz%2BDHywsHwB9HywyP1EArz%2BDJaWlpYBLAAAAAX%2FnAAABLAETAAPABMAFwAgACkAABMhMhYVERQGIyEiJjURNDYXESERAyERIQcjIgYVFBY7AQERMzI2NTQmI8gCvHywsHz9RHywsBgDhGT9RAK8ZIImOTYpgv4Mgik2OSYETLB8%2Fgx8sLB8AfR8sMj9RAK8%2FagB9GRWQUFUASz%2B1FRBQVYAAAAF%2F5wAAASwBEwADwATAB8AJQApAAATITIWFREUBiMhIiY1ETQ2FxEhEQUjFTMRITUzNSMRIQEjESM1MwMjNTPIArx8sLB8%2FUR8sLAYA4T%2BDMjI%2FtTIyAEsAZBkZMjIZGQETLB8%2Fgx8sLB8AfR8sMj9RAK8yGT%2B1GRkASz%2BDAGQZP4MZAAG%2F5wAAASwBEwADwATABkAHwAjACcAABMhMhYVERQGIyEiJjURNDYXESERBTMRIREzASMRIzUzBRUzNQEjNTPIArx8sLB8%2FUR8sLAYA4T9RMj%2B1GQCWGRkyP2oZAEsZGQETLB8%2Fgx8sLB8AfR8sMj9RAK8yP5wAfT%2BDAGQZMjIyP7UZAAF%2F5wAAASwBEwADwATABwAIgAmAAATITIWFREUBiMhIiY1ETQ2FxEhEQEHIzU3NSM1IQEjESM1MwMjNTPIArx8sLB8%2FUR8sLAYA4T%2BDMdkx8gBLAGQZGTIx2RkBEywfP4MfLCwfAH0fLDI%2FUQCvP5wyDLIlmT%2BDAGQZP4MZAAAAAMACQAJBKcEpwAPABsAJQAAADIeAhQOAiIuAjQ%2BAQQiDgEUHgEyPgE0JgchFSEVISc1NyEB4PDbnl5entvw255eXp4BxeTCcXHC5MJxcWz%2B1AEs%2FtRkZAEsBKdentvw255eXp7b8NueTHHC5MJxccLkwtDIZGTIZAAAAAAEAAkACQSnBKcADwAbACcAKwAAADIeAhQOAiIuAjQ%2BAQQiDgEUHgEyPgE0JgcVBxcVIycjFSMRIQcVMzUB4PDbnl5entvw255eXp4BxeTCcXHC5MJxcWwyZGRklmQBLMjIBKdentvw255eXp7b8NueTHHC5MJxccLkwtBkMmQyZGQBkGRkZAAAAv%2Fy%2F50EwgRBACAANgAAATIWFzYzMhYUBisBNTQmIyEiBh0BIyImNTQ2NyY1ND4BEzMyFhURMzIWDwEGIi8BJjY7ARE0NgH3brUsLC54qqp4gB0V%2FtQVHd5QcFZBAmKqepYKD4kVCg3fDSYN3w0KFYkPBEF3YQ6t8a36FR0dFfpzT0VrDhMSZKpi%2FbMPCv7tFxD0EBD0EBcBEwoPAAAAAAL%2F8v%2BcBMMEQQAcADMAAAEyFhc2MzIWFxQGBwEmIgcBIyImNTQ2NyY1ND4BExcWBisBERQGKwEiJjURIyImNzY3NjIB9m62LCsueaoBeFr%2Bhg0lDf6DCU9xVkECYqnm3w0KFYkPCpYKD4kVCg3HGBMZBEF3YQ%2BteGOkHAFoEBD%2Bk3NPRWsOExNkqWP9kuQQF%2F7tCg8PCgETFxDMGBMAAAABAGQAAARMBG0AGAAAJTUhATMBMwkBMwEzASEVIyIGHQEhNTQmIwK8AZD%2B8qr%2B8qr%2B1P7Uqv7yqv7yAZAyFR0BkB0VZGQBLAEsAU3%2Bs%2F7U%2FtRkHRUyMhUdAAAAAAEAeQAABDcEmwAvAAABMhYXHgEVFAYHFhUUBiMiJxUyFh0BITU0NjM1BiMiJjU0Ny4BNTQ2MzIXNCY1NDYCWF6TGll7OzIJaUo3LRUd%2FtQdFS03SmkELzlpSgUSAqMEm3FZBoNaPWcfHRpKaR77HRUyMhUd%2Bx5pShIUFVg1SmkCAhAFdKMAAAAGACcAFASJBJwAEQAqAEIASgBiAHsAAAEWEgIHDgEiJicmAhI3PgEyFgUiBw4BBwYWHwEWMzI3Njc2Nz4BLwEmJyYXIgcOAQcGFh8BFjMyNz4BNz4BLwEmJyYWJiIGFBYyNjciBw4BBw4BHwEWFxYzMjc%2BATc2Ji8BJhciBwYHBgcOAR8BFhcWMzI3PgE3NiYvASYD8m9PT29T2dzZU29PT29T2dzZ%2Fj0EBHmxIgQNDCQDBBcGG0dGYAsNAwkDCwccBAVQdRgEDA0iBAQWBhJROQwMAwkDCwf5Y4xjY4xjVhYGElE6CwwDCQMLBwgEBVB1GAQNDCIEjRcGG0dGYAsNAwkDCwcIBAR5sSIEDQwkAwPyb%2F7V%2FtVvU1dXU28BKwErb1NXVxwBIrF5DBYDCQEWYEZHGwMVDCMNBgSRAhh1UA0WAwkBFTpREgMVCyMMBwT6Y2OMY2MVFTpREQQVCyMMBwQCGHVQDRYDCQEkFmBGRxsDFQwjDQYEASKxeQwWAwkBAAAABQBkAAAD6ASwAAwADwAWABwAIgAAASERIzUhFSERNDYzIQEjNQMzByczNTMDISImNREFFRQGKwECvAEstP6s%2FoQPCgI%2FASzIZKLU1KJktP51Cg8DhA8KwwMg%2FoTIyALzCg%2F%2B1Mj84NTUyP4MDwoBi8jDCg8AAAAABQBkAAAD6ASwAAkADAATABoAIQAAASERCQERNDYzIQEjNRMjFSM1IzcDISImPQEpARUUBisBNQK8ASz%2Bov3aDwoCPwEsyD6iZKLUqv6dCg8BfAIIDwqbAyD9%2BAFe%2FdoERwoP%2FtTI%2FHzIyNT%2BZA8KNzcKD1AAAAAAAwAAAAAEsAP0AAgAGQAfAAABIxUzFyERIzcFMzIeAhUhFSEDETM0PgIBMwMhASEEiqJkZP7UotT9EsgbGiEOASz9qMhkDiEaAnPw8PzgASwB9AMgyGQBLNTUBBErJGT%2BogHCJCsRBP5w%2FnAB9AAAAAMAAAAABEwETAAZADIAOQAAATMyFh0BMzIWHQEUBiMhIiY9ATQ2OwE1NDYFNTIWFREUBiMhIic3ARE0NjMVFBYzITI2AQc1IzUzNQKKZBUdMhUdHRX%2B1BUdHRUyHQFzKTs7Kf2oARP2%2Fro7KVg%2BASw%2BWP201MjIBEwdFTIdFWQVHR0VZBUdMhUd%2BpY7KfzgKTsE9gFGAUQpO5Y%2BWFj95tSiZKIAAwBkAAAEvARMABkANgA9AAABMzIWHQEzMhYdARQGIyEiJj0BNDY7ATU0NgU1MhYVESMRMxQOAiMhIiY1ETQ2MxUUFjMhMjYBBzUjNTM1AcJkFR0yFR0dFf7UFR0dFTIdAXMpO8jIDiEaG%2F2oKTs7KVg%2BASw%2BWAGc1MjIBEwdFTIdFWQVHR0VZBUdMhUd%2BpY7Kf4M%2FtQkKxEEOykDICk7lj5YWP3m1KJkogAAAAP%2FogAABRYE1AALABsAHwAACQEWBiMhIiY3ATYyEyMiBhcTHgE7ATI2NxM2JgMVMzUCkgJ9FyAs%2BwQsIBcCfRZARNAUGAQ6BCMUNhQjBDoEGODIBK37sCY3NyYEUCf%2BTB0U%2FtIUHR0UAS4UHf4MZGQAAAAACQAAAAAETARMAA8AHwAvAD8ATwBfAG8AfwCPAAABMzIWHQEUBisBIiY9ATQ2EzMyFh0BFAYrASImPQE0NiEzMhYdARQGKwEiJj0BNDYBMzIWHQEUBisBIiY9ATQ2ITMyFh0BFAYrASImPQE0NiEzMhYdARQGKwEiJj0BNDYBMzIWHQEUBisBIiY9ATQ2ITMyFh0BFAYrASImPQE0NiEzMhYdARQGKwEiJj0BNDYBqfoKDw8K%2BgoPDwr6Cg8PCvoKDw8BmvoKDw8K%2BgoPD%2Fzq%2BgoPDwr6Cg8PAZr6Cg8PCvoKDw8BmvoKDw8K%2BgoPD%2Fzq%2BgoPDwr6Cg8PAZr6Cg8PCvoKDw8BmvoKDw8K%2BgoPDwRMDwqWCg8PCpYKD%2F7UDwqWCg8PCpYKDw8KlgoPDwqWCg%2F%2B1A8KlgoPDwqWCg8PCpYKDw8KlgoPDwqWCg8PCpYKD%2F7UDwqWCg8PCpYKDw8KlgoPDwqWCg8PCpYKDw8KlgoPAAAAAwAAAAAEsAUUABkAKQAzAAABMxUjFSEyFg8BBgchJi8BJjYzITUjNTM1MwEhMhYUBisBFyE3IyImNDYDITIWHQEhNTQ2ArxkZAFePjEcQiko%2FPwoKUIcMT4BXmRkyP4%2BArwVHR0VDIn8SooNFR0dswRMFR37UB0EsMhkTzeEUzMzU4Q3T2TIZPx8HSodZGQdKh3%2B1B0VMjIVHQAABAAAAAAEsAUUAAUAGQArADUAAAAyFhUjNAchFhUUByEyFg8BIScmNjMhJjU0AyEyFhQGKwEVBSElNSMiJjQ2AyEyFh0BITU0NgIwUDnCPAE6EgMBSCkHIq%2F9WrIiCikBSAOvArwVHR0VlgET%2FEoBE5YVHR2zBEwVHftQHQUUOykpjSUmCBEhFpGRFiERCCb%2BlR0qHcjIyMgdKh39qB0VMjIVHQAEAAAAAASwBJ0ABwAUACQALgAAADIWFAYiJjQTMzIWFRQXITY1NDYzASEyFhQGKwEXITcjIiY0NgMhMhYdASE1NDYCDZZqapZqty4iKyf%2BvCcrI%2F7NArwVHR0VDYr8SokMFR0dswRMFR37UB0EnWqWamqW%2Fus5Okxra0w6Of5yHSodZGQdKh3%2B1B0VMjIVHQAEAAAAAASwBRQADwAcACwANgAAATIeARUUBiImNTQ3FzcnNhMzMhYVFBchNjU0NjMBITIWFAYrARchNyMiJjQ2AyEyFh0BITU0NgJYL1szb5xvIpBvoyIfLiIrJ%2F68Jysj%2Fs0CvBUdHRUNivxKiQwVHR2zBEwVHftQHQUUa4s2Tm9vTj5Rj2%2BjGv4KOTpMa2tMOjn%2Bch0qHWRkHSod%2FtQdFTIyFR0AAAADAAAAAASwBRIAEgAiACwAAAEFFSEUHgMXIS4BNTQ%2BAjcBITIWFAYrARchNyMiJjQ2AyEyFh0BITU0NgJYASz%2B1CU%2FP00T%2Fe48PUJtj0r%2BogK8FR0dFQ2K%2FEqJDBUdHbMETBUd%2B1AdBLChizlmUT9IGVO9VFShdksE%2FH4dKh1kZB0qHf7UHRUyMhUdAAIAyAAAA%2BgFFAAPACkAAAAyFh0BHgEdASE1NDY3NTQDITIWFyMVMxUjFTMVIxUzFAYjISImNRE0NgIvUjsuNv5wNi5kAZA2XBqsyMjIyMh1U%2F5wU3V1BRQ7KU4aXDYyMjZcGk4p%2Fkc2LmRkZGRkU3V1UwGQU3UAAAMAZP%2F%2FBEwETAAPAC8AMwAAEyEyFhURFAYjISImNRE0NgMhMhYdARQGIyEXFhQGIi8BIQcGIiY0PwEhIiY9ATQ2BQchJ5YDhBUdHRX8fBUdHQQDtgoPDwr%2B5eANGiUNWP30Vw0mGg3g%2Ft8KDw8BqmQBRGQETB0V%2FgwVHR0VAfQVHf1EDwoyCg%2FgDSUbDVhYDRslDeAPCjIKD2RkZAAAAAAEAAAAAASwBEwAGQAjAC0ANwAAEyEyFh0BIzQmKwEiBhUjNCYrASIGFSM1NDYDITIWFREhETQ2ExUUBisBIiY9ASEVFAYrASImPQHIAyBTdWQ7KfopO2Q7KfopO2R1EQPoKTv7UDvxHRVkFR0D6B0VZBUdBEx1U8gpOzspKTs7KchTdf4MOyn%2B1AEsKTv%2BDDIVHR0VMjIVHR0VMgADAAEAAASpBKwADQARABsAAAkBFhQPASEBJjQ3ATYyCQMDITIWHQEhNTQ2AeACqh8fg%2F4f%2FfsgIAEnH1n%2BrAFWAS%2F%2Bq6IDIBUd%2FHwdBI39VR9ZH4MCBh9ZHwEoH%2F5u%2FqoBMAFV%2FBsdFTIyFR0AAAAAAgCPAAAEIQSwABcALwAAAQMuASMhIgYHAwYWMyEVFBYyNj0BMzI2AyE1NDY7ATU0NjsBETMRMzIWHQEzMhYVBCG9CCcV%2FnAVJwi9CBMVAnEdKh19FROo%2Fa0dFTIdFTDILxUdMhUdAocB%2BhMcHBP%2BBhMclhUdHRWWHP2MMhUdMhUdASz%2B1B0VMh0VAAAEAAAAAASwBLAADQAQAB8AIgAAASERFAYjIREBNTQ2MyEBIzUBIREUBiMhIiY1ETQ2MyEBIzUDhAEsDwr%2Bif7UDwoBdwEsyP2oASwPCv12Cg8PCgF3ASzIAyD9wQoPAk8BLFQKD%2F7UyP4M%2FcEKDw8KA7YKD%2F7UyAAC%2F5wAZAUUBEcARgBWAAABMzIeAhcWFxY2NzYnJjc%2BARYXFgcOASsBDgEPAQ4BKwEiJj8BBisBIicHDgErASImPwEmLwEuAT0BNDY7ATY3JyY2OwE2BSMiBh0BFBY7ATI2PQE0JgHkw0uOakkMEhEfQwoKGRMKBQ8XDCkCA1Y9Pgc4HCcDIhVkFRgDDDEqwxgpCwMiFWQVGAMaVCyfExwdFXwLLW8QBxXLdAFF%2BgoPDwr6Cg8PBEdBa4pJDgYKISAiJRsQCAYIDCw9P1c3fCbqFB0dFEYOCEAUHR0UnUplNQcmFTIVHVdPXw4TZV8PCjIKDw8KMgoPAAb%2FnP%2FmBRQEfgAJACQANAA8AFIAYgAAASU2Fh8BFgYPASUzMhYfASEyFh0BFAYHBQYmJyYjISImPQE0NhcjIgYdARQ7ATI2NTQmJyYEIgYUFjI2NAE3PgEeARceAT8BFxYGDwEGJi8BJjYlBwYfAR4BPwE2Jy4BJy4BAoEBpxMuDiAOAxCL%2FCtqQ0geZgM3FR0cE%2F0fFyIJKjr%2B1D5YWLlQExIqhhALIAsSAYBALS1ALf4PmBIgHhMQHC0aPzANITNQL3wpgigJASlmHyElDR0RPRMFAhQHCxADhPcICxAmDyoNeMgiNtQdFTIVJgeEBBQPQ1g%2ByD5YrBwVODMQEAtEERzJLUAtLUD%2B24ITChESEyMgAwWzPUkrRSgJL5cvfRxYGyYrDwkLNRAhFEgJDAQAAAAAAwBkAAAEOQSwAFEAYABvAAABMzIWHQEeARcWDgIPATIeBRUUDgUjFRQGKwEiJj0BIxUUBisBIiY9ASMiJj0BNDY7AREjIiY9ATQ2OwE1NDY7ATIWHQEzNTQ2AxUhMj4CNTc0LgMjARUhMj4CNTc0LgMjAnGWCg9PaAEBIC4uEBEGEjQwOiodFyI2LUAjGg8KlgoPZA8KlgoPrwoPDwpLSwoPDwqvDwqWCg9kD9cBBxwpEwsBAQsTKRz%2B%2BQFrHCkTCwEBCxMpHASwDwptIW1KLk0tHwYGAw8UKDJOLTtdPCoVCwJLCg8PCktLCg8PCksPCpYKDwJYDwqWCg9LCg8PCktLCg%2F%2B1MgVHR0LCgQOIhoW%2FnDIFR0dCwoEDiIaFgAAAwAEAAIEsASuABcAKQAsAAATITIWFREUBg8BDgEjISImJy4CNRE0NgQiDgQPARchNy4FAyMT1AMMVnokEhIdgVL9xFKCHAgYKHoCIIx9VkcrHQYGnAIwnAIIIClJVSGdwwSuelb%2BYDO3QkJXd3ZYHFrFMwGgVnqZFyYtLSUMDPPzBQ8sKDEj%2FsIBBQACAMgAAAOEBRQADwAZAAABMzIWFREUBiMhIiY1ETQ2ARUUBisBIiY9AQHblmesVCn%2BPilUrAFINhWWFTYFFKxn%2FgwpVFQpAfRnrPwY4RU2NhXhAAACAMgAAAOEBRQADwAZAAABMxQWMxEUBiMhIiY1ETQ2ARUUBisBIiY9AQHbYLOWVCn%2BPilUrAFINhWWFTYFFJaz%2FkIpVFQpAfRnrPwY4RU2NhXhAAACAAAAFAUOBBoAFAAaAAAJASUHFRcVJwc1NzU0Jj4CPwEnCQEFJTUFJQUO%2FYL%2Bhk5klpZkAQEBBQQvkwKCAVz%2Bov6iAV4BXgL%2F%2FuWqPOCWx5SVyJb6BA0GCgYDKEEBG%2F1ipqaTpaUAAAMAZAH0BLADIAAHAA8AFwAAEjIWFAYiJjQkMhYUBiImNCQyFhQGIiY0vHxYWHxYAeh8WFh8WAHofFhYfFgDIFh8WFh8WFh8WFh8WFh8WFh8AAAAAAMBkAAAArwETAAHAA8AFwAAADIWFAYiJjQSMhYUBiImNBIyFhQGIiY0Aeh8WFh8WFh8WFh8WFh8WFh8WARMWHxYWHz%2ByFh8WFh8%2FshYfFhYfAAAAAMAZABkBEwETAAPAB8ALwAAEyEyFh0BFAYjISImPQE0NhMhMhYdARQGIyEiJj0BNDYTITIWHQEUBiMhIiY9ATQ2fQO2Cg8PCvxKCg8PCgO2Cg8PCvxKCg8PCgO2Cg8PCvxKCg8PBEwPCpYKDw8KlgoP%2FnAPCpYKDw8KlgoP%2FnAPCpYKDw8KlgoPAAAABAAAAAAEsASwAA8AHwAvADMAAAEhMhYVERQGIyEiJjURNDYFISIGFREUFjMhMjY1ETQmBSEyFhURFAYjISImNRE0NhcVITUBXgH0ory7o%2F4Mpbm5Asv9qCk7OykCWCk7O%2F2xAfQVHR0V%2FgwVHR1HAZAEsLuj%2FgylubmlAfSlucg7Kf2oKTs7KQJYKTtkHRX%2B1BUdHRUBLBUdZMjIAAAAAAEAZABkBLAETAA7AAATITIWFAYrARUzMhYUBisBFTMyFhQGKwEVMzIWFAYjISImNDY7ATUjIiY0NjsBNSMiJjQ2OwE1IyImNDaWA%2BgVHR0VMjIVHR0VMjIVHR0VMjIVHR0V%2FBgVHR0VMjIVHR0VMjIVHR0VMjIVHR0ETB0qHcgdKh3IHSodyB0qHR0qHcgdKh3IHSodyB0qHQAAAAYBLAAFA%2BgEowAHAA0AEwAZAB8AKgAAAR4BBgcuATYBMhYVIiYlFAYjNDYBMhYVIiYlFAYjNDYDFRQGIiY9ARYzMgKKVz8%2FV1c%2FP%2F75fLB8sAK8sHyw%2FcB8sHywArywfLCwHSodKAMRBKNDsrJCQrKy%2FsCwfLB8fLB8sP7UsHywfHywfLD%2B05AVHR0VjgQAAAH%2FtQDIBJQDgQBCAAABNzYXAR4BBw4BKwEyFRQOBCsBIhE0NyYiBxYVECsBIi4DNTQzIyImJyY2NwE2HwEeAQ4BLwEHIScHBi4BNgLpRRkUASoLCAYFGg8IAQQNGyc%2FKZK4ChRUFQu4jjBJJxkHAgcPGQYGCAsBKhQaTBQVCiMUM7YDe7YsFCMKFgNuEwYS%2FtkLHw8OEw0dNkY4MhwBIBgXBAQYF%2F7gKjxTQyMNEw4PHwoBKBIHEwUjKBYGDMHBDAUWKCMAAAAAAgAAAAAEsASwACUAQwAAASM0LgUrAREUFh8BFSE1Mj4DNREjIg4FFSMRIQEjNC4DKwERFBYXMxUjNTI1ESMiDgMVIzUhBLAyCAsZEyYYGcgyGRn%2BcAQOIhoWyBkYJhMZCwgyA%2Bj9RBkIChgQEWQZDQzIMmQREBgKCBkB9AOEFSAVDggDAfyuFhkBAmRkAQUJFQ4DUgEDCA4VIBUBLP0SDxMKBQH%2BVwsNATIyGQGpAQUKEw%2BWAAAAAAMAAAAABEwErgAdACAAMAAAATUiJy4BLwEBIwEGBw4BDwEVITUiJj8BIRcWBiMVARsBARUUBiMhIiY9ATQ2MyEyFgPoGR4OFgUE%2Ft9F%2FtQSFQkfCwsBETE7EkUBJT0NISf%2B7IZ5AbEdFfwYFR0dFQPoFR0BLDIgDiIKCwLr%2FQ4jFQkTBQUyMisusKYiQTIBhwFW%2Fqr942QVHR0VZBUdHQADAAAAAASwBLAADwBHAEoAABMhMhYVERQGIyEiJjURNDYFIyIHAQYHBgcGHQEUFjMhMjY9ATQmIyInJj8BIRcWBwYjIgYdARQWMyEyNj0BNCYnIicmJyMBJhMjEzIETBUdHRX7tBUdHQJGRg0F%2FtUREhImDAsJAREIDAwINxAKCj8BCjkLEQwYCAwMCAE5CAwLCBEZGQ8B%2FuAFDsVnBLAdFfu0FR0dFQRMFR1SDP0PIBMSEAUNMggMDAgyCAwXDhmjmR8YEQwIMggMDAgyBwwBGRskAuwM%2FgUBCAAABAAAAAAEsASwAAMAEwAjACcAAAEhNSEFITIWFREUBiMhIiY1ETQ2KQEyFhURFAYjISImNRE0NhcRIREEsPtQBLD7ggGQFR0dFf5wFR0dAm0BkBUdHRX%2BcBUdHUcBLARMZMgdFfx8FR0dFQOEFR0dFf5wFR0dFQGQFR1k%2FtQBLAAEAAAAAASwBLAADwAfACMAJwAAEyEyFhURFAYjISImNRE0NgEhMhYVERQGIyEiJjURNDYXESEREyE1ITIBkBUdHRX%2BcBUdHQJtAZAVHR0V%2FnAVHR1HASzI%2B1AEsASwHRX8fBUdHRUDhBUd%2FgwdFf5wFR0dFQGQFR1k%2FtQBLP2oZAAAAAACAAAAZASwA%2BgAJwArAAATITIWFREzNTQ2MyEyFh0BMxUjFRQGIyEiJj0BIxEUBiMhIiY1ETQ2AREhETIBkBUdZB0VAZAVHWRkHRX%2BcBUdZB0V%2FnAVHR0CnwEsA%2BgdFf6ilhUdHRWWZJYVHR0Vlv6iFR0dFQMgFR3%2B1P7UASwAAAQAAAAABLAEsAADABMAFwAnAAAzIxEzFyEyFhURFAYjISImNRE0NhcRIREBITIWFREUBiMhIiY1ETQ2ZGRklgGQFR0dFf5wFR0dRwEs%2FqIDhBUdHRX8fBUdHQSwZB0V%2FnAVHR0VAZAVHWT%2B1AEs%2FgwdFf5wFR0dFQGQFR0AAAAAAgBkAAAETASwACcAKwAAATMyFhURFAYrARUhMhYVERQGIyEiJjURNDYzITUjIiY1ETQ2OwE1MwcRIRECWJYVHR0VlgHCFR0dFfx8FR0dFQFelhUdHRWWZMgBLARMHRX%2BcBUdZB0V%2FnAVHR0VAZAVHWQdFQGQFR1kyP7UASwAAAAEAAAAAASwBLAAAwATABcAJwAAISMRMwUhMhYVERQGIyEiJjURNDYXESERASEyFhURFAYjISImNRE0NgSwZGT9dgGQFR0dFf5wFR0dRwEs%2FK4DhBUdHRX8fBUdHQSwZB0V%2FnAVHR0VAZAVHWT%2B1AEs%2FgwdFf5wFR0dFQGQFR0AAAEBLAAwA28EgAAPAAAJAQYjIiY1ETQ2MzIXARYUA2H%2BEhcSDhAQDhIXAe4OAjX%2BEhcbGQPoGRsX%2FhIOKgAAAAABAUEAMgOEBH4ACwAACQE2FhURFAYnASY0AU8B7h0qKh3%2BEg4CewHuHREp%2FBgpER0B7g4qAAAAAAEAMgFBBH4DhAALAAATITIWBwEGIicBJjZkA%2BgpER3%2BEg4qDv4SHREDhCod%2FhIODgHuHSoAAAAAAQAyASwEfgNvAAsAAAkBFgYjISImNwE2MgJ7Ae4dESn8GCkRHQHuDioDYf4SHSoqHQHuDgAAAAACAAgAAASwBCgABgAKAAABFQE1LQE1ASE1IQK8%2FUwBnf5jBKj84AMgAuW2%2Fr3dwcHd%2B9jIAAAAAAIAAABkBLAEsAALADEAAAEjFTMVIREzNSM1IQEzND4FOwERFAYPARUhNSIuAzURMzIeBRUzESEEsMjI%2FtTIyAEs%2B1AyCAsZEyYYGWQyGRkBkAQOIhoWZBkYJhMZCwgy%2FOADhGRkASxkZP4MFSAVDggDAf3aFhkBAmRkAQUJFQ4CJgEDCA4VIBUBLAAAAgAAAAAETAPoACUAMQAAASM0LgUrAREUFh8BFSE1Mj4DNREjIg4FFSMRIQEjFTMVIREzNSM1IQMgMggLGRMmGBlkMhkZ%2FnAEDiIaFmQZGCYTGQsIMgMgASzIyP7UyMgBLAK8FSAVDggDAf3aFhkCAWRkAQUJFQ4CJgEDCA4VIBUBLPzgZGQBLGRkAAABAMgAZgNyBEoAEgAAATMyFgcJARYGKwEiJwEmNDcBNgK9oBAKDP4wAdAMChCgDQr%2BKQcHAdcKBEoWDP4w%2FjAMFgkB1wgUCAHXCQAAAQE%2BAGYD6ARKABIAAAEzMhcBFhQHAQYrASImNwkBJjYBU6ANCgHXBwf%2BKQoNoBAKDAHQ%2FjAMCgRKCf4pCBQI%2FikJFgwB0AHQDBYAAAEAZgDIBEoDcgASAAAAFh0BFAcBBiInASY9ATQ2FwkBBDQWCf4pCBQI%2FikJFgwB0AHQA3cKEKANCv4pBwcB1woNoBAKDP4wAdAAAAABAGYBPgRKA%2BgAEgAACQEWHQEUBicJAQYmPQE0NwE2MgJqAdcJFgz%2BMP4wDBYJAdcIFAPh%2FikKDaAQCgwB0P4wDAoQoA0KAdcHAAAAAgDZ%2F%2FkEPQSwAAUAOgAAARQGIzQ2BTMyFh8BNjc%2BAh4EBgcOBgcGIiYjIgYiJy4DLwEuAT4EHgEXJyY2A%2BiwfLD%2BVmQVJgdPBQsiKFAzRyorDwURAQQSFyozTSwNOkkLDkc3EDlfNyYHBw8GDyUqPjdGMR%2BTDA0EsHywfLDIHBPCAQIGBwcFDx81S21DBxlLR1xKQhEFBQcHGWt0bCQjP2hJNyATBwMGBcASGAAAAAACAMgAFQOEBLAAFgAaAAATITIWFREUBisBEQcGJjURIyImNRE0NhcVITX6AlgVHR0Vlv8TGpYVHR2rASwEsB0V%2FnAVHf4MsgkQFQKKHRUBkBUdZGRkAAAAAgDIABkETASwAA4AEgAAEyEyFhURBRElIREjETQ2ARU3NfoC7ic9%2FUQCWP1EZB8BDWQEsFEs%2FFt1A7Z9%2FBgEARc0%2FV1kFGQAAQAAAAECTW%2FDBF9fDzz1AB8EsAAAAADQdnOXAAAAANB2c5f%2FUf%2BcBdwFFAAAAAgAAgAAAAAAAAABAAAFFP%2BFAAAFFP9R%2FtQF3AABAAAAAAAAAAAAAAAAAAAAowG4ACgAAAAAAZAAAASwAAAEsABkBLAAAASwAAAEsABwAooAAAUUAAACigAABRQAAAGxAAABRQAAANgAAADYAAAAogAAAQQAAABIAAABBAAAAUUAAASwAGQEsAB7BLAAyASwAMgB9AAABLD%2F8gSwAAAEsAAABLD%2F8ASwAAAEsAAOBLAACQSwAGQEsP%2FTBLD%2F0wSwAAAEsAAABLAAAASwAAAEsAAABLAAJgSwAG4EsAAXBLAAFwSwABcEsABkBLAAGgSwAGQEsAAMBLAAZASwABcEsP%2BcBLAAZASwABcEsAAXBLAAAASwABcEsAAXBLAAFwSwAGQEsAAABLAAZASwAAAEsAAABLAAAASwAAAEsAAABLAAAASwAAAEsAAABLAAZASwAMgEsAAABLAAAASwADUEsABkBLAAyASw%2F7UEsAAhBLAAAASwAAAEsAAABLAAAASwAAAEsP%2BcBLAAAASwAAAEsAAABLAA2wSwABcEsAB1BLAAAASwAAAEsAAABLAACgSwAMgEsAAABLAAnQSwAMgEsADIBLAAyASwAAAEsP%2F%2BBLABLASwAGQEsACIBLABOwSwABcEsAAXBLAAFwSwABcEsAAXBLAAFwSwAAAEsAAXBLAAFwSwABcEsAAXBLAAAASwALcEsAC3BLAAAASwAAAEsABJBLAAFwSwAAAEsAAABLAAXQSw%2F9wEsP%2FcBLD%2FnwSwAGQEsAAABLAAAASwAAAEsABkBLD%2F%2FwSwAAAEsP9RBLAABgSwAAAEsAAABLABRQSwAAEEsAAABLD%2FnASwAEoEsAAUBLAAAASwAAAEsAAABLD%2FnASwAGEEsP%2F9BLAAFgSwABYEsAAWBLAAFgSwABgEsAAABMQAAASwAGQAAAAAAAD%2F2ABkADkAyAAAAScAZAAZABkAGQAZABkAGQAZAAAAAAAAAAAAAADZAAAAAAAOAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAMAZABkAAAAEAAAAAAAZP%2Bc%2F5z%2FnP%2Bc%2F5z%2FnP%2Bc%2F5wACQAJ%2F%2FL%2F8gBkAHkAJwBkAGQAAAAAAGT%2FogAAAAAAAAAAAAAAAADIAGQAAAABAI8AAP%2Bc%2F5wAZAAEAMgAyAAAAGQBkABkAAAAZAEs%2F7UAAAAAAAAAAAAAAAAAAABkAAABLAFBADIAMgAIAAAAAADIAT4AZgBmANkAyADIAAAAKgAqACoAKgCyAOgA6AFOAU4BTgFOAU4BTgFOAU4BTgFOAU4BTgFOAU4BpAIGAiICfgKGAqwC5ANGA24DjAPEBAgEMgRiBKIE3AVcBboGcgb0ByAHYgfKCB4IYgi%2BCTYJhAm2Cd4KKApMCpQK4gswC4oLygwIDFgNKg1eDbAODg5oDrQPKA%2BmD%2BYQEhBUEJAQqhEqEXYRthIKEjgSfBLAExoTdBPQFCoU1BU8FagVzBYEFjYWYBawFv4XUhemGAIYLhhqGJYYsBjgGP4ZKBloGZQZxBnaGe4aNhpoGrga9hteG7QcMhyUHOIdHB1EHWwdlB28HeYeLh52HsAfYh%2FSIEYgviEyIXYhuCJAIpYiuCMOIyIjOCN6I8Ij4CQCJDAkXiSWJOIlNCVgJbwmFCZ%2BJuYnUCe8J%2FgoNChwKKwpoCnMKiYqSiqEKworeiwILGgsuizsLRwtiC30LiguZi6iLtgvDi9GL34vsi%2F4MD4whDDSMRIxYDGuMegyJDJeMpoy3jMiMz4zaDO2NBg0YDSoNNI1LDWeNeg2PjZ8Ntw3GjdON5I31DgQOEI4hjjIOQo5SjmIOcw6HDpsOpo63jugO9w8GDxQPKI8%2BD0yPew%2BOj6MPtQ%2FKD9uP6o%2F%2BkBIQIBAxkECQX5CGEKoQu5DGENCQ3ZDoEPKRBBEYESuRPZFWkW2RgZGdEa0RvZHNkd2R7ZH9kgWSDJITkhqSIZIzEkSSThJXkmESapKAkouSlIAAQAAARcApwARAAAAAAACAAAAAQABAAAAQAAuAAAAAAAAABAAxgABAAAAAAATABIAAAADAAEECQAAAGoAEgADAAEECQABACgAfAADAAEECQACAA4ApAADAAEECQADAEwAsgADAAEECQAEADgA%2FgADAAEECQAFAHgBNgADAAEECQAGADYBrgADAAEECQAIABYB5AADAAEECQAJABYB%2BgADAAEECQALACQCEAADAAEECQAMACQCNAADAAEECQATACQCWAADAAEECQDIABYCfAADAAEECQDJADACkgADAAEECdkDABoCwnd3dy5nbHlwaGljb25zLmNvbQBDAG8AcAB5AHIAaQBnAGgAdAAgAKkAIAAyADAAMQA0ACAAYgB5ACAASgBhAG4AIABLAG8AdgBhAHIAaQBrAC4AIABBAGwAbAAgAHIAaQBnAGgAdABzACAAcgBlAHMAZQByAHYAZQBkAC4ARwBMAFkAUABIAEkAQwBPAE4AUwAgAEgAYQBsAGYAbABpAG4AZwBzAFIAZQBnAHUAbABhAHIAMQAuADAAMAA5ADsAVQBLAFcATgA7AEcATABZAFAASABJAEMATwBOAFMASABhAGwAZgBsAGkAbgBnAHMALQBSAGUAZwB1AGwAYQByAEcATABZAFAASABJAEMATwBOAFMAIABIAGEAbABmAGwAaQBuAGcAcwAgAFIAZQBnAHUAbABhAHIAVgBlAHIAcwBpAG8AbgAgADEALgAwADAAOQA7AFAAUwAgADAAMAAxAC4AMAAwADkAOwBoAG8AdABjAG8AbgB2ACAAMQAuADAALgA3ADAAOwBtAGEAawBlAG8AdABmAC4AbABpAGIAMgAuADUALgA1ADgAMwAyADkARwBMAFkAUABIAEkAQwBPAE4AUwBIAGEAbABmAGwAaQBuAGcAcwAtAFIAZQBnAHUAbABhAHIASgBhAG4AIABLAG8AdgBhAHIAaQBrAEoAYQBuACAASwBvAHYAYQByAGkAawB3AHcAdwAuAGcAbAB5AHAAaABpAGMAbwBuAHMALgBjAG8AbQB3AHcAdwAuAGcAbAB5AHAAaABpAGMAbwBuAHMALgBjAG8AbQB3AHcAdwAuAGcAbAB5AHAAaABpAGMAbwBuAHMALgBjAG8AbQBXAGUAYgBmAG8AbgB0ACAAMQAuADAAVwBlAGQAIABPAGMAdAAgADIAOQAgADAANgA6ADMANgA6ADAANwAgADIAMAAxADQARgBvAG4AdAAgAFMAcQB1AGkAcgByAGUAbAAAAAIAAAAAAAD%2FtQAyAAAAAAAAAAAAAAAAAAAAAAAAAAABFwAAAQIBAwADAA0ADgEEAJYBBQEGAQcBCAEJAQoBCwEMAQ0BDgEPARABEQESARMA7wEUARUBFgEXARgBGQEaARsBHAEdAR4BHwEgASEBIgEjASQBJQEmAScBKAEpASoBKwEsAS0BLgEvATABMQEyATMBNAE1ATYBNwE4ATkBOgE7ATwBPQE%2BAT8BQAFBAUIBQwFEAUUBRgFHAUgBSQFKAUsBTAFNAU4BTwFQAVEBUgFTAVQBVQFWAVcBWAFZAVoBWwFcAV0BXgFfAWABYQFiAWMBZAFlAWYBZwFoAWkBagFrAWwBbQFuAW8BcAFxAXIBcwF0AXUBdgF3AXgBeQF6AXsBfAF9AX4BfwGAAYEBggGDAYQBhQGGAYcBiAGJAYoBiwGMAY0BjgGPAZABkQGSAZMBlAGVAZYBlwGYAZkBmgGbAZwBnQGeAZ8BoAGhAaIBowGkAaUBpgGnAagBqQGqAasBrAGtAa4BrwGwAbEBsgGzAbQBtQG2AbcBuAG5AboBuwG8Ab0BvgG%2FAcABwQHCAcMBxAHFAcYBxwHIAckBygHLAcwBzQHOAc8B0AHRAdIB0wHUAdUB1gHXAdgB2QHaAdsB3AHdAd4B3wHgAeEB4gHjAeQB5QHmAecB6AHpAeoB6wHsAe0B7gHvAfAB8QHyAfMB9AH1AfYB9wH4AfkB%2BgH7AfwB%2FQH%2BAf8CAAIBAgICAwIEAgUCBgIHAggCCQIKAgsCDAINAg4CDwIQAhECEgZnbHlwaDEGZ2x5cGgyB3VuaTAwQTAHdW5pMjAwMAd1bmkyMDAxB3VuaTIwMDIHdW5pMjAwMwd1bmkyMDA0B3VuaTIwMDUHdW5pMjAwNgd1bmkyMDA3B3VuaTIwMDgHdW5pMjAwOQd1bmkyMDBBB3VuaTIwMkYHdW5pMjA1RgRFdXJvB3VuaTIwQkQHdW5pMjMxQgd1bmkyNUZDB3VuaTI2MDEHdW5pMjZGQQd1bmkyNzA5B3VuaTI3MEYHdW5pRTAwMQd1bmlFMDAyB3VuaUUwMDMHdW5pRTAwNQd1bmlFMDA2B3VuaUUwMDcHdW5pRTAwOAd1bmlFMDA5B3VuaUUwMTAHdW5pRTAxMQd1bmlFMDEyB3VuaUUwMTMHdW5pRTAxNAd1bmlFMDE1B3VuaUUwMTYHdW5pRTAxNwd1bmlFMDE4B3VuaUUwMTkHdW5pRTAyMAd1bmlFMDIxB3VuaUUwMjIHdW5pRTAyMwd1bmlFMDI0B3VuaUUwMjUHdW5pRTAyNgd1bmlFMDI3B3VuaUUwMjgHdW5pRTAyOQd1bmlFMDMwB3VuaUUwMzEHdW5pRTAzMgd1bmlFMDMzB3VuaUUwMzQHdW5pRTAzNQd1bmlFMDM2B3VuaUUwMzcHdW5pRTAzOAd1bmlFMDM5B3VuaUUwNDAHdW5pRTA0MQd1bmlFMDQyB3VuaUUwNDMHdW5pRTA0NAd1bmlFMDQ1B3VuaUUwNDYHdW5pRTA0Nwd1bmlFMDQ4B3VuaUUwNDkHdW5pRTA1MAd1bmlFMDUxB3VuaUUwNTIHdW5pRTA1Mwd1bmlFMDU0B3VuaUUwNTUHdW5pRTA1Ngd1bmlFMDU3B3VuaUUwNTgHdW5pRTA1OQd1bmlFMDYwB3VuaUUwNjIHdW5pRTA2Mwd1bmlFMDY0B3VuaUUwNjUHdW5pRTA2Ngd1bmlFMDY3B3VuaUUwNjgHdW5pRTA2OQd1bmlFMDcwB3VuaUUwNzEHdW5pRTA3Mgd1bmlFMDczB3VuaUUwNzQHdW5pRTA3NQd1bmlFMDc2B3VuaUUwNzcHdW5pRTA3OAd1bmlFMDc5B3VuaUUwODAHdW5pRTA4MQd1bmlFMDgyB3VuaUUwODMHdW5pRTA4NAd1bmlFMDg1B3VuaUUwODYHdW5pRTA4Nwd1bmlFMDg4B3VuaUUwODkHdW5pRTA5MAd1bmlFMDkxB3VuaUUwOTIHdW5pRTA5Mwd1bmlFMDk0B3VuaUUwOTUHdW5pRTA5Ngd1bmlFMDk3B3VuaUUxMDEHdW5pRTEwMgd1bmlFMTAzB3VuaUUxMDQHdW5pRTEwNQd1bmlFMTA2B3VuaUUxMDcHdW5pRTEwOAd1bmlFMTA5B3VuaUUxMTAHdW5pRTExMQd1bmlFMTEyB3VuaUUxMTMHdW5pRTExNAd1bmlFMTE1B3VuaUUxMTYHdW5pRTExNwd1bmlFMTE4B3VuaUUxMTkHdW5pRTEyMAd1bmlFMTIxB3VuaUUxMjIHdW5pRTEyMwd1bmlFMTI0B3VuaUUxMjUHdW5pRTEyNgd1bmlFMTI3B3VuaUUxMjgHdW5pRTEyOQd1bmlFMTMwB3VuaUUxMzEHdW5pRTEzMgd1bmlFMTMzB3VuaUUxMzQHdW5pRTEzNQd1bmlFMTM2B3VuaUUxMzcHdW5pRTEzOAd1bmlFMTM5B3VuaUUxNDAHdW5pRTE0MQd1bmlFMTQyB3VuaUUxNDMHdW5pRTE0NAd1bmlFMTQ1B3VuaUUxNDYHdW5pRTE0OAd1bmlFMTQ5B3VuaUUxNTAHdW5pRTE1MQd1bmlFMTUyB3VuaUUxNTMHdW5pRTE1NAd1bmlFMTU1B3VuaUUxNTYHdW5pRTE1Nwd1bmlFMTU4B3VuaUUxNTkHdW5pRTE2MAd1bmlFMTYxB3VuaUUxNjIHdW5pRTE2Mwd1bmlFMTY0B3VuaUUxNjUHdW5pRTE2Ngd1bmlFMTY3B3VuaUUxNjgHdW5pRTE2OQd1bmlFMTcwB3VuaUUxNzEHdW5pRTE3Mgd1bmlFMTczB3VuaUUxNzQHdW5pRTE3NQd1bmlFMTc2B3VuaUUxNzcHdW5pRTE3OAd1bmlFMTc5B3VuaUUxODAHdW5pRTE4MQd1bmlFMTgyB3VuaUUxODMHdW5pRTE4NAd1bmlFMTg1B3VuaUUxODYHdW5pRTE4Nwd1bmlFMTg4B3VuaUUxODkHdW5pRTE5MAd1bmlFMTkxB3VuaUUxOTIHdW5pRTE5Mwd1bmlFMTk0B3VuaUUxOTUHdW5pRTE5Nwd1bmlFMTk4B3VuaUUxOTkHdW5pRTIwMAd1bmlFMjAxB3VuaUUyMDIHdW5pRTIwMwd1bmlFMjA0B3VuaUUyMDUHdW5pRTIwNgd1bmlFMjA5B3VuaUUyMTAHdW5pRTIxMQd1bmlFMjEyB3VuaUUyMTMHdW5pRTIxNAd1bmlFMjE1B3VuaUUyMTYHdW5pRTIxOAd1bmlFMjE5B3VuaUUyMjEHdW5pRTIyMwd1bmlFMjI0B3VuaUUyMjUHdW5pRTIyNgd1bmlFMjI3B3VuaUUyMzAHdW5pRTIzMQd1bmlFMjMyB3VuaUUyMzMHdW5pRTIzNAd1bmlFMjM1B3VuaUUyMzYHdW5pRTIzNwd1bmlFMjM4B3VuaUUyMzkHdW5pRTI0MAd1bmlFMjQxB3VuaUUyNDIHdW5pRTI0Mwd1bmlFMjQ0B3VuaUUyNDUHdW5pRTI0Ngd1bmlFMjQ3B3VuaUUyNDgHdW5pRTI0OQd1bmlFMjUwB3VuaUUyNTEHdW5pRTI1Mgd1bmlFMjUzB3VuaUUyNTQHdW5pRTI1NQd1bmlFMjU2B3VuaUUyNTcHdW5pRTI1OAd1bmlFMjU5B3VuaUUyNjAHdW5pRjhGRgZ1MUY1MTEGdTFGNkFBAAAAAAFUUMMXAAA%3D%29%20format%28%27truetype%27%29%2Curl%28data%3Aimage%2Fsvg%2Bxml%3Bbase64%2CPD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI%2FPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiID4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgo8bWV0YWRhdGE%2BPC9tZXRhZGF0YT4KPGRlZnM%2BCjxmb250IGlkPSJnbHlwaGljb25zX2hhbGZsaW5nc3JlZ3VsYXIiIGhvcml6LWFkdi14PSIxMjAwIiA%2BCjxmb250LWZhY2UgdW5pdHMtcGVyLWVtPSIxMjAwIiBhc2NlbnQ9Ijk2MCIgZGVzY2VudD0iLTI0MCIgLz4KPG1pc3NpbmctZ2x5cGggaG9yaXotYWR2LXg9IjUwMCIgLz4KPGdseXBoIGhvcml6LWFkdi14PSIwIiAvPgo8Z2x5cGggaG9yaXotYWR2LXg9IjQwMCIgLz4KPGdseXBoIHVuaWNvZGU9IiAiIC8%2BCjxnbHlwaCB1bmljb2RlPSIqIiBkPSJNNjAwIDExMDBxMTUgMCAzNCAtMS41dDMwIC0zLjVsMTEgLTFxMTAgLTIgMTcuNSAtMTAuNXQ3LjUgLTE4LjV2LTIyNGwxNTggMTU4cTcgNyAxOCA4dDE5IC02bDEwNiAtMTA2cTcgLTggNiAtMTl0LTggLTE4bC0xNTggLTE1OGgyMjRxMTAgMCAxOC41IC03LjV0MTAuNSAtMTcuNXE2IC00MSA2IC03NXEwIC0xNSAtMS41IC0zNHQtMy41IC0zMGwtMSAtMTFxLTIgLTEwIC0xMC41IC0xNy41dC0xOC41IC03LjVoLTIyNGwxNTggLTE1OCBxNyAtNyA4IC0xOHQtNiAtMTlsLTEwNiAtMTA2cS04IC03IC0xOSAtNnQtMTggOGwtMTU4IDE1OHYtMjI0cTAgLTEwIC03LjUgLTE4LjV0LTE3LjUgLTEwLjVxLTQxIC02IC03NSAtNnEtMTUgMCAtMzQgMS41dC0zMCAzLjVsLTExIDFxLTEwIDIgLTE3LjUgMTAuNXQtNy41IDE4LjV2MjI0bC0xNTggLTE1OHEtNyAtNyAtMTggLTh0LTE5IDZsLTEwNiAxMDZxLTcgOCAtNiAxOXQ4IDE4bDE1OCAxNThoLTIyNHEtMTAgMCAtMTguNSA3LjUgdC0xMC41IDE3LjVxLTYgNDEgLTYgNzVxMCAxNSAxLjUgMzR0My41IDMwbDEgMTFxMiAxMCAxMC41IDE3LjV0MTguNSA3LjVoMjI0bC0xNTggMTU4cS03IDcgLTggMTh0NiAxOWwxMDYgMTA2cTggNyAxOSA2dDE4IC04bDE1OCAtMTU4djIyNHEwIDEwIDcuNSAxOC41dDE3LjUgMTAuNXE0MSA2IDc1IDZ6IiAvPgo8Z2x5cGggdW5pY29kZT0iKyIgZD0iTTQ1MCAxMTAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMzUwaDM1MHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0zNTB2LTM1MHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMjAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYzNTBoLTM1MHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MjAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNSBoMzUwdjM1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4YTA7IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4YTU7IiBkPSJNODI1IDExMDBoMjUwcTEwIDAgMTIuNSAtNXQtNS41IC0xM2wtMzY0IC0zNjRxLTYgLTYgLTExIC0xOGgyNjhxMTAgMCAxMyAtNnQtMyAtMTRsLTEyMCAtMTYwcS02IC04IC0xOCAtMTR0LTIyIC02aC0xMjV2LTEwMGgyNzVxMTAgMCAxMyAtNnQtMyAtMTRsLTEyMCAtMTYwcS02IC04IC0xOCAtMTR0LTIyIC02aC0xMjV2LTE3NHEwIC0xMSAtNy41IC0xOC41dC0xOC41IC03LjVoLTE0OHEtMTEgMCAtMTguNSA3LjV0LTcuNSAxOC41djE3NCBoLTI3NXEtMTAgMCAtMTMgNnQzIDE0bDEyMCAxNjBxNiA4IDE4IDE0dDIyIDZoMTI1djEwMGgtMjc1cS0xMCAwIC0xMyA2dDMgMTRsMTIwIDE2MHE2IDggMTggMTR0MjIgNmgxMThxLTUgMTIgLTExIDE4bC0zNjQgMzY0cS04IDggLTUuNSAxM3QxMi41IDVoMjUwcTI1IDAgNDMgLTE4bDE2NCAtMTY0cTggLTggMTggLTh0MTggOGwxNjQgMTY0cTE4IDE4IDQzIDE4eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDIwMDA7IiBob3Jpei1hZHYteD0iNjUwIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjAwMTsiIGhvcml6LWFkdi14PSIxMzAwIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjAwMjsiIGhvcml6LWFkdi14PSI2NTAiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyMDAzOyIgaG9yaXotYWR2LXg9IjEzMDAiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyMDA0OyIgaG9yaXotYWR2LXg9IjQzMyIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDIwMDU7IiBob3Jpei1hZHYteD0iMzI1IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjAwNjsiIGhvcml6LWFkdi14PSIyMTYiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyMDA3OyIgaG9yaXotYWR2LXg9IjIxNiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDIwMDg7IiBob3Jpei1hZHYteD0iMTYyIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjAwOTsiIGhvcml6LWFkdi14PSIyNjAiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyMDBhOyIgaG9yaXotYWR2LXg9IjcyIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjAyZjsiIGhvcml6LWFkdi14PSIyNjAiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyMDVmOyIgaG9yaXotYWR2LXg9IjMyNSIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDIwYWM7IiBkPSJNNzQ0IDExOThxMjQyIDAgMzU0IC0xODlxNjAgLTEwNCA2NiAtMjA5aC0xODFxMCA0NSAtMTcuNSA4Mi41dC00My41IDYxLjV0LTU4IDQwLjV0LTYwLjUgMjR0LTUxLjUgNy41cS0xOSAwIC00MC41IC01LjV0LTQ5LjUgLTIwLjV0LTUzIC0zOHQtNDkgLTYyLjV0LTM5IC04OS41aDM3OWwtMTAwIC0xMDBoLTMwMHEtNiAtNTAgLTYgLTEwMGg0MDZsLTEwMCAtMTAwaC0zMDBxOSAtNzQgMzMgLTEzMnQ1Mi41IC05MXQ2MS41IC01NC41dDU5IC0yOSB0NDcgLTcuNXEyMiAwIDUwLjUgNy41dDYwLjUgMjQuNXQ1OCA0MXQ0My41IDYxdDE3LjUgODBoMTc0cS0zMCAtMTcxIC0xMjggLTI3OHEtMTA3IC0xMTcgLTI3NCAtMTE3cS0yMDYgMCAtMzI0IDE1OHEtMzYgNDggLTY5IDEzM3QtNDUgMjA0aC0yMTdsMTAwIDEwMGgxMTJxMSA0NyA2IDEwMGgtMjE4bDEwMCAxMDBoMTM0cTIwIDg3IDUxIDE1My41dDYyIDEwMy41cTExNyAxNDEgMjk3IDE0MXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyMGJkOyIgZD0iTTQyOCAxMjAwaDM1MHE2NyAwIDEyMCAtMTN0ODYgLTMxdDU3IC00OS41dDM1IC01Ni41dDE3IC02NC41dDYuNSAtNjAuNXQwLjUgLTU3di0xNi41di0xNi41cTAgLTM2IC0wLjUgLTU3dC02LjUgLTYxdC0xNyAtNjV0LTM1IC01N3QtNTcgLTUwLjV0LTg2IC0zMS41dC0xMjAgLTEzaC0xNzhsLTIgLTEwMGgyODhxMTAgMCAxMyAtNnQtMyAtMTRsLTEyMCAtMTYwcS02IC04IC0xOCAtMTR0LTIyIC02aC0xMzh2LTE3NXEwIC0xMSAtNS41IC0xOCB0LTE1LjUgLTdoLTE0OXEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE3NWgtMjY3cS0xMCAwIC0xMyA2dDMgMTRsMTIwIDE2MHE2IDggMTggMTR0MjIgNmgxMTd2MTAwaC0yNjdxLTEwIDAgLTEzIDZ0MyAxNGwxMjAgMTYwcTYgOCAxOCAxNHQyMiA2aDExN3Y0NzVxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNNjAwIDEwMDB2LTMwMGgyMDNxNjQgMCA4Ni41IDMzdDIyLjUgMTE5cTAgODQgLTIyLjUgMTE2dC04Ni41IDMyaC0yMDN6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjIxMjsiIGQ9Ik0yNTAgNzAwaDgwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC04MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjMxYjsiIGQ9Ik0xMDAwIDEyMDB2LTE1MHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTB2LTEwMHEwIC05MSAtNDkuNSAtMTY1LjV0LTEzMC41IC0xMDkuNXE4MSAtMzUgMTMwLjUgLTEwOS41dDQ5LjUgLTE2NS41di0xNTBoNTBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTE1MGgtODAwdjE1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoNTB2MTUwcTAgOTEgNDkuNSAxNjUuNXQxMzAuNSAxMDkuNXEtODEgMzUgLTEzMC41IDEwOS41IHQtNDkuNSAxNjUuNXYxMDBoLTUwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxNTBoODAwek00MDAgMTAwMHYtMTAwcTAgLTYwIDMyLjUgLTEwOS41dDg3LjUgLTczLjVxMjggLTEyIDQ0IC0zN3QxNiAtNTV0LTE2IC01NXQtNDQgLTM3cS01NSAtMjQgLTg3LjUgLTczLjV0LTMyLjUgLTEwOS41di0xNTBoNDAwdjE1MHEwIDYwIC0zMi41IDEwOS41dC04Ny41IDczLjVxLTI4IDEyIC00NCAzN3QtMTYgNTV0MTYgNTV0NDQgMzcgcTU1IDI0IDg3LjUgNzMuNXQzMi41IDEwOS41djEwMGgtNDAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDI1ZmM7IiBob3Jpei1hZHYteD0iNTAwIiBkPSJNMCAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDI2MDE7IiBkPSJNNTAzIDEwODlxMTEwIDAgMjAwLjUgLTU5LjV0MTM0LjUgLTE1Ni41cTQ0IDE0IDkwIDE0cTEyMCAwIDIwNSAtODYuNXQ4NSAtMjA2LjVxMCAtMTIxIC04NSAtMjA3LjV0LTIwNSAtODYuNWgtNzUwcS03OSAwIC0xMzUuNSA1N3QtNTYuNSAxMzdxMCA2OSA0Mi41IDEyMi41dDEwOC41IDY3LjVxLTIgMTIgLTIgMzdxMCAxNTMgMTA4IDI2MC41dDI2MCAxMDcuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyNmZhOyIgZD0iTTc3NCAxMTkzLjVxMTYgLTkuNSAyMC41IC0yN3QtNS41IC0zMy41bC0xMzYgLTE4N2w0NjcgLTc0NmgzMHEyMCAwIDM1IC0xOC41dDE1IC0zOS41di00MmgtMTIwMHY0MnEwIDIxIDE1IDM5LjV0MzUgMTguNWgzMGw0NjggNzQ2bC0xMzUgMTgzcS0xMCAxNiAtNS41IDM0dDIwLjUgMjh0MzQgNS41dDI4IC0yMC41bDExMSAtMTQ4bDExMiAxNTBxOSAxNiAyNyAyMC41dDM0IC01ek02MDAgMjAwaDM3N2wtMTgyIDExMmwtMTk1IDUzNHYtNjQ2eiAiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3gyNzA5OyIgZD0iTTI1IDExMDBoMTE1MHExMCAwIDEyLjUgLTV0LTUuNSAtMTNsLTU2NCAtNTY3cS04IC04IC0xOCAtOHQtMTggOGwtNTY0IDU2N3EtOCA4IC01LjUgMTN0MTIuNSA1ek0xOCA4ODJsMjY0IC0yNjRxOCAtOCA4IC0xOHQtOCAtMThsLTI2NCAtMjY0cS04IC04IC0xMyAtNS41dC01IDEyLjV2NTUwcTAgMTAgNSAxMi41dDEzIC01LjV6TTkxOCA2MThsMjY0IDI2NHE4IDggMTMgNS41dDUgLTEyLjV2LTU1MHEwIC0xMCAtNSAtMTIuNXQtMTMgNS41IGwtMjY0IDI2NHEtOCA4IC04IDE4dDggMTh6TTgxOCA0ODJsMzY0IC0zNjRxOCAtOCA1LjUgLTEzdC0xMi41IC01aC0xMTUwcS0xMCAwIC0xMi41IDV0NS41IDEzbDM2NCAzNjRxOCA4IDE4IDh0MTggLThsMTY0IC0xNjRxOCAtOCAxOCAtOHQxOCA4bDE2NCAxNjRxOCA4IDE4IDh0MTggLTh6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4MjcwZjsiIGQ9Ik0xMDExIDEyMTBxMTkgMCAzMyAtMTNsMTUzIC0xNTNxMTMgLTE0IDEzIC0zM3QtMTMgLTMzbC05OSAtOTJsLTIxNCAyMTRsOTUgOTZxMTMgMTQgMzIgMTR6TTEwMTMgODAwbC02MTUgLTYxNGwtMjE0IDIxNGw2MTQgNjE0ek0zMTcgOTZsLTMzMyAtMTEybDExMCAzMzV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAwMTsiIGQ9Ik03MDAgNjUwdi01NTBoMjUwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MGgtODAwdjUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNWgyNTB2NTUwbC01MDAgNTUwaDEyMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAwMjsiIGQ9Ik0zNjggMTAxN2w2NDUgMTYzcTM5IDE1IDYzIDB0MjQgLTQ5di04MzFxMCAtNTUgLTQxLjUgLTk1LjV0LTExMS41IC02My41cS03OSAtMjUgLTE0NyAtNC41dC04NiA3NXQyNS41IDExMS41dDEyMi41IDgycTcyIDI0IDEzOCA4djUyMWwtNjAwIC0xNTV2LTYwNnEwIC00MiAtNDQgLTkwdC0xMDkgLTY5cS03OSAtMjYgLTE0NyAtNS41dC04NiA3NS41dDI1LjUgMTExLjV0MTIyLjUgODIuNXE3MiAyNCAxMzggN3Y2MzlxMCAzOCAxNC41IDU5IHQ1My41IDM0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMDM7IiBkPSJNNTAwIDExOTFxMTAwIDAgMTkxIC0zOXQxNTYuNSAtMTA0LjV0MTA0LjUgLTE1Ni41dDM5IC0xOTFsLTEgLTJsMSAtNXEwIC0xNDEgLTc4IC0yNjJsMjc1IC0yNzRxMjMgLTI2IDIyLjUgLTQ0LjV0LTIyLjUgLTQyLjVsLTU5IC01OHEtMjYgLTIwIC00Ni41IC0yMHQtMzkuNSAyMGwtMjc1IDI3NHEtMTE5IC03NyAtMjYxIC03N2wtNSAxbC0yIC0xcS0xMDAgMCAtMTkxIDM5dC0xNTYuNSAxMDQuNXQtMTA0LjUgMTU2LjV0LTM5IDE5MSB0MzkgMTkxdDEwNC41IDE1Ni41dDE1Ni41IDEwNC41dDE5MSAzOXpNNTAwIDEwMjJxLTg4IDAgLTE2MiAtNDN0LTExNyAtMTE3dC00MyAtMTYydDQzIC0xNjJ0MTE3IC0xMTd0MTYyIC00M3QxNjIgNDN0MTE3IDExN3Q0MyAxNjJ0LTQzIDE2MnQtMTE3IDExN3QtMTYyIDQzeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMDU7IiBkPSJNNjQ5IDk0OXE0OCA2OCAxMDkuNSAxMDR0MTIxLjUgMzguNXQxMTguNSAtMjB0MTAyLjUgLTY0dDcxIC0xMDAuNXQyNyAtMTIzcTAgLTU3IC0zMy41IC0xMTcuNXQtOTQgLTEyNC41dC0xMjYuNSAtMTI3LjV0LTE1MCAtMTUyLjV0LTE0NiAtMTc0cS02MiA4NSAtMTQ1LjUgMTc0dC0xNTAgMTUyLjV0LTEyNi41IDEyNy41dC05My41IDEyNC41dC0zMy41IDExNy41cTAgNjQgMjggMTIzdDczIDEwMC41dDEwNCA2NHQxMTkgMjAgdDEyMC41IC0zOC41dDEwNC41IC0xMDR6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAwNjsiIGQ9Ik00MDcgODAwbDEzMSAzNTNxNyAxOSAxNy41IDE5dDE3LjUgLTE5bDEyOSAtMzUzaDQyMXEyMSAwIDI0IC04LjV0LTE0IC0yMC41bC0zNDIgLTI0OWwxMzAgLTQwMXE3IC0yMCAtMC41IC0yNS41dC0yNC41IDYuNWwtMzQzIDI0NmwtMzQyIC0yNDdxLTE3IC0xMiAtMjQuNSAtNi41dC0wLjUgMjUuNWwxMzAgNDAwbC0zNDcgMjUxcS0xNyAxMiAtMTQgMjAuNXQyMyA4LjVoNDI5eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMDc7IiBkPSJNNDA3IDgwMGwxMzEgMzUzcTcgMTkgMTcuNSAxOXQxNy41IC0xOWwxMjkgLTM1M2g0MjFxMjEgMCAyNCAtOC41dC0xNCAtMjAuNWwtMzQyIC0yNDlsMTMwIC00MDFxNyAtMjAgLTAuNSAtMjUuNXQtMjQuNSA2LjVsLTM0MyAyNDZsLTM0MiAtMjQ3cS0xNyAtMTIgLTI0LjUgLTYuNXQtMC41IDI1LjVsMTMwIDQwMGwtMzQ3IDI1MXEtMTcgMTIgLTE0IDIwLjV0MjMgOC41aDQyOXpNNDc3IDcwMGgtMjQwbDE5NyAtMTQybC03NCAtMjI2IGwxOTMgMTM5bDE5NSAtMTQwbC03NCAyMjlsMTkyIDE0MGgtMjM0bC03OCAyMTF6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAwODsiIGQ9Ik02MDAgMTIwMHExMjQgMCAyMTIgLTg4dDg4IC0yMTJ2LTI1MHEwIC00NiAtMzEgLTk4dC02OSAtNTJ2LTc1cTAgLTEwIDYgLTIxLjV0MTUgLTE3LjVsMzU4IC0yMzBxOSAtNSAxNSAtMTYuNXQ2IC0yMS41di05M3EwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTExNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY5M3EwIDEwIDYgMjEuNXQxNSAxNi41bDM1OCAyMzBxOSA2IDE1IDE3LjV0NiAyMS41djc1cS0zOCAwIC02OSA1MiB0LTMxIDk4djI1MHEwIDEyNCA4OCAyMTJ0MjEyIDg4eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMDk7IiBkPSJNMjUgMTEwMGgxMTUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMTA1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTExNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxMDUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTEwMCAxMDAwdi0xMDBoMTAwdjEwMGgtMTAwek04NzUgMTAwMGgtNTUwcS0xMCAwIC0xNy41IC03LjV0LTcuNSAtMTcuNXYtMzUwcTAgLTEwIDcuNSAtMTcuNXQxNy41IC03LjVoNTUwIHExMCAwIDE3LjUgNy41dDcuNSAxNy41djM1MHEwIDEwIC03LjUgMTcuNXQtMTcuNSA3LjV6TTEwMDAgMTAwMHYtMTAwaDEwMHYxMDBoLTEwMHpNMTAwIDgwMHYtMTAwaDEwMHYxMDBoLTEwMHpNMTAwMCA4MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTEwMCA2MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTEwMDAgNjAwdi0xMDBoMTAwdjEwMGgtMTAwek04NzUgNTAwaC01NTBxLTEwIDAgLTE3LjUgLTcuNXQtNy41IC0xNy41di0zNTBxMCAtMTAgNy41IC0xNy41IHQxNy41IC03LjVoNTUwcTEwIDAgMTcuNSA3LjV0Ny41IDE3LjV2MzUwcTAgMTAgLTcuNSAxNy41dC0xNy41IDcuNXpNMTAwIDQwMHYtMTAwaDEwMHYxMDBoLTEwMHpNMTAwMCA0MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTEwMCAyMDB2LTEwMGgxMDB2MTAwaC0xMDB6TTEwMDAgMjAwdi0xMDBoMTAwdjEwMGgtMTAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMTA7IiBkPSJNNTAgMTEwMGg0MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTQwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNDAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY0MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek02NTAgMTEwMGg0MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTQwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNDAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY0MDAgcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgNTAwaDQwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNDAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC00MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djQwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTY1MCA1MDBoNDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di00MDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTQwMCBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djQwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAxMTsiIGQ9Ik01MCAxMTAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTQ1MCAxMTAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek04NTAgMTEwMGgyMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTIwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMjAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYyMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCA3MDBoMjAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0yMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTIwMCBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTQ1MCA3MDBoMjAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0yMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTIwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MjAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNODUwIDcwMGgyMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTIwMCBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTIwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MjAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgMzAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTQ1MCAzMDBoMjAwIHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTg1MCAzMDBoMjAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0yMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTIwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MjAwcTAgMjEgMTQuNSAzNS41IHQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAxMjsiIGQ9Ik01MCAxMTAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTQ1MCAxMTAwaDcwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC03MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCA3MDBoMjAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0yMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTIwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MjAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNDUwIDcwMGg3MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTIwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNzAwIHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MjAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgMzAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTQ1MCAzMDBoNzAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0yMDAgcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC03MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAxMzsiIGQ9Ik00NjUgNDc3bDU3MSA1NzFxOCA4IDE4IDh0MTcgLThsMTc3IC0xNzdxOCAtNyA4IC0xN3QtOCAtMThsLTc4MyAtNzg0cS03IC04IC0xNy41IC04dC0xNy41IDhsLTM4NCAzODRxLTggOCAtOCAxOHQ4IDE3bDE3NyAxNzdxNyA4IDE3IDh0MTggLThsMTcxIC0xNzFxNyAtNyAxOCAtN3QxOCA3eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMTQ7IiBkPSJNOTA0IDEwODNsMTc4IC0xNzlxOCAtOCA4IC0xOC41dC04IC0xNy41bC0yNjcgLTI2OGwyNjcgLTI2OHE4IC03IDggLTE3LjV0LTggLTE4LjVsLTE3OCAtMTc4cS04IC04IC0xOC41IC04dC0xNy41IDhsLTI2OCAyNjdsLTI2OCAtMjY3cS03IC04IC0xNy41IC04dC0xOC41IDhsLTE3OCAxNzhxLTggOCAtOCAxOC41dDggMTcuNWwyNjcgMjY4bC0yNjcgMjY4cS04IDcgLTggMTcuNXQ4IDE4LjVsMTc4IDE3OHE4IDggMTguNSA4dDE3LjUgLTggbDI2OCAtMjY3bDI2OCAyNjhxNyA3IDE3LjUgN3QxOC41IC03eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMTU7IiBkPSJNNTA3IDExNzdxOTggMCAxODcuNSAtMzguNXQxNTQuNSAtMTAzLjV0MTAzLjUgLTE1NC41dDM4LjUgLTE4Ny41cTAgLTE0MSAtNzggLTI2MmwzMDAgLTI5OXE4IC04IDggLTE4LjV0LTggLTE4LjVsLTEwOSAtMTA4cS03IC04IC0xNy41IC04dC0xOC41IDhsLTMwMCAyOTlxLTExOSAtNzcgLTI2MSAtNzdxLTk4IDAgLTE4OCAzOC41dC0xNTQuNSAxMDN0LTEwMyAxNTQuNXQtMzguNSAxODh0MzguNSAxODcuNXQxMDMgMTU0LjUgdDE1NC41IDEwMy41dDE4OCAzOC41ek01MDYuNSAxMDIzcS04OS41IDAgLTE2NS41IC00NHQtMTIwIC0xMjAuNXQtNDQgLTE2NnQ0NCAtMTY1LjV0MTIwIC0xMjB0MTY1LjUgLTQ0dDE2NiA0NHQxMjAuNSAxMjB0NDQgMTY1LjV0LTQ0IDE2NnQtMTIwLjUgMTIwLjV0LTE2NiA0NHpNNDI1IDkwMGgxNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di03NWg3NXExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTE1MHEwIC0xMCAtNy41IC0xNy41IHQtMTcuNSAtNy41aC03NXYtNzVxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0xNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY3NWgtNzVxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWg3NXY3NXEwIDEwIDcuNSAxNy41dDE3LjUgNy41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMTY7IiBkPSJNNTA3IDExNzdxOTggMCAxODcuNSAtMzguNXQxNTQuNSAtMTAzLjV0MTAzLjUgLTE1NC41dDM4LjUgLTE4Ny41cTAgLTE0MSAtNzggLTI2MmwzMDAgLTI5OXE4IC04IDggLTE4LjV0LTggLTE4LjVsLTEwOSAtMTA4cS03IC04IC0xNy41IC04dC0xOC41IDhsLTMwMCAyOTlxLTExOSAtNzcgLTI2MSAtNzdxLTk4IDAgLTE4OCAzOC41dC0xNTQuNSAxMDN0LTEwMyAxNTQuNXQtMzguNSAxODh0MzguNSAxODcuNXQxMDMgMTU0LjUgdDE1NC41IDEwMy41dDE4OCAzOC41ek01MDYuNSAxMDIzcS04OS41IDAgLTE2NS41IC00NHQtMTIwIC0xMjAuNXQtNDQgLTE2NnQ0NCAtMTY1LjV0MTIwIC0xMjB0MTY1LjUgLTQ0dDE2NiA0NHQxMjAuNSAxMjB0NDQgMTY1LjV0LTQ0IDE2NnQtMTIwLjUgMTIwLjV0LTE2NiA0NHpNMzI1IDgwMGgzNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0zNTBxLTEwIDAgLTE3LjUgNy41IHQtNy41IDE3LjV2MTUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAxNzsiIGQ9Ik01NTAgMTIwMGgxMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTQwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY0MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek04MDAgOTc1djE2NnExNjcgLTYyIDI3MiAtMjA5LjV0MTA1IC0zMzEuNXEwIC0xMTcgLTQ1LjUgLTIyNHQtMTIzIC0xODQuNXQtMTg0LjUgLTEyM3QtMjI0IC00NS41dC0yMjQgNDUuNSB0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHEwIDE4NCAxMDUgMzMxLjV0MjcyIDIwOS41di0xNjZxLTEwMyAtNTUgLTE2NSAtMTU1dC02MiAtMjIwcTAgLTExNiA1NyAtMjE0LjV0MTU1LjUgLTE1NS41dDIxNC41IC01N3QyMTQuNSA1N3QxNTUuNSAxNTUuNXQ1NyAyMTQuNXEwIDEyMCAtNjIgMjIwdC0xNjUgMTU1eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMTg7IiBkPSJNMTAyNSAxMjAwaDE1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTExNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0xNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxMTUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTcyNSA4MDBoMTUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtNzUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMTUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2NzUwIHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek00MjUgNTAwaDE1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTQ1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTE1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djQ1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek0xMjUgMzAwaDE1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTI1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTE1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41IHYyNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDE5OyIgZD0iTTYwMCAxMTc0cTMzIDAgNzQgLTVsMzggLTE1Mmw1IC0xcTQ5IC0xNCA5NCAtMzlsNSAtMmwxMzQgODBxNjEgLTQ4IDEwNCAtMTA1bC04MCAtMTM0bDMgLTVxMjUgLTQ0IDM5IC05M2wxIC02bDE1MiAtMzhxNSAtNDMgNSAtNzNxMCAtMzQgLTUgLTc0bC0xNTIgLTM4bC0xIC02cS0xNSAtNDkgLTM5IC05M2wtMyAtNWw4MCAtMTM0cS00OCAtNjEgLTEwNCAtMTA1bC0xMzQgODFsLTUgLTNxLTQ0IC0yNSAtOTQgLTM5bC01IC0ybC0zOCAtMTUxIHEtNDMgLTUgLTc0IC01cS0zMyAwIC03NCA1bC0zOCAxNTFsLTUgMnEtNDkgMTQgLTk0IDM5bC01IDNsLTEzNCAtODFxLTYwIDQ4IC0xMDQgMTA1bDgwIDEzNGwtMyA1cS0yNSA0NSAtMzggOTNsLTIgNmwtMTUxIDM4cS02IDQyIC02IDc0cTAgMzMgNiA3M2wxNTEgMzhsMiA2cTEzIDQ4IDM4IDkzbDMgNWwtODAgMTM0cTQ3IDYxIDEwNSAxMDVsMTMzIC04MGw1IDJxNDUgMjUgOTQgMzlsNSAxbDM4IDE1MnE0MyA1IDc0IDV6TTYwMCA4MTUgcS04OSAwIC0xNTIgLTYzdC02MyAtMTUxLjV0NjMgLTE1MS41dDE1MiAtNjN0MTUyIDYzdDYzIDE1MS41dC02MyAxNTEuNXQtMTUyIDYzeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMjA7IiBkPSJNNTAwIDEzMDBoMzAwcTQxIDAgNzAuNSAtMjkuNXQyOS41IC03MC41di0xMDBoMjc1cTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtNzVoLTExMDB2NzVxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgyNzV2MTAwcTAgNDEgMjkuNSA3MC41dDcwLjUgMjkuNXpNNTAwIDEyMDB2LTEwMGgzMDB2MTAwaC0zMDB6TTExMDAgOTAwdi04MDBxMCAtNDEgLTI5LjUgLTcwLjV0LTcwLjUgLTI5LjVoLTcwMHEtNDEgMCAtNzAuNSAyOS41dC0yOS41IDcwLjUgdjgwMGg5MDB6TTMwMCA4MDB2LTcwMGgxMDB2NzAwaC0xMDB6TTUwMCA4MDB2LTcwMGgxMDB2NzAwaC0xMDB6TTcwMCA4MDB2LTcwMGgxMDB2NzAwaC0xMDB6TTkwMCA4MDB2LTcwMGgxMDB2NzAwaC0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAyMTsiIGQ9Ik0xOCA2MThsNjIwIDYwOHE4IDcgMTguNSA3dDE3LjUgLTdsNjA4IC02MDhxOCAtOCA1LjUgLTEzdC0xMi41IC01aC0xNzV2LTU3NXEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTI1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djM3NWgtMzAwdi0zNzVxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY1NzVoLTE3NXEtMTAgMCAtMTIuNSA1dDUuNSAxM3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDIyOyIgZD0iTTYwMCAxMjAwdi00MDBxMCAtNDEgMjkuNSAtNzAuNXQ3MC41IC0yOS41aDMwMHYtNjUwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC04MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djExMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDQ1MHpNMTAwMCA4MDBoLTI1MHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MjUweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMjM7IiBkPSJNNjAwIDExNzdxMTE3IDAgMjI0IC00NS41dDE4NC41IC0xMjN0MTIzIC0xODQuNXQ0NS41IC0yMjR0LTQ1LjUgLTIyNHQtMTIzIC0xODQuNXQtMTg0LjUgLTEyM3QtMjI0IC00NS41dC0yMjQgNDUuNXQtMTg0LjUgMTIzdC0xMjMgMTg0LjV0LTQ1LjUgMjI0dDQ1LjUgMjI0dDEyMyAxODQuNXQxODQuNSAxMjN0MjI0IDQ1LjV6TTYwMCAxMDI3cS0xMTYgMCAtMjE0LjUgLTU3dC0xNTUuNSAtMTU1LjV0LTU3IC0yMTQuNXQ1NyAtMjE0LjUgdDE1NS41IC0xNTUuNXQyMTQuNSAtNTd0MjE0LjUgNTd0MTU1LjUgMTU1LjV0NTcgMjE0LjV0LTU3IDIxNC41dC0xNTUuNSAxNTUuNXQtMjE0LjUgNTd6TTUyNSA5MDBoNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0yNzVoMTc1cTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYzNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDI0OyIgZD0iTTEzMDAgMGgtNTM4bC00MSA0MDBoLTI0MmwtNDEgLTQwMGgtNTM4bDQzMSAxMjAwaDIwOWwtMjEgLTMwMGgxNjJsLTIwIDMwMGgyMDh6TTUxNSA4MDBsLTI3IC0zMDBoMjI0bC0yNyAzMDBoLTE3MHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDI1OyIgZD0iTTU1MCAxMjAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNDUwaDE5MXEyMCAwIDI1LjUgLTExLjV0LTcuNSAtMjcuNWwtMzI3IC00MDBxLTEzIC0xNiAtMzIgLTE2dC0zMiAxNmwtMzI3IDQwMHEtMTMgMTYgLTcuNSAyNy41dDI1LjUgMTEuNWgxOTF2NDUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNMTEyNSA0MDBoNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0zNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41IGgtMTA1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djM1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41aDUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMTc1aDkwMHYxNzVxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDI2OyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek02MDAgMTAyN3EtMTE2IDAgLTIxNC41IC01N3QtMTU1LjUgLTE1NS41dC01NyAtMjE0LjV0NTcgLTIxNC41IHQxNTUuNSAtMTU1LjV0MjE0LjUgLTU3dDIxNC41IDU3dDE1NS41IDE1NS41dDU3IDIxNC41dC01NyAyMTQuNXQtMTU1LjUgMTU1LjV0LTIxNC41IDU3ek01MjUgOTAwaDE1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTI3NWgxMzdxMjEgMCAyNiAtMTEuNXQtOCAtMjcuNWwtMjIzIC0yNzVxLTEzIC0xNiAtMzIgLTE2dC0zMiAxNmwtMjIzIDI3NXEtMTMgMTYgLTggMjcuNXQyNiAxMS41aDEzN3YyNzVxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXogIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAyNzsiIGQ9Ik02MDAgMTE3N3ExMTcgMCAyMjQgLTQ1LjV0MTg0LjUgLTEyM3QxMjMgLTE4NC41dDQ1LjUgLTIyNHQtNDUuNSAtMjI0dC0xMjMgLTE4NC41dC0xODQuNSAtMTIzdC0yMjQgLTQ1LjV0LTIyNCA0NS41dC0xODQuNSAxMjN0LTEyMyAxODQuNXQtNDUuNSAyMjR0NDUuNSAyMjR0MTIzIDE4NC41dDE4NC41IDEyM3QyMjQgNDUuNXpNNjAwIDEwMjdxLTExNiAwIC0yMTQuNSAtNTd0LTE1NS41IC0xNTUuNXQtNTcgLTIxNC41dDU3IC0yMTQuNSB0MTU1LjUgLTE1NS41dDIxNC41IC01N3QyMTQuNSA1N3QxNTUuNSAxNTUuNXQ1NyAyMTQuNXQtNTcgMjE0LjV0LTE1NS41IDE1NS41dC0yMTQuNSA1N3pNNjMyIDkxNGwyMjMgLTI3NXExMyAtMTYgOCAtMjcuNXQtMjYgLTExLjVoLTEzN3YtMjc1cTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMTUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2Mjc1aC0xMzdxLTIxIDAgLTI2IDExLjV0OCAyNy41bDIyMyAyNzVxMTMgMTYgMzIgMTYgdDMyIC0xNnoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDI4OyIgZD0iTTIyNSAxMjAwaDc1MHExMCAwIDE5LjUgLTd0MTIuNSAtMTdsMTg2IC02NTJxNyAtMjQgNyAtNDl2LTQyNXEwIC0xMiAtNCAtMjd0LTkgLTE3cS0xMiAtNiAtMzcgLTZoLTExMDBxLTEyIDAgLTI3IDR0LTE3IDhxLTYgMTMgLTYgMzhsMSA0MjVxMCAyNSA3IDQ5bDE4NSA2NTJxMyAxMCAxMi41IDE3dDE5LjUgN3pNODc4IDEwMDBoLTU1NnEtMTAgMCAtMTkgLTd0LTExIC0xOGwtODcgLTQ1MHEtMiAtMTEgNCAtMTh0MTYgLTdoMTUwIHExMCAwIDE5LjUgLTd0MTEuNSAtMTdsMzggLTE1MnEyIC0xMCAxMS41IC0xN3QxOS41IC03aDI1MHExMCAwIDE5LjUgN3QxMS41IDE3bDM4IDE1MnEyIDEwIDExLjUgMTd0MTkuNSA3aDE1MHExMCAwIDE2IDd0NCAxOGwtODcgNDUwcS0yIDExIC0xMSAxOHQtMTkgN3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDI5OyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek02MDAgMTAyN3EtMTE2IDAgLTIxNC41IC01N3QtMTU1LjUgLTE1NS41dC01NyAtMjE0LjV0NTcgLTIxNC41IHQxNTUuNSAtMTU1LjV0MjE0LjUgLTU3dDIxNC41IDU3dDE1NS41IDE1NS41dDU3IDIxNC41dC01NyAyMTQuNXQtMTU1LjUgMTU1LjV0LTIxNC41IDU3ek01NDAgODIwbDI1MyAtMTkwcTE3IC0xMiAxNyAtMzB0LTE3IC0zMGwtMjUzIC0xOTBxLTE2IC0xMiAtMjggLTYuNXQtMTIgMjYuNXY0MDBxMCAyMSAxMiAyNi41dDI4IC02LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAzMDsiIGQ9Ik05NDcgMTA2MGwxMzUgMTM1cTcgNyAxMi41IDV0NS41IC0xM3YtMzYycTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMzYycS0xMSAwIC0xMyA1LjV0NSAxMi41bDEzMyAxMzNxLTEwOSA3NiAtMjM4IDc2cS0xMTYgMCAtMjE0LjUgLTU3dC0xNTUuNSAtMTU1LjV0LTU3IC0yMTQuNXQ1NyAtMjE0LjV0MTU1LjUgLTE1NS41dDIxNC41IC01N3QyMTQuNSA1N3QxNTUuNSAxNTUuNXQ1NyAyMTQuNWgxNTBxMCAtMTE3IC00NS41IC0yMjQgdC0xMjMgLTE4NC41dC0xODQuNSAtMTIzdC0yMjQgLTQ1LjV0LTIyNCA0NS41dC0xODQuNSAxMjN0LTEyMyAxODQuNXQtNDUuNSAyMjR0NDUuNSAyMjR0MTIzIDE4NC41dDE4NC41IDEyM3QyMjQgNDUuNXExOTIgMCAzNDcgLTExN3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDMxOyIgZD0iTTk0NyAxMDYwbDEzNSAxMzVxNyA3IDEyLjUgNXQ1LjUgLTEzdi0zNjFxMCAtMTEgLTcuNSAtMTguNXQtMTguNSAtNy41aC0zNjFxLTExIDAgLTEzIDUuNXQ1IDEyLjVsMTM0IDEzNHEtMTEwIDc1IC0yMzkgNzVxLTExNiAwIC0yMTQuNSAtNTd0LTE1NS41IC0xNTUuNXQtNTcgLTIxNC41aC0xNTBxMCAxMTcgNDUuNSAyMjR0MTIzIDE4NC41dDE4NC41IDEyM3QyMjQgNDUuNXExOTIgMCAzNDcgLTExN3pNMTAyNyA2MDBoMTUwIHEwIC0xMTcgLTQ1LjUgLTIyNHQtMTIzIC0xODQuNXQtMTg0LjUgLTEyM3QtMjI0IC00NS41cS0xOTIgMCAtMzQ4IDExOGwtMTM0IC0xMzRxLTcgLTggLTEyLjUgLTUuNXQtNS41IDEyLjV2MzYwcTAgMTEgNy41IDE4LjV0MTguNSA3LjVoMzYwcTEwIDAgMTIuNSAtNS41dC01LjUgLTEyLjVsLTEzMyAtMTMzcTExMCAtNzYgMjQwIC03NnExMTYgMCAyMTQuNSA1N3QxNTUuNSAxNTUuNXQ1NyAyMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDMyOyIgZD0iTTEyNSAxMjAwaDEwNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xMTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMTA1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djExNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNMTA3NSAxMDAwaC04NTBxLTEwIDAgLTE3LjUgLTcuNXQtNy41IC0xNy41di04NTBxMCAtMTAgNy41IC0xNy41dDE3LjUgLTcuNWg4NTBxMTAgMCAxNy41IDcuNXQ3LjUgMTcuNXY4NTAgcTAgMTAgLTcuNSAxNy41dC0xNy41IDcuNXpNMzI1IDkwMGg1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek01MjUgOTAwaDQ1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtNDUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2NTAgcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTMyNSA3MDBoNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di01MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2NTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNNTI1IDcwMGg0NTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di01MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTQ1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djUwIHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek0zMjUgNTAwaDUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC01MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTUyNSA1MDBoNDUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC00NTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY1MCBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNMzI1IDMwMGg1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek01MjUgMzAwaDQ1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtNDUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2NTAgcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAzMzsiIGQ9Ik05MDAgODAwdjIwMHEwIDgzIC01OC41IDE0MS41dC0xNDEuNSA1OC41aC0zMDBxLTgyIDAgLTE0MSAtNTl0LTU5IC0xNDF2LTIwMGgtMTAwcS00MSAwIC03MC41IC0yOS41dC0yOS41IC03MC41di02MDBxMCAtNDEgMjkuNSAtNzAuNXQ3MC41IC0yOS41aDkwMHE0MSAwIDcwLjUgMjkuNXQyOS41IDcwLjV2NjAwcTAgNDEgLTI5LjUgNzAuNXQtNzAuNSAyOS41aC0xMDB6TTQwMCA4MDB2MTUwcTAgMjEgMTUgMzUuNXQzNSAxNC41aDIwMCBxMjAgMCAzNSAtMTQuNXQxNSAtMzUuNXYtMTUwaC0zMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAzNDsiIGQ9Ik0xMjUgMTEwMGg1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTEwNzVoLTEwMHYxMDc1cTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTEwNzUgMTA1MnE0IDAgOSAtMnExNiAtNiAxNiAtMjN2LTQyMXEwIC02IC0zIC0xMnEtMzMgLTU5IC02Ni41IC05OXQtNjUuNSAtNTh0LTU2LjUgLTI0LjV0LTUyLjUgLTYuNXEtMjYgMCAtNTcuNSA2LjV0LTUyLjUgMTMuNXQtNjAgMjFxLTQxIDE1IC02MyAyMi41dC01Ny41IDE1dC02NS41IDcuNSBxLTg1IDAgLTE2MCAtNTdxLTcgLTUgLTE1IC01cS02IDAgLTExIDNxLTE0IDcgLTE0IDIydjQzOHEyMiA1NSA4MiA5OC41dDExOSA0Ni41cTIzIDIgNDMgMC41dDQzIC03dDMyLjUgLTguNXQzOCAtMTN0MzIuNSAtMTFxNDEgLTE0IDYzLjUgLTIxdDU3IC0xNHQ2My41IC03cTEwMyAwIDE4MyA4N3E3IDggMTggOHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDM1OyIgZD0iTTYwMCAxMTc1cTExNiAwIDIyNyAtNDkuNXQxOTIuNSAtMTMxdDEzMSAtMTkyLjV0NDkuNSAtMjI3di0zMDBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC01MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djMwMHEwIDEyNyAtNzAuNSAyMzEuNXQtMTg0LjUgMTYxLjV0LTI0NSA1N3QtMjQ1IC01N3QtMTg0LjUgLTE2MS41dC03MC41IC0yMzEuNXYtMzAwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtNTAgcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2MzAwcTAgMTE2IDQ5LjUgMjI3dDEzMSAxOTIuNXQxOTIuNSAxMzF0MjI3IDQ5LjV6TTIyMCA1MDBoMTYwcTggMCAxNCAtNnQ2IC0xNHYtNDYwcTAgLTggLTYgLTE0dC0xNCAtNmgtMTYwcS04IDAgLTE0IDZ0LTYgMTR2NDYwcTAgOCA2IDE0dDE0IDZ6TTgyMCA1MDBoMTYwcTggMCAxNCAtNnQ2IC0xNHYtNDYwcTAgLTggLTYgLTE0dC0xNCAtNmgtMTYwcS04IDAgLTE0IDZ0LTYgMTR2NDYwIHEwIDggNiAxNHQxNCA2eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMzY7IiBkPSJNMzIxIDgxNGwyNTggMTcycTkgNiAxNSAyLjV0NiAtMTMuNXYtNzUwcTAgLTEwIC02IC0xMy41dC0xNSAyLjVsLTI1OCAxNzJxLTIxIDE0IC00NiAxNGgtMjUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2MzUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjVoMjUwcTI1IDAgNDYgMTR6TTkwMCA2NjhsMTIwIDEyMHE3IDcgMTcgN3QxNyAtN2wzNCAtMzRxNyAtNyA3IC0xN3QtNyAtMTdsLTEyMCAtMTIwbDEyMCAtMTIwcTcgLTcgNyAtMTcgdC03IC0xN2wtMzQgLTM0cS03IC03IC0xNyAtN3QtMTcgN2wtMTIwIDExOWwtMTIwIC0xMTlxLTcgLTcgLTE3IC03dC0xNyA3bC0zNCAzNHEtNyA3IC03IDE3dDcgMTdsMTE5IDEyMGwtMTE5IDEyMHEtNyA3IC03IDE3dDcgMTdsMzQgMzRxNyA4IDE3IDh0MTcgLTh6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTAzNzsiIGQ9Ik0zMjEgODE0bDI1OCAxNzJxOSA2IDE1IDIuNXQ2IC0xMy41di03NTBxMCAtMTAgLTYgLTEzLjV0LTE1IDIuNWwtMjU4IDE3MnEtMjEgMTQgLTQ2IDE0aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYzNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgyNTBxMjUgMCA0NiAxNHpNNzY2IDkwMGg0cTEwIC0xIDE2IC0xMHE5NiAtMTI5IDk2IC0yOTBxMCAtMTU0IC05MCAtMjgxcS02IC05IC0xNyAtMTBsLTMgLTFxLTkgMCAtMTYgNiBsLTI5IDIzcS03IDcgLTguNSAxNi41dDQuNSAxNy41cTcyIDEwMyA3MiAyMjlxMCAxMzIgLTc4IDIzOHEtNiA4IC00LjUgMTh0OS41IDE3bDI5IDIycTcgNSAxNSA1eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwMzg7IiBkPSJNOTY3IDEwMDRoM3ExMSAtMSAxNyAtMTBxMTM1IC0xNzkgMTM1IC0zOTZxMCAtMTA1IC0zNCAtMjA2LjV0LTk4IC0xODUuNXEtNyAtOSAtMTcgLTEwaC0zcS05IDAgLTE2IDZsLTQyIDM0cS04IDYgLTkgMTZ0NSAxOHExMTEgMTUwIDExMSAzMjhxMCA5MCAtMjkuNSAxNzZ0LTg0LjUgMTU3cS02IDkgLTUgMTl0MTAgMTZsNDIgMzNxNyA1IDE1IDV6TTMyMSA4MTRsMjU4IDE3MnE5IDYgMTUgMi41dDYgLTEzLjV2LTc1MHEwIC0xMCAtNiAtMTMuNSB0LTE1IDIuNWwtMjU4IDE3MnEtMjEgMTQgLTQ2IDE0aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYzNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgyNTBxMjUgMCA0NiAxNHpNNzY2IDkwMGg0cTEwIC0xIDE2IC0xMHE5NiAtMTI5IDk2IC0yOTBxMCAtMTU0IC05MCAtMjgxcS02IC05IC0xNyAtMTBsLTMgLTFxLTkgMCAtMTYgNmwtMjkgMjNxLTcgNyAtOC41IDE2LjV0NC41IDE3LjVxNzIgMTAzIDcyIDIyOXEwIDEzMiAtNzggMjM4IHEtNiA4IC00LjUgMTguNXQ5LjUgMTYuNWwyOSAyMnE3IDUgMTUgNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDM5OyIgZD0iTTUwMCA5MDBoMTAwdi0xMDBoLTEwMHYtMTAwaC00MDB2LTEwMGgtMTAwdjYwMGg1MDB2LTMwMHpNMTIwMCA3MDBoLTIwMHYtMTAwaDIwMHYtMjAwaC0zMDB2MzAwaC0yMDB2MzAwaC0xMDB2MjAwaDYwMHYtNTAwek0xMDAgMTEwMHYtMzAwaDMwMHYzMDBoLTMwMHpNODAwIDExMDB2LTMwMGgzMDB2MzAwaC0zMDB6TTMwMCA5MDBoLTEwMHYxMDBoMTAwdi0xMDB6TTEwMDAgOTAwaC0xMDB2MTAwaDEwMHYtMTAwek0zMDAgNTAwaDIwMHYtNTAwIGgtNTAwdjUwMGgyMDB2MTAwaDEwMHYtMTAwek04MDAgMzAwaDIwMHYtMTAwaC0xMDB2LTEwMGgtMjAwdjEwMGgtMTAwdjEwMGgxMDB2MjAwaC0yMDB2MTAwaDMwMHYtMzAwek0xMDAgNDAwdi0zMDBoMzAwdjMwMGgtMzAwek0zMDAgMjAwaC0xMDB2MTAwaDEwMHYtMTAwek0xMjAwIDIwMGgtMTAwdjEwMGgxMDB2LTEwMHpNNzAwIDBoLTEwMHYxMDBoMTAwdi0xMDB6TTEyMDAgMGgtMzAwdjEwMGgzMDB2LTEwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDQwOyIgZD0iTTEwMCAyMDBoLTEwMHYxMDAwaDEwMHYtMTAwMHpNMzAwIDIwMGgtMTAwdjEwMDBoMTAwdi0xMDAwek03MDAgMjAwaC0yMDB2MTAwMGgyMDB2LTEwMDB6TTkwMCAyMDBoLTEwMHYxMDAwaDEwMHYtMTAwMHpNMTIwMCAyMDBoLTIwMHYxMDAwaDIwMHYtMTAwMHpNNDAwIDBoLTMwMHYxMDBoMzAwdi0xMDB6TTYwMCAwaC0xMDB2OTFoMTAwdi05MXpNODAwIDBoLTEwMHY5MWgxMDB2LTkxek0xMTAwIDBoLTIwMHY5MWgyMDB2LTkxeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNDE7IiBkPSJNNTAwIDEyMDBsNjgyIC02ODJxOCAtOCA4IC0xOHQtOCAtMThsLTQ2NCAtNDY0cS04IC04IC0xOCAtOHQtMTggOGwtNjgyIDY4MmwxIDQ3NXEwIDEwIDcuNSAxNy41dDE3LjUgNy41aDQ3NHpNMzE5LjUgMTAyNC41cS0yOS41IDI5LjUgLTcxIDI5LjV0LTcxIC0yOS41dC0yOS41IC03MS41dDI5LjUgLTcxLjV0NzEgLTI5LjV0NzEgMjkuNXQyOS41IDcxLjV0LTI5LjUgNzEuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDQyOyIgZD0iTTUwMCAxMjAwbDY4MiAtNjgycTggLTggOCAtMTh0LTggLTE4bC00NjQgLTQ2NHEtOCAtOCAtMTggLTh0LTE4IDhsLTY4MiA2ODJsMSA0NzVxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWg0NzR6TTgwMCAxMjAwbDY4MiAtNjgycTggLTggOCAtMTh0LTggLTE4bC00NjQgLTQ2NHEtOCAtOCAtMTggLTh0LTE4IDhsLTU2IDU2bDQyNCA0MjZsLTcwMCA3MDBoMTUwek0zMTkuNSAxMDI0LjVxLTI5LjUgMjkuNSAtNzEgMjkuNXQtNzEgLTI5LjUgdC0yOS41IC03MS41dDI5LjUgLTcxLjV0NzEgLTI5LjV0NzEgMjkuNXQyOS41IDcxLjV0LTI5LjUgNzEuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDQzOyIgZD0iTTMwMCAxMjAwaDgyNXE3NSAwIDc1IC03NXYtOTAwcTAgLTI1IC0xOCAtNDNsLTY0IC02NHEtOCAtOCAtMTMgLTUuNXQtNSAxMi41djk1MHEwIDEwIC03LjUgMTcuNXQtMTcuNSA3LjVoLTcwMHEtMjUgMCAtNDMgLTE4bC02NCAtNjRxLTggLTggLTUuNSAtMTN0MTIuNSAtNWg3MDBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di05NTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC04NTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY5NzUgcTAgMjUgMTggNDNsMTM5IDEzOXExOCAxOCA0MyAxOHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDQ0OyIgZD0iTTI1MCAxMjAwaDgwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTE1MGwtNDUwIDQ0NGwtNDUwIC00NDV2MTE1MXEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA0NTsiIGQ9Ik04MjIgMTIwMGgtNDQ0cS0xMSAwIC0xOSAtNy41dC05IC0xNy41bC03OCAtMzAxcS03IC0yNCA3IC00NWw1NyAtMTA4cTYgLTkgMTcuNSAtMTV0MjEuNSAtNmg0NTBxMTAgMCAyMS41IDZ0MTcuNSAxNWw2MiAxMDhxMTQgMjEgNyA0NWwtODMgMzAxcS0xIDEwIC05IDE3LjV0LTE5IDcuNXpNMTE3NSA4MDBoLTE1MHEtMTAgMCAtMjEgLTYuNXQtMTUgLTE1LjVsLTc4IC0xNTZxLTQgLTkgLTE1IC0xNS41dC0yMSAtNi41aC01NTAgcS0xMCAwIC0yMSA2LjV0LTE1IDE1LjVsLTc4IDE1NnEtNCA5IC0xNSAxNS41dC0yMSA2LjVoLTE1MHEtMTAgMCAtMTcuNSAtNy41dC03LjUgLTE3LjV2LTY1MHEwIC0xMCA3LjUgLTE3LjV0MTcuNSAtNy41aDE1MHExMCAwIDE3LjUgNy41dDcuNSAxNy41djE1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41aDc1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTE1MHEwIC0xMCA3LjUgLTE3LjV0MTcuNSAtNy41aDE1MHExMCAwIDE3LjUgNy41IHQ3LjUgMTcuNXY2NTBxMCAxMCAtNy41IDE3LjV0LTE3LjUgNy41ek04NTAgMjAwaC01MDBxLTEwIDAgLTE5LjUgLTd0LTExLjUgLTE3bC0zOCAtMTUycS0yIC0xMCAzLjUgLTE3dDE1LjUgLTdoNjAwcTEwIDAgMTUuNSA3dDMuNSAxN2wtMzggMTUycS0yIDEwIC0xMS41IDE3dC0xOS41IDd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA0NjsiIGQ9Ik01MDAgMTEwMGgyMDBxNTYgMCAxMDIuNSAtMjAuNXQ3Mi41IC01MHQ0NCAtNTl0MjUgLTUwLjVsNiAtMjBoMTUwcTQxIDAgNzAuNSAtMjkuNXQyOS41IC03MC41di02MDBxMCAtNDEgLTI5LjUgLTcwLjV0LTcwLjUgLTI5LjVoLTEwMDBxLTQxIDAgLTcwLjUgMjkuNXQtMjkuNSA3MC41djYwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjVoMTUwcTIgOCA2LjUgMjEuNXQyNCA0OHQ0NSA2MXQ3MiA0OHQxMDIuNSAyMS41ek05MDAgODAwdi0xMDAgaDEwMHYxMDBoLTEwMHpNNjAwIDczMHEtOTUgMCAtMTYyLjUgLTY3LjV0LTY3LjUgLTE2Mi41dDY3LjUgLTE2Mi41dDE2Mi41IC02Ny41dDE2Mi41IDY3LjV0NjcuNSAxNjIuNXQtNjcuNSAxNjIuNXQtMTYyLjUgNjcuNXpNNjAwIDYwM3E0MyAwIDczIC0zMHQzMCAtNzN0LTMwIC03M3QtNzMgLTMwdC03MyAzMHQtMzAgNzN0MzAgNzN0NzMgMzB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA0NzsiIGQ9Ik02ODEgMTE5OWwzODUgLTk5OHEyMCAtNTAgNjAgLTkycTE4IC0xOSAzNi41IC0yOS41dDI3LjUgLTExLjVsMTAgLTJ2LTY2aC00MTd2NjZxNTMgMCA3NSA0My41dDUgODguNWwtODIgMjIyaC0zOTFxLTU4IC0xNDUgLTkyIC0yMzRxLTExIC0zNCAtNi41IC01N3QyNS41IC0zN3Q0NiAtMjB0NTUgLTZ2LTY2aC0zNjV2NjZxNTYgMjQgODQgNTJxMTIgMTIgMjUgMzAuNXQyMCAzMS41bDcgMTNsMzk5IDEwMDZoOTN6TTQxNiA1MjFoMzQwIGwtMTYyIDQ1N3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDQ4OyIgZD0iTTc1MyA2NDFxNSAtMSAxNC41IC00LjV0MzYgLTE1LjV0NTAuNSAtMjYuNXQ1My41IC00MHQ1MC41IC01NC41dDM1LjUgLTcwdDE0LjUgLTg3cTAgLTY3IC0yNy41IC0xMjUuNXQtNzEuNSAtOTcuNXQtOTguNSAtNjYuNXQtMTA4LjUgLTQwLjV0LTEwMiAtMTNoLTUwMHY4OXE0MSA3IDcwLjUgMzIuNXQyOS41IDY1LjV2ODI3cTAgMjQgLTAuNSAzNHQtMy41IDI0dC04LjUgMTkuNXQtMTcgMTMuNXQtMjggMTIuNXQtNDIuNSAxMS41djcxIGw0NzEgLTFxNTcgMCAxMTUuNSAtMjAuNXQxMDggLTU3dDgwLjUgLTk0dDMxIC0xMjQuNXEwIC01MSAtMTUuNSAtOTYuNXQtMzggLTc0LjV0LTQ1IC01MC41dC0zOC41IC0zMC41ek00MDAgNzAwaDEzOXE3OCAwIDEzMC41IDQ4LjV0NTIuNSAxMjIuNXEwIDQxIC04LjUgNzAuNXQtMjkuNSA1NS41dC02Mi41IDM5LjV0LTEwMy41IDEzLjVoLTExOHYtMzUwek00MDAgMjAwaDIxNnE4MCAwIDEyMSA1MC41dDQxIDEzMC41cTAgOTAgLTYyLjUgMTU0LjUgdC0xNTYuNSA2NC41aC0xNTl2LTQwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDQ5OyIgZD0iTTg3NyAxMjAwbDIgLTU3cS04MyAtMTkgLTExNiAtNDUuNXQtNDAgLTY2LjVsLTEzMiAtODM5cS05IC00OSAxMyAtNjl0OTYgLTI2di05N2gtNTAwdjk3cTE4NiAxNiAyMDAgOThsMTczIDgzMnEzIDE3IDMgMzB0LTEuNSAyMi41dC05IDE3LjV0LTEzLjUgMTIuNXQtMjEuNSAxMHQtMjYgOC41dC0zMy41IDEwcS0xMyAzIC0xOSA1djU3aDQyNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDUwOyIgZD0iTTEzMDAgOTAwaC01MHEwIDIxIC00IDM3dC05LjUgMjYuNXQtMTggMTcuNXQtMjIgMTF0LTI4LjUgNS41dC0zMSAydC0zNyAwLjVoLTIwMHYtODUwcTAgLTIyIDI1IC0zNC41dDUwIC0xMy41bDI1IC0ydi0xMDBoLTQwMHYxMDBxNCAwIDExIDAuNXQyNCAzdDMwIDd0MjQgMTV0MTEgMjQuNXY4NTBoLTIwMHEtMjUgMCAtMzcgLTAuNXQtMzEgLTJ0LTI4LjUgLTUuNXQtMjIgLTExdC0xOCAtMTcuNXQtOS41IC0yNi41dC00IC0zN2gtNTB2MzAwIGgxMDAwdi0zMDB6TTE3NSAxMDAwaC03NXYtODAwaDc1bC0xMjUgLTE2N2wtMTI1IDE2N2g3NXY4MDBoLTc1bDEyNSAxNjd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA1MTsiIGQ9Ik0xMTAwIDkwMGgtNTBxMCAyMSAtNCAzN3QtOS41IDI2LjV0LTE4IDE3LjV0LTIyIDExdC0yOC41IDUuNXQtMzEgMnQtMzcgMC41aC0yMDB2LTY1MHEwIC0yMiAyNSAtMzQuNXQ1MCAtMTMuNWwyNSAtMnYtMTAwaC00MDB2MTAwcTQgMCAxMSAwLjV0MjQgM3QzMCA3dDI0IDE1dDExIDI0LjV2NjUwaC0yMDBxLTI1IDAgLTM3IC0wLjV0LTMxIC0ydC0yOC41IC01LjV0LTIyIC0xMXQtMTggLTE3LjV0LTkuNSAtMjYuNXQtNCAtMzdoLTUwdjMwMCBoMTAwMHYtMzAwek0xMTY3IDUwbC0xNjcgLTEyNXY3NWgtODAwdi03NWwtMTY3IDEyNWwxNjcgMTI1di03NWg4MDB2NzV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA1MjsiIGQ9Ik01MCAxMTAwaDYwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC02MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTUwIDgwMGgxMDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEwMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCA1MDBoODAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTgwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgMjAwaDExMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTEwMCBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA1MzsiIGQ9Ik0yNTAgMTEwMGg3MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNzAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCA4MDBoMTEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDAgcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNMjUwIDUwMGg3MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNzAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCAyMDBoMTEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwIHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDU0OyIgZD0iTTUwMCA5NTB2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNWg2MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNjAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXpNMTAwIDY1MHYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDEwMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTAwMCBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41ek0zMDAgMzUwdjEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoODAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTgwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV6TTAgNTB2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNWgxMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDAgcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDU1OyIgZD0iTTUwIDExMDBoMTEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCA4MDBoMTEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDAgcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgNTAwaDExMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTEwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgMjAwaDExMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTEwMCBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA1NjsiIGQ9Ik01MCAxMTAwaDEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTM1MCAxMTAwaDgwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC04MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCA4MDBoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNMzUwIDgwMGg4MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtODAwIHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgNTAwaDEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTM1MCA1MDBoODAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDAgcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC04MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTUwIDIwMGgxMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek0zNTAgMjAwaDgwMCBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtODAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNTc7IiBkPSJNNDAwIDBoLTEwMHYxMTAwaDEwMHYtMTEwMHpNNTUwIDExMDBoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTUwIDgwMGg1MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTAwIHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNMjY3IDU1MGwtMTY3IC0xMjV2NzVoLTIwMHYxMDBoMjAwdjc1ek01NTAgNTAwaDMwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0zMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTU1MCAyMDBoNjAwIHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC02MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA1ODsiIGQ9Ik01MCAxMTAwaDEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTkwMCAwaC0xMDB2MTEwMGgxMDB2LTExMDB6TTUwIDgwMGg1MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTAwIHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNMTEwMCA2MDBoMjAwdi0xMDBoLTIwMHYtNzVsLTE2NyAxMjVsMTY3IDEyNXYtNzV6TTUwIDUwMGgzMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMzAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek01MCAyMDBoNjAwIHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC02MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA1OTsiIGQ9Ik03NSAxMDAwaDc1MHEzMSAwIDUzIC0yMnQyMiAtNTN2LTY1MHEwIC0zMSAtMjIgLTUzdC01MyAtMjJoLTc1MHEtMzEgMCAtNTMgMjJ0LTIyIDUzdjY1MHEwIDMxIDIyIDUzdDUzIDIyek0xMjAwIDMwMGwtMzAwIDMwMGwzMDAgMzAwdi02MDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA2MDsiIGQ9Ik00NCAxMTAwaDExMTJxMTggMCAzMSAtMTN0MTMgLTMxdi0xMDEycTAgLTE4IC0xMyAtMzF0LTMxIC0xM2gtMTExMnEtMTggMCAtMzEgMTN0LTEzIDMxdjEwMTJxMCAxOCAxMyAzMXQzMSAxM3pNMTAwIDEwMDB2LTczN2wyNDcgMTgybDI5OCAtMTMxbC03NCAxNTZsMjkzIDMxOGwyMzYgLTI4OHY1MDBoLTEwMDB6TTM0MiA4ODRxNTYgMCA5NSAtMzl0MzkgLTk0LjV0LTM5IC05NXQtOTUgLTM5LjV0LTk1IDM5LjV0LTM5IDk1dDM5IDk0LjUgdDk1IDM5eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNjI7IiBkPSJNNjQ4IDExNjlxMTE3IDAgMjE2IC02MHQxNTYuNSAtMTYxdDU3LjUgLTIxOHEwIC0xMTUgLTcwIC0yNThxLTY5IC0xMDkgLTE1OCAtMjI1LjV0LTE0MyAtMTc5LjVsLTU0IC02MnEtOSA4IC0yNS41IDI0LjV0LTYzLjUgNjcuNXQtOTEgMTAzdC05OC41IDEyOHQtOTUuNSAxNDhxLTYwIDEzMiAtNjAgMjQ5cTAgODggMzQgMTY5LjV0OTEuNSAxNDJ0MTM3IDk2LjV0MTY2LjUgMzZ6TTY1Mi41IDk3NHEtOTEuNSAwIC0xNTYuNSAtNjUgdC02NSAtMTU3dDY1IC0xNTYuNXQxNTYuNSAtNjQuNXQxNTYuNSA2NC41dDY1IDE1Ni41dC02NSAxNTd0LTE1Ni41IDY1eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNjM7IiBkPSJNNjAwIDExNzdxMTE3IDAgMjI0IC00NS41dDE4NC41IC0xMjN0MTIzIC0xODQuNXQ0NS41IC0yMjR0LTQ1LjUgLTIyNHQtMTIzIC0xODQuNXQtMTg0LjUgLTEyM3QtMjI0IC00NS41dC0yMjQgNDUuNXQtMTg0LjUgMTIzdC0xMjMgMTg0LjV0LTQ1LjUgMjI0dDQ1LjUgMjI0dDEyMyAxODQuNXQxODQuNSAxMjN0MjI0IDQ1LjV6TTYwMCAxNzN2ODU0cS0xMTYgMCAtMjE0LjUgLTU3dC0xNTUuNSAtMTU1LjV0LTU3IC0yMTQuNXQ1NyAtMjE0LjUgdDE1NS41IC0xNTUuNXQyMTQuNSAtNTd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA2NDsiIGQ9Ik01NTQgMTI5NXEyMSAtNzIgNTcuNSAtMTQzLjV0NzYgLTEzMHQ4MyAtMTE4dDgyLjUgLTExN3Q3MCAtMTE2dDQ5LjUgLTEyNnQxOC41IC0xMzYuNXEwIC03MSAtMjUuNSAtMTM1dC02OC41IC0xMTF0LTk5IC04MnQtMTE4LjUgLTU0dC0xMjUuNSAtMjNxLTg0IDUgLTE2MS41IDM0dC0xMzkuNSA3OC41dC05OSAxMjV0LTM3IDE2NC41cTAgNjkgMTggMTM2LjV0NDkuNSAxMjYuNXQ2OS41IDExNi41dDgxLjUgMTE3LjV0ODMuNSAxMTkgdDc2LjUgMTMxdDU4LjUgMTQzek0zNDQgNzEwcS0yMyAtMzMgLTQzLjUgLTcwLjV0LTQwLjUgLTEwMi41dC0xNyAtMTIzcTEgLTM3IDE0LjUgLTY5LjV0MzAgLTUydDQxIC0zN3QzOC41IC0yNC41dDMzIC0xNXEyMSAtNyAzMiAtMXQxMyAyMmw2IDM0cTIgMTAgLTIuNSAyMnQtMTMuNSAxOXEtNSA0IC0xNCAxMnQtMjkuNSA0MC41dC0zMi41IDczLjVxLTI2IDg5IDYgMjcxcTIgMTEgLTYgMTFxLTggMSAtMTUgLTEweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNjU7IiBkPSJNMTAwMCAxMDEzbDEwOCAxMTVxMiAxIDUgMnQxMyAydDIwLjUgLTF0MjUgLTkuNXQyOC41IC0yMS41cTIyIC0yMiAyNyAtNDN0MCAtMzJsLTYgLTEwbC0xMDggLTExNXpNMzUwIDExMDBoNDAwcTUwIDAgMTA1IC0xM2wtMTg3IC0xODdoLTM2OHEtNDEgMCAtNzAuNSAtMjkuNXQtMjkuNSAtNzAuNXYtNTAwcTAgLTQxIDI5LjUgLTcwLjV0NzAuNSAtMjkuNWg1MDBxNDEgMCA3MC41IDI5LjV0MjkuNSA3MC41djE4MmwyMDAgMjAwdi0zMzIgcTAgLTE2NSAtOTMuNSAtMjU3LjV0LTI1Ni41IC05Mi41aC00MDBxLTE2NSAwIC0yNTcuNSA5Mi41dC05Mi41IDI1Ny41djQwMHEwIDE2NSA5Mi41IDI1Ny41dDI1Ny41IDkyLjV6TTEwMDkgODAzbC0zNjIgLTM2MmwtMTYxIC01MGw1NSAxNzBsMzU1IDM1NXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDY2OyIgZD0iTTM1MCAxMTAwaDM2MXEtMTY0IC0xNDYgLTIxNiAtMjAwaC0xOTVxLTQxIDAgLTcwLjUgLTI5LjV0LTI5LjUgLTcwLjV2LTUwMHEwIC00MSAyOS41IC03MC41dDcwLjUgLTI5LjVoNTAwcTQxIDAgNzAuNSAyOS41dDI5LjUgNzAuNWwyMDAgMTUzdi0xMDNxMCAtMTY1IC05Mi41IC0yNTcuNXQtMjU3LjUgLTkyLjVoLTQwMHEtMTY1IDAgLTI1Ny41IDkyLjV0LTkyLjUgMjU3LjV2NDAwcTAgMTY1IDkyLjUgMjU3LjV0MjU3LjUgOTIuNXogTTgyNCAxMDczbDMzOSAtMzAxcTggLTcgOCAtMTcuNXQtOCAtMTcuNWwtMzQwIC0zMDZxLTcgLTYgLTEyLjUgLTR0LTYuNSAxMXYyMDNxLTI2IDEgLTU0LjUgMHQtNzguNSAtNy41dC05MiAtMTcuNXQtODYgLTM1dC03MCAtNTdxMTAgNTkgMzMgMTA4dDUxLjUgODEuNXQ2NSA1OC41dDY4LjUgNDAuNXQ2NyAyNC41dDU2IDEzLjV0NDAgNC41djIxMHExIDEwIDYuNSAxMi41dDEzLjUgLTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDY3OyIgZD0iTTM1MCAxMTAwaDM1MHE2MCAwIDEyNyAtMjNsLTE3OCAtMTc3aC0zNDlxLTQxIDAgLTcwLjUgLTI5LjV0LTI5LjUgLTcwLjV2LTUwMHEwIC00MSAyOS41IC03MC41dDcwLjUgLTI5LjVoNTAwcTQxIDAgNzAuNSAyOS41dDI5LjUgNzAuNXY2OWwyMDAgMjAwdi0yMTlxMCAtMTY1IC05Mi41IC0yNTcuNXQtMjU3LjUgLTkyLjVoLTQwMHEtMTY1IDAgLTI1Ny41IDkyLjV0LTkyLjUgMjU3LjV2NDAwcTAgMTY1IDkyLjUgMjU3LjV0MjU3LjUgOTIuNXogTTY0MyA2MzlsMzk1IDM5NXE3IDcgMTcuNSA3dDE3LjUgLTdsMTAxIC0xMDFxNyAtNyA3IC0xNy41dC03IC0xNy41bC01MzEgLTUzMnEtNyAtNyAtMTcuNSAtN3QtMTcuNSA3bC0yNDggMjQ4cS03IDcgLTcgMTcuNXQ3IDE3LjVsMTAxIDEwMXE3IDcgMTcuNSA3dDE3LjUgLTdsMTExIC0xMTFxOCAtNyAxOCAtN3QxOCA3eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNjg7IiBkPSJNMzE4IDkxOGwyNjQgMjY0cTggOCAxOCA4dDE4IC04bDI2MCAtMjY0cTcgLTggNC41IC0xM3QtMTIuNSAtNWgtMTcwdi0yMDBoMjAwdjE3M3EwIDEwIDUgMTJ0MTMgLTVsMjY0IC0yNjBxOCAtNyA4IC0xNy41dC04IC0xNy41bC0yNjQgLTI2NXEtOCAtNyAtMTMgLTV0LTUgMTJ2MTczaC0yMDB2LTIwMGgxNzBxMTAgMCAxMi41IC01dC00LjUgLTEzbC0yNjAgLTI2NHEtOCAtOCAtMTggLTh0LTE4IDhsLTI2NCAyNjRxLTggOCAtNS41IDEzIHQxMi41IDVoMTc1djIwMGgtMjAwdi0xNzNxMCAtMTAgLTUgLTEydC0xMyA1bC0yNjQgMjY1cS04IDcgLTggMTcuNXQ4IDE3LjVsMjY0IDI2MHE4IDcgMTMgNXQ1IC0xMnYtMTczaDIwMHYyMDBoLTE3NXEtMTAgMCAtMTIuNSA1dDUuNSAxM3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDY5OyIgZD0iTTI1MCAxMTAwaDEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNDM4bDQ2NCA0NTNxMTUgMTQgMjUuNSAxMHQxMC41IC0yNXYtMTAwMHEwIC0yMSAtMTAuNSAtMjV0LTI1LjUgMTBsLTQ2NCA0NTN2LTQzOHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDcwOyIgZD0iTTUwIDExMDBoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di00MzhsNDY0IDQ1M3ExNSAxNCAyNS41IDEwdDEwLjUgLTI1di00MzhsNDY0IDQ1M3ExNSAxNCAyNS41IDEwdDEwLjUgLTI1di0xMDAwcTAgLTIxIC0xMC41IC0yNXQtMjUuNSAxMGwtNDY0IDQ1M3YtNDM4cTAgLTIxIC0xMC41IC0yNXQtMjUuNSAxMGwtNDY0IDQ1M3YtNDM4cTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMDBxLTIxIDAgLTM1LjUgMTQuNSB0LTE0LjUgMzUuNXYxMDAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDcxOyIgZD0iTTEyMDAgMTA1MHYtMTAwMHEwIC0yMSAtMTAuNSAtMjV0LTI1LjUgMTBsLTQ2NCA0NTN2LTQzOHEwIC0yMSAtMTAuNSAtMjV0LTI1LjUgMTBsLTQ5MiA0ODBxLTE1IDE0IC0xNSAzNXQxNSAzNWw0OTIgNDgwcTE1IDE0IDI1LjUgMTB0MTAuNSAtMjV2LTQzOGw0NjQgNDUzcTE1IDE0IDI1LjUgMTB0MTAuNSAtMjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA3MjsiIGQ9Ik0yNDMgMTA3NGw4MTQgLTQ5OHExOCAtMTEgMTggLTI2dC0xOCAtMjZsLTgxNCAtNDk4cS0xOCAtMTEgLTMwLjUgLTR0LTEyLjUgMjh2MTAwMHEwIDIxIDEyLjUgMjh0MzAuNSAtNHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDczOyIgZD0iTTI1MCAxMDAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtODAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djgwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTY1MCAxMDAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtODAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djgwMCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNzQ7IiBkPSJNMTEwMCA5NTB2LTgwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtODAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY4MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDgwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDc1OyIgZD0iTTUwMCA2MTJ2NDM4cTAgMjEgMTAuNSAyNXQyNS41IC0xMGw0OTIgLTQ4MHExNSAtMTQgMTUgLTM1dC0xNSAtMzVsLTQ5MiAtNDgwcS0xNSAtMTQgLTI1LjUgLTEwdC0xMC41IDI1djQzOGwtNDY0IC00NTNxLTE1IC0xNCAtMjUuNSAtMTB0LTEwLjUgMjV2MTAwMHEwIDIxIDEwLjUgMjV0MjUuNSAtMTB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA3NjsiIGQ9Ik0xMDQ4IDExMDJsMTAwIDFxMjAgMCAzNSAtMTQuNXQxNSAtMzUuNWw1IC0xMDAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41bC0xMDAgLTFxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41bC0yIDQzN2wtNDYzIC00NTRxLTE0IC0xNSAtMjQuNSAtMTAuNXQtMTAuNSAyNS41bC0yIDQzN2wtNDYyIC00NTVxLTE1IC0xNCAtMjUuNSAtOS41dC0xMC41IDI0LjVsLTUgMTAwMHEwIDIxIDEwLjUgMjUuNXQyNS41IC0xMC41bDQ2NiAtNDUwIGwtMiA0MzhxMCAyMCAxMC41IDI0LjV0MjUuNSAtOS41bDQ2NiAtNDUxbC0yIDQzOHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA3NzsiIGQ9Ik04NTAgMTEwMGgxMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NDM4bC00NjQgLTQ1M3EtMTUgLTE0IC0yNS41IC0xMHQtMTAuNSAyNXYxMDAwcTAgMjEgMTAuNSAyNXQyNS41IC0xMGw0NjQgLTQ1M3Y0MzhxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwNzg7IiBkPSJNNjg2IDEwODFsNTAxIC01NDBxMTUgLTE1IDEwLjUgLTI2dC0yNi41IC0xMWgtMTA0MnEtMjIgMCAtMjYuNSAxMXQxMC41IDI2bDUwMSA1NDBxMTUgMTUgMzYgMTV0MzYgLTE1ek0xNTAgNDAwaDEwMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTAwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDc5OyIgZD0iTTg4NSA5MDBsLTM1MiAtMzUzbDM1MiAtMzUzbC0xOTcgLTE5OGwtNTUyIDU1Mmw1NTIgNTUweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwODA7IiBkPSJNMTA2NCA1NDdsLTU1MSAtNTUxbC0xOTggMTk4bDM1MyAzNTNsLTM1MyAzNTNsMTk4IDE5OHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDgxOyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek02NTAgOTAwaC0xMDBxLTIxIDAgLTM1LjUgLTE0LjV0LTE0LjUgLTM1LjV2LTE1MGgtMTUwIHEtMjEgMCAtMzUuNSAtMTQuNXQtMTQuNSAtMzUuNXYtMTAwcTAgLTIxIDE0LjUgLTM1LjV0MzUuNSAtMTQuNWgxNTB2LTE1MHEwIC0yMSAxNC41IC0zNS41dDM1LjUgLTE0LjVoMTAwcTIxIDAgMzUuNSAxNC41dDE0LjUgMzUuNXYxNTBoMTUwcTIxIDAgMzUuNSAxNC41dDE0LjUgMzUuNXYxMDBxMCAyMSAtMTQuNSAzNS41dC0zNS41IDE0LjVoLTE1MHYxNTBxMCAyMSAtMTQuNSAzNS41dC0zNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA4MjsiIGQ9Ik02MDAgMTE3N3ExMTcgMCAyMjQgLTQ1LjV0MTg0LjUgLTEyM3QxMjMgLTE4NC41dDQ1LjUgLTIyNHQtNDUuNSAtMjI0dC0xMjMgLTE4NC41dC0xODQuNSAtMTIzdC0yMjQgLTQ1LjV0LTIyNCA0NS41dC0xODQuNSAxMjN0LTEyMyAxODQuNXQtNDUuNSAyMjR0NDUuNSAyMjR0MTIzIDE4NC41dDE4NC41IDEyM3QyMjQgNDUuNXpNODUwIDcwMGgtNTAwcS0yMSAwIC0zNS41IC0xNC41dC0xNC41IC0zNS41di0xMDBxMCAtMjEgMTQuNSAtMzUuNSB0MzUuNSAtMTQuNWg1MDBxMjEgMCAzNS41IDE0LjV0MTQuNSAzNS41djEwMHEwIDIxIC0xNC41IDM1LjV0LTM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDgzOyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek03NDEuNSA5MTNxLTEyLjUgMCAtMjEuNSAtOWwtMTIwIC0xMjBsLTEyMCAxMjBxLTkgOSAtMjEuNSA5IHQtMjEuNSAtOWwtMTQxIC0xNDFxLTkgLTkgLTkgLTIxLjV0OSAtMjEuNWwxMjAgLTEyMGwtMTIwIC0xMjBxLTkgLTkgLTkgLTIxLjV0OSAtMjEuNWwxNDEgLTE0MXE5IC05IDIxLjUgLTl0MjEuNSA5bDEyMCAxMjBsMTIwIC0xMjBxOSAtOSAyMS41IC05dDIxLjUgOWwxNDEgMTQxcTkgOSA5IDIxLjV0LTkgMjEuNWwtMTIwIDEyMGwxMjAgMTIwcTkgOSA5IDIxLjV0LTkgMjEuNWwtMTQxIDE0MXEtOSA5IC0yMS41IDl6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA4NDsiIGQ9Ik02MDAgMTE3N3ExMTcgMCAyMjQgLTQ1LjV0MTg0LjUgLTEyM3QxMjMgLTE4NC41dDQ1LjUgLTIyNHQtNDUuNSAtMjI0dC0xMjMgLTE4NC41dC0xODQuNSAtMTIzdC0yMjQgLTQ1LjV0LTIyNCA0NS41dC0xODQuNSAxMjN0LTEyMyAxODQuNXQtNDUuNSAyMjR0NDUuNSAyMjR0MTIzIDE4NC41dDE4NC41IDEyM3QyMjQgNDUuNXpNNTQ2IDYyM2wtODQgODVxLTcgNyAtMTcuNSA3dC0xOC41IC03bC0xMzkgLTEzOXEtNyAtOCAtNyAtMTh0NyAtMTggbDI0MiAtMjQxcTcgLTggMTcuNSAtOHQxNy41IDhsMzc1IDM3NXE3IDcgNyAxNy41dC03IDE4LjVsLTEzOSAxMzlxLTcgNyAtMTcuNSA3dC0xNy41IC03eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwODU7IiBkPSJNNjAwIDExNzdxMTE3IDAgMjI0IC00NS41dDE4NC41IC0xMjN0MTIzIC0xODQuNXQ0NS41IC0yMjR0LTQ1LjUgLTIyNHQtMTIzIC0xODQuNXQtMTg0LjUgLTEyM3QtMjI0IC00NS41dC0yMjQgNDUuNXQtMTg0LjUgMTIzdC0xMjMgMTg0LjV0LTQ1LjUgMjI0dDQ1LjUgMjI0dDEyMyAxODQuNXQxODQuNSAxMjN0MjI0IDQ1LjV6TTU4OCA5NDFxLTI5IDAgLTU5IC01LjV0LTYzIC0yMC41dC01OCAtMzguNXQtNDEuNSAtNjN0LTE2LjUgLTg5LjUgcTAgLTI1IDIwIC0yNWgxMzFxMzAgLTUgMzUgMTFxNiAyMCAyMC41IDI4dDQ1LjUgOHEyMCAwIDMxLjUgLTEwLjV0MTEuNSAtMjguNXEwIC0yMyAtNyAtMzR0LTI2IC0xOHEtMSAwIC0xMy41IC00dC0xOS41IC03LjV0LTIwIC0xMC41dC0yMiAtMTd0LTE4LjUgLTI0dC0xNS41IC0zNXQtOCAtNDZxLTEgLTggNS41IC0xNi41dDIwLjUgLTguNWgxNzNxNyAwIDIyIDh0MzUgMjh0MzcuNSA0OHQyOS41IDc0dDEyIDEwMHEwIDQ3IC0xNyA4MyB0LTQyLjUgNTd0LTU5LjUgMzQuNXQtNjQgMTh0LTU5IDQuNXpNNjc1IDQwMGgtMTUwcS0xMCAwIC0xNy41IC03LjV0LTcuNSAtMTcuNXYtMTUwcTAgLTEwIDcuNSAtMTcuNXQxNy41IC03LjVoMTUwcTEwIDAgMTcuNSA3LjV0Ny41IDE3LjV2MTUwcTAgMTAgLTcuNSAxNy41dC0xNy41IDcuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDg2OyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek02NzUgMTAwMGgtMTUwcS0xMCAwIC0xNy41IC03LjV0LTcuNSAtMTcuNXYtMTUwcTAgLTEwIDcuNSAtMTcuNSB0MTcuNSAtNy41aDE1MHExMCAwIDE3LjUgNy41dDcuNSAxNy41djE1MHEwIDEwIC03LjUgMTcuNXQtMTcuNSA3LjV6TTY3NSA3MDBoLTI1MHEtMTAgMCAtMTcuNSAtNy41dC03LjUgLTE3LjV2LTUwcTAgLTEwIDcuNSAtMTcuNXQxNy41IC03LjVoNzV2LTIwMGgtNzVxLTEwIDAgLTE3LjUgLTcuNXQtNy41IC0xNy41di01MHEwIC0xMCA3LjUgLTE3LjV0MTcuNSAtNy41aDM1MHExMCAwIDE3LjUgNy41dDcuNSAxNy41djUwcTAgMTAgLTcuNSAxNy41IHQtMTcuNSA3LjVoLTc1djI3NXEwIDEwIC03LjUgMTcuNXQtMTcuNSA3LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA4NzsiIGQ9Ik01MjUgMTIwMGgxNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xOTRxMTAzIC0yNyAxNzguNSAtMTAyLjV0MTAyLjUgLTE3OC41aDE5NHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTE1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTE5NHEtMjcgLTEwMyAtMTAyLjUgLTE3OC41dC0xNzguNSAtMTAyLjV2LTE5NHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTE1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE5NCBxLTEwMyAyNyAtMTc4LjUgMTAyLjV0LTEwMi41IDE3OC41aC0xOTRxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgxOTRxMjcgMTAzIDEwMi41IDE3OC41dDE3OC41IDEwMi41djE5NHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek03MDAgODkzdi0xNjhxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0xNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxNjhxLTY4IC0yMyAtMTE5IC03NCB0LTc0IC0xMTloMTY4cTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMTY4cTIzIC02OCA3NCAtMTE5dDExOSAtNzR2MTY4cTAgMTAgNy41IDE3LjV0MTcuNSA3LjVoMTUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMTY4cTY4IDIzIDExOSA3NHQ3NCAxMTloLTE2OHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41aDE2OCBxLTIzIDY4IC03NCAxMTl0LTExOSA3NHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDg4OyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek02MDAgMTAyN3EtMTE2IDAgLTIxNC41IC01N3QtMTU1LjUgLTE1NS41dC01NyAtMjE0LjV0NTcgLTIxNC41IHQxNTUuNSAtMTU1LjV0MjE0LjUgLTU3dDIxNC41IDU3dDE1NS41IDE1NS41dDU3IDIxNC41dC01NyAyMTQuNXQtMTU1LjUgMTU1LjV0LTIxNC41IDU3ek03NTkgODIzbDY0IC02NHE3IC03IDcgLTE3LjV0LTcgLTE3LjVsLTEyNCAtMTI0bDEyNCAtMTI0cTcgLTcgNyAtMTcuNXQtNyAtMTcuNWwtNjQgLTY0cS03IC03IC0xNy41IC03dC0xNy41IDdsLTEyNCAxMjRsLTEyNCAtMTI0cS03IC03IC0xNy41IC03dC0xNy41IDdsLTY0IDY0IHEtNyA3IC03IDE3LjV0NyAxNy41bDEyNCAxMjRsLTEyNCAxMjRxLTcgNyAtNyAxNy41dDcgMTcuNWw2NCA2NHE3IDcgMTcuNSA3dDE3LjUgLTdsMTI0IC0xMjRsMTI0IDEyNHE3IDcgMTcuNSA3dDE3LjUgLTd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA4OTsiIGQ9Ik02MDAgMTE3N3ExMTcgMCAyMjQgLTQ1LjV0MTg0LjUgLTEyM3QxMjMgLTE4NC41dDQ1LjUgLTIyNHQtNDUuNSAtMjI0dC0xMjMgLTE4NC41dC0xODQuNSAtMTIzdC0yMjQgLTQ1LjV0LTIyNCA0NS41dC0xODQuNSAxMjN0LTEyMyAxODQuNXQtNDUuNSAyMjR0NDUuNSAyMjR0MTIzIDE4NC41dDE4NC41IDEyM3QyMjQgNDUuNXpNNjAwIDEwMjdxLTExNiAwIC0yMTQuNSAtNTd0LTE1NS41IC0xNTUuNXQtNTcgLTIxNC41dDU3IC0yMTQuNSB0MTU1LjUgLTE1NS41dDIxNC41IC01N3QyMTQuNSA1N3QxNTUuNSAxNTUuNXQ1NyAyMTQuNXQtNTcgMjE0LjV0LTE1NS41IDE1NS41dC0yMTQuNSA1N3pNNzgyIDc4OGwxMDYgLTEwNnE3IC03IDcgLTE3LjV0LTcgLTE3LjVsLTMyMCAtMzIxcS04IC03IC0xOCAtN3QtMTggN2wtMjAyIDIwM3EtOCA3IC04IDE3LjV0OCAxNy41bDEwNiAxMDZxNyA4IDE3LjUgOHQxNy41IC04bDc5IC03OWwxOTcgMTk3cTcgNyAxNy41IDd0MTcuNSAtN3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDkwOyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek02MDAgMTAyN3EtMTE2IDAgLTIxNC41IC01N3QtMTU1LjUgLTE1NS41dC01NyAtMjE0LjVxMCAtMTIwIDY1IC0yMjUgbDU4NyA1ODdxLTEwNSA2NSAtMjI1IDY1ek05NjUgODE5bC01ODQgLTU4NHExMDQgLTYyIDIxOSAtNjJxMTE2IDAgMjE0LjUgNTd0MTU1LjUgMTU1LjV0NTcgMjE0LjVxMCAxMTUgLTYyIDIxOXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDkxOyIgZD0iTTM5IDU4Mmw1MjIgNDI3cTE2IDEzIDI3LjUgOHQxMS41IC0yNnYtMjkxaDU1MHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC01NTB2LTI5MXEwIC0yMSAtMTEuNSAtMjZ0LTI3LjUgOGwtNTIyIDQyN3EtMTYgMTMgLTE2IDMydDE2IDMyeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUwOTI7IiBkPSJNNjM5IDEwMDlsNTIyIC00MjdxMTYgLTEzIDE2IC0zMnQtMTYgLTMybC01MjIgLTQyN3EtMTYgLTEzIC0yNy41IC04dC0xMS41IDI2djI5MWgtNTUwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYyMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDU1MHYyOTFxMCAyMSAxMS41IDI2dDI3LjUgLTh6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA5MzsiIGQ9Ik02ODIgMTE2MWw0MjcgLTUyMnExMyAtMTYgOCAtMjcuNXQtMjYgLTExLjVoLTI5MXYtNTUwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0yMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djU1MGgtMjkxcS0yMSAwIC0yNiAxMS41dDggMjcuNWw0MjcgNTIycTEzIDE2IDMyIDE2dDMyIC0xNnoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDk0OyIgZD0iTTU1MCAxMjAwaDIwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTUwaDI5MXEyMSAwIDI2IC0xMS41dC04IC0yNy41bC00MjcgLTUyMnEtMTMgLTE2IC0zMiAtMTZ0LTMyIDE2bC00MjcgNTIycS0xMyAxNiAtOCAyNy41dDI2IDExLjVoMjkxdjU1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTA5NTsiIGQ9Ik02MzkgMTEwOWw1MjIgLTQyN3ExNiAtMTMgMTYgLTMydC0xNiAtMzJsLTUyMiAtNDI3cS0xNiAtMTMgLTI3LjUgLTh0LTExLjUgMjZ2MjkxcS05NCAtMiAtMTgyIC0yMHQtMTcwLjUgLTUydC0xNDcgLTkyLjV0LTEwMC41IC0xMzUuNXE1IDEwNSAyNyAxOTMuNXQ2Ny41IDE2N3QxMTMgMTM1dDE2NyA5MS41dDIyNS41IDQydjI2MnEwIDIxIDExLjUgMjZ0MjcuNSAtOHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDk2OyIgZD0iTTg1MCAxMjAwaDMwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMzAwcTAgLTIxIC0xMC41IC0yNXQtMjQuNSAxMGwtOTQgOTRsLTI0OSAtMjQ5cS04IC03IC0xOCAtN3QtMTggN2wtMTA2IDEwNnEtNyA4IC03IDE4dDcgMThsMjQ5IDI0OWwtOTQgOTRxLTE0IDE0IC0xMCAyNC41dDI1IDEwLjV6TTM1MCAwaC0zMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djMwMHEwIDIxIDEwLjUgMjV0MjQuNSAtMTBsOTQgLTk0bDI0OSAyNDkgcTggNyAxOCA3dDE4IC03bDEwNiAtMTA2cTcgLTggNyAtMTh0LTcgLTE4bC0yNDkgLTI0OWw5NCAtOTRxMTQgLTE0IDEwIC0yNC41dC0yNSAtMTAuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMDk3OyIgZD0iTTEwMTQgMTEyMGwxMDYgLTEwNnE3IC04IDcgLTE4dC03IC0xOGwtMjQ5IC0yNDlsOTQgLTk0cTE0IC0xNCAxMCAtMjQuNXQtMjUgLTEwLjVoLTMwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MzAwcTAgMjEgMTAuNSAyNXQyNC41IC0xMGw5NCAtOTRsMjQ5IDI0OXE4IDcgMTggN3QxOCAtN3pNMjUwIDYwMGgzMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTMwMHEwIC0yMSAtMTAuNSAtMjV0LTI0LjUgMTBsLTk0IDk0IGwtMjQ5IC0yNDlxLTggLTcgLTE4IC03dC0xOCA3bC0xMDYgMTA2cS03IDggLTcgMTh0NyAxOGwyNDkgMjQ5bC05NCA5NHEtMTQgMTQgLTEwIDI0LjV0MjUgMTAuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTAxOyIgZD0iTTYwMCAxMTc3cTExNyAwIDIyNCAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI0dC00NS41IC0yMjR0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNCAtNDUuNXQtMjI0IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNHQ0NS41IDIyNHQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNCA0NS41ek03MDQgOTAwaC0yMDhxLTIwIDAgLTMyIC0xNC41dC04IC0zNC41bDU4IC0zMDJxNCAtMjAgMjEuNSAtMzQuNSB0MzcuNSAtMTQuNWg1NHEyMCAwIDM3LjUgMTQuNXQyMS41IDM0LjVsNTggMzAycTQgMjAgLTggMzQuNXQtMzIgMTQuNXpNNjc1IDQwMGgtMTUwcS0xMCAwIC0xNy41IC03LjV0LTcuNSAtMTcuNXYtMTUwcTAgLTEwIDcuNSAtMTcuNXQxNy41IC03LjVoMTUwcTEwIDAgMTcuNSA3LjV0Ny41IDE3LjV2MTUwcTAgMTAgLTcuNSAxNy41dC0xNy41IDcuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTAyOyIgZD0iTTI2MCAxMjAwcTkgMCAxOSAtMnQxNSAtNGw1IC0ycTIyIC0xMCA0NCAtMjNsMTk2IC0xMThxMjEgLTEzIDM2IC0yNHEyOSAtMjEgMzcgLTEycTExIDEzIDQ5IDM1bDE5NiAxMThxMjIgMTMgNDUgMjNxMTcgNyAzOCA3cTIzIDAgNDcgLTE2LjV0MzcgLTMzLjVsMTMgLTE2cTE0IC0yMSAxOCAtNDVsMjUgLTEyM2w4IC00NHExIC05IDguNSAtMTQuNXQxNy41IC01LjVoNjFxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di01MCBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC01MHEtMTAgMCAtMTcuNSAtNy41dC03LjUgLTE3LjV2LTE3NWgtNDAwdjMwMGgtMjAwdi0zMDBoLTQwMHYxNzVxMCAxMCAtNy41IDE3LjV0LTE3LjUgNy41aC01MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjVoNjFxMTEgMCAxOCAzdDcgOHEwIDQgOSA1MmwyNSAxMjhxNSAyNSAxOSA0NXEyIDMgNSA3dDEzLjUgMTV0MjEuNSAxOS41dDI2LjUgMTUuNSB0MjkuNSA3ek05MTUgMTA3OWwtMTY2IC0xNjJxLTcgLTcgLTUgLTEydDEyIC01aDIxOXExMCAwIDE1IDd0MiAxN2wtNTEgMTQ5cS0zIDEwIC0xMSAxMnQtMTUgLTZ6TTQ2MyA5MTdsLTE3NyAxNTdxLTggNyAtMTYgNXQtMTEgLTEybC01MSAtMTQzcS0zIC0xMCAyIC0xN3QxNSAtN2gyMzFxMTEgMCAxMi41IDV0LTUuNSAxMnpNNTAwIDBoLTM3NXEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djM3NWg0MDB2LTQwMHpNMTEwMCA0MDB2LTM3NSBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0zNzV2NDAwaDQwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTAzOyIgZD0iTTExNjUgMTE5MHE4IDMgMjEgLTYuNXQxMyAtMTcuNXEtMiAtMTc4IC0yNC41IC0zMjMuNXQtNTUuNSAtMjQ1LjV0LTg3IC0xNzQuNXQtMTAyLjUgLTExOC41dC0xMTggLTY4LjV0LTExOC41IC0zM3QtMTIwIC00LjV0LTEwNSA5LjV0LTkwIDE2LjVxLTYxIDEyIC03OCAxMXEtNCAxIC0xMi41IDB0LTM0IC0xNC41dC01Mi41IC00MC41bC0xNTMgLTE1M3EtMjYgLTI0IC0zNyAtMTQuNXQtMTEgNDMuNXEwIDY0IDQyIDEwMnE4IDggNTAuNSA0NSB0NjYuNSA1OHExOSAxNyAzNSA0N3QxMyA2MXEtOSA1NSAtMTAgMTAyLjV0NyAxMTF0MzcgMTMwdDc4IDEyOS41cTM5IDUxIDgwIDg4dDg5LjUgNjMuNXQ5NC41IDQ1dDExMy41IDM2dDEyOSAzMXQxNTcuNSAzN3QxODIgNDcuNXpNMTExNiAxMDk4cS04IDkgLTIyLjUgLTN0LTQ1LjUgLTUwcS0zOCAtNDcgLTExOSAtMTAzLjV0LTE0MiAtODkuNWwtNjIgLTMzcS01NiAtMzAgLTEwMiAtNTd0LTEwNCAtNjh0LTEwMi41IC04MC41dC04NS41IC05MSB0LTY0IC0xMDQuNXEtMjQgLTU2IC0zMSAtODZ0MiAtMzJ0MzEuNSAxNy41dDU1LjUgNTkuNXEyNSAzMCA5NCA3NS41dDEyNS41IDc3LjV0MTQ3LjUgODFxNzAgMzcgMTE4LjUgNjl0MTAyIDc5LjV0OTkgMTExdDg2LjUgMTQ4LjVxMjIgNTAgMjQgNjB0LTYgMTl6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEwNDsiIGQ9Ik02NTMgMTIzMXEtMzkgLTY3IC01NC41IC0xMzF0LTEwLjUgLTExNC41dDI0LjUgLTk2LjV0NDcuNSAtODB0NjMuNSAtNjIuNXQ2OC41IC00Ni41dDY1IC0zMHEtNCA3IC0xNy41IDM1dC0xOC41IDM5LjV0LTE3IDM5LjV0LTE3IDQzdC0xMyA0MnQtOS41IDQ0LjV0LTIgNDJ0NCA0M3QxMy41IDM5dDIzIDM4LjVxOTYgLTQyIDE2NSAtMTA3LjV0MTA1IC0xMzh0NTIgLTE1NnQxMyAtMTU5dC0xOSAtMTQ5LjVxLTEzIC01NSAtNDQgLTEwNi41IHQtNjggLTg3dC03OC41IC02NC41dC03Mi41IC00NXQtNTMgLTIycS03MiAtMjIgLTEyNyAtMTFxLTMxIDYgLTEzIDE5cTYgMyAxNyA3cTEzIDUgMzIuNSAyMXQ0MSA0NHQzOC41IDYzLjV0MjEuNSA4MS41dC02LjUgOTQuNXQtNTAgMTA3dC0xMDQgMTE1LjVxMTAgLTEwNCAtMC41IC0xODl0LTM3IC0xNDAuNXQtNjUgLTkzdC04NCAtNTJ0LTkzLjUgLTExdC05NSAyNC41cS04MCAzNiAtMTMxLjUgMTE0dC01My41IDE3MXEtMiAyMyAwIDQ5LjUgdDQuNSA1Mi41dDEzLjUgNTZ0MjcuNSA2MHQ0NiA2NC41dDY5LjUgNjguNXEtOCAtNTMgLTUgLTEwMi41dDE3LjUgLTkwdDM0IC02OC41dDQ0LjUgLTM5dDQ5IC0ycTMxIDEzIDM4LjUgMzZ0LTQuNSA1NXQtMjkgNjQuNXQtMzYgNzV0LTI2IDc1LjVxLTE1IDg1IDIgMTYxLjV0NTMuNSAxMjguNXQ4NS41IDkyLjV0OTMuNSA2MXQ4MS41IDI1LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEwNTsiIGQ9Ik02MDAgMTA5NHE4MiAwIDE2MC41IC0yMi41dDE0MCAtNTl0MTE2LjUgLTgyLjV0OTQuNSAtOTV0NjggLTk1dDQyLjUgLTgyLjV0MTQgLTU3LjV0LTE0IC01Ny41dC00MyAtODIuNXQtNjguNSAtOTV0LTk0LjUgLTk1dC0xMTYuNSAtODIuNXQtMTQwIC01OXQtMTU5LjUgLTIyLjV0LTE1OS41IDIyLjV0LTE0MCA1OXQtMTE2LjUgODIuNXQtOTQuNSA5NXQtNjguNSA5NXQtNDMgODIuNXQtMTQgNTcuNXQxNCA1Ny41dDQyLjUgODIuNXQ2OCA5NSB0OTQuNSA5NXQxMTYuNSA4Mi41dDE0MCA1OXQxNjAuNSAyMi41ek04ODggODI5cS0xNSAxNSAtMTggMTJ0NSAtMjJxMjUgLTU3IDI1IC0xMTlxMCAtMTI0IC04OCAtMjEydC0yMTIgLTg4dC0yMTIgODh0LTg4IDIxMnEwIDU5IDIzIDExNHE4IDE5IDQuNSAyMnQtMTcuNSAtMTJxLTcwIC02OSAtMTYwIC0xODRxLTEzIC0xNiAtMTUgLTQwLjV0OSAtNDIuNXEyMiAtMzYgNDcgLTcxdDcwIC04MnQ5Mi41IC04MXQxMTMgLTU4LjV0MTMzLjUgLTI0LjUgdDEzMy41IDI0dDExMyA1OC41dDkyLjUgODEuNXQ3MCA4MS41dDQ3IDcwLjVxMTEgMTggOSA0Mi41dC0xNCA0MS41cS05MCAxMTcgLTE2MyAxODl6TTQ0OCA3MjdsLTM1IC0zNnEtMTUgLTE1IC0xOS41IC0zOC41dDQuNSAtNDEuNXEzNyAtNjggOTMgLTExNnExNiAtMTMgMzguNSAtMTF0MzYuNSAxN2wzNSAzNHExNCAxNSAxMi41IDMzLjV0LTE2LjUgMzMuNXEtNDQgNDQgLTg5IDExN3EtMTEgMTggLTI4IDIwdC0zMiAtMTJ6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEwNjsiIGQ9Ik01OTIgMGgtMTQ4bDMxIDEyMHEtOTEgMjAgLTE3NS41IDY4LjV0LTE0My41IDEwNi41dC0xMDMuNSAxMTl0LTY2LjUgMTEwdC0yMiA3NnEwIDIxIDE0IDU3LjV0NDIuNSA4Mi41dDY4IDk1dDk0LjUgOTV0MTE2LjUgODIuNXQxNDAgNTl0MTYwLjUgMjIuNXE2MSAwIDEyNiAtMTVsMzIgMTIxaDE0OHpNOTQ0IDc3MGw0NyAxODFxMTA4IC04NSAxNzYuNSAtMTkydDY4LjUgLTE1OXEwIC0yNiAtMTkuNSAtNzF0LTU5LjUgLTEwMnQtOTMgLTExMiB0LTEyOSAtMTA0LjV0LTE1OCAtNzUuNWw0NiAxNzNxNzcgNDkgMTM2IDExN3Q5NyAxMzFxMTEgMTggOSA0Mi41dC0xNCA0MS41cS01NCA3MCAtMTA3IDEzMHpNMzEwIDgyNHEtNzAgLTY5IC0xNjAgLTE4NHEtMTMgLTE2IC0xNSAtNDAuNXQ5IC00Mi41cTE4IC0zMCAzOSAtNjB0NTcgLTcwLjV0NzQgLTczdDkwIC02MXQxMDUgLTQxLjVsNDEgMTU0cS0xMDcgMTggLTE3OC41IDEwMS41dC03MS41IDE5My41cTAgNTkgMjMgMTE0cTggMTkgNC41IDIyIHQtMTcuNSAtMTJ6TTQ0OCA3MjdsLTM1IC0zNnEtMTUgLTE1IC0xOS41IC0zOC41dDQuNSAtNDEuNXEzNyAtNjggOTMgLTExNnExNiAtMTMgMzguNSAtMTF0MzYuNSAxN2wxMiAxMWwyMiA4NmwtMyA0cS00NCA0NCAtODkgMTE3cS0xMSAxOCAtMjggMjB0LTMyIC0xMnoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTA3OyIgZD0iTS05MCAxMDBsNjQyIDEwNjZxMjAgMzEgNDggMjguNXQ0OCAtMzUuNWw2NDIgLTEwNTZxMjEgLTMyIDcuNSAtNjcuNXQtNTAuNSAtMzUuNWgtMTI5NHEtMzcgMCAtNTAuNSAzNHQ3LjUgNjZ6TTE1NSAyMDBoMzQ1djc1cTAgMTAgNy41IDE3LjV0MTcuNSA3LjVoMTUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtNzVoMzQ1bC00NDUgNzIzek00OTYgNzAwaDIwOHEyMCAwIDMyIC0xNC41dDggLTM0LjVsLTU4IC0yNTIgcS00IC0yMCAtMjEuNSAtMzQuNXQtMzcuNSAtMTQuNWgtNTRxLTIwIDAgLTM3LjUgMTQuNXQtMjEuNSAzNC41bC01OCAyNTJxLTQgMjAgOCAzNC41dDMyIDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEwODsiIGQ9Ik02NTAgMTIwMHE2MiAwIDEwNiAtNDR0NDQgLTEwNnYtMzM5bDM2MyAtMzI1cTE1IC0xNCAyNiAtMzguNXQxMSAtNDQuNXYtNDFxMCAtMjAgLTEyIC0yNi41dC0yOSA1LjVsLTM1OSAyNDl2LTI2M3ExMDAgLTkzIDEwMCAtMTEzdi02NHEwIC0yMSAtMTMgLTI5dC0zMiAxbC0yMDUgMTI4bC0yMDUgLTEyOHEtMTkgLTkgLTMyIC0xdC0xMyAyOXY2NHEwIDIwIDEwMCAxMTN2MjYzbC0zNTkgLTI0OXEtMTcgLTEyIC0yOSAtNS41dC0xMiAyNi41djQxIHEwIDIwIDExIDQ0LjV0MjYgMzguNWwzNjMgMzI1djMzOXEwIDYyIDQ0IDEwNnQxMDYgNDR6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEwOTsiIGQ9Ik04NTAgMTIwMGgxMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTUwaDUwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xNTBoLTExMDB2MTUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNWg1MHY1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MGg1MDB2NTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek0xMTAwIDgwMHYtNzUwcTAgLTIxIC0xNC41IC0zNS41IHQtMzUuNSAtMTQuNWgtMTAwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NzUwaDExMDB6TTEwMCA2MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTMwMCA2MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTUwMCA2MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTcwMCA2MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTkwMCA2MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTEwMCA0MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTMwMCA0MDB2LTEwMGgxMDB2MTAwaC0xMDB6TTUwMCA0MDAgdi0xMDBoMTAwdjEwMGgtMTAwek03MDAgNDAwdi0xMDBoMTAwdjEwMGgtMTAwek05MDAgNDAwdi0xMDBoMTAwdjEwMGgtMTAwek0xMDAgMjAwdi0xMDBoMTAwdjEwMGgtMTAwek0zMDAgMjAwdi0xMDBoMTAwdjEwMGgtMTAwek01MDAgMjAwdi0xMDBoMTAwdjEwMGgtMTAwek03MDAgMjAwdi0xMDBoMTAwdjEwMGgtMTAwek05MDAgMjAwdi0xMDBoMTAwdjEwMGgtMTAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTA7IiBkPSJNMTEzNSAxMTY1bDI0OSAtMjMwcTE1IC0xNCAxNSAtMzV0LTE1IC0zNWwtMjQ5IC0yMzBxLTE0IC0xNCAtMjQuNSAtMTB0LTEwLjUgMjV2MTUwaC0xNTlsLTYwMCAtNjAwaC0yOTFxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoMjA5bDYwMCA2MDBoMjQxdjE1MHEwIDIxIDEwLjUgMjV0MjQuNSAtMTB6TTUyMiA4MTlsLTE0MSAtMTQxbC0xMjIgMTIyaC0yMDlxLTIxIDAgLTM1LjUgMTQuNSB0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDI5MXpNMTEzNSA1NjVsMjQ5IC0yMzBxMTUgLTE0IDE1IC0zNXQtMTUgLTM1bC0yNDkgLTIzMHEtMTQgLTE0IC0yNC41IC0xMHQtMTAuNSAyNXYxNTBoLTI0MWwtMTgxIDE4MWwxNDEgMTQxbDEyMiAtMTIyaDE1OXYxNTBxMCAyMSAxMC41IDI1dDI0LjUgLTEweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTE7IiBkPSJNMTAwIDExMDBoMTAwMHE0MSAwIDcwLjUgLTI5LjV0MjkuNSAtNzAuNXYtNjAwcTAgLTQxIC0yOS41IC03MC41dC03MC41IC0yOS41aC01OTZsLTMwNCAtMzAwdjMwMGgtMTAwcS00MSAwIC03MC41IDI5LjV0LTI5LjUgNzAuNXY2MDBxMCA0MSAyOS41IDcwLjV0NzAuNSAyOS41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTI7IiBkPSJNMTUwIDEyMDBoMjAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0yNTBoLTMwMHYyNTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek04NTAgMTIwMGgyMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTI1MGgtMzAwdjI1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTExMDAgODAwdi0zMDBxMCAtNDEgLTMgLTc3LjV0LTE1IC04OS41dC0zMiAtOTZ0LTU4IC04OXQtODkgLTc3dC0xMjkgLTUxdC0xNzQgLTIwdC0xNzQgMjAgdC0xMjkgNTF0LTg5IDc3dC01OCA4OXQtMzIgOTZ0LTE1IDg5LjV0LTMgNzcuNXYzMDBoMzAwdi0yNTB2LTI3di00Mi41dDEuNSAtNDF0NSAtMzh0MTAgLTM1dDE2LjUgLTMwdDI1LjUgLTI0LjV0MzUgLTE5dDQ2LjUgLTEydDYwIC00dDYwIDQuNXQ0Ni41IDEyLjV0MzUgMTkuNXQyNSAyNS41dDE3IDMwLjV0MTAgMzV0NSAzOHQyIDQwLjV0LTAuNSA0MnYyNXYyNTBoMzAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTM7IiBkPSJNMTEwMCA0MTFsLTE5OCAtMTk5bC0zNTMgMzUzbC0zNTMgLTM1M2wtMTk3IDE5OWw1NTEgNTUxeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTQ7IiBkPSJNMTEwMSA3ODlsLTU1MCAtNTUxbC01NTEgNTUxbDE5OCAxOTlsMzUzIC0zNTNsMzUzIDM1M3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTE1OyIgZD0iTTQwNCAxMDAwaDc0NnEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTUxaDE1MHEyMSAwIDI1IC0xMC41dC0xMCAtMjQuNWwtMjMwIC0yNDlxLTE0IC0xNSAtMzUgLTE1dC0zNSAxNWwtMjMwIDI0OXEtMTQgMTQgLTEwIDI0LjV0MjUgMTAuNWgxNTB2NDAxaC0zODF6TTEzNSA5ODRsMjMwIC0yNDlxMTQgLTE0IDEwIC0yNC41dC0yNSAtMTAuNWgtMTUwdi00MDBoMzg1bDIxNSAtMjAwaC03NTBxLTIxIDAgLTM1LjUgMTQuNSB0LTE0LjUgMzUuNXY1NTBoLTE1MHEtMjEgMCAtMjUgMTAuNXQxMCAyNC41bDIzMCAyNDlxMTQgMTUgMzUgMTV0MzUgLTE1eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTY7IiBkPSJNNTYgMTIwMGg5NHExNyAwIDMxIC0xMXQxOCAtMjdsMzggLTE2Mmg4OTZxMjQgMCAzOSAtMTguNXQxMCAtNDIuNWwtMTAwIC00NzVxLTUgLTIxIC0yNyAtNDIuNXQtNTUgLTIxLjVoLTYzM2w0OCAtMjAwaDUzNXEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTB2LTUwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41dC0zNS41IDE0LjV0LTE0LjUgMzUuNXY1MGgtMzAwdi01MCBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjV0LTM1LjUgMTQuNXQtMTQuNSAzNS41djUwaC0zMXEtMTggMCAtMzIuNSAxMHQtMjAuNSAxOWwtNSAxMGwtMjAxIDk2MWgtNTRxLTIwIDAgLTM1IDE0LjV0LTE1IDM1LjV0MTUgMzUuNXQzNSAxNC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTc7IiBkPSJNMTIwMCAxMDAwdi0xMDBoLTEyMDB2MTAwaDIwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjVoMzAwcTQxIDAgNzAuNSAtMjkuNXQyOS41IC03MC41aDUwMHpNMCA4MDBoMTIwMHYtODAwaC0xMjAwdjgwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTE4OyIgZD0iTTIwMCA4MDBsLTIwMCAtNDAwdjYwMGgyMDBxMCA0MSAyOS41IDcwLjV0NzAuNSAyOS41aDMwMHE0MiAwIDcxIC0yOS41dDI5IC03MC41aDUwMHYtMjAwaC0xMDAwek0xNTAwIDcwMGwtMzAwIC03MDBoLTEyMDBsMzAwIDcwMGgxMjAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMTk7IiBkPSJNNjM1IDExODRsMjMwIC0yNDlxMTQgLTE0IDEwIC0yNC41dC0yNSAtMTAuNWgtMTUwdi02MDFoMTUwcTIxIDAgMjUgLTEwLjV0LTEwIC0yNC41bC0yMzAgLTI0OXEtMTQgLTE1IC0zNSAtMTV0LTM1IDE1bC0yMzAgMjQ5cS0xNCAxNCAtMTAgMjQuNXQyNSAxMC41aDE1MHY2MDFoLTE1MHEtMjEgMCAtMjUgMTAuNXQxMCAyNC41bDIzMCAyNDlxMTQgMTUgMzUgMTV0MzUgLTE1eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMjA7IiBkPSJNOTM2IDg2NGwyNDkgLTIyOXExNCAtMTUgMTQgLTM1LjV0LTE0IC0zNS41bC0yNDkgLTIyOXEtMTUgLTE1IC0yNS41IC0xMC41dC0xMC41IDI0LjV2MTUxaC02MDB2LTE1MXEwIC0yMCAtMTAuNSAtMjQuNXQtMjUuNSAxMC41bC0yNDkgMjI5cS0xNCAxNSAtMTQgMzUuNXQxNCAzNS41bDI0OSAyMjlxMTUgMTUgMjUuNSAxMC41dDEwLjUgLTI1LjV2LTE0OWg2MDB2MTQ5cTAgMjEgMTAuNSAyNS41dDI1LjUgLTEwLjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEyMTsiIGQ9Ik0xMTY5IDQwMGwtMTcyIDczMnEtNSAyMyAtMjMgNDUuNXQtMzggMjIuNWgtNjcycS0yMCAwIC0zOCAtMjB0LTIzIC00MWwtMTcyIC03MzloMTEzOHpNMTEwMCAzMDBoLTEwMDBxLTQxIDAgLTcwLjUgLTI5LjV0LTI5LjUgLTcwLjV2LTEwMHEwIC00MSAyOS41IC03MC41dDcwLjUgLTI5LjVoMTAwMHE0MSAwIDcwLjUgMjkuNXQyOS41IDcwLjV2MTAwcTAgNDEgLTI5LjUgNzAuNXQtNzAuNSAyOS41ek04MDAgMTAwdjEwMGgxMDB2LTEwMGgtMTAwIHpNMTAwMCAxMDB2MTAwaDEwMHYtMTAwaC0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEyMjsiIGQ9Ik0xMTUwIDExMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTg1MHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNXQtMzUuNSAxNC41dC0xNC41IDM1LjV2ODUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNMTAwMCAyMDBsLTY3NSAyMDBoLTM4bDQ3IC0yNzZxMyAtMTYgLTUuNSAtMjB0LTI5LjUgLTRoLTdoLTg0cS0yMCAwIC0zNC41IDE0dC0xOC41IDM1cS01NSAzMzcgLTU1IDM1MXYyNTB2NnEwIDE2IDEgMjMuNXQ2LjUgMTQgdDE3LjUgNi41aDIwMGw2NzUgMjUwdi04NTB6TTAgNzUwdi0yNTBxLTQgMCAtMTEgMC41dC0yNCA2dC0zMCAxNXQtMjQgMzB0LTExIDQ4LjV2NTBxMCAyNiAxMC41IDQ2dDI1IDMwdDI5IDE2dDI1LjUgN3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTIzOyIgZD0iTTU1MyAxMjAwaDk0cTIwIDAgMjkgLTEwLjV0MyAtMjkuNWwtMTggLTM3cTgzIC0xOSAxNDQgLTgyLjV0NzYgLTE0MC41bDYzIC0zMjdsMTE4IC0xNzNoMTdxMTkgMCAzMyAtMTQuNXQxNCAtMzV0LTEzIC00MC41dC0zMSAtMjdxLTggLTQgLTIzIC05LjV0LTY1IC0xOS41dC0xMDMgLTI1dC0xMzIuNSAtMjB0LTE1OC41IC05cS01NyAwIC0xMTUgNXQtMTA0IDEydC04OC41IDE1LjV0LTczLjUgMTcuNXQtNTQuNSAxNnQtMzUuNSAxMmwtMTEgNCBxLTE4IDggLTMxIDI4dC0xMyA0MC41dDE0IDM1dDMzIDE0LjVoMTdsMTE4IDE3M2w2MyAzMjdxMTUgNzcgNzYgMTQwdDE0NCA4M2wtMTggMzJxLTYgMTkgMy41IDMydDI4LjUgMTN6TTQ5OCAxMTBxNTAgLTYgMTAyIC02cTUzIDAgMTAyIDZxLTEyIC00OSAtMzkuNSAtNzkuNXQtNjIuNSAtMzAuNXQtNjMgMzAuNXQtMzkgNzkuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTI0OyIgZD0iTTgwMCA5NDZsMjI0IDc4bC03OCAtMjI0bDIzNCAtNDVsLTE4MCAtMTU1bDE4MCAtMTU1bC0yMzQgLTQ1bDc4IC0yMjRsLTIyNCA3OGwtNDUgLTIzNGwtMTU1IDE4MGwtMTU1IC0xODBsLTQ1IDIzNGwtMjI0IC03OGw3OCAyMjRsLTIzNCA0NWwxODAgMTU1bC0xODAgMTU1bDIzNCA0NWwtNzggMjI0bDIyNCAtNzhsNDUgMjM0bDE1NSAtMTgwbDE1NSAxODB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEyNTsiIGQ9Ik02NTAgMTIwMGg1MHE0MCAwIDcwIC00MC41dDMwIC04NC41di0xNTBsLTI4IC0xMjVoMzI4cTQwIDAgNzAgLTQwLjV0MzAgLTg0LjV2LTEwMHEwIC00NSAtMjkgLTc0bC0yMzggLTM0NHEtMTYgLTI0IC0zOCAtNDAuNXQtNDUgLTE2LjVoLTI1MHEtNyAwIC00MiAyNXQtNjYgNTBsLTMxIDI1aC02MXEtNDUgMCAtNzIuNSAxOHQtMjcuNSA1N3Y0MDBxMCAzNiAyMCA2M2wxNDUgMTk2bDk2IDE5OHExMyAyOCAzNy41IDQ4dDUxLjUgMjB6IE02NTAgMTEwMGwtMTAwIC0yMTJsLTE1MCAtMjEzdi0zNzVoMTAwbDEzNiAtMTAwaDIxNGwyNTAgMzc1djEyNWgtNDUwbDUwIDIyNXYxNzVoLTUwek01MCA4MDBoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTI2OyIgZD0iTTYwMCAxMTAwaDI1MHEyMyAwIDQ1IC0xNi41dDM4IC00MC41bDIzOCAtMzQ0cTI5IC0yOSAyOSAtNzR2LTEwMHEwIC00NCAtMzAgLTg0LjV0LTcwIC00MC41aC0zMjhxMjggLTExOCAyOCAtMTI1di0xNTBxMCAtNDQgLTMwIC04NC41dC03MCAtNDAuNWgtNTBxLTI3IDAgLTUxLjUgMjB0LTM3LjUgNDhsLTk2IDE5OGwtMTQ1IDE5NnEtMjAgMjcgLTIwIDYzdjQwMHEwIDM5IDI3LjUgNTd0NzIuNSAxOGg2MXExMjQgMTAwIDEzOSAxMDB6IE01MCAxMDAwaDEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djUwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTYzNiAxMDAwbC0xMzYgLTEwMGgtMTAwdi0zNzVsMTUwIC0yMTNsMTAwIC0yMTJoNTB2MTc1bC01MCAyMjVoNDUwdjEyNWwtMjUwIDM3NWgtMjE0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMjc7IiBkPSJNMzU2IDg3M2wzNjMgMjMwcTMxIDE2IDUzIC02bDExMCAtMTEycTEzIC0xMyAxMy41IC0zMnQtMTEuNSAtMzRsLTg0IC0xMjFoMzAycTg0IDAgMTM4IC0zOHQ1NCAtMTEwdC01NSAtMTExdC0xMzkgLTM5aC0xMDZsLTEzMSAtMzM5cS02IC0yMSAtMTkuNSAtNDF0LTI4LjUgLTIwaC0zNDJxLTcgMCAtOTAgODF0LTgzIDk0djUyNXEwIDE3IDE0IDM1LjV0MjggMjguNXpNNDAwIDc5MnYtNTAzbDEwMCAtODloMjkzbDEzMSAzMzkgcTYgMjEgMTkuNSA0MXQyOC41IDIwaDIwM3EyMSAwIDMwLjUgMjV0MC41IDUwdC0zMSAyNWgtNDU2aC03aC02aC01LjV0LTYgMC41dC01IDEuNXQtNSAydC00IDIuNXQtNCA0dC0yLjUgNC41cS0xMiAyNSA1IDQ3bDE0NiAxODNsLTg2IDgzek01MCA4MDBoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NTAwIHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEyODsiIGQ9Ik00NzUgMTEwM2wzNjYgLTIzMHEyIC0xIDYgLTMuNXQxNCAtMTAuNXQxOCAtMTYuNXQxNC41IC0yMHQ2LjUgLTIyLjV2LTUyNXEwIC0xMyAtODYgLTk0dC05MyAtODFoLTM0MnEtMTUgMCAtMjguNSAyMHQtMTkuNSA0MWwtMTMxIDMzOWgtMTA2cS04NSAwIC0xMzkuNSAzOXQtNTQuNSAxMTF0NTQgMTEwdDEzOCAzOGgzMDJsLTg1IDEyMXEtMTEgMTUgLTEwLjUgMzR0MTMuNSAzMmwxMTAgMTEycTIyIDIyIDUzIDZ6TTM3MCA5NDVsMTQ2IC0xODMgcTE3IC0yMiA1IC00N3EtMiAtMiAtMy41IC00LjV0LTQgLTR0LTQgLTIuNXQtNSAtMnQtNSAtMS41dC02IC0wLjVoLTZoLTYuNWgtNmgtNDc1di0xMDBoMjIxcTE1IDAgMjkgLTIwdDIwIC00MWwxMzAgLTMzOWgyOTRsMTA2IDg5djUwM2wtMzQyIDIzNnpNMTA1MCA4MDBoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjUgdjUwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEyOTsiIGQ9Ik01NTAgMTI5NHE3MiAwIDExMSAtNTV0MzkgLTEzOXYtMTA2bDMzOSAtMTMxcTIxIC02IDQxIC0xOS41dDIwIC0yOC41di0zNDJxMCAtNyAtODEgLTkwdC05NCAtODNoLTUyNXEtMTcgMCAtMzUuNSAxNHQtMjguNSAyOGwtOSAxNGwtMjMwIDM2M3EtMTYgMzEgNiA1M2wxMTIgMTEwcTEzIDEzIDMyIDEzLjV0MzQgLTExLjVsMTIxIC04NHYzMDJxMCA4NCAzOCAxMzh0MTEwIDU0ek02MDAgOTcydjIwM3EwIDIxIC0yNSAzMC41dC01MCAwLjUgdC0yNSAtMzF2LTQ1NnYtN3YtNnYtNS41dC0wLjUgLTZ0LTEuNSAtNXQtMiAtNXQtMi41IC00dC00IC00dC00LjUgLTIuNXEtMjUgLTEyIC00NyA1bC0xODMgMTQ2bC04MyAtODZsMjM2IC0zMzloNTAzbDg5IDEwMHYyOTNsLTMzOSAxMzFxLTIxIDYgLTQxIDE5LjV0LTIwIDI4LjV6TTQ1MCAyMDBoNTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTUwMCBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEzMDsiIGQ9Ik0zNTAgMTEwMGg1MDBxMjEgMCAzNS41IDE0LjV0MTQuNSAzNS41djEwMHEwIDIxIC0xNC41IDM1LjV0LTM1LjUgMTQuNWgtNTAwcS0yMSAwIC0zNS41IC0xNC41dC0xNC41IC0zNS41di0xMDBxMCAtMjEgMTQuNSAtMzUuNXQzNS41IC0xNC41ek02MDAgMzA2di0xMDZxMCAtODQgLTM5IC0xMzl0LTExMSAtNTV0LTExMCA1NHQtMzggMTM4djMwMmwtMTIxIC04NHEtMTUgLTEyIC0zNCAtMTEuNXQtMzIgMTMuNWwtMTEyIDExMCBxLTIyIDIyIC02IDUzbDIzMCAzNjNxMSAyIDMuNSA2dDEwLjUgMTMuNXQxNi41IDE3dDIwIDEzLjV0MjIuNSA2aDUyNXExMyAwIDk0IC04M3Q4MSAtOTB2LTM0MnEwIC0xNSAtMjAgLTI4LjV0LTQxIC0xOS41ek0zMDggOTAwbC0yMzYgLTMzOWw4MyAtODZsMTgzIDE0NnEyMiAxNyA0NyA1cTIgLTEgNC41IC0yLjV0NCAtNHQyLjUgLTR0MiAtNXQxLjUgLTV0MC41IC02di01LjV2LTZ2LTd2LTQ1NnEwIC0yMiAyNSAtMzF0NTAgMC41dDI1IDMwLjUgdjIwM3EwIDE1IDIwIDI4LjV0NDEgMTkuNWwzMzkgMTMxdjI5M2wtODkgMTAwaC01MDN6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEzMTsiIGQ9Ik02MDAgMTE3OHExMTggMCAyMjUgLTQ1LjV0MTg0LjUgLTEyM3QxMjMgLTE4NC41dDQ1LjUgLTIyNXQtNDUuNSAtMjI1dC0xMjMgLTE4NC41dC0xODQuNSAtMTIzdC0yMjUgLTQ1LjV0LTIyNSA0NS41dC0xODQuNSAxMjN0LTEyMyAxODQuNXQtNDUuNSAyMjV0NDUuNSAyMjV0MTIzIDE4NC41dDE4NC41IDEyM3QyMjUgNDUuNXpNOTE0IDYzMmwtMjc1IDIyM3EtMTYgMTMgLTI3LjUgOHQtMTEuNSAtMjZ2LTEzN2gtMjc1IHEtMTAgMCAtMTcuNSAtNy41dC03LjUgLTE3LjV2LTE1MHEwIC0xMCA3LjUgLTE3LjV0MTcuNSAtNy41aDI3NXYtMTM3cTAgLTIxIDExLjUgLTI2dDI3LjUgOGwyNzUgMjIzcTE2IDEzIDE2IDMydC0xNiAzMnoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTMyOyIgZD0iTTYwMCAxMTc4cTExOCAwIDIyNSAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI1dC00NS41IC0yMjV0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNSAtNDUuNXQtMjI1IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNXQ0NS41IDIyNXQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNSA0NS41ek01NjEgODU1bC0yNzUgLTIyM3EtMTYgLTEzIC0xNiAtMzJ0MTYgLTMybDI3NSAtMjIzcTE2IC0xMyAyNy41IC04IHQxMS41IDI2djEzN2gyNzVxMTAgMCAxNy41IDcuNXQ3LjUgMTcuNXYxNTBxMCAxMCAtNy41IDE3LjV0LTE3LjUgNy41aC0yNzV2MTM3cTAgMjEgLTExLjUgMjZ0LTI3LjUgLTh6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEzMzsiIGQ9Ik02MDAgMTE3OHExMTggMCAyMjUgLTQ1LjV0MTg0LjUgLTEyM3QxMjMgLTE4NC41dDQ1LjUgLTIyNXQtNDUuNSAtMjI1dC0xMjMgLTE4NC41dC0xODQuNSAtMTIzdC0yMjUgLTQ1LjV0LTIyNSA0NS41dC0xODQuNSAxMjN0LTEyMyAxODQuNXQtNDUuNSAyMjV0NDUuNSAyMjV0MTIzIDE4NC41dDE4NC41IDEyM3QyMjUgNDUuNXpNODU1IDYzOWwtMjIzIDI3NXEtMTMgMTYgLTMyIDE2dC0zMiAtMTZsLTIyMyAtMjc1cS0xMyAtMTYgLTggLTI3LjUgdDI2IC0xMS41aDEzN3YtMjc1cTAgLTEwIDcuNSAtMTcuNXQxNy41IC03LjVoMTUwcTEwIDAgMTcuNSA3LjV0Ny41IDE3LjV2Mjc1aDEzN3EyMSAwIDI2IDExLjV0LTggMjcuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTM0OyIgZD0iTTYwMCAxMTc4cTExOCAwIDIyNSAtNDUuNXQxODQuNSAtMTIzdDEyMyAtMTg0LjV0NDUuNSAtMjI1dC00NS41IC0yMjV0LTEyMyAtMTg0LjV0LTE4NC41IC0xMjN0LTIyNSAtNDUuNXQtMjI1IDQ1LjV0LTE4NC41IDEyM3QtMTIzIDE4NC41dC00NS41IDIyNXQ0NS41IDIyNXQxMjMgMTg0LjV0MTg0LjUgMTIzdDIyNSA0NS41ek02NzUgOTAwaC0xNTBxLTEwIDAgLTE3LjUgLTcuNXQtNy41IC0xNy41di0yNzVoLTEzN3EtMjEgMCAtMjYgLTExLjUgdDggLTI3LjVsMjIzIC0yNzVxMTMgLTE2IDMyIC0xNnQzMiAxNmwyMjMgMjc1cTEzIDE2IDggMjcuNXQtMjYgMTEuNWgtMTM3djI3NXEwIDEwIC03LjUgMTcuNXQtMTcuNSA3LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTEzNTsiIGQ9Ik02MDAgMTE3NnExMTYgMCAyMjIuNSAtNDZ0MTg0IC0xMjMuNXQxMjMuNSAtMTg0dDQ2IC0yMjIuNXQtNDYgLTIyMi41dC0xMjMuNSAtMTg0dC0xODQgLTEyMy41dC0yMjIuNSAtNDZ0LTIyMi41IDQ2dC0xODQgMTIzLjV0LTEyMy41IDE4NHQtNDYgMjIyLjV0NDYgMjIyLjV0MTIzLjUgMTg0dDE4NCAxMjMuNXQyMjIuNSA0NnpNNjI3IDExMDFxLTE1IC0xMiAtMzYuNSAtMjAuNXQtMzUuNSAtMTJ0LTQzIC04dC0zOSAtNi41IHEtMTUgLTMgLTQ1LjUgMHQtNDUuNSAtMnEtMjAgLTcgLTUxLjUgLTI2LjV0LTM0LjUgLTM0LjVxLTMgLTExIDYuNSAtMjIuNXQ4LjUgLTE4LjVxLTMgLTM0IC0yNy41IC05MXQtMjkuNSAtNzlxLTkgLTM0IDUgLTkzdDggLTg3cTAgLTkgMTcgLTQ0LjV0MTYgLTU5LjVxMTIgMCAyMyAtNXQyMy41IC0xNXQxOS41IC0xNHExNiAtOCAzMyAtMTV0NDAuNSAtMTV0MzQuNSAtMTJxMjEgLTkgNTIuNSAtMzJ0NjAgLTM4dDU3LjUgLTExIHE3IC0xNSAtMyAtMzR0LTIyLjUgLTQwdC05LjUgLTM4cTEzIC0yMSAyMyAtMzQuNXQyNy41IC0yNy41dDM2LjUgLTE4cTAgLTcgLTMuNSAtMTZ0LTMuNSAtMTR0NSAtMTdxMTA0IC0yIDIyMSAxMTJxMzAgMjkgNDYuNSA0N3QzNC41IDQ5dDIxIDYzcS0xMyA4IC0zNyA4LjV0LTM2IDcuNXEtMTUgNyAtNDkuNSAxNXQtNTEuNSAxOXEtMTggMCAtNDEgLTAuNXQtNDMgLTEuNXQtNDIgLTYuNXQtMzggLTE2LjVxLTUxIC0zNSAtNjYgLTEyIHEtNCAxIC0zLjUgMjUuNXQwLjUgMjUuNXEtNiAxMyAtMjYuNSAxNy41dC0yNC41IDYuNXExIDE1IC0wLjUgMzAuNXQtNyAyOHQtMTguNSAxMS41dC0zMSAtMjFxLTIzIC0yNSAtNDIgNHEtMTkgMjggLTggNThxNiAxNiAyMiAyMnE2IC0xIDI2IC0xLjV0MzMuNSAtNHQxOS41IC0xMy41cTcgLTEyIDE4IC0yNHQyMS41IC0yMC41dDIwIC0xNXQxNS41IC0xMC41bDUgLTNxMiAxMiA3LjUgMzAuNXQ4IDM0LjV0LTAuNSAzMnEtMyAxOCAzLjUgMjkgdDE4IDIyLjV0MTUuNSAyNC41cTYgMTQgMTAuNSAzNXQ4IDMxdDE1LjUgMjIuNXQzNCAyMi41cS02IDE4IDEwIDM2cTggMCAyNCAtMS41dDI0LjUgLTEuNXQyMCA0LjV0MjAuNSAxNS41cS0xMCAyMyAtMzEgNDIuNXQtMzcuNSAyOS41dC00OSAyN3QtNDMuNSAyM3EwIDEgMiA4dDMgMTEuNXQxLjUgMTAuNXQtMSA5LjV0LTQuNSA0LjVxMzEgLTEzIDU4LjUgLTE0LjV0MzguNSAyLjVsMTIgNXE1IDI4IC05LjUgNDZ0LTM2LjUgMjR0LTUwIDE1IHQtNDEgMjBxLTE4IC00IC0zNyAwek02MTMgOTk0cTAgLTE3IDggLTQydDE3IC00NXQ5IC0yM3EtOCAxIC0zOS41IDUuNXQtNTIuNSAxMHQtMzcgMTYuNXEzIDExIDE2IDI5LjV0MTYgMjUuNXExMCAtMTAgMTkgLTEwdDE0IDZ0MTMuNSAxNC41dDE2LjUgMTIuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTM2OyIgZD0iTTc1NiAxMTU3cTE2NCA5MiAzMDYgLTlsLTI1OSAtMTM4bDE0NSAtMjMybDI1MSAxMjZxNiAtODkgLTM0IC0xNTYuNXQtMTE3IC0xMTAuNXEtNjAgLTM0IC0xMjcgLTM5LjV0LTEyNiAxNi41bC01OTYgLTU5NnEtMTUgLTE2IC0zNi41IC0xNnQtMzYuNSAxNmwtMTExIDExMHEtMTUgMTUgLTE1IDM2LjV0MTUgMzcuNWw2MDAgNTk5cS0zNCAxMDEgNS41IDIwMS41dDEzNS41IDE1NC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMzc7IiBob3Jpei1hZHYteD0iMTIyMCIgZD0iTTEwMCAxMTk2aDEwMDBxNDEgMCA3MC41IC0yOS41dDI5LjUgLTcwLjV2LTEwMHEwIC00MSAtMjkuNSAtNzAuNXQtNzAuNSAtMjkuNWgtMTAwMHEtNDEgMCAtNzAuNSAyOS41dC0yOS41IDcwLjV2MTAwcTAgNDEgMjkuNSA3MC41dDcwLjUgMjkuNXpNMTEwMCAxMDk2aC0yMDB2LTEwMGgyMDB2MTAwek0xMDAgNzk2aDEwMDBxNDEgMCA3MC41IC0yOS41dDI5LjUgLTcwLjV2LTEwMHEwIC00MSAtMjkuNSAtNzAuNXQtNzAuNSAtMjkuNWgtMTAwMCBxLTQxIDAgLTcwLjUgMjkuNXQtMjkuNSA3MC41djEwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjV6TTExMDAgNjk2aC01MDB2LTEwMGg1MDB2MTAwek0xMDAgMzk2aDEwMDBxNDEgMCA3MC41IC0yOS41dDI5LjUgLTcwLjV2LTEwMHEwIC00MSAtMjkuNSAtNzAuNXQtNzAuNSAtMjkuNWgtMTAwMHEtNDEgMCAtNzAuNSAyOS41dC0yOS41IDcwLjV2MTAwcTAgNDEgMjkuNSA3MC41dDcwLjUgMjkuNXpNMTEwMCAyOTZoLTMwMHYtMTAwaDMwMHYxMDB6ICIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxMzg7IiBkPSJNMTUwIDEyMDBoOTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41dC0xNC41IC0zNS41dC0zNS41IC0xNC41aC05MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41dDE0LjUgMzUuNXQzNS41IDE0LjV6TTcwMCA1MDB2LTMwMGwtMjAwIC0yMDB2NTAwbC0zNTAgNTAwaDkwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTM5OyIgZD0iTTUwMCAxMjAwaDIwMHE0MSAwIDcwLjUgLTI5LjV0MjkuNSAtNzAuNXYtMTAwaDMwMHE0MSAwIDcwLjUgLTI5LjV0MjkuNSAtNzAuNXYtNDAwaC01MDB2MTAwaC0yMDB2LTEwMGgtNTAwdjQwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjVoMzAwdjEwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjV6TTUwMCAxMTAwdi0xMDBoMjAwdjEwMGgtMjAwek0xMjAwIDQwMHYtMjAwcTAgLTQxIC0yOS41IC03MC41dC03MC41IC0yOS41aC0xMDAwIHEtNDEgMCAtNzAuNSAyOS41dC0yOS41IDcwLjV2MjAwaDEyMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE0MDsiIGQ9Ik01MCAxMjAwaDMwMHEyMSAwIDI1IC0xMC41dC0xMCAtMjQuNWwtOTQgLTk0bDE5OSAtMTk5cTcgLTggNyAtMTh0LTcgLTE4bC0xMDYgLTEwNnEtOCAtNyAtMTggLTd0LTE4IDdsLTE5OSAxOTlsLTk0IC05NHEtMTQgLTE0IC0yNC41IC0xMHQtMTAuNSAyNXYzMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek04NTAgMTIwMGgzMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTMwMHEwIC0yMSAtMTAuNSAtMjV0LTI0LjUgMTBsLTk0IDk0IGwtMTk5IC0xOTlxLTggLTcgLTE4IC03dC0xOCA3bC0xMDYgMTA2cS03IDggLTcgMTh0NyAxOGwxOTkgMTk5bC05NCA5NHEtMTQgMTQgLTEwIDI0LjV0MjUgMTAuNXpNMzY0IDQ3MGwxMDYgLTEwNnE3IC04IDcgLTE4dC03IC0xOGwtMTk5IC0xOTlsOTQgLTk0cTE0IC0xNCAxMCAtMjQuNXQtMjUgLTEwLjVoLTMwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MzAwcTAgMjEgMTAuNSAyNXQyNC41IC0xMGw5NCAtOTRsMTk5IDE5OSBxOCA3IDE4IDd0MTggLTd6TTEwNzEgMjcxbDk0IDk0cTE0IDE0IDI0LjUgMTB0MTAuNSAtMjV2LTMwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMzAwcS0yMSAwIC0yNSAxMC41dDEwIDI0LjVsOTQgOTRsLTE5OSAxOTlxLTcgOCAtNyAxOHQ3IDE4bDEwNiAxMDZxOCA3IDE4IDd0MTggLTd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE0MTsiIGQ9Ik01OTYgMTE5MnExMjEgMCAyMzEuNSAtNDcuNXQxOTAgLTEyN3QxMjcgLTE5MHQ0Ny41IC0yMzEuNXQtNDcuNSAtMjMxLjV0LTEyNyAtMTkwLjV0LTE5MCAtMTI3dC0yMzEuNSAtNDd0LTIzMS41IDQ3dC0xOTAuNSAxMjd0LTEyNyAxOTAuNXQtNDcgMjMxLjV0NDcgMjMxLjV0MTI3IDE5MHQxOTAuNSAxMjd0MjMxLjUgNDcuNXpNNTk2IDEwMTBxLTExMiAwIC0yMDcuNSAtNTUuNXQtMTUxIC0xNTF0LTU1LjUgLTIwNy41dDU1LjUgLTIwNy41IHQxNTEgLTE1MXQyMDcuNSAtNTUuNXQyMDcuNSA1NS41dDE1MSAxNTF0NTUuNSAyMDcuNXQtNTUuNSAyMDcuNXQtMTUxIDE1MXQtMjA3LjUgNTUuNXpNNDU0LjUgOTA1cTIyLjUgMCAzOC41IC0xNnQxNiAtMzguNXQtMTYgLTM5dC0zOC41IC0xNi41dC0zOC41IDE2LjV0LTE2IDM5dDE2IDM4LjV0MzguNSAxNnpNNzU0LjUgOTA1cTIyLjUgMCAzOC41IC0xNnQxNiAtMzguNXQtMTYgLTM5dC0zOCAtMTYuNXEtMTQgMCAtMjkgMTBsLTU1IC0xNDUgcTE3IC0yMyAxNyAtNTFxMCAtMzYgLTI1LjUgLTYxLjV0LTYxLjUgLTI1LjV0LTYxLjUgMjUuNXQtMjUuNSA2MS41cTAgMzIgMjAuNSA1Ni41dDUxLjUgMjkuNWwxMjIgMTI2bDEgMXEtOSAxNCAtOSAyOHEwIDIzIDE2IDM5dDM4LjUgMTZ6TTM0NS41IDcwOXEyMi41IDAgMzguNSAtMTZ0MTYgLTM4LjV0LTE2IC0zOC41dC0zOC41IC0xNnQtMzguNSAxNnQtMTYgMzguNXQxNiAzOC41dDM4LjUgMTZ6TTg1NC41IDcwOXEyMi41IDAgMzguNSAtMTYgdDE2IC0zOC41dC0xNiAtMzguNXQtMzguNSAtMTZ0LTM4LjUgMTZ0LTE2IDM4LjV0MTYgMzguNXQzOC41IDE2eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNDI7IiBkPSJNNTQ2IDE3M2w0NjkgNDcwcTkxIDkxIDk5IDE5MnE3IDk4IC01MiAxNzUuNXQtMTU0IDk0LjVxLTIyIDQgLTQ3IDRxLTM0IDAgLTY2LjUgLTEwdC01Ni41IC0yM3QtNTUuNSAtMzh0LTQ4IC00MS41dC00OC41IC00Ny41cS0zNzYgLTM3NSAtMzkxIC0zOTBxLTMwIC0yNyAtNDUgLTQxLjV0LTM3LjUgLTQxdC0zMiAtNDYuNXQtMTYgLTQ3LjV0LTEuNSAtNTYuNXE5IC02MiA1My41IC05NXQ5OS41IC0zM3E3NCAwIDEyNSA1MWw1NDggNTQ4IHEzNiAzNiAyMCA3NXEtNyAxNiAtMjEuNSAyNnQtMzIuNSAxMHEtMjYgMCAtNTAgLTIzcS0xMyAtMTIgLTM5IC0zOGwtMzQxIC0zMzhxLTE1IC0xNSAtMzUuNSAtMTUuNXQtMzQuNSAxMy41dC0xNCAzNC41dDE0IDM0LjVxMzI3IDMzMyAzNjEgMzY3cTM1IDM1IDY3LjUgNTEuNXQ3OC41IDE2LjVxMTQgMCAyOSAtMXE0NCAtOCA3NC41IC0zNS41dDQzLjUgLTY4LjVxMTQgLTQ3IDIgLTk2LjV0LTQ3IC04NC41cS0xMiAtMTEgLTMyIC0zMiB0LTc5LjUgLTgxdC0xMTQuNSAtMTE1dC0xMjQuNSAtMTIzLjV0LTEyMyAtMTE5LjV0LTk2LjUgLTg5dC01NyAtNDVxLTU2IC0yNyAtMTIwIC0yN3EtNzAgMCAtMTI5IDMydC05MyA4OXEtNDggNzggLTM1IDE3M3Q4MSAxNjNsNTExIDUxMXE3MSA3MiAxMTEgOTZxOTEgNTUgMTk4IDU1cTgwIDAgMTUyIC0zM3E3OCAtMzYgMTI5LjUgLTEwM3Q2Ni41IC0xNTRxMTcgLTkzIC0xMSAtMTgzLjV0LTk0IC0xNTYuNWwtNDgyIC00NzYgcS0xNSAtMTUgLTM2IC0xNnQtMzcgMTR0LTE3LjUgMzR0MTQuNSAzNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTQzOyIgZD0iTTY0OSA5NDlxNDggNjggMTA5LjUgMTA0dDEyMS41IDM4LjV0MTE4LjUgLTIwdDEwMi41IC02NHQ3MSAtMTAwLjV0MjcgLTEyM3EwIC01NyAtMzMuNSAtMTE3LjV0LTk0IC0xMjQuNXQtMTI2LjUgLTEyNy41dC0xNTAgLTE1Mi41dC0xNDYgLTE3NHEtNjIgODUgLTE0NS41IDE3NHQtMTUwIDE1Mi41dC0xMjYuNSAxMjcuNXQtOTMuNSAxMjQuNXQtMzMuNSAxMTcuNXEwIDY0IDI4IDEyM3Q3MyAxMDAuNXQxMDQgNjR0MTE5IDIwIHQxMjAuNSAtMzguNXQxMDQuNSAtMTA0ek04OTYgOTcycS0zMyAwIC02NC41IC0xOXQtNTYuNSAtNDZ0LTQ3LjUgLTUzLjV0LTQzLjUgLTQ1LjV0LTM3LjUgLTE5dC0zNiAxOXQtNDAgNDUuNXQtNDMgNTMuNXQtNTQgNDZ0LTY1LjUgMTlxLTY3IDAgLTEyMi41IC01NS41dC01NS41IC0xMzIuNXEwIC0yMyAxMy41IC01MXQ0NiAtNjV0NTcuNSAtNjN0NzYgLTc1bDIyIC0yMnExNSAtMTQgNDQgLTQ0dDUwLjUgLTUxdDQ2IC00NHQ0MSAtMzV0MjMgLTEyIHQyMy41IDEydDQyLjUgMzZ0NDYgNDR0NTIuNSA1MnQ0NCA0M3E0IDQgMTIgMTNxNDMgNDEgNjMuNSA2MnQ1MiA1NXQ0NiA1NXQyNiA0NnQxMS41IDQ0cTAgNzkgLTUzIDEzMy41dC0xMjAgNTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTQ0OyIgZD0iTTc3Ni41IDEyMTRxOTMuNSAwIDE1OS41IC02NmwxNDEgLTE0MXE2NiAtNjYgNjYgLTE2MHEwIC00MiAtMjggLTk1LjV0LTYyIC04Ny41bC0yOSAtMjlxLTMxIDUzIC03NyA5OWwtMTggMThsOTUgOTVsLTI0NyAyNDhsLTM4OSAtMzg5bDIxMiAtMjEybC0xMDUgLTEwNmwtMTkgMThsLTE0MSAxNDFxLTY2IDY2IC02NiAxNTl0NjYgMTU5bDI4MyAyODNxNjUgNjYgMTU4LjUgNjZ6TTYwMCA3MDZsMTA1IDEwNXExMCAtOCAxOSAtMTdsMTQxIC0xNDEgcTY2IC02NiA2NiAtMTU5dC02NiAtMTU5bC0yODMgLTI4M3EtNjYgLTY2IC0xNTkgLTY2dC0xNTkgNjZsLTE0MSAxNDFxLTY2IDY2IC02NiAxNTkuNXQ2NiAxNTkuNWw1NSA1NXEyOSAtNTUgNzUgLTEwMmwxOCAtMTdsLTk1IC05NWwyNDcgLTI0OGwzODkgMzg5eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNDU7IiBkPSJNNjAzIDEyMDBxODUgMCAxNjIgLTE1dDEyNyAtMzh0NzkgLTQ4dDI5IC00NnYtOTUzcTAgLTQxIC0yOS41IC03MC41dC03MC41IC0yOS41aC02MDBxLTQxIDAgLTcwLjUgMjkuNXQtMjkuNSA3MC41djk1M3EwIDIxIDMwIDQ2LjV0ODEgNDh0MTI5IDM3LjV0MTYzIDE1ek0zMDAgMTAwMHYtNzAwaDYwMHY3MDBoLTYwMHpNNjAwIDI1NHEtNDMgMCAtNzMuNSAtMzAuNXQtMzAuNSAtNzMuNXQzMC41IC03My41dDczLjUgLTMwLjV0NzMuNSAzMC41IHQzMC41IDczLjV0LTMwLjUgNzMuNXQtNzMuNSAzMC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNDY7IiBkPSJNOTAyIDExODVsMjgzIC0yODJxMTUgLTE1IDE1IC0zNnQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNXQtMzUgMTVsLTM2IDM1bC0yNzkgLTI2N3YtMzAwbC0yMTIgMjEwbC0zMDggLTMwN2wtMjgwIC0yMDNsMjAzIDI4MGwzMDcgMzA4bC0yMTAgMjEyaDMwMGwyNjcgMjc5bC0zNSAzNnEtMTUgMTQgLTE1IDM1dDE0LjUgMzUuNXQzNS41IDE0LjV0MzUgLTE1eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNDg7IiBkPSJNNzAwIDEyNDh2LTc4cTM4IC01IDcyLjUgLTE0LjV0NzUuNSAtMzEuNXQ3MSAtNTMuNXQ1MiAtODR0MjQgLTExOC41aC0xNTlxLTQgMzYgLTEwLjUgNTl0LTIxIDQ1dC00MCAzNS41dC02NC41IDIwLjV2LTMwN2w2NCAtMTNxMzQgLTcgNjQgLTE2LjV0NzAgLTMydDY3LjUgLTUyLjV0NDcuNSAtODB0MjAgLTExMnEwIC0xMzkgLTg5IC0yMjR0LTI0NCAtOTd2LTc3aC0xMDB2NzlxLTE1MCAxNiAtMjM3IDEwM3EtNDAgNDAgLTUyLjUgOTMuNSB0LTE1LjUgMTM5LjVoMTM5cTUgLTc3IDQ4LjUgLTEyNnQxMTcuNSAtNjV2MzM1bC0yNyA4cS00NiAxNCAtNzkgMjYuNXQtNzIgMzZ0LTYzIDUydC00MCA3Mi41dC0xNiA5OHEwIDcwIDI1IDEyNnQ2Ny41IDkydDk0LjUgNTd0MTEwIDI3djc3aDEwMHpNNjAwIDc1NHYyNzRxLTI5IC00IC01MCAtMTF0LTQyIC0yMS41dC0zMS41IC00MS41dC0xMC41IC02NXEwIC0yOSA3IC01MC41dDE2LjUgLTM0dDI4LjUgLTIyLjV0MzEuNSAtMTR0MzcuNSAtMTAgcTkgLTMgMTMgLTR6TTcwMCA1NDd2LTMxMHEyMiAyIDQyLjUgNi41dDQ1IDE1LjV0NDEuNSAyN3QyOSA0MnQxMiA1OS41dC0xMi41IDU5LjV0LTM4IDQ0LjV0LTUzIDMxdC02Ni41IDI0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE0OTsiIGQ9Ik01NjEgMTE5N3E4NCAwIDE2MC41IC00MHQxMjMuNSAtMTA5LjV0NDcgLTE0Ny41aC0xNTNxMCA0MCAtMTkuNSA3MS41dC00OS41IDQ4LjV0LTU5LjUgMjZ0LTU1LjUgOXEtMzcgMCAtNzkgLTE0LjV0LTYyIC0zNS41cS00MSAtNDQgLTQxIC0xMDFxMCAtMjYgMTMuNSAtNjN0MjYuNSAtNjF0MzcgLTY2cTYgLTkgOSAtMTRoMjQxdi0xMDBoLTE5N3E4IC01MCAtMi41IC0xMTV0LTMxLjUgLTk1cS00NSAtNjIgLTk5IC0xMTIgcTM0IDEwIDgzIDE3LjV0NzEgNy41cTMyIDEgMTAyIC0xNnQxMDQgLTE3cTgzIDAgMTM2IDMwbDUwIC0xNDdxLTMxIC0xOSAtNTggLTMwLjV0LTU1IC0xNS41dC00MiAtNC41dC00NiAtMC41cS0yMyAwIC03NiAxN3QtMTExIDMyLjV0LTk2IDExLjVxLTM5IC0zIC04MiAtMTZ0LTY3IC0yNWwtMjMgLTExbC01NSAxNDVxNCAzIDE2IDExdDE1LjUgMTAuNXQxMyA5dDE1LjUgMTJ0MTQuNSAxNHQxNy41IDE4LjVxNDggNTUgNTQgMTI2LjUgdC0zMCAxNDIuNWgtMjIxdjEwMGgxNjZxLTIzIDQ3IC00NCAxMDRxLTcgMjAgLTEyIDQxLjV0LTYgNTUuNXQ2IDY2LjV0MjkuNSA3MC41dDU4LjUgNzFxOTcgODggMjYzIDg4eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNTA7IiBkPSJNNDAwIDMwMGgxNTBxMjEgMCAyNSAtMTF0LTEwIC0yNWwtMjMwIC0yNTBxLTE0IC0xNSAtMzUgLTE1dC0zNSAxNWwtMjMwIDI1MHEtMTQgMTQgLTEwIDI1dDI1IDExaDE1MHY5MDBoMjAwdi05MDB6TTkzNSAxMTg0bDIzMCAtMjQ5cTE0IC0xNCAxMCAtMjQuNXQtMjUgLTEwLjVoLTE1MHYtOTAwaC0yMDB2OTAwaC0xNTBxLTIxIDAgLTI1IDEwLjV0MTAgMjQuNWwyMzAgMjQ5cTE0IDE1IDM1IDE1dDM1IC0xNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTUxOyIgZD0iTTEwMDAgNzAwaC0xMDB2MTAwaC0xMDB2LTEwMGgtMTAwdjUwMGgzMDB2LTUwMHpNNDAwIDMwMGgxNTBxMjEgMCAyNSAtMTF0LTEwIC0yNWwtMjMwIC0yNTBxLTE0IC0xNSAtMzUgLTE1dC0zNSAxNWwtMjMwIDI1MHEtMTQgMTQgLTEwIDI1dDI1IDExaDE1MHY5MDBoMjAwdi05MDB6TTgwMSAxMTAwdi0yMDBoMTAwdjIwMGgtMTAwek0xMDAwIDM1MGwtMjAwIC0yNTBoMjAwdi0xMDBoLTMwMHYxNTBsMjAwIDI1MGgtMjAwdjEwMGgzMDB2LTE1MHogIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE1MjsiIGQ9Ik00MDAgMzAwaDE1MHEyMSAwIDI1IC0xMXQtMTAgLTI1bC0yMzAgLTI1MHEtMTQgLTE1IC0zNSAtMTV0LTM1IDE1bC0yMzAgMjUwcS0xNCAxNCAtMTAgMjV0MjUgMTFoMTUwdjkwMGgyMDB2LTkwMHpNMTAwMCAxMDUwbC0yMDAgLTI1MGgyMDB2LTEwMGgtMzAwdjE1MGwyMDAgMjUwaC0yMDB2MTAwaDMwMHYtMTUwek0xMDAwIDBoLTEwMHYxMDBoLTEwMHYtMTAwaC0xMDB2NTAwaDMwMHYtNTAwek04MDEgNDAwdi0yMDBoMTAwdjIwMGgtMTAweiAiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTUzOyIgZD0iTTQwMCAzMDBoMTUwcTIxIDAgMjUgLTExdC0xMCAtMjVsLTIzMCAtMjUwcS0xNCAtMTUgLTM1IC0xNXQtMzUgMTVsLTIzMCAyNTBxLTE0IDE0IC0xMCAyNXQyNSAxMWgxNTB2OTAwaDIwMHYtOTAwek0xMDAwIDcwMGgtMTAwdjQwMGgtMTAwdjEwMGgyMDB2LTUwMHpNMTEwMCAwaC0xMDB2MTAwaC0yMDB2NDAwaDMwMHYtNTAwek05MDEgNDAwdi0yMDBoMTAwdjIwMGgtMTAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNTQ7IiBkPSJNNDAwIDMwMGgxNTBxMjEgMCAyNSAtMTF0LTEwIC0yNWwtMjMwIC0yNTBxLTE0IC0xNSAtMzUgLTE1dC0zNSAxNWwtMjMwIDI1MHEtMTQgMTQgLTEwIDI1dDI1IDExaDE1MHY5MDBoMjAwdi05MDB6TTExMDAgNzAwaC0xMDB2MTAwaC0yMDB2NDAwaDMwMHYtNTAwek05MDEgMTEwMHYtMjAwaDEwMHYyMDBoLTEwMHpNMTAwMCAwaC0xMDB2NDAwaC0xMDB2MTAwaDIwMHYtNTAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNTU7IiBkPSJNNDAwIDMwMGgxNTBxMjEgMCAyNSAtMTF0LTEwIC0yNWwtMjMwIC0yNTBxLTE0IC0xNSAtMzUgLTE1dC0zNSAxNWwtMjMwIDI1MHEtMTQgMTQgLTEwIDI1dDI1IDExaDE1MHY5MDBoMjAwdi05MDB6TTkwMCAxMDAwaC0yMDB2MjAwaDIwMHYtMjAwek0xMDAwIDcwMGgtMzAwdjIwMGgzMDB2LTIwMHpNMTEwMCA0MDBoLTQwMHYyMDBoNDAwdi0yMDB6TTEyMDAgMTAwaC01MDB2MjAwaDUwMHYtMjAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNTY7IiBkPSJNNDAwIDMwMGgxNTBxMjEgMCAyNSAtMTF0LTEwIC0yNWwtMjMwIC0yNTBxLTE0IC0xNSAtMzUgLTE1dC0zNSAxNWwtMjMwIDI1MHEtMTQgMTQgLTEwIDI1dDI1IDExaDE1MHY5MDBoMjAwdi05MDB6TTEyMDAgMTAwMGgtNTAwdjIwMGg1MDB2LTIwMHpNMTEwMCA3MDBoLTQwMHYyMDBoNDAwdi0yMDB6TTEwMDAgNDAwaC0zMDB2MjAwaDMwMHYtMjAwek05MDAgMTAwaC0yMDB2MjAwaDIwMHYtMjAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNTc7IiBkPSJNMzUwIDExMDBoNDAwcTE2MiAwIDI1NiAtOTMuNXQ5NCAtMjU2LjV2LTQwMHEwIC0xNjUgLTkzLjUgLTI1Ny41dC0yNTYuNSAtOTIuNWgtNDAwcS0xNjUgMCAtMjU3LjUgOTIuNXQtOTIuNSAyNTcuNXY0MDBxMCAxNjUgOTIuNSAyNTcuNXQyNTcuNSA5Mi41ek04MDAgOTAwaC01MDBxLTQxIDAgLTcwLjUgLTI5LjV0LTI5LjUgLTcwLjV2LTUwMHEwIC00MSAyOS41IC03MC41dDcwLjUgLTI5LjVoNTAwcTQxIDAgNzAuNSAyOS41dDI5LjUgNzAuNSB2NTAwcTAgNDEgLTI5LjUgNzAuNXQtNzAuNSAyOS41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNTg7IiBkPSJNMzUwIDExMDBoNDAwcTE2NSAwIDI1Ny41IC05Mi41dDkyLjUgLTI1Ny41di00MDBxMCAtMTY1IC05Mi41IC0yNTcuNXQtMjU3LjUgLTkyLjVoLTQwMHEtMTYzIDAgLTI1Ni41IDkyLjV0LTkzLjUgMjU3LjV2NDAwcTAgMTYzIDk0IDI1Ni41dDI1NiA5My41ek04MDAgOTAwaC01MDBxLTQxIDAgLTcwLjUgLTI5LjV0LTI5LjUgLTcwLjV2LTUwMHEwIC00MSAyOS41IC03MC41dDcwLjUgLTI5LjVoNTAwcTQxIDAgNzAuNSAyOS41dDI5LjUgNzAuNSB2NTAwcTAgNDEgLTI5LjUgNzAuNXQtNzAuNSAyOS41ek00NDAgNzcwbDI1MyAtMTkwcTE3IC0xMiAxNyAtMzB0LTE3IC0zMGwtMjUzIC0xOTBxLTE2IC0xMiAtMjggLTYuNXQtMTIgMjYuNXY0MDBxMCAyMSAxMiAyNi41dDI4IC02LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE1OTsiIGQ9Ik0zNTAgMTEwMGg0MDBxMTYzIDAgMjU2LjUgLTk0dDkzLjUgLTI1NnYtNDAwcTAgLTE2NSAtOTIuNSAtMjU3LjV0LTI1Ny41IC05Mi41aC00MDBxLTE2NSAwIC0yNTcuNSA5Mi41dC05Mi41IDI1Ny41djQwMHEwIDE2MyA5Mi41IDI1Ni41dDI1Ny41IDkzLjV6TTgwMCA5MDBoLTUwMHEtNDEgMCAtNzAuNSAtMjkuNXQtMjkuNSAtNzAuNXYtNTAwcTAgLTQxIDI5LjUgLTcwLjV0NzAuNSAtMjkuNWg1MDBxNDEgMCA3MC41IDI5LjV0MjkuNSA3MC41IHY1MDBxMCA0MSAtMjkuNSA3MC41dC03MC41IDI5LjV6TTM1MCA3MDBoNDAwcTIxIDAgMjYuNSAtMTJ0LTYuNSAtMjhsLTE5MCAtMjUzcS0xMiAtMTcgLTMwIC0xN3QtMzAgMTdsLTE5MCAyNTNxLTEyIDE2IC02LjUgMjh0MjYuNSAxMnoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTYwOyIgZD0iTTM1MCAxMTAwaDQwMHExNjUgMCAyNTcuNSAtOTIuNXQ5Mi41IC0yNTcuNXYtNDAwcTAgLTE2MyAtOTIuNSAtMjU2LjV0LTI1Ny41IC05My41aC00MDBxLTE2MyAwIC0yNTYuNSA5NHQtOTMuNSAyNTZ2NDAwcTAgMTY1IDkyLjUgMjU3LjV0MjU3LjUgOTIuNXpNODAwIDkwMGgtNTAwcS00MSAwIC03MC41IC0yOS41dC0yOS41IC03MC41di01MDBxMCAtNDEgMjkuNSAtNzAuNXQ3MC41IC0yOS41aDUwMHE0MSAwIDcwLjUgMjkuNXQyOS41IDcwLjUgdjUwMHEwIDQxIC0yOS41IDcwLjV0LTcwLjUgMjkuNXpNNTgwIDY5M2wxOTAgLTI1M3ExMiAtMTYgNi41IC0yOHQtMjYuNSAtMTJoLTQwMHEtMjEgMCAtMjYuNSAxMnQ2LjUgMjhsMTkwIDI1M3ExMiAxNyAzMCAxN3QzMCAtMTd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE2MTsiIGQ9Ik01NTAgMTEwMGg0MDBxMTY1IDAgMjU3LjUgLTkyLjV0OTIuNSAtMjU3LjV2LTQwMHEwIC0xNjUgLTkyLjUgLTI1Ny41dC0yNTcuNSAtOTIuNWgtNDAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDQ1MHE0MSAwIDcwLjUgMjkuNXQyOS41IDcwLjV2NTAwcTAgNDEgLTI5LjUgNzAuNXQtNzAuNSAyOS41aC00NTBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek0zMzggODY3bDMyNCAtMjg0cTE2IC0xNCAxNiAtMzN0LTE2IC0zM2wtMzI0IC0yODRxLTE2IC0xNCAtMjcgLTl0LTExIDI2djE1MGgtMjUwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYyMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDI1MHYxNTBxMCAyMSAxMSAyNnQyNyAtOXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTYyOyIgZD0iTTc5MyAxMTgybDkgLTlxOCAtMTAgNSAtMjdxLTMgLTExIC03OSAtMjI1LjV0LTc4IC0yMjEuNWwzMDAgMXEyNCAwIDMyLjUgLTE3LjV0LTUuNSAtMzUuNXEtMSAwIC0xMzMuNSAtMTU1dC0yNjcgLTMxMi41dC0xMzguNSAtMTYyLjVxLTEyIC0xNSAtMjYgLTE1aC05bC05IDhxLTkgMTEgLTQgMzJxMiA5IDQyIDEyMy41dDc5IDIyNC41bDM5IDExMGgtMzAycS0yMyAwIC0zMSAxOXEtMTAgMjEgNiA0MXE3NSA4NiAyMDkuNSAyMzcuNSB0MjI4IDI1N3Q5OC41IDExMS41cTkgMTYgMjUgMTZoOXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTYzOyIgZD0iTTM1MCAxMTAwaDQwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC00NTBxLTQxIDAgLTcwLjUgLTI5LjV0LTI5LjUgLTcwLjV2LTUwMHEwIC00MSAyOS41IC03MC41dDcwLjUgLTI5LjVoNDUwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTQwMHEtMTY1IDAgLTI1Ny41IDkyLjV0LTkyLjUgMjU3LjV2NDAwIHEwIDE2NSA5Mi41IDI1Ny41dDI1Ny41IDkyLjV6TTkzOCA4NjdsMzI0IC0yODRxMTYgLTE0IDE2IC0zM3QtMTYgLTMzbC0zMjQgLTI4NHEtMTYgLTE0IC0yNyAtOXQtMTEgMjZ2MTUwaC0yNTBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djIwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoMjUwdjE1MHEwIDIxIDExIDI2dDI3IC05eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNjQ7IiBkPSJNNzUwIDEyMDBoNDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di00MDBxMCAtMjEgLTEwLjUgLTI1dC0yNC41IDEwbC0xMDkgMTA5bC0zMTIgLTMxMnEtMTUgLTE1IC0zNS41IC0xNXQtMzUuNSAxNWwtMTQxIDE0MXEtMTUgMTUgLTE1IDM1LjV0MTUgMzUuNWwzMTIgMzEybC0xMDkgMTA5cS0xNCAxNCAtMTAgMjQuNXQyNSAxMC41ek00NTYgOTAwaC0xNTZxLTQxIDAgLTcwLjUgLTI5LjV0LTI5LjUgLTcwLjV2LTUwMCBxMCAtNDEgMjkuNSAtNzAuNXQ3MC41IC0yOS41aDUwMHE0MSAwIDcwLjUgMjkuNXQyOS41IDcwLjV2MTQ4bDIwMCAyMDB2LTI5OHEwIC0xNjUgLTkzLjUgLTI1Ny41dC0yNTYuNSAtOTIuNWgtNDAwcS0xNjUgMCAtMjU3LjUgOTIuNXQtOTIuNSAyNTcuNXY0MDBxMCAxNjUgOTIuNSAyNTcuNXQyNTcuNSA5Mi41aDMwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTY1OyIgZD0iTTYwMCAxMTg2cTExOSAwIDIyNy41IC00Ni41dDE4NyAtMTI1dDEyNSAtMTg3dDQ2LjUgLTIyNy41dC00Ni41IC0yMjcuNXQtMTI1IC0xODd0LTE4NyAtMTI1dC0yMjcuNSAtNDYuNXQtMjI3LjUgNDYuNXQtMTg3IDEyNXQtMTI1IDE4N3QtNDYuNSAyMjcuNXQ0Ni41IDIyNy41dDEyNSAxODd0MTg3IDEyNXQyMjcuNSA0Ni41ek02MDAgMTAyMnEtMTE1IDAgLTIxMiAtNTYuNXQtMTUzLjUgLTE1My41dC01Ni41IC0yMTJ0NTYuNSAtMjEyIHQxNTMuNSAtMTUzLjV0MjEyIC01Ni41dDIxMiA1Ni41dDE1My41IDE1My41dDU2LjUgMjEydC01Ni41IDIxMnQtMTUzLjUgMTUzLjV0LTIxMiA1Ni41ek02MDAgNzk0cTgwIDAgMTM3IC01N3Q1NyAtMTM3dC01NyAtMTM3dC0xMzcgLTU3dC0xMzcgNTd0LTU3IDEzN3Q1NyAxMzd0MTM3IDU3eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNjY7IiBkPSJNNDUwIDEyMDBoMjAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0zNTBoMjQ1cTIwIDAgMjUgLTExdC05IC0yNmwtMzgzIC00MjZxLTE0IC0xNSAtMzMuNSAtMTV0LTMyLjUgMTVsLTM3OSA0MjZxLTEzIDE1IC04LjUgMjZ0MjUuNSAxMWgyNTB2MzUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNTAgMzAwaDEwMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTI1MGgtMTEwMHYyNTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41eiBNOTAwIDIwMHYtNTBoMTAwdjUwaC0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE2NzsiIGQ9Ik01ODMgMTE4MmwzNzggLTQzNXExNCAtMTUgOSAtMzF0LTI2IC0xNmgtMjQ0di0yNTBxMCAtMjAgLTE3IC0zNXQtMzkgLTE1aC0yMDBxLTIwIDAgLTMyIDE0LjV0LTEyIDM1LjV2MjUwaC0yNTBxLTIwIDAgLTI1LjUgMTYuNXQ4LjUgMzEuNWwzODMgNDMxcTE0IDE2IDMzLjUgMTd0MzMuNSAtMTR6TTUwIDMwMGgxMDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0yNTBoLTExMDB2MjUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXogTTkwMCAyMDB2LTUwaDEwMHY1MGgtMTAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNjg7IiBkPSJNMzk2IDcyM2wzNjkgMzY5cTcgNyAxNy41IDd0MTcuNSAtN2wxMzkgLTEzOXE3IC04IDcgLTE4LjV0LTcgLTE3LjVsLTUyNSAtNTI1cS03IC04IC0xNy41IC04dC0xNy41IDhsLTI5MiAyOTFxLTcgOCAtNyAxOHQ3IDE4bDEzOSAxMzlxOCA3IDE4LjUgN3QxNy41IC03ek01MCAzMDBoMTAwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjUwaC0xMTAwdjI1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTkwMCAyMDB2LTUwaDEwMHY1MCBoLTEwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTY5OyIgZD0iTTEzNSAxMDIzbDE0MiAxNDJxMTQgMTQgMzUgMTR0MzUgLTE0bDc3IC03N2wtMjEyIC0yMTJsLTc3IDc2cS0xNCAxNSAtMTQgMzZ0MTQgMzV6TTY1NSA4NTVsMjEwIDIxMHExNCAxNCAyNC41IDEwdDEwLjUgLTI1bC0yIC01OTlxLTEgLTIwIC0xNS41IC0zNXQtMzUuNSAtMTVsLTU5NyAtMXEtMjEgMCAtMjUgMTAuNXQxMCAyNC41bDIwOCAyMDhsLTE1NCAxNTVsMjEyIDIxMnpNNTAgMzAwaDEwMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjUgdi0yNTBoLTExMDB2MjUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNOTAwIDIwMHYtNTBoMTAwdjUwaC0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE3MDsiIGQ9Ik0zNTAgMTIwMGw1OTkgLTJxMjAgLTEgMzUgLTE1LjV0MTUgLTM1LjVsMSAtNTk3cTAgLTIxIC0xMC41IC0yNXQtMjQuNSAxMGwtMjA4IDIwOGwtMTU1IC0xNTRsLTIxMiAyMTJsMTU1IDE1NGwtMjEwIDIxMHEtMTQgMTQgLTEwIDI0LjV0MjUgMTAuNXpNNTI0IDUxMmwtNzYgLTc3cS0xNSAtMTQgLTM2IC0xNHQtMzUgMTRsLTE0MiAxNDJxLTE0IDE0IC0xNCAzNXQxNCAzNWw3NyA3N3pNNTAgMzAwaDEwMDBxMjEgMCAzNS41IC0xNC41IHQxNC41IC0zNS41di0yNTBoLTExMDB2MjUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNOTAwIDIwMHYtNTBoMTAwdjUwaC0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE3MTsiIGQ9Ik0xMjAwIDEwM2wtNDgzIDI3NmwtMzE0IC0zOTl2NDIzaC0zOTlsMTE5NiA3OTZ2LTEwOTZ6TTQ4MyA0MjR2LTIzMGw2ODMgOTUzeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNzI7IiBkPSJNMTEwMCAxMDAwdi04NTBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTE1MHY0MDBoLTcwMHYtNDAwaC0xNTBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMDBxMCAyMCAxNC41IDM1dDM1LjUgMTVoMjUwdi0zMDBoNTAwdjMwMGgxMDB6TTcwMCAxMDAwaC0xMDB2MjAwaDEwMHYtMjAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNzM7IiBkPSJNMTEwMCAxMDAwbC0yIC0xNDlsLTI5OSAtMjk5bC05NSA5NXEtOSA5IC0yMS41IDl0LTIxLjUgLTlsLTE0OSAtMTQ3aC0zMTJ2LTQwMGgtMTUwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDAwcTAgMjAgMTQuNSAzNXQzNS41IDE1aDI1MHYtMzAwaDUwMHYzMDBoMTAwek03MDAgMTAwMGgtMTAwdjIwMGgxMDB2LTIwMHpNMTEzMiA2MzhsMTA2IC0xMDZxNyAtNyA3IC0xNy41dC03IC0xNy41bC00MjAgLTQyMXEtOCAtNyAtMTggLTcgdC0xOCA3bC0yMDIgMjAzcS04IDcgLTggMTcuNXQ4IDE3LjVsMTA2IDEwNnE3IDggMTcuNSA4dDE3LjUgLThsNzkgLTc5bDI5NyAyOTdxNyA3IDE3LjUgN3QxNy41IC03eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNzQ7IiBkPSJNMTEwMCAxMDAwdi0yNjlsLTEwMyAtMTAzbC0xMzQgMTM0cS0xNSAxNSAtMzMuNSAxNi41dC0zNC41IC0xMi41bC0yNjYgLTI2NmgtMzI5di00MDBoLTE1MHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwMHEwIDIwIDE0LjUgMzV0MzUuNSAxNWgyNTB2LTMwMGg1MDB2MzAwaDEwMHpNNzAwIDEwMDBoLTEwMHYyMDBoMTAwdi0yMDB6TTEyMDIgNTcybDcwIC03MHExNSAtMTUgMTUgLTM1LjV0LTE1IC0zNS41bC0xMzEgLTEzMSBsMTMxIC0xMzFxMTUgLTE1IDE1IC0zNS41dC0xNSAtMzUuNWwtNzAgLTcwcS0xNSAtMTUgLTM1LjUgLTE1dC0zNS41IDE1bC0xMzEgMTMxbC0xMzEgLTEzMXEtMTUgLTE1IC0zNS41IC0xNXQtMzUuNSAxNWwtNzAgNzBxLTE1IDE1IC0xNSAzNS41dDE1IDM1LjVsMTMxIDEzMWwtMTMxIDEzMXEtMTUgMTUgLTE1IDM1LjV0MTUgMzUuNWw3MCA3MHExNSAxNSAzNS41IDE1dDM1LjUgLTE1bDEzMSAtMTMxbDEzMSAxMzFxMTUgMTUgMzUuNSAxNSB0MzUuNSAtMTV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE3NTsiIGQ9Ik0xMTAwIDEwMDB2LTMwMGgtMzUwcS0yMSAwIC0zNS41IC0xNC41dC0xNC41IC0zNS41di0xNTBoLTUwMHYtNDAwaC0xNTBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMDBxMCAyMCAxNC41IDM1dDM1LjUgMTVoMjUwdi0zMDBoNTAwdjMwMGgxMDB6TTcwMCAxMDAwaC0xMDB2MjAwaDEwMHYtMjAwek04NTAgNjAwaDEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMjUwaDE1MHEyMSAwIDI1IC0xMC41dC0xMCAtMjQuNSBsLTIzMCAtMjMwcS0xNCAtMTQgLTM1IC0xNHQtMzUgMTRsLTIzMCAyMzBxLTE0IDE0IC0xMCAyNC41dDI1IDEwLjVoMTUwdjI1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE3NjsiIGQ9Ik0xMTAwIDEwMDB2LTQwMGwtMTY1IDE2NXEtMTQgMTUgLTM1IDE1dC0zNSAtMTVsLTI2MyAtMjY1aC00MDJ2LTQwMGgtMTUwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDAwcTAgMjAgMTQuNSAzNXQzNS41IDE1aDI1MHYtMzAwaDUwMHYzMDBoMTAwek03MDAgMTAwMGgtMTAwdjIwMGgxMDB2LTIwMHpNOTM1IDU2NWwyMzAgLTIyOXExNCAtMTUgMTAgLTI1LjV0LTI1IC0xMC41aC0xNTB2LTI1MHEwIC0yMCAtMTQuNSAtMzUgdC0zNS41IC0xNWgtMTAwcS0yMSAwIC0zNS41IDE1dC0xNC41IDM1djI1MGgtMTUwcS0yMSAwIC0yNSAxMC41dDEwIDI1LjVsMjMwIDIyOXExNCAxNSAzNSAxNXQzNSAtMTV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE3NzsiIGQ9Ik01MCAxMTAwaDExMDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTE1MGgtMTIwMHYxNTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek0xMjAwIDgwMHYtNTUwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY1NTBoMTIwMHpNMTAwIDUwMHYtMjAwaDQwMHYyMDBoLTQwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTc4OyIgZD0iTTkzNSAxMTY1bDI0OCAtMjMwcTE0IC0xNCAxNCAtMzV0LTE0IC0zNWwtMjQ4IC0yMzBxLTE0IC0xNCAtMjQuNSAtMTB0LTEwLjUgMjV2MTUwaC00MDB2MjAwaDQwMHYxNTBxMCAyMSAxMC41IDI1dDI0LjUgLTEwek0yMDAgODAwaC01MHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNWg1MHYtMjAwek00MDAgODAwaC0xMDB2MjAwaDEwMHYtMjAwek0xOCA0MzVsMjQ3IDIzMCBxMTQgMTQgMjQuNSAxMHQxMC41IC0yNXYtMTUwaDQwMHYtMjAwaC00MDB2LTE1MHEwIC0yMSAtMTAuNSAtMjV0LTI0LjUgMTBsLTI0NyAyMzBxLTE1IDE0IC0xNSAzNXQxNSAzNXpNOTAwIDMwMGgtMTAwdjIwMGgxMDB2LTIwMHpNMTAwMCA1MDBoNTFxMjAgMCAzNC41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzQuNSAtMTQuNWgtNTF2MjAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxNzk7IiBkPSJNODYyIDEwNzNsMjc2IDExNnEyNSAxOCA0My41IDh0MTguNSAtNDF2LTExMDZxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTIwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2Mzk3cS00IDEgLTExIDV0LTI0IDE3LjV0LTMwIDI5dC0yNCA0MnQtMTEgNTYuNXYzNTlxMCAzMSAxOC41IDY1dDQzLjUgNTJ6TTU1MCAxMjAwcTIyIDAgMzQuNSAtMTIuNXQxNC41IC0yNC41bDEgLTEzdi00NTBxMCAtMjggLTEwLjUgLTU5LjUgdC0yNSAtNTZ0LTI5IC00NXQtMjUuNSAtMzEuNWwtMTAgLTExdi00NDdxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTIwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NDQ3cS00IDQgLTExIDExLjV0LTI0IDMwLjV0LTMwIDQ2dC0yNCA1NXQtMTEgNjB2NDUwcTAgMiAwLjUgNS41dDQgMTJ0OC41IDE1dDE0LjUgMTJ0MjIuNSA1LjVxMjAgMCAzMi41IC0xMi41dDE0LjUgLTI0LjVsMyAtMTN2LTM1MGgxMDB2MzUwdjUuNXQyLjUgMTIgdDcgMTV0MTUgMTJ0MjUuNSA1LjVxMjMgMCAzNS41IC0xMi41dDEzLjUgLTI0LjVsMSAtMTN2LTM1MGgxMDB2MzUwcTAgMiAwLjUgNS41dDMgMTJ0NyAxNXQxNSAxMnQyNC41IDUuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTgwOyIgZD0iTTEyMDAgMTEwMHYtNTZxLTQgMCAtMTEgLTAuNXQtMjQgLTN0LTMwIC03LjV0LTI0IC0xNXQtMTEgLTI0di04ODhxMCAtMjIgMjUgLTM0LjV0NTAgLTEzLjVsMjUgLTJ2LTU2aC00MDB2NTZxNzUgMCA4Ny41IDYuNXQxMi41IDQzLjV2Mzk0aC01MDB2LTM5NHEwIC0zNyAxMi41IC00My41dDg3LjUgLTYuNXYtNTZoLTQwMHY1NnE0IDAgMTEgMC41dDI0IDN0MzAgNy41dDI0IDE1dDExIDI0djg4OHEwIDIyIC0yNSAzNC41dC01MCAxMy41IGwtMjUgMnY1Nmg0MDB2LTU2cS03NSAwIC04Ny41IC02LjV0LTEyLjUgLTQzLjV2LTM5NGg1MDB2Mzk0cTAgMzcgLTEyLjUgNDMuNXQtODcuNSA2LjV2NTZoNDAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxODE7IiBkPSJNNjc1IDEwMDBoMzc1cTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xNTBoLTEwNWwtMjk1IC05OHY5OGwtMjAwIDIwMGgtNDAwbDEwMCAxMDBoMzc1ek0xMDAgOTAwaDMwMHE0MSAwIDcwLjUgLTI5LjV0MjkuNSAtNzAuNXYtNTAwcTAgLTQxIC0yOS41IC03MC41dC03MC41IC0yOS41aC0zMDBxLTQxIDAgLTcwLjUgMjkuNXQtMjkuNSA3MC41djUwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjV6TTEwMCA4MDB2LTIwMGgzMDB2MjAwIGgtMzAwek0xMTAwIDUzNWwtNDAwIC0xMzN2MTYzbDQwMCAxMzN2LTE2M3pNMTAwIDUwMHYtMjAwaDMwMHYyMDBoLTMwMHpNMTEwMCAzOTh2LTI0OHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMzc1bC0xMDAgLTEwMGgtMzc1bC0xMDAgMTAwaDQwMGwyMDAgMjAwaDEwNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTgyOyIgZD0iTTE3IDEwMDdsMTYyIDE2MnExNyAxNyA0MCAxNHQzNyAtMjJsMTM5IC0xOTRxMTQgLTIwIDExIC00NC41dC0yMCAtNDEuNWwtMTE5IC0xMThxMTAyIC0xNDIgMjI4IC0yNjh0MjY3IC0yMjdsMTE5IDExOHExNyAxNyA0Mi41IDE5dDQ0LjUgLTEybDE5MiAtMTM2cTE5IC0xNCAyMi41IC0zNy41dC0xMy41IC00MC41bC0xNjMgLTE2MnEtMyAtMSAtOS41IC0xdC0yOS41IDJ0LTQ3LjUgNnQtNjIuNSAxNC41dC03Ny41IDI2LjV0LTkwIDQyLjUgdC0xMDEuNSA2MHQtMTExIDgzdC0xMTkgMTA4LjVxLTc0IDc0IC0xMzMuNSAxNTAuNXQtOTQuNSAxMzguNXQtNjAgMTE5LjV0LTM0LjUgMTAwdC0xNSA3NC41dC00LjUgNDh6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE4MzsiIGQ9Ik02MDAgMTEwMHE5MiAwIDE3NSAtMTAuNXQxNDEuNSAtMjd0MTA4LjUgLTM2LjV0ODEuNSAtNDB0NTMuNSAtMzd0MzEgLTI3bDkgLTEwdi0yMDBxMCAtMjEgLTE0LjUgLTMzdC0zNC41IC05bC0yMDIgMzRxLTIwIDMgLTM0LjUgMjB0LTE0LjUgMzh2MTQ2cS0xNDEgMjQgLTMwMCAyNHQtMzAwIC0yNHYtMTQ2cTAgLTIxIC0xNC41IC0zOHQtMzQuNSAtMjBsLTIwMiAtMzRxLTIwIC0zIC0zNC41IDl0LTE0LjUgMzN2MjAwcTMgNCA5LjUgMTAuNSB0MzEgMjZ0NTQgMzcuNXQ4MC41IDM5LjV0MTA5IDM3LjV0MTQxIDI2LjV0MTc1IDEwLjV6TTYwMCA3OTVxNTYgMCA5NyAtOS41dDYwIC0yMy41dDMwIC0yOHQxMiAtMjRsMSAtMTB2LTUwbDM2NSAtMzAzcTE0IC0xNSAyNC41IC00MHQxMC41IC00NXYtMjEycTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYyMTJxMCAyMCAxMC41IDQ1dDI0LjUgNDBsMzY1IDMwM3Y1MCBxMCA0IDEgMTAuNXQxMiAyM3QzMCAyOXQ2MCAyMi41dDk3IDEweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxODQ7IiBkPSJNMTEwMCA3MDBsLTIwMCAtMjAwaC02MDBsLTIwMCAyMDB2NTAwaDIwMHYtMjAwaDIwMHYyMDBoMjAwdi0yMDBoMjAwdjIwMGgyMDB2LTUwMHpNMjUwIDQwMGg3MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV0LTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEybDEzNyAtMTAwaC05NTBsMTM3IDEwMGgtMTJxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41dDE0LjUgMzUuNXQzNS41IDE0LjV6TTUwIDEwMGgxMTAwcTIxIDAgMzUuNSAtMTQuNSB0MTQuNSAtMzUuNXYtNTBoLTEyMDB2NTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxODU7IiBkPSJNNzAwIDExMDBoLTEwMHEtNDEgMCAtNzAuNSAtMjkuNXQtMjkuNSAtNzAuNXYtMTAwMGgzMDB2MTAwMHEwIDQxIC0yOS41IDcwLjV0LTcwLjUgMjkuNXpNMTEwMCA4MDBoLTEwMHEtNDEgMCAtNzAuNSAtMjkuNXQtMjkuNSAtNzAuNXYtNzAwaDMwMHY3MDBxMCA0MSAtMjkuNSA3MC41dC03MC41IDI5LjV6TTQwMCAwaC0zMDB2NDAwcTAgNDEgMjkuNSA3MC41dDcwLjUgMjkuNWgxMDBxNDEgMCA3MC41IC0yOS41dDI5LjUgLTcwLjV2LTQwMHogIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE4NjsiIGQ9Ik0yMDAgMTEwMGg3MDBxMTI0IDAgMjEyIC04OHQ4OCAtMjEydi01MDBxMCAtMTI0IC04OCAtMjEydC0yMTIgLTg4aC03MDBxLTEyNCAwIC0yMTIgODh0LTg4IDIxMnY1MDBxMCAxMjQgODggMjEydDIxMiA4OHpNMTAwIDkwMHYtNzAwaDkwMHY3MDBoLTkwMHpNNTAwIDcwMGgtMjAwdi0xMDBoMjAwdi0zMDBoLTMwMHYxMDBoMjAwdjEwMGgtMjAwdjMwMGgzMDB2LTEwMHpNOTAwIDcwMHYtMzAwbC0xMDAgLTEwMGgtMjAwdjUwMGgyMDB6IE03MDAgNzAwdi0zMDBoMTAwdjMwMGgtMTAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxODc7IiBkPSJNMjAwIDExMDBoNzAwcTEyNCAwIDIxMiAtODh0ODggLTIxMnYtNTAwcTAgLTEyNCAtODggLTIxMnQtMjEyIC04OGgtNzAwcS0xMjQgMCAtMjEyIDg4dC04OCAyMTJ2NTAwcTAgMTI0IDg4IDIxMnQyMTIgODh6TTEwMCA5MDB2LTcwMGg5MDB2NzAwaC05MDB6TTUwMCAzMDBoLTEwMHYyMDBoLTEwMHYtMjAwaC0xMDB2NTAwaDEwMHYtMjAwaDEwMHYyMDBoMTAwdi01MDB6TTkwMCA3MDB2LTMwMGwtMTAwIC0xMDBoLTIwMHY1MDBoMjAweiBNNzAwIDcwMHYtMzAwaDEwMHYzMDBoLTEwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTg4OyIgZD0iTTIwMCAxMTAwaDcwMHExMjQgMCAyMTIgLTg4dDg4IC0yMTJ2LTUwMHEwIC0xMjQgLTg4IC0yMTJ0LTIxMiAtODhoLTcwMHEtMTI0IDAgLTIxMiA4OHQtODggMjEydjUwMHEwIDEyNCA4OCAyMTJ0MjEyIDg4ek0xMDAgOTAwdi03MDBoOTAwdjcwMGgtOTAwek01MDAgNzAwaC0yMDB2LTMwMGgyMDB2LTEwMGgtMzAwdjUwMGgzMDB2LTEwMHpNOTAwIDcwMGgtMjAwdi0zMDBoMjAwdi0xMDBoLTMwMHY1MDBoMzAwdi0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE4OTsiIGQ9Ik0yMDAgMTEwMGg3MDBxMTI0IDAgMjEyIC04OHQ4OCAtMjEydi01MDBxMCAtMTI0IC04OCAtMjEydC0yMTIgLTg4aC03MDBxLTEyNCAwIC0yMTIgODh0LTg4IDIxMnY1MDBxMCAxMjQgODggMjEydDIxMiA4OHpNMTAwIDkwMHYtNzAwaDkwMHY3MDBoLTkwMHpNNTAwIDQwMGwtMzAwIDE1MGwzMDAgMTUwdi0zMDB6TTkwMCA1NTBsLTMwMCAtMTUwdjMwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTkwOyIgZD0iTTIwMCAxMTAwaDcwMHExMjQgMCAyMTIgLTg4dDg4IC0yMTJ2LTUwMHEwIC0xMjQgLTg4IC0yMTJ0LTIxMiAtODhoLTcwMHEtMTI0IDAgLTIxMiA4OHQtODggMjEydjUwMHEwIDEyNCA4OCAyMTJ0MjEyIDg4ek0xMDAgOTAwdi03MDBoOTAwdjcwMGgtOTAwek05MDAgMzAwaC03MDB2NTAwaDcwMHYtNTAwek04MDAgNzAwaC0xMzBxLTM4IDAgLTY2LjUgLTQzdC0yOC41IC0xMDh0MjcgLTEwN3Q2OCAtNDJoMTMwdjMwMHpNMzAwIDcwMHYtMzAwIGgxMzBxNDEgMCA2OCA0MnQyNyAxMDd0LTI4LjUgMTA4dC02Ni41IDQzaC0xMzB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE5MTsiIGQ9Ik0yMDAgMTEwMGg3MDBxMTI0IDAgMjEyIC04OHQ4OCAtMjEydi01MDBxMCAtMTI0IC04OCAtMjEydC0yMTIgLTg4aC03MDBxLTEyNCAwIC0yMTIgODh0LTg4IDIxMnY1MDBxMCAxMjQgODggMjEydDIxMiA4OHpNMTAwIDkwMHYtNzAwaDkwMHY3MDBoLTkwMHpNNTAwIDcwMGgtMjAwdi0xMDBoMjAwdi0zMDBoLTMwMHYxMDBoMjAwdjEwMGgtMjAwdjMwMGgzMDB2LTEwMHpNOTAwIDMwMGgtMTAwdjQwMGgtMTAwdjEwMGgyMDB2LTUwMHogTTcwMCAzMDBoLTEwMHYxMDBoMTAwdi0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE5MjsiIGQ9Ik0yMDAgMTEwMGg3MDBxMTI0IDAgMjEyIC04OHQ4OCAtMjEydi01MDBxMCAtMTI0IC04OCAtMjEydC0yMTIgLTg4aC03MDBxLTEyNCAwIC0yMTIgODh0LTg4IDIxMnY1MDBxMCAxMjQgODggMjEydDIxMiA4OHpNMTAwIDkwMHYtNzAwaDkwMHY3MDBoLTkwMHpNMzAwIDcwMGgyMDB2LTQwMGgtMzAwdjUwMGgxMDB2LTEwMHpNOTAwIDMwMGgtMTAwdjQwMGgtMTAwdjEwMGgyMDB2LTUwMHpNMzAwIDYwMHYtMjAwaDEwMHYyMDBoLTEwMHogTTcwMCAzMDBoLTEwMHYxMDBoMTAwdi0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE5MzsiIGQ9Ik0yMDAgMTEwMGg3MDBxMTI0IDAgMjEyIC04OHQ4OCAtMjEydi01MDBxMCAtMTI0IC04OCAtMjEydC0yMTIgLTg4aC03MDBxLTEyNCAwIC0yMTIgODh0LTg4IDIxMnY1MDBxMCAxMjQgODggMjEydDIxMiA4OHpNMTAwIDkwMHYtNzAwaDkwMHY3MDBoLTkwMHpNNTAwIDUwMGwtMTk5IC0yMDBoLTEwMHY1MGwxOTkgMjAwdjE1MGgtMjAwdjEwMGgzMDB2LTMwMHpNOTAwIDMwMGgtMTAwdjQwMGgtMTAwdjEwMGgyMDB2LTUwMHpNNzAxIDMwMGgtMTAwIHYxMDBoMTAwdi0xMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTE5NDsiIGQ9Ik02MDAgMTE5MXExMjAgMCAyMjkuNSAtNDd0MTg4LjUgLTEyNnQxMjYgLTE4OC41dDQ3IC0yMjkuNXQtNDcgLTIyOS41dC0xMjYgLTE4OC41dC0xODguNSAtMTI2dC0yMjkuNSAtNDd0LTIyOS41IDQ3dC0xODguNSAxMjZ0LTEyNiAxODguNXQtNDcgMjI5LjV0NDcgMjI5LjV0MTI2IDE4OC41dDE4OC41IDEyNnQyMjkuNSA0N3pNNjAwIDEwMjFxLTExNCAwIC0yMTEgLTU2LjV0LTE1My41IC0xNTMuNXQtNTYuNSAtMjExdDU2LjUgLTIxMSB0MTUzLjUgLTE1My41dDIxMSAtNTYuNXQyMTEgNTYuNXQxNTMuNSAxNTMuNXQ1Ni41IDIxMXQtNTYuNSAyMTF0LTE1My41IDE1My41dC0yMTEgNTYuNXpNODAwIDcwMGgtMzAwdi0yMDBoMzAwdi0xMDBoLTMwMGwtMTAwIDEwMHYyMDBsMTAwIDEwMGgzMDB2LTEwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTk1OyIgZD0iTTYwMCAxMTkxcTEyMCAwIDIyOS41IC00N3QxODguNSAtMTI2dDEyNiAtMTg4LjV0NDcgLTIyOS41dC00NyAtMjI5LjV0LTEyNiAtMTg4LjV0LTE4OC41IC0xMjZ0LTIyOS41IC00N3QtMjI5LjUgNDd0LTE4OC41IDEyNnQtMTI2IDE4OC41dC00NyAyMjkuNXQ0NyAyMjkuNXQxMjYgMTg4LjV0MTg4LjUgMTI2dDIyOS41IDQ3ek02MDAgMTAyMXEtMTE0IDAgLTIxMSAtNTYuNXQtMTUzLjUgLTE1My41dC01Ni41IC0yMTF0NTYuNSAtMjExIHQxNTMuNSAtMTUzLjV0MjExIC01Ni41dDIxMSA1Ni41dDE1My41IDE1My41dDU2LjUgMjExdC01Ni41IDIxMXQtMTUzLjUgMTUzLjV0LTIxMSA1Ni41ek04MDAgNzAwdi0xMDBsLTUwIC01MGwxMDAgLTEwMHYtNTBoLTEwMGwtMTAwIDEwMGgtMTUwdi0xMDBoLTEwMHY0MDBoMzAwek01MDAgNzAwdi0xMDBoMjAwdjEwMGgtMjAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxOTc7IiBkPSJNNTAzIDEwODlxMTEwIDAgMjAwLjUgLTU5LjV0MTM0LjUgLTE1Ni41cTQ0IDE0IDkwIDE0cTEyMCAwIDIwNSAtODYuNXQ4NSAtMjA3dC04NSAtMjA3dC0yMDUgLTg2LjVoLTEyOHYyNTBxMCAyMSAtMTQuNSAzNS41dC0zNS41IDE0LjVoLTMwMHEtMjEgMCAtMzUuNSAtMTQuNXQtMTQuNSAtMzUuNXYtMjUwaC0yMjJxLTgwIDAgLTEzNiA1Ny41dC01NiAxMzYuNXEwIDY5IDQzIDEyMi41dDEwOCA2Ny41cS0yIDE5IC0yIDM3cTAgMTAwIDQ5IDE4NSB0MTM0IDEzNHQxODUgNDl6TTUyNSA1MDBoMTUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMjc1aDEzN3EyMSAwIDI2IC0xMS41dC04IC0yNy41bC0yMjMgLTI0NHEtMTMgLTE2IC0zMiAtMTZ0LTMyIDE2bC0yMjMgMjQ0cS0xMyAxNiAtOCAyNy41dDI2IDExLjVoMTM3djI3NXEwIDEwIDcuNSAxNy41dDE3LjUgNy41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUxOTg7IiBkPSJNNTAyIDEwODlxMTEwIDAgMjAxIC01OS41dDEzNSAtMTU2LjVxNDMgMTUgODkgMTVxMTIxIDAgMjA2IC04Ni41dDg2IC0yMDYuNXEwIC05OSAtNjAgLTE4MXQtMTUwIC0xMTBsLTM3OCAzNjBxLTEzIDE2IC0zMS41IDE2dC0zMS41IC0xNmwtMzgxIC0zNjVoLTlxLTc5IDAgLTEzNS41IDU3LjV0LTU2LjUgMTM2LjVxMCA2OSA0MyAxMjIuNXQxMDggNjcuNXEtMiAxOSAtMiAzOHEwIDEwMCA0OSAxODQuNXQxMzMuNSAxMzR0MTg0LjUgNDkuNXogTTYzMiA0NjdsMjIzIC0yMjhxMTMgLTE2IDggLTI3LjV0LTI2IC0xMS41aC0xMzd2LTI3NXEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTE1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djI3NWgtMTM3cS0yMSAwIC0yNiAxMS41dDggMjcuNXExOTkgMjA0IDIyMyAyMjhxMTkgMTkgMzEuNSAxOXQzMi41IC0xOXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMTk5OyIgZD0iTTcwMCAxMDB2MTAwaDQwMGwtMjcwIDMwMGgxNzBsLTI3MCAzMDBoMTcwbC0zMDAgMzMzbC0zMDAgLTMzM2gxNzBsLTI3MCAtMzAwaDE3MGwtMjcwIC0zMDBoNDAwdi0xMDBoLTUwcS0yMSAwIC0zNS41IC0xNC41dC0xNC41IC0zNS41di01MGg0MDB2NTBxMCAyMSAtMTQuNSAzNS41dC0zNS41IDE0LjVoLTUweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMDA7IiBkPSJNNjAwIDExNzlxOTQgMCAxNjcuNSAtNTYuNXQ5OS41IC0xNDUuNXE4OSAtNiAxNTAuNSAtNzEuNXQ2MS41IC0xNTUuNXEwIC02MSAtMjkuNSAtMTEyLjV0LTc5LjUgLTgyLjVxOSAtMjkgOSAtNTVxMCAtNzQgLTUyLjUgLTEyNi41dC0xMjYuNSAtNTIuNXEtNTUgMCAtMTAwIDMwdi0yNTFxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTUwaC0zMDB2NTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41djI1MXEtNDUgLTMwIC0xMDAgLTMwIHEtNzQgMCAtMTI2LjUgNTIuNXQtNTIuNSAxMjYuNXEwIDE4IDQgMzhxLTQ3IDIxIC03NS41IDY1dC0yOC41IDk3cTAgNzQgNTIuNSAxMjYuNXQxMjYuNSA1Mi41cTUgMCAyMyAtMnEwIDIgLTEgMTB0LTEgMTNxMCAxMTYgODEuNSAxOTcuNXQxOTcuNSA4MS41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMDE7IiBkPSJNMTAxMCAxMDEwcTExMSAtMTExIDE1MC41IC0yNjAuNXQwIC0yOTl0LTE1MC41IC0yNjAuNXEtODMgLTgzIC0xOTEuNSAtMTI2LjV0LTIxOC41IC00My41dC0yMTguNSA0My41dC0xOTEuNSAxMjYuNXEtMTExIDExMSAtMTUwLjUgMjYwLjV0MCAyOTl0MTUwLjUgMjYwLjVxODMgODMgMTkxLjUgMTI2LjV0MjE4LjUgNDMuNXQyMTguNSAtNDMuNXQxOTEuNSAtMTI2LjV6TTQ3NiAxMDY1cS00IDAgLTggLTFxLTEyMSAtMzQgLTIwOS41IC0xMjIuNSB0LTEyMi41IC0yMDkuNXEtNCAtMTIgMi41IC0yM3QxOC41IC0xNGwzNiAtOXEzIC0xIDcgLTFxMjMgMCAyOSAyMnEyNyA5NiA5OCAxNjZxNzAgNzEgMTY2IDk4cTExIDMgMTcuNSAxMy41dDMuNSAyMi41bC05IDM1cS0zIDEzIC0xNCAxOXEtNyA0IC0xNSA0ek01MTIgOTIwcS00IDAgLTkgLTJxLTgwIC0yNCAtMTM4LjUgLTgyLjV0LTgyLjUgLTEzOC41cS00IC0xMyAyIC0yNHQxOSAtMTRsMzQgLTlxNCAtMSA4IC0xcTIyIDAgMjggMjEgcTE4IDU4IDU4LjUgOTguNXQ5Ny41IDU4LjVxMTIgMyAxOCAxMy41dDMgMjEuNWwtOSAzNXEtMyAxMiAtMTQgMTlxLTcgNCAtMTUgNHpNNzE5LjUgNzE5LjVxLTQ5LjUgNDkuNSAtMTE5LjUgNDkuNXQtMTE5LjUgLTQ5LjV0LTQ5LjUgLTExOS41dDQ5LjUgLTExOS41dDExOS41IC00OS41dDExOS41IDQ5LjV0NDkuNSAxMTkuNXQtNDkuNSAxMTkuNXpNODU1IDU1MXEtMjIgMCAtMjggLTIxcS0xOCAtNTggLTU4LjUgLTk4LjV0LTk4LjUgLTU3LjUgcS0xMSAtNCAtMTcgLTE0LjV0LTMgLTIxLjVsOSAtMzVxMyAtMTIgMTQgLTE5cTcgLTQgMTUgLTRxNCAwIDkgMnE4MCAyNCAxMzguNSA4Mi41dDgyLjUgMTM4LjVxNCAxMyAtMi41IDI0dC0xOC41IDE0bC0zNCA5cS00IDEgLTggMXpNMTAwMCA1MTVxLTIzIDAgLTI5IC0yMnEtMjcgLTk2IC05OCAtMTY2cS03MCAtNzEgLTE2NiAtOThxLTExIC0zIC0xNy41IC0xMy41dC0zLjUgLTIyLjVsOSAtMzVxMyAtMTMgMTQgLTE5cTcgLTQgMTUgLTQgcTQgMCA4IDFxMTIxIDM0IDIwOS41IDEyMi41dDEyMi41IDIwOS41cTQgMTIgLTIuNSAyM3QtMTguNSAxNGwtMzYgOXEtMyAxIC03IDF6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIwMjsiIGQ9Ik03MDAgODAwaDMwMHYtMzgwaC0xODB2MjAwaC0zNDB2LTIwMGgtMzgwdjc1NXEwIDEwIDcuNSAxNy41dDE3LjUgNy41aDU3NXYtNDAwek0xMDAwIDkwMGgtMjAwdjIwMHpNNzAwIDMwMGgxNjJsLTIxMiAtMjEybC0yMTIgMjEyaDE2MnYyMDBoMTAwdi0yMDB6TTUyMCAwaC0zOTVxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYzOTV6TTEwMDAgMjIwdi0xOTVxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0xOTV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIwMzsiIGQ9Ik03MDAgODAwaDMwMHYtNTIwbC0zNTAgMzUwbC01NTAgLTU1MHYxMDk1cTAgMTAgNy41IDE3LjV0MTcuNSA3LjVoNTc1di00MDB6TTEwMDAgOTAwaC0yMDB2MjAwek04NjIgMjAwaC0xNjJ2LTIwMGgtMTAwdjIwMGgtMTYybDIxMiAyMTJ6TTQ4MCAwaC0zNTVxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY1NWgzODB2LTgwek0xMDAwIDgwdi01NXEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTE1NXY4MGgxODB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIwNDsiIGQ9Ik0xMTYyIDgwMGgtMTYydi0yMDBoMTAwbDEwMCAtMTAwaC0zMDB2MzAwaC0xNjJsMjEyIDIxMnpNMjAwIDgwMGgyMDBxMjcgMCA0MCAtMnQyOS41IC0xMC41dDIzLjUgLTMwdDcgLTU3LjVoMzAwdi0xMDBoLTYwMGwtMjAwIC0zNTB2NDUwaDEwMHEwIDM2IDcgNTcuNXQyMy41IDMwdDI5LjUgMTAuNXQ0MCAyek04MDAgNDAwaDI0MGwtMjQwIC00MDBoLTgwMGwzMDAgNTAwaDUwMHYtMTAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMDU7IiBkPSJNNjUwIDExMDBoMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MGg1MHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0zMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djEwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoNTB2NTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek0xMDAwIDg1MHYxNTBxNDEgMCA3MC41IC0yOS41dDI5LjUgLTcwLjV2LTgwMCBxMCAtNDEgLTI5LjUgLTcwLjV0LTcwLjUgLTI5LjVoLTYwMHEtMSAwIC0yMCA0bDI0NiAyNDZsLTMyNiAzMjZ2MzI0cTAgNDEgMjkuNSA3MC41dDcwLjUgMjkuNXYtMTUwcTAgLTYyIDQ0IC0xMDZ0MTA2IC00NGgzMDBxNjIgMCAxMDYgNDR0NDQgMTA2ek00MTIgMjUwbC0yMTIgLTIxMnYxNjJoLTIwMHYxMDBoMjAwdjE2MnoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjA2OyIgZD0iTTQ1MCAxMTAwaDEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTBoNTBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMzAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDUwdjUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNODAwIDg1MHYxNTBxNDEgMCA3MC41IC0yOS41dDI5LjUgLTcwLjV2LTUwMCBoLTIwMHYtMzAwaDIwMHEwIC0zNiAtNyAtNTcuNXQtMjMuNSAtMzB0LTI5LjUgLTEwLjV0LTQwIC0yaC02MDBxLTQxIDAgLTcwLjUgMjkuNXQtMjkuNSA3MC41djgwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjV2LTE1MHEwIC02MiA0NCAtMTA2dDEwNiAtNDRoMzAwcTYyIDAgMTA2IDQ0dDQ0IDEwNnpNMTIxMiAyNTBsLTIxMiAtMjEydjE2MmgtMjAwdjEwMGgyMDB2MTYyeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMDk7IiBkPSJNNjU4IDExOTdsNjM3IC0xMTA0cTIzIC0zOCA3IC02NS41dC02MCAtMjcuNWgtMTI3NnEtNDQgMCAtNjAgMjcuNXQ3IDY1LjVsNjM3IDExMDRxMjIgMzkgNTQgMzl0NTQgLTM5ek03MDQgODAwaC0yMDhxLTIwIDAgLTMyIC0xNC41dC04IC0zNC41bDU4IC0zMDJxNCAtMjAgMjEuNSAtMzQuNXQzNy41IC0xNC41aDU0cTIwIDAgMzcuNSAxNC41dDIxLjUgMzQuNWw1OCAzMDJxNCAyMCAtOCAzNC41dC0zMiAxNC41ek01MDAgMzAwdi0xMDBoMjAwIHYxMDBoLTIwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjEwOyIgZD0iTTQyNSAxMTAwaDI1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTE1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTI1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek00MjUgODAwaDI1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTE1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTI1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE1MHEwIDEwIDcuNSAxNy41IHQxNy41IDcuNXpNODI1IDgwMGgyNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNMjUgNTAwaDI1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTE1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTI1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE1MCBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNNDI1IDUwMGgyNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNODI1IDUwMGgyNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNSB2MTUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTI1IDIwMGgyNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0yNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXYxNTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNNDI1IDIwMGgyNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di0xNTBxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0yNTBxLTEwIDAgLTE3LjUgNy41IHQtNy41IDE3LjV2MTUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTgyNSAyMDBoMjUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMjUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2MTUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIxMTsiIGQ9Ik03MDAgMTIwMGgxMDB2LTIwMGgtMTAwdi0xMDBoMzUwcTYyIDAgODYuNSAtMzkuNXQtMy41IC05NC41bC02NiAtMTMycS00MSAtODMgLTgxIC0xMzRoLTc3MnEtNDAgNTEgLTgxIDEzNGwtNjYgMTMycS0yOCA1NSAtMy41IDk0LjV0ODYuNSAzOS41aDM1MHYxMDBoLTEwMHYyMDBoMTAwdjEwMGgyMDB2LTEwMHpNMjUwIDQwMGg3MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV0LTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEybDEzNyAtMTAwIGgtOTUwbDEzOCAxMDBoLTEzcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXQxNC41IDM1LjV0MzUuNSAxNC41ek01MCAxMDBoMTEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTBoLTEyMDB2NTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMTI7IiBkPSJNNjAwIDEzMDBxNDAgMCA2OC41IC0yOS41dDI4LjUgLTcwLjVoLTE5NHEwIDQxIDI4LjUgNzAuNXQ2OC41IDI5LjV6TTQ0MyAxMTAwaDMxNHExOCAtMzcgMTggLTc1cTAgLTggLTMgLTI1aDMyOHE0MSAwIDQ0LjUgLTE2LjV0LTMwLjUgLTM4LjVsLTE3NSAtMTQ1aC02NzhsLTE3OCAxNDVxLTM0IDIyIC0yOSAzOC41dDQ2IDE2LjVoMzI4cS0zIDE3IC0zIDI1cTAgMzggMTggNzV6TTI1MCA3MDBoNzAwcTIxIDAgMzUuNSAtMTQuNSB0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTUwdi0yMDBsMjc1IC0yMDBoLTk1MGwyNzUgMjAwdjIwMGgtMTUwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXQxNC41IDM1LjV0MzUuNSAxNC41ek01MCAxMDBoMTEwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTBoLTEyMDB2NTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMTM7IiBkPSJNNjAwIDExODFxNzUgMCAxMjggLTUzdDUzIC0xMjh0LTUzIC0xMjh0LTEyOCAtNTN0LTEyOCA1M3QtNTMgMTI4dDUzIDEyOHQxMjggNTN6TTYwMiA3OThoNDZxMzQgMCA1NS41IC0yOC41dDIxLjUgLTg2LjVxMCAtNzYgMzkgLTE4M2gtMzI0cTM5IDEwNyAzOSAxODNxMCA1OCAyMS41IDg2LjV0NTYuNSAyOC41aDQ1ek0yNTAgNDAwaDcwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTMgbDEzOCAtMTAwaC05NTBsMTM3IDEwMGgtMTJxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41dDE0LjUgMzUuNXQzNS41IDE0LjV6TTUwIDEwMGgxMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MGgtMTIwMHY1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIxNDsiIGQ9Ik02MDAgMTMwMHE0NyAwIDkyLjUgLTUzLjV0NzEgLTEyM3QyNS41IC0xMjMuNXEwIC03OCAtNTUuNSAtMTMzLjV0LTEzMy41IC01NS41dC0xMzMuNSA1NS41dC01NS41IDEzMy41cTAgNjIgMzQgMTQzbDE0NCAtMTQzbDExMSAxMTFsLTE2MyAxNjNxMzQgMjYgNjMgMjZ6TTYwMiA3OThoNDZxMzQgMCA1NS41IC0yOC41dDIxLjUgLTg2LjVxMCAtNzYgMzkgLTE4M2gtMzI0cTM5IDEwNyAzOSAxODNxMCA1OCAyMS41IDg2LjV0NTYuNSAyOC41aDQ1IHpNMjUwIDQwMGg3MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV0LTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTEzbDEzOCAtMTAwaC05NTBsMTM3IDEwMGgtMTJxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41dDE0LjUgMzUuNXQzNS41IDE0LjV6TTUwIDEwMGgxMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MGgtMTIwMHY1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIxNTsiIGQ9Ik02MDAgMTIwMGwzMDAgLTE2MXYtMTM5aC0zMDBxMCAtNTcgMTguNSAtMTA4dDUwIC05MS41dDYzIC03MnQ3MCAtNjcuNXQ1Ny41IC02MWgtNTMwcS02MCA4MyAtOTAuNSAxNzcuNXQtMzAuNSAxNzguNXQzMyAxNjQuNXQ4Ny41IDEzOS41dDEyNiA5Ni41dDE0NS41IDQxLjV2LTk4ek0yNTAgNDAwaDcwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTNsMTM4IC0xMDBoLTk1MGwxMzcgMTAwIGgtMTJxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41dDE0LjUgMzUuNXQzNS41IDE0LjV6TTUwIDEwMGgxMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MGgtMTIwMHY1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIxNjsiIGQ9Ik02MDAgMTMwMHE0MSAwIDcwLjUgLTI5LjV0MjkuNSAtNzAuNXYtNzhxNDYgLTI2IDczIC03MnQyNyAtMTAwdi01MGgtNDAwdjUwcTAgNTQgMjcgMTAwdDczIDcydjc4cTAgNDEgMjkuNSA3MC41dDcwLjUgMjkuNXpNNDAwIDgwMGg0MDBxNTQgMCAxMDAgLTI3dDcyIC03M2gtMTcydi0xMDBoMjAwdi0xMDBoLTIwMHYtMTAwaDIwMHYtMTAwaC0yMDB2LTEwMGgyMDBxMCAtODMgLTU4LjUgLTE0MS41dC0xNDEuNSAtNTguNWgtNDAwIHEtODMgMCAtMTQxLjUgNTguNXQtNTguNSAxNDEuNXY0MDBxMCA4MyA1OC41IDE0MS41dDE0MS41IDU4LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIxODsiIGQ9Ik0xNTAgMTEwMGg5MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTUwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtOTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY1MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek0xMjUgNDAwaDk1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMjgzbDIyNCAtMjI0cTEzIC0xMyAxMyAtMzEuNXQtMTMgLTMyIHQtMzEuNSAtMTMuNXQtMzEuNSAxM2wtODggODhoLTUyNGwtODcgLTg4cS0xMyAtMTMgLTMyIC0xM3QtMzIgMTMuNXQtMTMgMzJ0MTMgMzEuNWwyMjQgMjI0aC0yODlxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41ek01NDEgMzAwbC0xMDAgLTEwMGgzMjRsLTEwMCAxMDBoLTEyNHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjE5OyIgZD0iTTIwMCAxMTAwaDgwMHE4MyAwIDE0MS41IC01OC41dDU4LjUgLTE0MS41di0yMDBoLTEwMHEwIDQxIC0yOS41IDcwLjV0LTcwLjUgMjkuNWgtMjUwcS00MSAwIC03MC41IC0yOS41dC0yOS41IC03MC41aC0xMDBxMCA0MSAtMjkuNSA3MC41dC03MC41IDI5LjVoLTI1MHEtNDEgMCAtNzAuNSAtMjkuNXQtMjkuNSAtNzAuNWgtMTAwdjIwMHEwIDgzIDU4LjUgMTQxLjV0MTQxLjUgNTguNXpNMTAwIDYwMGgxMDAwcTQxIDAgNzAuNSAtMjkuNSB0MjkuNSAtNzAuNXYtMzAwaC0xMjAwdjMwMHEwIDQxIDI5LjUgNzAuNXQ3MC41IDI5LjV6TTMwMCAxMDB2LTUwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djUwaDIwMHpNMTEwMCAxMDB2LTUwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djUwaDIwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjIxOyIgZD0iTTQ4MCAxMTY1bDY4MiAtNjgzcTMxIC0zMSAzMSAtNzUuNXQtMzEgLTc1LjVsLTEzMSAtMTMxaC00ODFsLTUxNyA1MThxLTMyIDMxIC0zMiA3NS41dDMyIDc1LjVsMjk1IDI5NnEzMSAzMSA3NS41IDMxdDc2LjUgLTMxek0xMDggNzk0bDM0MiAtMzQybDMwMyAzMDRsLTM0MSAzNDF6TTI1MCAxMDBoODAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di01MGgtOTAwdjUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjIzOyIgZD0iTTEwNTcgNjQ3bC0xODkgNTA2cS04IDE5IC0yNy41IDMzdC00MC41IDE0aC00MDBxLTIxIDAgLTQwLjUgLTE0dC0yNy41IC0zM2wtMTg5IC01MDZxLTggLTE5IDEuNSAtMzN0MzAuNSAtMTRoNjI1di0xNTBxMCAtMjEgMTQuNSAtMzUuNXQzNS41IC0xNC41dDM1LjUgMTQuNXQxNC41IDM1LjV2MTUwaDEyNXEyMSAwIDMwLjUgMTR0MS41IDMzek04OTcgMGgtNTk1djUwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNWg1MHY1MCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDQ4djMwMGgyMDB2LTMwMGg0N3EyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTBoNTBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTUweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMjQ7IiBkPSJNOTAwIDgwMGgzMDB2LTU3NXEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTM3NXY1OTFsLTMwMCAzMDB2ODRxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgzNzV2LTQwMHpNMTIwMCA5MDBoLTIwMHYyMDB6TTQwMCA2MDBoMzAwdi01NzVxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC02NTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY5NTBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgzNzV2LTQwMHpNNzAwIDcwMGgtMjAwdjIwMHogIiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIyNTsiIGQ9Ik00ODQgMTA5NWgxOTVxNzUgMCAxNDYgLTMyLjV0MTI0IC04NnQ4OS41IC0xMjIuNXQ0OC41IC0xNDJxMTggLTE0IDM1IC0yMHEzMSAtMTAgNjQuNSA2LjV0NDMuNSA0OC41cTEwIDM0IC0xNSA3MXEtMTkgMjcgLTkgNDNxNSA4IDEyLjUgMTF0MTkgLTF0MjMuNSAtMTZxNDEgLTQ0IDM5IC0xMDVxLTMgLTYzIC00NiAtMTA2LjV0LTEwNCAtNDMuNWgtNjJxLTcgLTU1IC0zNSAtMTE3dC01NiAtMTAwbC0zOSAtMjM0cS0zIC0yMCAtMjAgLTM0LjUgdC0zOCAtMTQuNWgtMTAwcS0yMSAwIC0zMyAxNC41dC05IDM0LjVsMTIgNzBxLTQ5IC0xNCAtOTEgLTE0aC0xOTVxLTI0IDAgLTY1IDhsLTExIC02NHEtMyAtMjAgLTIwIC0zNC41dC0zOCAtMTQuNWgtMTAwcS0yMSAwIC0zMyAxNC41dC05IDM0LjVsMjYgMTU3cS04NCA3NCAtMTI4IDE3NWwtMTU5IDUzcS0xOSA3IC0zMyAyNnQtMTQgNDB2NTBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDEyNHExMSA4NyA1NiAxNjZsLTExMSA5NSBxLTE2IDE0IC0xMi41IDIzLjV0MjQuNSA5LjVoMjAzcTExNiAxMDEgMjUwIDEwMXpNNjc1IDEwMDBoLTI1MHEtMTAgMCAtMTcuNSAtNy41dC03LjUgLTE3LjV2LTUwcTAgLTEwIDcuNSAtMTcuNXQxNy41IC03LjVoMjUwcTEwIDAgMTcuNSA3LjV0Ny41IDE3LjV2NTBxMCAxMCAtNy41IDE3LjV0LTE3LjUgNy41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMjY7IiBkPSJNNjQxIDkwMGw0MjMgMjQ3cTE5IDggNDIgMi41dDM3IC0yMS41bDMyIC0zOHExNCAtMTUgMTIuNSAtMzZ0LTE3LjUgLTM0bC0xMzkgLTEyMGgtMzkwek01MCAxMTAwaDEwNnE2NyAwIDEwMyAtMTd0NjYgLTcxbDEwMiAtMjEyaDgyM3EyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNTBxMCAtMjEgLTE0IC00MHQtMzMgLTI2bC03MzcgLTEzMnEtMjMgLTQgLTQwIDZ0LTI2IDI1cS00MiA2NyAtMTAwIDY3aC0zMDBxLTYyIDAgLTEwNiA0NCB0LTQ0IDEwNnYyMDBxMCA2MiA0NCAxMDZ0MTA2IDQ0ek0xNzMgOTI4aC04MHEtMTkgMCAtMjggLTE0dC05IC0zNXYtNTZxMCAtNTEgNDIgLTUxaDEzNHExNiAwIDIxLjUgOHQ1LjUgMjRxMCAxMSAtMTYgNDV0LTI3IDUxcS0xOCAyOCAtNDMgMjh6TTU1MCA3MjdxLTMyIDAgLTU0LjUgLTIyLjV0LTIyLjUgLTU0LjV0MjIuNSAtNTQuNXQ1NC41IC0yMi41dDU0LjUgMjIuNXQyMi41IDU0LjV0LTIyLjUgNTQuNXQtNTQuNSAyMi41ek0xMzAgMzg5IGwxNTIgMTMwcTE4IDE5IDM0IDI0dDMxIC0zLjV0MjQuNSAtMTcuNXQyNS41IC0yOHEyOCAtMzUgNTAuNSAtNTF0NDguNSAtMTNsNjMgNWw0OCAtMTc5cTEzIC02MSAtMy41IC05Ny41dC02Ny41IC03OS41bC04MCAtNjlxLTQ3IC00MCAtMTA5IC0zNS41dC0xMDMgNTEuNWwtMTMwIDE1MXEtNDAgNDcgLTM1LjUgMTA5LjV0NTEuNSAxMDIuNXpNMzgwIDM3N2wtMTAyIC04OHEtMzEgLTI3IDIgLTY1bDM3IC00M3ExMyAtMTUgMjcuNSAtMTkuNSB0MzEuNSA2LjVsNjEgNTNxMTkgMTYgMTQgNDlxLTIgMjAgLTEyIDU2dC0xNyA0NXEtMTEgMTIgLTE5IDE0dC0yMyAtOHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjI3OyIgZD0iTTYyNSAxMjAwaDE1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTEwOXE3OSAtMzMgMTMxIC04Ny41dDUzIC0xMjguNXExIC00NiAtMTUgLTg0LjV0LTM5IC02MXQtNDYgLTM4dC0zOSAtMjEuNWwtMTcgLTZxNiAwIDE1IC0xLjV0MzUgLTl0NTAgLTE3LjV0NTMgLTMwdDUwIC00NXQzNS41IC02NHQxNC41IC04NHEwIC01OSAtMTEuNSAtMTA1LjV0LTI4LjUgLTc2LjV0LTQ0IC01MXQtNDkuNSAtMzEuNXQtNTQuNSAtMTZ0LTQ5LjUgLTYuNSB0LTQzLjUgLTF2LTc1cTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtMTUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2NzVoLTEwMHYtNzVxMCAtMTAgLTcuNSAtMTcuNXQtMTcuNSAtNy41aC0xNTBxLTEwIDAgLTE3LjUgNy41dC03LjUgMTcuNXY3NWgtMTc1cS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2MTUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjVoNzV2NjAwaC03NXEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE1MCBxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgxNzV2NzVxMCAxMCA3LjUgMTcuNXQxNy41IDcuNWgxNTBxMTAgMCAxNy41IC03LjV0Ny41IC0xNy41di03NWgxMDB2NzVxMCAxMCA3LjUgMTcuNXQxNy41IDcuNXpNNDAwIDkwMHYtMjAwaDI2M3EyOCAwIDQ4LjUgMTAuNXQzMCAyNXQxNSAyOXQ1LjUgMjUuNWwxIDEwcTAgNCAtMC41IDExdC02IDI0dC0xNSAzMHQtMzAgMjR0LTQ4LjUgMTFoLTI2M3pNNDAwIDUwMHYtMjAwaDM2M3EyOCAwIDQ4LjUgMTAuNSB0MzAgMjV0MTUgMjl0NS41IDI1LjVsMSAxMHEwIDQgLTAuNSAxMXQtNiAyNHQtMTUgMzB0LTMwIDI0dC00OC41IDExaC0zNjN6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIzMDsiIGQ9Ik0yMTIgMTE5OGg3ODBxODYgMCAxNDcgLTYxdDYxIC0xNDd2LTQxNnEwIC01MSAtMTggLTE0Mi41dC0zNiAtMTU3LjVsLTE4IC02NnEtMjkgLTg3IC05My41IC0xNDYuNXQtMTQ2LjUgLTU5LjVoLTU3MnEtODIgMCAtMTQ3IDU5dC05MyAxNDdxLTggMjggLTIwIDczdC0zMiAxNDMuNXQtMjAgMTQ5LjV2NDE2cTAgODYgNjEgMTQ3dDE0NyA2MXpNNjAwIDEwNDVxLTcwIDAgLTEzMi41IC0xMS41dC0xMDUuNSAtMzAuNXQtNzguNSAtNDEuNSB0LTU3IC00NXQtMzYgLTQxdC0yMC41IC0zMC41bC02IC0xMmwxNTYgLTI0M2g1NjBsMTU2IDI0M3EtMiA1IC02IDEyLjV0LTIwIDI5LjV0LTM2LjUgNDJ0LTU3IDQ0LjV0LTc5IDQydC0xMDUgMjkuNXQtMTMyLjUgMTJ6TTc2MiA3MDNoLTE1N2wxOTUgMjYxeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMzE7IiBkPSJNNDc1IDEzMDBoMTUwcTEwMyAwIDE4OSAtODZ0ODYgLTE4OXYtNTAwcTAgLTQxIC00MiAtODN0LTgzIC00MmgtNDUwcS00MSAwIC04MyA0MnQtNDIgODN2NTAwcTAgMTAzIDg2IDE4OXQxODkgODZ6TTcwMCAzMDB2LTIyNXEwIC0yMSAtMjcgLTQ4dC00OCAtMjdoLTE1MHEtMjEgMCAtNDggMjd0LTI3IDQ4djIyNWgzMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIzMjsiIGQ9Ik00NzUgMTMwMGg5NnEwIC0xNTAgODkuNSAtMjM5LjV0MjM5LjUgLTg5LjV2LTQ0NnEwIC00MSAtNDIgLTgzdC04MyAtNDJoLTQ1MHEtNDEgMCAtODMgNDJ0LTQyIDgzdjUwMHEwIDEwMyA4NiAxODl0MTg5IDg2ek03MDAgMzAwdi0yMjVxMCAtMjEgLTI3IC00OHQtNDggLTI3aC0xNTBxLTIxIDAgLTQ4IDI3dC0yNyA0OHYyMjVoMzAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMzM7IiBkPSJNMTI5NCA3NjdsLTYzOCAtMjgzbC0zNzggMTcwbC03OCAtNjB2LTIyNGwxMDAgLTE1MHYtMTk5bC0xNTAgMTQ4bC0xNTAgLTE0OXYyMDBsMTAwIDE1MHYyNTBxMCA0IC0wLjUgMTAuNXQwIDkuNXQxIDh0MyA4dDYuNSA2bDQ3IDQwbC0xNDcgNjVsNjQyIDI4M3pNMTAwMCAzODBsLTM1MCAtMTY2bC0zNTAgMTY2djE0N2wzNTAgLTE2NWwzNTAgMTY1di0xNDd6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIzNDsiIGQ9Ik0yNTAgODAwcTYyIDAgMTA2IC00NHQ0NCAtMTA2dC00NCAtMTA2dC0xMDYgLTQ0dC0xMDYgNDR0LTQ0IDEwNnQ0NCAxMDZ0MTA2IDQ0ek02NTAgODAwcTYyIDAgMTA2IC00NHQ0NCAtMTA2dC00NCAtMTA2dC0xMDYgLTQ0dC0xMDYgNDR0LTQ0IDEwNnQ0NCAxMDZ0MTA2IDQ0ek0xMDUwIDgwMHE2MiAwIDEwNiAtNDR0NDQgLTEwNnQtNDQgLTEwNnQtMTA2IC00NHQtMTA2IDQ0dC00NCAxMDZ0NDQgMTA2dDEwNiA0NHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjM1OyIgZD0iTTU1MCAxMTAwcTYyIDAgMTA2IC00NHQ0NCAtMTA2dC00NCAtMTA2dC0xMDYgLTQ0dC0xMDYgNDR0LTQ0IDEwNnQ0NCAxMDZ0MTA2IDQ0ek01NTAgNzAwcTYyIDAgMTA2IC00NHQ0NCAtMTA2dC00NCAtMTA2dC0xMDYgLTQ0dC0xMDYgNDR0LTQ0IDEwNnQ0NCAxMDZ0MTA2IDQ0ek01NTAgMzAwcTYyIDAgMTA2IC00NHQ0NCAtMTA2dC00NCAtMTA2dC0xMDYgLTQ0dC0xMDYgNDR0LTQ0IDEwNnQ0NCAxMDZ0MTA2IDQ0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMzY7IiBkPSJNMTI1IDExMDBoOTUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtOTUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2MTUwcTAgMTAgNy41IDE3LjV0MTcuNSA3LjV6TTEyNSA3MDBoOTUwcTEwIDAgMTcuNSAtNy41dDcuNSAtMTcuNXYtMTUwcTAgLTEwIC03LjUgLTE3LjV0LTE3LjUgLTcuNWgtOTUwcS0xMCAwIC0xNy41IDcuNXQtNy41IDE3LjV2MTUwcTAgMTAgNy41IDE3LjUgdDE3LjUgNy41ek0xMjUgMzAwaDk1MHExMCAwIDE3LjUgLTcuNXQ3LjUgLTE3LjV2LTE1MHEwIC0xMCAtNy41IC0xNy41dC0xNy41IC03LjVoLTk1MHEtMTAgMCAtMTcuNSA3LjV0LTcuNSAxNy41djE1MHEwIDEwIDcuNSAxNy41dDE3LjUgNy41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMzc7IiBkPSJNMzUwIDEyMDBoNTAwcTE2MiAwIDI1NiAtOTMuNXQ5NCAtMjU2LjV2LTUwMHEwIC0xNjUgLTkzLjUgLTI1Ny41dC0yNTYuNSAtOTIuNWgtNTAwcS0xNjUgMCAtMjU3LjUgOTIuNXQtOTIuNSAyNTcuNXY1MDBxMCAxNjUgOTIuNSAyNTcuNXQyNTcuNSA5Mi41ek05MDAgMTAwMGgtNjAwcS00MSAwIC03MC41IC0yOS41dC0yOS41IC03MC41di02MDBxMCAtNDEgMjkuNSAtNzAuNXQ3MC41IC0yOS41aDYwMHE0MSAwIDcwLjUgMjkuNSB0MjkuNSA3MC41djYwMHEwIDQxIC0yOS41IDcwLjV0LTcwLjUgMjkuNXpNMzUwIDkwMGg1MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTMwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYzMDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek00MDAgODAwdi0yMDBoNDAwdjIwMGgtNDAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyMzg7IiBkPSJNMTUwIDExMDBoMTAwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTB2LTIwMGg1MHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTB2LTIwMGg1MHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNTB2LTIwMGg1MHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXQtMTQuNSAtMzUuNSB0LTM1LjUgLTE0LjVoLTEwMDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41dDE0LjUgMzUuNXQzNS41IDE0LjVoNTB2MjAwaC01MHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV0MTQuNSAzNS41dDM1LjUgMTQuNWg1MHYyMDBoLTUwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXQxNC41IDM1LjV0MzUuNSAxNC41aDUwdjIwMGgtNTBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41dDE0LjUgMzUuNXQzNS41IDE0LjV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTIzOTsiIGQ9Ik02NTAgMTE4N3E4NyAtNjcgMTE4LjUgLTE1NnQwIC0xNzh0LTExOC41IC0xNTVxLTg3IDY2IC0xMTguNSAxNTV0MCAxNzh0MTE4LjUgMTU2ek0zMDAgODAwcTEyNCAwIDIxMiAtODh0ODggLTIxMnEtMTI0IDAgLTIxMiA4OHQtODggMjEyek0xMDAwIDgwMHEwIC0xMjQgLTg4IC0yMTJ0LTIxMiAtODhxMCAxMjQgODggMjEydDIxMiA4OHpNMzAwIDUwMHExMjQgMCAyMTIgLTg4dDg4IC0yMTJxLTEyNCAwIC0yMTIgODh0LTg4IDIxMnogTTEwMDAgNTAwcTAgLTEyNCAtODggLTIxMnQtMjEyIC04OHEwIDEyNCA4OCAyMTJ0MjEyIDg4ek03MDAgMTk5di0xNDRxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjV0LTM1LjUgMTQuNXQtMTQuNSAzNS41djE0MnE0MCAtNCA0MyAtNHExNyAwIDU3IDZ6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTI0MDsiIGQ9Ik03NDUgODc4bDY5IDE5cTI1IDYgNDUgLTEybDI5OCAtMjk1cTExIC0xMSAxNSAtMjYuNXQtMiAtMzAuNXEtNSAtMTQgLTE4IC0yMy41dC0yOCAtOS41aC04cTEgMCAxIC0xM3EwIC0yOSAtMiAtNTZ0LTguNSAtNjJ0LTIwIC02M3QtMzMgLTUzdC01MSAtMzl0LTcyLjUgLTE0aC0xNDZxLTE4NCAwIC0xODQgMjg4cTAgMjQgMTAgNDdxLTIwIDQgLTYyIDR0LTYzIC00cTExIC0yNCAxMSAtNDdxMCAtMjg4IC0xODQgLTI4OGgtMTQyIHEtNDggMCAtODQuNSAyMXQtNTYgNTF0LTMyIDcxLjV0LTE2IDc1dC0zLjUgNjguNXEwIDEzIDIgMTNoLTdxLTE1IDAgLTI3LjUgOS41dC0xOC41IDIzLjVxLTYgMTUgLTIgMzAuNXQxNSAyNS41bDI5OCAyOTZxMjAgMTggNDYgMTFsNzYgLTE5cTIwIC01IDMwLjUgLTIyLjV0NS41IC0zNy41dC0yMi41IC0zMXQtMzcuNSAtNWwtNTEgMTJsLTE4MiAtMTkzaDg5MWwtMTgyIDE5M2wtNDQgLTEycS0yMCAtNSAtMzcuNSA2dC0yMi41IDMxdDYgMzcuNSB0MzEgMjIuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjQxOyIgZD0iTTEyMDAgOTAwaC01MHEwIDIxIC00IDM3dC05LjUgMjYuNXQtMTggMTcuNXQtMjIgMTF0LTI4LjUgNS41dC0zMSAydC0zNyAwLjVoLTIwMHYtODUwcTAgLTIyIDI1IC0zNC41dDUwIC0xMy41bDI1IC0ydi0xMDBoLTQwMHYxMDBxNCAwIDExIDAuNXQyNCAzdDMwIDd0MjQgMTV0MTEgMjQuNXY4NTBoLTIwMHEtMjUgMCAtMzcgLTAuNXQtMzEgLTJ0LTI4LjUgLTUuNXQtMjIgLTExdC0xOCAtMTcuNXQtOS41IC0yNi41dC00IC0zN2gtNTB2MzAwIGgxMDAwdi0zMDB6TTUwMCA0NTBoLTI1cTAgMTUgLTQgMjQuNXQtOSAxNC41dC0xNyA3LjV0LTIwIDN0LTI1IDAuNWgtMTAwdi00MjVxMCAtMTEgMTIuNSAtMTcuNXQyNS41IC03LjVoMTJ2LTUwaC0yMDB2NTBxNTAgMCA1MCAyNXY0MjVoLTEwMHEtMTcgMCAtMjUgLTAuNXQtMjAgLTN0LTE3IC03LjV0LTkgLTE0LjV0LTQgLTI0LjVoLTI1djE1MGg1MDB2LTE1MHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjQyOyIgZD0iTTEwMDAgMzAwdjUwcS0yNSAwIC01NSAzMnEtMTQgMTQgLTI1IDMxdC0xNiAyN2wtNCAxMWwtMjg5IDc0N2gtNjlsLTMwMCAtNzU0cS0xOCAtMzUgLTM5IC01NnEtOSAtOSAtMjQuNSAtMTguNXQtMjYuNSAtMTQuNWwtMTEgLTV2LTUwaDI3M3Y1MHEtNDkgMCAtNzguNSAyMS41dC0xMS41IDY3LjVsNjkgMTc2aDI5M2w2MSAtMTY2cTEzIC0zNCAtMy41IC02Ni41dC01NS41IC0zMi41di01MGgzMTJ6TTQxMiA2OTFsMTM0IDM0MmwxMjEgLTM0MiBoLTI1NXpNMTEwMCAxNTB2LTEwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtMTAwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2MTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNWgxMDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyNDM7IiBkPSJNNTAgMTIwMGgxMTAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xMTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xMTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXYxMTAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNjExIDExMThoLTcwcS0xMyAwIC0xOCAtMTJsLTI5OSAtNzUzcS0xNyAtMzIgLTM1IC01MXEtMTggLTE4IC01NiAtMzRxLTEyIC01IC0xMiAtMTh2LTUwcTAgLTggNS41IC0xNHQxNC41IC02IGgyNzNxOCAwIDE0IDZ0NiAxNHY1MHEwIDggLTYgMTR0LTE0IDZxLTU1IDAgLTcxIDIzcS0xMCAxNCAwIDM5bDYzIDE2M2gyNjZsNTcgLTE1M3ExMSAtMzEgLTYgLTU1cS0xMiAtMTcgLTM2IC0xN3EtOCAwIC0xNCAtNnQtNiAtMTR2LTUwcTAgLTggNiAtMTR0MTQgLTZoMzEzcTggMCAxNCA2dDYgMTR2NTBxMCA3IC01LjUgMTN0LTEzLjUgN3EtMTcgMCAtNDIgMjVxLTI1IDI3IC00MCA2M2gtMWwtMjg4IDc0OHEtNSAxMiAtMTkgMTJ6TTYzOSA2MTEgaC0xOTdsMTAzIDI2NHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjQ0OyIgZD0iTTEyMDAgMTEwMGgtMTIwMHYxMDBoMTIwMHYtMTAwek01MCAxMDAwaDQwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtOTAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC00MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djkwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTY1MCAxMDAwaDQwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNDAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC00MDAgcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY0MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek03MDAgOTAwdi0zMDBoMzAwdjMwMGgtMzAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyNDU7IiBkPSJNNTAgMTIwMGg0MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTkwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNDAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY5MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek02NTAgNzAwaDQwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNDAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC00MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djQwMCBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek03MDAgNjAwdi0zMDBoMzAwdjMwMGgtMzAwek0xMjAwIDBoLTEyMDB2MTAwaDEyMDB2LTEwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjQ2OyIgZD0iTTUwIDEwMDBoNDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0zNTBoMTAwdjE1MHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoNDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di0xNTBoMTAwdi0xMDBoLTEwMHYtMTUwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC00MDBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djE1MGgtMTAwdi0zNTBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTQwMCBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djgwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTcwMCA3MDB2LTMwMGgzMDB2MzAwaC0zMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTI0NzsiIGQ9Ik0xMDAgMGgtMTAwdjEyMDBoMTAwdi0xMjAwek0yNTAgMTEwMGg0MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTQwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtNDAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY0MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41ek0zMDAgMTAwMHYtMzAwaDMwMHYzMDBoLTMwMHpNMjUwIDUwMGg5MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTQwMCBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTkwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NDAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjQ4OyIgZD0iTTYwMCAxMTAwaDE1MHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNDAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xNTB2LTEwMGg0NTBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTQwMHEwIC0yMSAtMTQuNSAtMzUuNXQtMzUuNSAtMTQuNWgtOTAwcS0yMSAwIC0zNS41IDE0LjV0LTE0LjUgMzUuNXY0MDBxMCAyMSAxNC41IDM1LjV0MzUuNSAxNC41aDM1MHYxMDBoLTE1MHEtMjEgMCAtMzUuNSAxNC41IHQtMTQuNSAzNS41djQwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjVoMTUwdjEwMGgxMDB2LTEwMHpNNDAwIDEwMDB2LTMwMGgzMDB2MzAwaC0zMDB6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTI0OTsiIGQ9Ik0xMjAwIDBoLTEwMHYxMjAwaDEwMHYtMTIwMHpNNTUwIDExMDBoNDAwcTIxIDAgMzUuNSAtMTQuNXQxNC41IC0zNS41di00MDBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTQwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NDAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXpNNjAwIDEwMDB2LTMwMGgzMDB2MzAwaC0zMDB6TTUwIDUwMGg5MDBxMjEgMCAzNS41IC0xNC41dDE0LjUgLTM1LjV2LTQwMCBxMCAtMjEgLTE0LjUgLTM1LjV0LTM1LjUgLTE0LjVoLTkwMHEtMjEgMCAtMzUuNSAxNC41dC0xNC41IDM1LjV2NDAwcTAgMjEgMTQuNSAzNS41dDM1LjUgMTQuNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjUwOyIgZD0iTTg2NSA1NjVsLTQ5NCAtNDk0cS0yMyAtMjMgLTQxIC0yM3EtMTQgMCAtMjIgMTMuNXQtOCAzOC41djEwMDBxMCAyNSA4IDM4LjV0MjIgMTMuNXExOCAwIDQxIC0yM2w0OTQgLTQ5NHExNCAtMTQgMTQgLTM1dC0xNCAtMzV6IiAvPgo8Z2x5cGggdW5pY29kZT0iJiN4ZTI1MTsiIGQ9Ik0zMzUgNjM1bDQ5NCA0OTRxMjkgMjkgNTAgMjAuNXQyMSAtNDkuNXYtMTAwMHEwIC00MSAtMjEgLTQ5LjV0LTUwIDIwLjVsLTQ5NCA0OTRxLTE0IDE0IC0xNCAzNXQxNCAzNXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjUyOyIgZD0iTTEwMCA5MDBoMTAwMHE0MSAwIDQ5LjUgLTIxdC0yMC41IC01MGwtNDk0IC00OTRxLTE0IC0xNCAtMzUgLTE0dC0zNSAxNGwtNDk0IDQ5NHEtMjkgMjkgLTIwLjUgNTB0NDkuNSAyMXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjUzOyIgZD0iTTYzNSA4NjVsNDk0IC00OTRxMjkgLTI5IDIwLjUgLTUwdC00OS41IC0yMWgtMTAwMHEtNDEgMCAtNDkuNSAyMXQyMC41IDUwbDQ5NCA0OTRxMTQgMTQgMzUgMTR0MzUgLTE0eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyNTQ7IiBkPSJNNzAwIDc0MXYtMTgybC02OTIgLTMyM3YyMjFsNDEzIDE5M2wtNDEzIDE5M3YyMjF6TTEyMDAgMGgtODAwdjIwMGg4MDB2LTIwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjU1OyIgZD0iTTEyMDAgOTAwaC0yMDB2LTEwMGgyMDB2LTEwMGgtMzAwdjMwMGgyMDB2MTAwaC0yMDB2MTAwaDMwMHYtMzAwek0wIDcwMGg1MHEwIDIxIDQgMzd0OS41IDI2LjV0MTggMTcuNXQyMiAxMXQyOC41IDUuNXQzMSAydDM3IDAuNWgxMDB2LTU1MHEwIC0yMiAtMjUgLTM0LjV0LTUwIC0xMy41bC0yNSAtMnYtMTAwaDQwMHYxMDBxLTQgMCAtMTEgMC41dC0yNCAzdC0zMCA3dC0yNCAxNXQtMTEgMjQuNXY1NTBoMTAwcTI1IDAgMzcgLTAuNXQzMSAtMiB0MjguNSAtNS41dDIyIC0xMXQxOCAtMTcuNXQ5LjUgLTI2LjV0NCAtMzdoNTB2MzAwaC04MDB2LTMwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjU2OyIgZD0iTTgwMCA3MDBoLTUwcTAgMjEgLTQgMzd0LTkuNSAyNi41dC0xOCAxNy41dC0yMiAxMXQtMjguNSA1LjV0LTMxIDJ0LTM3IDAuNWgtMTAwdi01NTBxMCAtMjIgMjUgLTM0LjV0NTAgLTE0LjVsMjUgLTF2LTEwMGgtNDAwdjEwMHE0IDAgMTEgMC41dDI0IDN0MzAgN3QyNCAxNXQxMSAyNC41djU1MGgtMTAwcS0yNSAwIC0zNyAtMC41dC0zMSAtMnQtMjguNSAtNS41dC0yMiAtMTF0LTE4IC0xNy41dC05LjUgLTI2LjV0LTQgLTM3aC01MHYzMDAgaDgwMHYtMzAwek0xMTAwIDIwMGgtMjAwdi0xMDBoMjAwdi0xMDBoLTMwMHYzMDBoMjAwdjEwMGgtMjAwdjEwMGgzMDB2LTMwMHoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjU3OyIgZD0iTTcwMSAxMDk4aDE2MHExNiAwIDIxIC0xMXQtNyAtMjNsLTQ2NCAtNDY0bDQ2NCAtNDY0cTEyIC0xMiA3IC0yM3QtMjEgLTExaC0xNjBxLTEzIDAgLTIzIDlsLTQ3MSA0NzFxLTcgOCAtNyAxOHQ3IDE4bDQ3MSA0NzFxMTAgOSAyMyA5eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGUyNTg7IiBkPSJNMzM5IDEwOThoMTYwcTEzIDAgMjMgLTlsNDcxIC00NzFxNyAtOCA3IC0xOHQtNyAtMThsLTQ3MSAtNDcxcS0xMCAtOSAtMjMgLTloLTE2MHEtMTYgMCAtMjEgMTF0NyAyM2w0NjQgNDY0bC00NjQgNDY0cS0xMiAxMiAtNyAyM3QyMSAxMXoiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjU5OyIgZD0iTTEwODcgODgycTExIC01IDExIC0yMXYtMTYwcTAgLTEzIC05IC0yM2wtNDcxIC00NzFxLTggLTcgLTE4IC03dC0xOCA3bC00NzEgNDcxcS05IDEwIC05IDIzdjE2MHEwIDE2IDExIDIxdDIzIC03bDQ2NCAtNDY0bDQ2NCA0NjRxMTIgMTIgMjMgN3oiIC8%2BCjxnbHlwaCB1bmljb2RlPSImI3hlMjYwOyIgZD0iTTYxOCA5OTNsNDcxIC00NzFxOSAtMTAgOSAtMjN2LTE2MHEwIC0xNiAtMTEgLTIxdC0yMyA3bC00NjQgNDY0bC00NjQgLTQ2NHEtMTIgLTEyIC0yMyAtN3QtMTEgMjF2MTYwcTAgMTMgOSAyM2w0NzEgNDcxcTggNyAxOCA3dDE4IC03eiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeGY4ZmY7IiBkPSJNMTAwMCAxMjAwcTAgLTEyNCAtODggLTIxMnQtMjEyIC04OHEwIDEyNCA4OCAyMTJ0MjEyIDg4ek00NTAgMTAwMGgxMDBxMjEgMCA0MCAtMTR0MjYgLTMzbDc5IC0xOTRxNSAxIDE2IDNxMzQgNiA1NCA5LjV0NjAgN3Q2NS41IDF0NjEgLTEwdDU2LjUgLTIzdDQyLjUgLTQydDI5IC02NHQ1IC05MnQtMTkuNSAtMTIxLjVxLTEgLTcgLTMgLTE5LjV0LTExIC01MHQtMjAuNSAtNzN0LTMyLjUgLTgxLjV0LTQ2LjUgLTgzdC02NCAtNzAgdC04Mi41IC01MHEtMTMgLTUgLTQyIC01dC02NS41IDIuNXQtNDcuNSAyLjVxLTE0IDAgLTQ5LjUgLTMuNXQtNjMgLTMuNXQtNDMuNSA3cS01NyAyNSAtMTA0LjUgNzguNXQtNzUgMTExLjV0LTQ2LjUgMTEydC0yNiA5MGwtNyAzNXEtMTUgNjMgLTE4IDExNXQ0LjUgODguNXQyNiA2NHQzOS41IDQzLjV0NTIgMjUuNXQ1OC41IDEzdDYyLjUgMnQ1OS41IC00LjV0NTUuNSAtOGwtMTQ3IDE5MnEtMTIgMTggLTUuNSAzMHQyNy41IDEyeiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDFmNTExOyIgZD0iTTI1MCAxMjAwaDYwMHEyMSAwIDM1LjUgLTE0LjV0MTQuNSAtMzUuNXYtNDAwcTAgLTIxIC0xNC41IC0zNS41dC0zNS41IC0xNC41aC0xNTB2LTUwMGwtMjU1IC0xNzhxLTE5IC05IC0zMiAtMXQtMTMgMjl2NjUwaC0xNTBxLTIxIDAgLTM1LjUgMTQuNXQtMTQuNSAzNS41djQwMHEwIDIxIDE0LjUgMzUuNXQzNS41IDE0LjV6TTQwMCAxMTAwdi0xMDBoMzAwdjEwMGgtMzAweiIgLz4KPGdseXBoIHVuaWNvZGU9IiYjeDFmNmFhOyIgZD0iTTI1MCAxMjAwaDc1MHEzOSAwIDY5LjUgLTQwLjV0MzAuNSAtODQuNXYtOTMzbC03MDAgLTExN3Y5NTBsNjAwIDEyNWgtNzAwdi0xMDAwaC0xMDB2MTAyNXEwIDIzIDE1LjUgNDl0MzQuNSAyNnpNNTAwIDUyNXYtMTAwbDEwMCAyMHYxMDB6IiAvPgo8L2ZvbnQ%2BCjwvZGVmcz48L3N2Zz4g%29%20format%28%27svg%27%29%7D%2Eglyphicon%7Bposition%3Arelative%3Btop%3A1px%3Bdisplay%3Ainline%2Dblock%3Bfont%2Dfamily%3A%27Glyphicons%20Halflings%27%3Bfont%2Dstyle%3Anormal%3Bfont%2Dweight%3A400%3Bline%2Dheight%3A1%3B%2Dwebkit%2Dfont%2Dsmoothing%3Aantialiased%3B%2Dmoz%2Dosx%2Dfont%2Dsmoothing%3Agrayscale%7D%2Eglyphicon%2Dasterisk%3Abefore%7Bcontent%3A%22%5C2a%22%7D%2Eglyphicon%2Dplus%3Abefore%7Bcontent%3A%22%5C2b%22%7D%2Eglyphicon%2Deur%3Abefore%2C%2Eglyphicon%2Deuro%3Abefore%7Bcontent%3A%22%5C20ac%22%7D%2Eglyphicon%2Dminus%3Abefore%7Bcontent%3A%22%5C2212%22%7D%2Eglyphicon%2Dcloud%3Abefore%7Bcontent%3A%22%5C2601%22%7D%2Eglyphicon%2Denvelope%3Abefore%7Bcontent%3A%22%5C2709%22%7D%2Eglyphicon%2Dpencil%3Abefore%7Bcontent%3A%22%5C270f%22%7D%2Eglyphicon%2Dglass%3Abefore%7Bcontent%3A%22%5Ce001%22%7D%2Eglyphicon%2Dmusic%3Abefore%7Bcontent%3A%22%5Ce002%22%7D%2Eglyphicon%2Dsearch%3Abefore%7Bcontent%3A%22%5Ce003%22%7D%2Eglyphicon%2Dheart%3Abefore%7Bcontent%3A%22%5Ce005%22%7D%2Eglyphicon%2Dstar%3Abefore%7Bcontent%3A%22%5Ce006%22%7D%2Eglyphicon%2Dstar%2Dempty%3Abefore%7Bcontent%3A%22%5Ce007%22%7D%2Eglyphicon%2Duser%3Abefore%7Bcontent%3A%22%5Ce008%22%7D%2Eglyphicon%2Dfilm%3Abefore%7Bcontent%3A%22%5Ce009%22%7D%2Eglyphicon%2Dth%2Dlarge%3Abefore%7Bcontent%3A%22%5Ce010%22%7D%2Eglyphicon%2Dth%3Abefore%7Bcontent%3A%22%5Ce011%22%7D%2Eglyphicon%2Dth%2Dlist%3Abefore%7Bcontent%3A%22%5Ce012%22%7D%2Eglyphicon%2Dok%3Abefore%7Bcontent%3A%22%5Ce013%22%7D%2Eglyphicon%2Dremove%3Abefore%7Bcontent%3A%22%5Ce014%22%7D%2Eglyphicon%2Dzoom%2Din%3Abefore%7Bcontent%3A%22%5Ce015%22%7D%2Eglyphicon%2Dzoom%2Dout%3Abefore%7Bcontent%3A%22%5Ce016%22%7D%2Eglyphicon%2Doff%3Abefore%7Bcontent%3A%22%5Ce017%22%7D%2Eglyphicon%2Dsignal%3Abefore%7Bcontent%3A%22%5Ce018%22%7D%2Eglyphicon%2Dcog%3Abefore%7Bcontent%3A%22%5Ce019%22%7D%2Eglyphicon%2Dtrash%3Abefore%7Bcontent%3A%22%5Ce020%22%7D%2Eglyphicon%2Dhome%3Abefore%7Bcontent%3A%22%5Ce021%22%7D%2Eglyphicon%2Dfile%3Abefore%7Bcontent%3A%22%5Ce022%22%7D%2Eglyphicon%2Dtime%3Abefore%7Bcontent%3A%22%5Ce023%22%7D%2Eglyphicon%2Droad%3Abefore%7Bcontent%3A%22%5Ce024%22%7D%2Eglyphicon%2Ddownload%2Dalt%3Abefore%7Bcontent%3A%22%5Ce025%22%7D%2Eglyphicon%2Ddownload%3Abefore%7Bcontent%3A%22%5Ce026%22%7D%2Eglyphicon%2Dupload%3Abefore%7Bcontent%3A%22%5Ce027%22%7D%2Eglyphicon%2Dinbox%3Abefore%7Bcontent%3A%22%5Ce028%22%7D%2Eglyphicon%2Dplay%2Dcircle%3Abefore%7Bcontent%3A%22%5Ce029%22%7D%2Eglyphicon%2Drepeat%3Abefore%7Bcontent%3A%22%5Ce030%22%7D%2Eglyphicon%2Drefresh%3Abefore%7Bcontent%3A%22%5Ce031%22%7D%2Eglyphicon%2Dlist%2Dalt%3Abefore%7Bcontent%3A%22%5Ce032%22%7D%2Eglyphicon%2Dlock%3Abefore%7Bcontent%3A%22%5Ce033%22%7D%2Eglyphicon%2Dflag%3Abefore%7Bcontent%3A%22%5Ce034%22%7D%2Eglyphicon%2Dheadphones%3Abefore%7Bcontent%3A%22%5Ce035%22%7D%2Eglyphicon%2Dvolume%2Doff%3Abefore%7Bcontent%3A%22%5Ce036%22%7D%2Eglyphicon%2Dvolume%2Ddown%3Abefore%7Bcontent%3A%22%5Ce037%22%7D%2Eglyphicon%2Dvolume%2Dup%3Abefore%7Bcontent%3A%22%5Ce038%22%7D%2Eglyphicon%2Dqrcode%3Abefore%7Bcontent%3A%22%5Ce039%22%7D%2Eglyphicon%2Dbarcode%3Abefore%7Bcontent%3A%22%5Ce040%22%7D%2Eglyphicon%2Dtag%3Abefore%7Bcontent%3A%22%5Ce041%22%7D%2Eglyphicon%2Dtags%3Abefore%7Bcontent%3A%22%5Ce042%22%7D%2Eglyphicon%2Dbook%3Abefore%7Bcontent%3A%22%5Ce043%22%7D%2Eglyphicon%2Dbookmark%3Abefore%7Bcontent%3A%22%5Ce044%22%7D%2Eglyphicon%2Dprint%3Abefore%7Bcontent%3A%22%5Ce045%22%7D%2Eglyphicon%2Dcamera%3Abefore%7Bcontent%3A%22%5Ce046%22%7D%2Eglyphicon%2Dfont%3Abefore%7Bcontent%3A%22%5Ce047%22%7D%2Eglyphicon%2Dbold%3Abefore%7Bcontent%3A%22%5Ce048%22%7D%2Eglyphicon%2Ditalic%3Abefore%7Bcontent%3A%22%5Ce049%22%7D%2Eglyphicon%2Dtext%2Dheight%3Abefore%7Bcontent%3A%22%5Ce050%22%7D%2Eglyphicon%2Dtext%2Dwidth%3Abefore%7Bcontent%3A%22%5Ce051%22%7D%2Eglyphicon%2Dalign%2Dleft%3Abefore%7Bcontent%3A%22%5Ce052%22%7D%2Eglyphicon%2Dalign%2Dcenter%3Abefore%7Bcontent%3A%22%5Ce053%22%7D%2Eglyphicon%2Dalign%2Dright%3Abefore%7Bcontent%3A%22%5Ce054%22%7D%2Eglyphicon%2Dalign%2Djustify%3Abefore%7Bcontent%3A%22%5Ce055%22%7D%2Eglyphicon%2Dlist%3Abefore%7Bcontent%3A%22%5Ce056%22%7D%2Eglyphicon%2Dindent%2Dleft%3Abefore%7Bcontent%3A%22%5Ce057%22%7D%2Eglyphicon%2Dindent%2Dright%3Abefore%7Bcontent%3A%22%5Ce058%22%7D%2Eglyphicon%2Dfacetime%2Dvideo%3Abefore%7Bcontent%3A%22%5Ce059%22%7D%2Eglyphicon%2Dpicture%3Abefore%7Bcontent%3A%22%5Ce060%22%7D%2Eglyphicon%2Dmap%2Dmarker%3Abefore%7Bcontent%3A%22%5Ce062%22%7D%2Eglyphicon%2Dadjust%3Abefore%7Bcontent%3A%22%5Ce063%22%7D%2Eglyphicon%2Dtint%3Abefore%7Bcontent%3A%22%5Ce064%22%7D%2Eglyphicon%2Dedit%3Abefore%7Bcontent%3A%22%5Ce065%22%7D%2Eglyphicon%2Dshare%3Abefore%7Bcontent%3A%22%5Ce066%22%7D%2Eglyphicon%2Dcheck%3Abefore%7Bcontent%3A%22%5Ce067%22%7D%2Eglyphicon%2Dmove%3Abefore%7Bcontent%3A%22%5Ce068%22%7D%2Eglyphicon%2Dstep%2Dbackward%3Abefore%7Bcontent%3A%22%5Ce069%22%7D%2Eglyphicon%2Dfast%2Dbackward%3Abefore%7Bcontent%3A%22%5Ce070%22%7D%2Eglyphicon%2Dbackward%3Abefore%7Bcontent%3A%22%5Ce071%22%7D%2Eglyphicon%2Dplay%3Abefore%7Bcontent%3A%22%5Ce072%22%7D%2Eglyphicon%2Dpause%3Abefore%7Bcontent%3A%22%5Ce073%22%7D%2Eglyphicon%2Dstop%3Abefore%7Bcontent%3A%22%5Ce074%22%7D%2Eglyphicon%2Dforward%3Abefore%7Bcontent%3A%22%5Ce075%22%7D%2Eglyphicon%2Dfast%2Dforward%3Abefore%7Bcontent%3A%22%5Ce076%22%7D%2Eglyphicon%2Dstep%2Dforward%3Abefore%7Bcontent%3A%22%5Ce077%22%7D%2Eglyphicon%2Deject%3Abefore%7Bcontent%3A%22%5Ce078%22%7D%2Eglyphicon%2Dchevron%2Dleft%3Abefore%7Bcontent%3A%22%5Ce079%22%7D%2Eglyphicon%2Dchevron%2Dright%3Abefore%7Bcontent%3A%22%5Ce080%22%7D%2Eglyphicon%2Dplus%2Dsign%3Abefore%7Bcontent%3A%22%5Ce081%22%7D%2Eglyphicon%2Dminus%2Dsign%3Abefore%7Bcontent%3A%22%5Ce082%22%7D%2Eglyphicon%2Dremove%2Dsign%3Abefore%7Bcontent%3A%22%5Ce083%22%7D%2Eglyphicon%2Dok%2Dsign%3Abefore%7Bcontent%3A%22%5Ce084%22%7D%2Eglyphicon%2Dquestion%2Dsign%3Abefore%7Bcontent%3A%22%5Ce085%22%7D%2Eglyphicon%2Dinfo%2Dsign%3Abefore%7Bcontent%3A%22%5Ce086%22%7D%2Eglyphicon%2Dscreenshot%3Abefore%7Bcontent%3A%22%5Ce087%22%7D%2Eglyphicon%2Dremove%2Dcircle%3Abefore%7Bcontent%3A%22%5Ce088%22%7D%2Eglyphicon%2Dok%2Dcircle%3Abefore%7Bcontent%3A%22%5Ce089%22%7D%2Eglyphicon%2Dban%2Dcircle%3Abefore%7Bcontent%3A%22%5Ce090%22%7D%2Eglyphicon%2Darrow%2Dleft%3Abefore%7Bcontent%3A%22%5Ce091%22%7D%2Eglyphicon%2Darrow%2Dright%3Abefore%7Bcontent%3A%22%5Ce092%22%7D%2Eglyphicon%2Darrow%2Dup%3Abefore%7Bcontent%3A%22%5Ce093%22%7D%2Eglyphicon%2Darrow%2Ddown%3Abefore%7Bcontent%3A%22%5Ce094%22%7D%2Eglyphicon%2Dshare%2Dalt%3Abefore%7Bcontent%3A%22%5Ce095%22%7D%2Eglyphicon%2Dresize%2Dfull%3Abefore%7Bcontent%3A%22%5Ce096%22%7D%2Eglyphicon%2Dresize%2Dsmall%3Abefore%7Bcontent%3A%22%5Ce097%22%7D%2Eglyphicon%2Dexclamation%2Dsign%3Abefore%7Bcontent%3A%22%5Ce101%22%7D%2Eglyphicon%2Dgift%3Abefore%7Bcontent%3A%22%5Ce102%22%7D%2Eglyphicon%2Dleaf%3Abefore%7Bcontent%3A%22%5Ce103%22%7D%2Eglyphicon%2Dfire%3Abefore%7Bcontent%3A%22%5Ce104%22%7D%2Eglyphicon%2Deye%2Dopen%3Abefore%7Bcontent%3A%22%5Ce105%22%7D%2Eglyphicon%2Deye%2Dclose%3Abefore%7Bcontent%3A%22%5Ce106%22%7D%2Eglyphicon%2Dwarning%2Dsign%3Abefore%7Bcontent%3A%22%5Ce107%22%7D%2Eglyphicon%2Dplane%3Abefore%7Bcontent%3A%22%5Ce108%22%7D%2Eglyphicon%2Dcalendar%3Abefore%7Bcontent%3A%22%5Ce109%22%7D%2Eglyphicon%2Drandom%3Abefore%7Bcontent%3A%22%5Ce110%22%7D%2Eglyphicon%2Dcomment%3Abefore%7Bcontent%3A%22%5Ce111%22%7D%2Eglyphicon%2Dmagnet%3Abefore%7Bcontent%3A%22%5Ce112%22%7D%2Eglyphicon%2Dchevron%2Dup%3Abefore%7Bcontent%3A%22%5Ce113%22%7D%2Eglyphicon%2Dchevron%2Ddown%3Abefore%7Bcontent%3A%22%5Ce114%22%7D%2Eglyphicon%2Dretweet%3Abefore%7Bcontent%3A%22%5Ce115%22%7D%2Eglyphicon%2Dshopping%2Dcart%3Abefore%7Bcontent%3A%22%5Ce116%22%7D%2Eglyphicon%2Dfolder%2Dclose%3Abefore%7Bcontent%3A%22%5Ce117%22%7D%2Eglyphicon%2Dfolder%2Dopen%3Abefore%7Bcontent%3A%22%5Ce118%22%7D%2Eglyphicon%2Dresize%2Dvertical%3Abefore%7Bcontent%3A%22%5Ce119%22%7D%2Eglyphicon%2Dresize%2Dhorizontal%3Abefore%7Bcontent%3A%22%5Ce120%22%7D%2Eglyphicon%2Dhdd%3Abefore%7Bcontent%3A%22%5Ce121%22%7D%2Eglyphicon%2Dbullhorn%3Abefore%7Bcontent%3A%22%5Ce122%22%7D%2Eglyphicon%2Dbell%3Abefore%7Bcontent%3A%22%5Ce123%22%7D%2Eglyphicon%2Dcertificate%3Abefore%7Bcontent%3A%22%5Ce124%22%7D%2Eglyphicon%2Dthumbs%2Dup%3Abefore%7Bcontent%3A%22%5Ce125%22%7D%2Eglyphicon%2Dthumbs%2Ddown%3Abefore%7Bcontent%3A%22%5Ce126%22%7D%2Eglyphicon%2Dhand%2Dright%3Abefore%7Bcontent%3A%22%5Ce127%22%7D%2Eglyphicon%2Dhand%2Dleft%3Abefore%7Bcontent%3A%22%5Ce128%22%7D%2Eglyphicon%2Dhand%2Dup%3Abefore%7Bcontent%3A%22%5Ce129%22%7D%2Eglyphicon%2Dhand%2Ddown%3Abefore%7Bcontent%3A%22%5Ce130%22%7D%2Eglyphicon%2Dcircle%2Darrow%2Dright%3Abefore%7Bcontent%3A%22%5Ce131%22%7D%2Eglyphicon%2Dcircle%2Darrow%2Dleft%3Abefore%7Bcontent%3A%22%5Ce132%22%7D%2Eglyphicon%2Dcircle%2Darrow%2Dup%3Abefore%7Bcontent%3A%22%5Ce133%22%7D%2Eglyphicon%2Dcircle%2Darrow%2Ddown%3Abefore%7Bcontent%3A%22%5Ce134%22%7D%2Eglyphicon%2Dglobe%3Abefore%7Bcontent%3A%22%5Ce135%22%7D%2Eglyphicon%2Dwrench%3Abefore%7Bcontent%3A%22%5Ce136%22%7D%2Eglyphicon%2Dtasks%3Abefore%7Bcontent%3A%22%5Ce137%22%7D%2Eglyphicon%2Dfilter%3Abefore%7Bcontent%3A%22%5Ce138%22%7D%2Eglyphicon%2Dbriefcase%3Abefore%7Bcontent%3A%22%5Ce139%22%7D%2Eglyphicon%2Dfullscreen%3Abefore%7Bcontent%3A%22%5Ce140%22%7D%2Eglyphicon%2Ddashboard%3Abefore%7Bcontent%3A%22%5Ce141%22%7D%2Eglyphicon%2Dpaperclip%3Abefore%7Bcontent%3A%22%5Ce142%22%7D%2Eglyphicon%2Dheart%2Dempty%3Abefore%7Bcontent%3A%22%5Ce143%22%7D%2Eglyphicon%2Dlink%3Abefore%7Bcontent%3A%22%5Ce144%22%7D%2Eglyphicon%2Dphone%3Abefore%7Bcontent%3A%22%5Ce145%22%7D%2Eglyphicon%2Dpushpin%3Abefore%7Bcontent%3A%22%5Ce146%22%7D%2Eglyphicon%2Dusd%3Abefore%7Bcontent%3A%22%5Ce148%22%7D%2Eglyphicon%2Dgbp%3Abefore%7Bcontent%3A%22%5Ce149%22%7D%2Eglyphicon%2Dsort%3Abefore%7Bcontent%3A%22%5Ce150%22%7D%2Eglyphicon%2Dsort%2Dby%2Dalphabet%3Abefore%7Bcontent%3A%22%5Ce151%22%7D%2Eglyphicon%2Dsort%2Dby%2Dalphabet%2Dalt%3Abefore%7Bcontent%3A%22%5Ce152%22%7D%2Eglyphicon%2Dsort%2Dby%2Dorder%3Abefore%7Bcontent%3A%22%5Ce153%22%7D%2Eglyphicon%2Dsort%2Dby%2Dorder%2Dalt%3Abefore%7Bcontent%3A%22%5Ce154%22%7D%2Eglyphicon%2Dsort%2Dby%2Dattributes%3Abefore%7Bcontent%3A%22%5Ce155%22%7D%2Eglyphicon%2Dsort%2Dby%2Dattributes%2Dalt%3Abefore%7Bcontent%3A%22%5Ce156%22%7D%2Eglyphicon%2Dunchecked%3Abefore%7Bcontent%3A%22%5Ce157%22%7D%2Eglyphicon%2Dexpand%3Abefore%7Bcontent%3A%22%5Ce158%22%7D%2Eglyphicon%2Dcollapse%2Ddown%3Abefore%7Bcontent%3A%22%5Ce159%22%7D%2Eglyphicon%2Dcollapse%2Dup%3Abefore%7Bcontent%3A%22%5Ce160%22%7D%2Eglyphicon%2Dlog%2Din%3Abefore%7Bcontent%3A%22%5Ce161%22%7D%2Eglyphicon%2Dflash%3Abefore%7Bcontent%3A%22%5Ce162%22%7D%2Eglyphicon%2Dlog%2Dout%3Abefore%7Bcontent%3A%22%5Ce163%22%7D%2Eglyphicon%2Dnew%2Dwindow%3Abefore%7Bcontent%3A%22%5Ce164%22%7D%2Eglyphicon%2Drecord%3Abefore%7Bcontent%3A%22%5Ce165%22%7D%2Eglyphicon%2Dsave%3Abefore%7Bcontent%3A%22%5Ce166%22%7D%2Eglyphicon%2Dopen%3Abefore%7Bcontent%3A%22%5Ce167%22%7D%2Eglyphicon%2Dsaved%3Abefore%7Bcontent%3A%22%5Ce168%22%7D%2Eglyphicon%2Dimport%3Abefore%7Bcontent%3A%22%5Ce169%22%7D%2Eglyphicon%2Dexport%3Abefore%7Bcontent%3A%22%5Ce170%22%7D%2Eglyphicon%2Dsend%3Abefore%7Bcontent%3A%22%5Ce171%22%7D%2Eglyphicon%2Dfloppy%2Ddisk%3Abefore%7Bcontent%3A%22%5Ce172%22%7D%2Eglyphicon%2Dfloppy%2Dsaved%3Abefore%7Bcontent%3A%22%5Ce173%22%7D%2Eglyphicon%2Dfloppy%2Dremove%3Abefore%7Bcontent%3A%22%5Ce174%22%7D%2Eglyphicon%2Dfloppy%2Dsave%3Abefore%7Bcontent%3A%22%5Ce175%22%7D%2Eglyphicon%2Dfloppy%2Dopen%3Abefore%7Bcontent%3A%22%5Ce176%22%7D%2Eglyphicon%2Dcredit%2Dcard%3Abefore%7Bcontent%3A%22%5Ce177%22%7D%2Eglyphicon%2Dtransfer%3Abefore%7Bcontent%3A%22%5Ce178%22%7D%2Eglyphicon%2Dcutlery%3Abefore%7Bcontent%3A%22%5Ce179%22%7D%2Eglyphicon%2Dheader%3Abefore%7Bcontent%3A%22%5Ce180%22%7D%2Eglyphicon%2Dcompressed%3Abefore%7Bcontent%3A%22%5Ce181%22%7D%2Eglyphicon%2Dearphone%3Abefore%7Bcontent%3A%22%5Ce182%22%7D%2Eglyphicon%2Dphone%2Dalt%3Abefore%7Bcontent%3A%22%5Ce183%22%7D%2Eglyphicon%2Dtower%3Abefore%7Bcontent%3A%22%5Ce184%22%7D%2Eglyphicon%2Dstats%3Abefore%7Bcontent%3A%22%5Ce185%22%7D%2Eglyphicon%2Dsd%2Dvideo%3Abefore%7Bcontent%3A%22%5Ce186%22%7D%2Eglyphicon%2Dhd%2Dvideo%3Abefore%7Bcontent%3A%22%5Ce187%22%7D%2Eglyphicon%2Dsubtitles%3Abefore%7Bcontent%3A%22%5Ce188%22%7D%2Eglyphicon%2Dsound%2Dstereo%3Abefore%7Bcontent%3A%22%5Ce189%22%7D%2Eglyphicon%2Dsound%2Ddolby%3Abefore%7Bcontent%3A%22%5Ce190%22%7D%2Eglyphicon%2Dsound%2D5%2D1%3Abefore%7Bcontent%3A%22%5Ce191%22%7D%2Eglyphicon%2Dsound%2D6%2D1%3Abefore%7Bcontent%3A%22%5Ce192%22%7D%2Eglyphicon%2Dsound%2D7%2D1%3Abefore%7Bcontent%3A%22%5Ce193%22%7D%2Eglyphicon%2Dcopyright%2Dmark%3Abefore%7Bcontent%3A%22%5Ce194%22%7D%2Eglyphicon%2Dregistration%2Dmark%3Abefore%7Bcontent%3A%22%5Ce195%22%7D%2Eglyphicon%2Dcloud%2Ddownload%3Abefore%7Bcontent%3A%22%5Ce197%22%7D%2Eglyphicon%2Dcloud%2Dupload%3Abefore%7Bcontent%3A%22%5Ce198%22%7D%2Eglyphicon%2Dtree%2Dconifer%3Abefore%7Bcontent%3A%22%5Ce199%22%7D%2Eglyphicon%2Dtree%2Ddeciduous%3Abefore%7Bcontent%3A%22%5Ce200%22%7D%2Eglyphicon%2Dcd%3Abefore%7Bcontent%3A%22%5Ce201%22%7D%2Eglyphicon%2Dsave%2Dfile%3Abefore%7Bcontent%3A%22%5Ce202%22%7D%2Eglyphicon%2Dopen%2Dfile%3Abefore%7Bcontent%3A%22%5Ce203%22%7D%2Eglyphicon%2Dlevel%2Dup%3Abefore%7Bcontent%3A%22%5Ce204%22%7D%2Eglyphicon%2Dcopy%3Abefore%7Bcontent%3A%22%5Ce205%22%7D%2Eglyphicon%2Dpaste%3Abefore%7Bcontent%3A%22%5Ce206%22%7D%2Eglyphicon%2Dalert%3Abefore%7Bcontent%3A%22%5Ce209%22%7D%2Eglyphicon%2Dequalizer%3Abefore%7Bcontent%3A%22%5Ce210%22%7D%2Eglyphicon%2Dking%3Abefore%7Bcontent%3A%22%5Ce211%22%7D%2Eglyphicon%2Dqueen%3Abefore%7Bcontent%3A%22%5Ce212%22%7D%2Eglyphicon%2Dpawn%3Abefore%7Bcontent%3A%22%5Ce213%22%7D%2Eglyphicon%2Dbishop%3Abefore%7Bcontent%3A%22%5Ce214%22%7D%2Eglyphicon%2Dknight%3Abefore%7Bcontent%3A%22%5Ce215%22%7D%2Eglyphicon%2Dbaby%2Dformula%3Abefore%7Bcontent%3A%22%5Ce216%22%7D%2Eglyphicon%2Dtent%3Abefore%7Bcontent%3A%22%5C26fa%22%7D%2Eglyphicon%2Dblackboard%3Abefore%7Bcontent%3A%22%5Ce218%22%7D%2Eglyphicon%2Dbed%3Abefore%7Bcontent%3A%22%5Ce219%22%7D%2Eglyphicon%2Dapple%3Abefore%7Bcontent%3A%22%5Cf8ff%22%7D%2Eglyphicon%2Derase%3Abefore%7Bcontent%3A%22%5Ce221%22%7D%2Eglyphicon%2Dhourglass%3Abefore%7Bcontent%3A%22%5C231b%22%7D%2Eglyphicon%2Dlamp%3Abefore%7Bcontent%3A%22%5Ce223%22%7D%2Eglyphicon%2Dduplicate%3Abefore%7Bcontent%3A%22%5Ce224%22%7D%2Eglyphicon%2Dpiggy%2Dbank%3Abefore%7Bcontent%3A%22%5Ce225%22%7D%2Eglyphicon%2Dscissors%3Abefore%7Bcontent%3A%22%5Ce226%22%7D%2Eglyphicon%2Dbitcoin%3Abefore%7Bcontent%3A%22%5Ce227%22%7D%2Eglyphicon%2Dbtc%3Abefore%7Bcontent%3A%22%5Ce227%22%7D%2Eglyphicon%2Dxbt%3Abefore%7Bcontent%3A%22%5Ce227%22%7D%2Eglyphicon%2Dyen%3Abefore%7Bcontent%3A%22%5C00a5%22%7D%2Eglyphicon%2Djpy%3Abefore%7Bcontent%3A%22%5C00a5%22%7D%2Eglyphicon%2Druble%3Abefore%7Bcontent%3A%22%5C20bd%22%7D%2Eglyphicon%2Drub%3Abefore%7Bcontent%3A%22%5C20bd%22%7D%2Eglyphicon%2Dscale%3Abefore%7Bcontent%3A%22%5Ce230%22%7D%2Eglyphicon%2Dice%2Dlolly%3Abefore%7Bcontent%3A%22%5Ce231%22%7D%2Eglyphicon%2Dice%2Dlolly%2Dtasted%3Abefore%7Bcontent%3A%22%5Ce232%22%7D%2Eglyphicon%2Deducation%3Abefore%7Bcontent%3A%22%5Ce233%22%7D%2Eglyphicon%2Doption%2Dhorizontal%3Abefore%7Bcontent%3A%22%5Ce234%22%7D%2Eglyphicon%2Doption%2Dvertical%3Abefore%7Bcontent%3A%22%5Ce235%22%7D%2Eglyphicon%2Dmenu%2Dhamburger%3Abefore%7Bcontent%3A%22%5Ce236%22%7D%2Eglyphicon%2Dmodal%2Dwindow%3Abefore%7Bcontent%3A%22%5Ce237%22%7D%2Eglyphicon%2Doil%3Abefore%7Bcontent%3A%22%5Ce238%22%7D%2Eglyphicon%2Dgrain%3Abefore%7Bcontent%3A%22%5Ce239%22%7D%2Eglyphicon%2Dsunglasses%3Abefore%7Bcontent%3A%22%5Ce240%22%7D%2Eglyphicon%2Dtext%2Dsize%3Abefore%7Bcontent%3A%22%5Ce241%22%7D%2Eglyphicon%2Dtext%2Dcolor%3Abefore%7Bcontent%3A%22%5Ce242%22%7D%2Eglyphicon%2Dtext%2Dbackground%3Abefore%7Bcontent%3A%22%5Ce243%22%7D%2Eglyphicon%2Dobject%2Dalign%2Dtop%3Abefore%7Bcontent%3A%22%5Ce244%22%7D%2Eglyphicon%2Dobject%2Dalign%2Dbottom%3Abefore%7Bcontent%3A%22%5Ce245%22%7D%2Eglyphicon%2Dobject%2Dalign%2Dhorizontal%3Abefore%7Bcontent%3A%22%5Ce246%22%7D%2Eglyphicon%2Dobject%2Dalign%2Dleft%3Abefore%7Bcontent%3A%22%5Ce247%22%7D%2Eglyphicon%2Dobject%2Dalign%2Dvertical%3Abefore%7Bcontent%3A%22%5Ce248%22%7D%2Eglyphicon%2Dobject%2Dalign%2Dright%3Abefore%7Bcontent%3A%22%5Ce249%22%7D%2Eglyphicon%2Dtriangle%2Dright%3Abefore%7Bcontent%3A%22%5Ce250%22%7D%2Eglyphicon%2Dtriangle%2Dleft%3Abefore%7Bcontent%3A%22%5Ce251%22%7D%2Eglyphicon%2Dtriangle%2Dbottom%3Abefore%7Bcontent%3A%22%5Ce252%22%7D%2Eglyphicon%2Dtriangle%2Dtop%3Abefore%7Bcontent%3A%22%5Ce253%22%7D%2Eglyphicon%2Dconsole%3Abefore%7Bcontent%3A%22%5Ce254%22%7D%2Eglyphicon%2Dsuperscript%3Abefore%7Bcontent%3A%22%5Ce255%22%7D%2Eglyphicon%2Dsubscript%3Abefore%7Bcontent%3A%22%5Ce256%22%7D%2Eglyphicon%2Dmenu%2Dleft%3Abefore%7Bcontent%3A%22%5Ce257%22%7D%2Eglyphicon%2Dmenu%2Dright%3Abefore%7Bcontent%3A%22%5Ce258%22%7D%2Eglyphicon%2Dmenu%2Ddown%3Abefore%7Bcontent%3A%22%5Ce259%22%7D%2Eglyphicon%2Dmenu%2Dup%3Abefore%7Bcontent%3A%22%5Ce260%22%7D%2A%7B%2Dwebkit%2Dbox%2Dsizing%3Aborder%2Dbox%3B%2Dmoz%2Dbox%2Dsizing%3Aborder%2Dbox%3Bbox%2Dsizing%3Aborder%2Dbox%7D%3Aafter%2C%3Abefore%7B%2Dwebkit%2Dbox%2Dsizing%3Aborder%2Dbox%3B%2Dmoz%2Dbox%2Dsizing%3Aborder%2Dbox%3Bbox%2Dsizing%3Aborder%2Dbox%7Dhtml%7Bfont%2Dsize%3A10px%3B%2Dwebkit%2Dtap%2Dhighlight%2Dcolor%3Argba%280%2C0%2C0%2C0%29%7Dbody%7Bfont%2Dfamily%3A%22Helvetica%20Neue%22%2CHelvetica%2CArial%2Csans%2Dserif%3Bfont%2Dsize%3A14px%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23333%3Bbackground%2Dcolor%3A%23fff%7Dbutton%2Cinput%2Cselect%2Ctextarea%7Bfont%2Dfamily%3Ainherit%3Bfont%2Dsize%3Ainherit%3Bline%2Dheight%3Ainherit%7Da%7Bcolor%3A%23337ab7%3Btext%2Ddecoration%3Anone%7Da%3Afocus%2Ca%3Ahover%7Bcolor%3A%2323527c%3Btext%2Ddecoration%3Aunderline%7Da%3Afocus%7Boutline%3Athin%20dotted%3Boutline%3A5px%20auto%20%2Dwebkit%2Dfocus%2Dring%2Dcolor%3Boutline%2Doffset%3A%2D2px%7Dfigure%7Bmargin%3A0%7Dimg%7Bvertical%2Dalign%3Amiddle%7D%2Ecarousel%2Dinner%3E%2Eitem%3Ea%3Eimg%2C%2Ecarousel%2Dinner%3E%2Eitem%3Eimg%2C%2Eimg%2Dresponsive%2C%2Ethumbnail%20a%3Eimg%2C%2Ethumbnail%3Eimg%7Bdisplay%3Ablock%3Bmax%2Dwidth%3A100%25%3Bheight%3Aauto%7D%2Eimg%2Drounded%7Bborder%2Dradius%3A6px%7D%2Eimg%2Dthumbnail%7Bdisplay%3Ainline%2Dblock%3Bmax%2Dwidth%3A100%25%3Bheight%3Aauto%3Bpadding%3A4px%3Bline%2Dheight%3A1%2E42857143%3Bbackground%2Dcolor%3A%23fff%3Bborder%3A1px%20solid%20%23ddd%3Bborder%2Dradius%3A4px%3B%2Dwebkit%2Dtransition%3Aall%20%2E2s%20ease%2Din%2Dout%3B%2Do%2Dtransition%3Aall%20%2E2s%20ease%2Din%2Dout%3Btransition%3Aall%20%2E2s%20ease%2Din%2Dout%7D%2Eimg%2Dcircle%7Bborder%2Dradius%3A50%25%7Dhr%7Bmargin%2Dtop%3A20px%3Bmargin%2Dbottom%3A20px%3Bborder%3A0%3Bborder%2Dtop%3A1px%20solid%20%23eee%7D%2Esr%2Donly%7Bposition%3Aabsolute%3Bwidth%3A1px%3Bheight%3A1px%3Bpadding%3A0%3Bmargin%3A%2D1px%3Boverflow%3Ahidden%3Bclip%3Arect%280%2C0%2C0%2C0%29%3Bborder%3A0%7D%2Esr%2Donly%2Dfocusable%3Aactive%2C%2Esr%2Donly%2Dfocusable%3Afocus%7Bposition%3Astatic%3Bwidth%3Aauto%3Bheight%3Aauto%3Bmargin%3A0%3Boverflow%3Avisible%3Bclip%3Aauto%7D%5Brole%3Dbutton%5D%7Bcursor%3Apointer%7D%2Eh1%2C%2Eh2%2C%2Eh3%2C%2Eh4%2C%2Eh5%2C%2Eh6%2Ch1%2Ch2%2Ch3%2Ch4%2Ch5%2Ch6%7Bfont%2Dfamily%3Ainherit%3Bfont%2Dweight%3A500%3Bline%2Dheight%3A1%2E1%3Bcolor%3Ainherit%7D%2Eh1%20%2Esmall%2C%2Eh1%20small%2C%2Eh2%20%2Esmall%2C%2Eh2%20small%2C%2Eh3%20%2Esmall%2C%2Eh3%20small%2C%2Eh4%20%2Esmall%2C%2Eh4%20small%2C%2Eh5%20%2Esmall%2C%2Eh5%20small%2C%2Eh6%20%2Esmall%2C%2Eh6%20small%2Ch1%20%2Esmall%2Ch1%20small%2Ch2%20%2Esmall%2Ch2%20small%2Ch3%20%2Esmall%2Ch3%20small%2Ch4%20%2Esmall%2Ch4%20small%2Ch5%20%2Esmall%2Ch5%20small%2Ch6%20%2Esmall%2Ch6%20small%7Bfont%2Dweight%3A400%3Bline%2Dheight%3A1%3Bcolor%3A%23777%7D%2Eh1%2C%2Eh2%2C%2Eh3%2Ch1%2Ch2%2Ch3%7Bmargin%2Dtop%3A20px%3Bmargin%2Dbottom%3A10px%7D%2Eh1%20%2Esmall%2C%2Eh1%20small%2C%2Eh2%20%2Esmall%2C%2Eh2%20small%2C%2Eh3%20%2Esmall%2C%2Eh3%20small%2Ch1%20%2Esmall%2Ch1%20small%2Ch2%20%2Esmall%2Ch2%20small%2Ch3%20%2Esmall%2Ch3%20small%7Bfont%2Dsize%3A65%25%7D%2Eh4%2C%2Eh5%2C%2Eh6%2Ch4%2Ch5%2Ch6%7Bmargin%2Dtop%3A10px%3Bmargin%2Dbottom%3A10px%7D%2Eh4%20%2Esmall%2C%2Eh4%20small%2C%2Eh5%20%2Esmall%2C%2Eh5%20small%2C%2Eh6%20%2Esmall%2C%2Eh6%20small%2Ch4%20%2Esmall%2Ch4%20small%2Ch5%20%2Esmall%2Ch5%20small%2Ch6%20%2Esmall%2Ch6%20small%7Bfont%2Dsize%3A75%25%7D%2Eh1%2Ch1%7Bfont%2Dsize%3A36px%7D%2Eh2%2Ch2%7Bfont%2Dsize%3A30px%7D%2Eh3%2Ch3%7Bfont%2Dsize%3A24px%7D%2Eh4%2Ch4%7Bfont%2Dsize%3A18px%7D%2Eh5%2Ch5%7Bfont%2Dsize%3A14px%7D%2Eh6%2Ch6%7Bfont%2Dsize%3A12px%7Dp%7Bmargin%3A0%200%2010px%7D%2Elead%7Bmargin%2Dbottom%3A20px%3Bfont%2Dsize%3A16px%3Bfont%2Dweight%3A300%3Bline%2Dheight%3A1%2E4%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Elead%7Bfont%2Dsize%3A21px%7D%7D%2Esmall%2Csmall%7Bfont%2Dsize%3A85%25%7D%2Emark%2Cmark%7Bpadding%3A%2E2em%3Bbackground%2Dcolor%3A%23fcf8e3%7D%2Etext%2Dleft%7Btext%2Dalign%3Aleft%7D%2Etext%2Dright%7Btext%2Dalign%3Aright%7D%2Etext%2Dcenter%7Btext%2Dalign%3Acenter%7D%2Etext%2Djustify%7Btext%2Dalign%3Ajustify%7D%2Etext%2Dnowrap%7Bwhite%2Dspace%3Anowrap%7D%2Etext%2Dlowercase%7Btext%2Dtransform%3Alowercase%7D%2Etext%2Duppercase%7Btext%2Dtransform%3Auppercase%7D%2Etext%2Dcapitalize%7Btext%2Dtransform%3Acapitalize%7D%2Etext%2Dmuted%7Bcolor%3A%23777%7D%2Etext%2Dprimary%7Bcolor%3A%23337ab7%7Da%2Etext%2Dprimary%3Afocus%2Ca%2Etext%2Dprimary%3Ahover%7Bcolor%3A%23286090%7D%2Etext%2Dsuccess%7Bcolor%3A%233c763d%7Da%2Etext%2Dsuccess%3Afocus%2Ca%2Etext%2Dsuccess%3Ahover%7Bcolor%3A%232b542c%7D%2Etext%2Dinfo%7Bcolor%3A%2331708f%7Da%2Etext%2Dinfo%3Afocus%2Ca%2Etext%2Dinfo%3Ahover%7Bcolor%3A%23245269%7D%2Etext%2Dwarning%7Bcolor%3A%238a6d3b%7Da%2Etext%2Dwarning%3Afocus%2Ca%2Etext%2Dwarning%3Ahover%7Bcolor%3A%2366512c%7D%2Etext%2Ddanger%7Bcolor%3A%23a94442%7Da%2Etext%2Ddanger%3Afocus%2Ca%2Etext%2Ddanger%3Ahover%7Bcolor%3A%23843534%7D%2Ebg%2Dprimary%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23337ab7%7Da%2Ebg%2Dprimary%3Afocus%2Ca%2Ebg%2Dprimary%3Ahover%7Bbackground%2Dcolor%3A%23286090%7D%2Ebg%2Dsuccess%7Bbackground%2Dcolor%3A%23dff0d8%7Da%2Ebg%2Dsuccess%3Afocus%2Ca%2Ebg%2Dsuccess%3Ahover%7Bbackground%2Dcolor%3A%23c1e2b3%7D%2Ebg%2Dinfo%7Bbackground%2Dcolor%3A%23d9edf7%7Da%2Ebg%2Dinfo%3Afocus%2Ca%2Ebg%2Dinfo%3Ahover%7Bbackground%2Dcolor%3A%23afd9ee%7D%2Ebg%2Dwarning%7Bbackground%2Dcolor%3A%23fcf8e3%7Da%2Ebg%2Dwarning%3Afocus%2Ca%2Ebg%2Dwarning%3Ahover%7Bbackground%2Dcolor%3A%23f7ecb5%7D%2Ebg%2Ddanger%7Bbackground%2Dcolor%3A%23f2dede%7Da%2Ebg%2Ddanger%3Afocus%2Ca%2Ebg%2Ddanger%3Ahover%7Bbackground%2Dcolor%3A%23e4b9b9%7D%2Epage%2Dheader%7Bpadding%2Dbottom%3A9px%3Bmargin%3A40px%200%2020px%3Bborder%2Dbottom%3A1px%20solid%20%23eee%7Dol%2Cul%7Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A10px%7Dol%20ol%2Col%20ul%2Cul%20ol%2Cul%20ul%7Bmargin%2Dbottom%3A0%7D%2Elist%2Dunstyled%7Bpadding%2Dleft%3A0%3Blist%2Dstyle%3Anone%7D%2Elist%2Dinline%7Bpadding%2Dleft%3A0%3Bmargin%2Dleft%3A%2D5px%3Blist%2Dstyle%3Anone%7D%2Elist%2Dinline%3Eli%7Bdisplay%3Ainline%2Dblock%3Bpadding%2Dright%3A5px%3Bpadding%2Dleft%3A5px%7Ddl%7Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A20px%7Ddd%2Cdt%7Bline%2Dheight%3A1%2E42857143%7Ddt%7Bfont%2Dweight%3A700%7Ddd%7Bmargin%2Dleft%3A0%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Edl%2Dhorizontal%20dt%7Bfloat%3Aleft%3Bwidth%3A160px%3Boverflow%3Ahidden%3Bclear%3Aleft%3Btext%2Dalign%3Aright%3Btext%2Doverflow%3Aellipsis%3Bwhite%2Dspace%3Anowrap%7D%2Edl%2Dhorizontal%20dd%7Bmargin%2Dleft%3A180px%7D%7Dabbr%5Bdata%2Doriginal%2Dtitle%5D%2Cabbr%5Btitle%5D%7Bcursor%3Ahelp%3Bborder%2Dbottom%3A1px%20dotted%20%23777%7D%2Einitialism%7Bfont%2Dsize%3A90%25%3Btext%2Dtransform%3Auppercase%7Dblockquote%7Bpadding%3A10px%2020px%3Bmargin%3A0%200%2020px%3Bfont%2Dsize%3A17%2E5px%3Bborder%2Dleft%3A5px%20solid%20%23eee%7Dblockquote%20ol%3Alast%2Dchild%2Cblockquote%20p%3Alast%2Dchild%2Cblockquote%20ul%3Alast%2Dchild%7Bmargin%2Dbottom%3A0%7Dblockquote%20%2Esmall%2Cblockquote%20footer%2Cblockquote%20small%7Bdisplay%3Ablock%3Bfont%2Dsize%3A80%25%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23777%7Dblockquote%20%2Esmall%3Abefore%2Cblockquote%20footer%3Abefore%2Cblockquote%20small%3Abefore%7Bcontent%3A%27%5C2014%20%5C00A0%27%7D%2Eblockquote%2Dreverse%2Cblockquote%2Epull%2Dright%7Bpadding%2Dright%3A15px%3Bpadding%2Dleft%3A0%3Btext%2Dalign%3Aright%3Bborder%2Dright%3A5px%20solid%20%23eee%3Bborder%2Dleft%3A0%7D%2Eblockquote%2Dreverse%20%2Esmall%3Abefore%2C%2Eblockquote%2Dreverse%20footer%3Abefore%2C%2Eblockquote%2Dreverse%20small%3Abefore%2Cblockquote%2Epull%2Dright%20%2Esmall%3Abefore%2Cblockquote%2Epull%2Dright%20footer%3Abefore%2Cblockquote%2Epull%2Dright%20small%3Abefore%7Bcontent%3A%27%27%7D%2Eblockquote%2Dreverse%20%2Esmall%3Aafter%2C%2Eblockquote%2Dreverse%20footer%3Aafter%2C%2Eblockquote%2Dreverse%20small%3Aafter%2Cblockquote%2Epull%2Dright%20%2Esmall%3Aafter%2Cblockquote%2Epull%2Dright%20footer%3Aafter%2Cblockquote%2Epull%2Dright%20small%3Aafter%7Bcontent%3A%27%5C00A0%20%5C2014%27%7Daddress%7Bmargin%2Dbottom%3A20px%3Bfont%2Dstyle%3Anormal%3Bline%2Dheight%3A1%2E42857143%7Dcode%2Ckbd%2Cpre%2Csamp%7Bfont%2Dfamily%3Amonospace%7Dcode%7Bpadding%3A2px%204px%3Bfont%2Dsize%3A90%25%3Bcolor%3A%23c7254e%3Bbackground%2Dcolor%3A%23f9f2f4%3Bborder%2Dradius%3A4px%7Dkbd%7Bpadding%3A2px%204px%3Bfont%2Dsize%3A90%25%3Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23333%3Bborder%2Dradius%3A3px%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%20%2D1px%200%20rgba%280%2C0%2C0%2C%2E25%29%3Bbox%2Dshadow%3Ainset%200%20%2D1px%200%20rgba%280%2C0%2C0%2C%2E25%29%7Dkbd%20kbd%7Bpadding%3A0%3Bfont%2Dsize%3A100%25%3Bfont%2Dweight%3A700%3B%2Dwebkit%2Dbox%2Dshadow%3Anone%3Bbox%2Dshadow%3Anone%7Dpre%7Bdisplay%3Ablock%3Bpadding%3A9%2E5px%3Bmargin%3A0%200%2010px%3Bfont%2Dsize%3A13px%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23333%3Bword%2Dbreak%3Abreak%2Dall%3Bword%2Dwrap%3Abreak%2Dword%3Bbackground%2Dcolor%3A%23f5f5f5%3Bborder%3A1px%20solid%20%23ccc%3Bborder%2Dradius%3A4px%7Dpre%20code%7Bpadding%3A0%3Bfont%2Dsize%3Ainherit%3Bcolor%3Ainherit%3Bwhite%2Dspace%3Apre%2Dwrap%3Bbackground%2Dcolor%3Atransparent%3Bborder%2Dradius%3A0%7D%2Epre%2Dscrollable%7Bmax%2Dheight%3A340px%3Boverflow%2Dy%3Ascroll%7D%2Econtainer%7Bpadding%2Dright%3A15px%3Bpadding%2Dleft%3A15px%3Bmargin%2Dright%3Aauto%3Bmargin%2Dleft%3Aauto%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Econtainer%7Bwidth%3A750px%7D%7D%40media%20%28min%2Dwidth%3A992px%29%7B%2Econtainer%7Bwidth%3A970px%7D%7D%40media%20%28min%2Dwidth%3A1200px%29%7B%2Econtainer%7Bwidth%3A1170px%7D%7D%2Econtainer%2Dfluid%7Bpadding%2Dright%3A15px%3Bpadding%2Dleft%3A15px%3Bmargin%2Dright%3Aauto%3Bmargin%2Dleft%3Aauto%7D%2Erow%7Bmargin%2Dright%3A%2D15px%3Bmargin%2Dleft%3A%2D15px%7D%2Ecol%2Dlg%2D1%2C%2Ecol%2Dlg%2D10%2C%2Ecol%2Dlg%2D11%2C%2Ecol%2Dlg%2D12%2C%2Ecol%2Dlg%2D2%2C%2Ecol%2Dlg%2D3%2C%2Ecol%2Dlg%2D4%2C%2Ecol%2Dlg%2D5%2C%2Ecol%2Dlg%2D6%2C%2Ecol%2Dlg%2D7%2C%2Ecol%2Dlg%2D8%2C%2Ecol%2Dlg%2D9%2C%2Ecol%2Dmd%2D1%2C%2Ecol%2Dmd%2D10%2C%2Ecol%2Dmd%2D11%2C%2Ecol%2Dmd%2D12%2C%2Ecol%2Dmd%2D2%2C%2Ecol%2Dmd%2D3%2C%2Ecol%2Dmd%2D4%2C%2Ecol%2Dmd%2D5%2C%2Ecol%2Dmd%2D6%2C%2Ecol%2Dmd%2D7%2C%2Ecol%2Dmd%2D8%2C%2Ecol%2Dmd%2D9%2C%2Ecol%2Dsm%2D1%2C%2Ecol%2Dsm%2D10%2C%2Ecol%2Dsm%2D11%2C%2Ecol%2Dsm%2D12%2C%2Ecol%2Dsm%2D2%2C%2Ecol%2Dsm%2D3%2C%2Ecol%2Dsm%2D4%2C%2Ecol%2Dsm%2D5%2C%2Ecol%2Dsm%2D6%2C%2Ecol%2Dsm%2D7%2C%2Ecol%2Dsm%2D8%2C%2Ecol%2Dsm%2D9%2C%2Ecol%2Dxs%2D1%2C%2Ecol%2Dxs%2D10%2C%2Ecol%2Dxs%2D11%2C%2Ecol%2Dxs%2D12%2C%2Ecol%2Dxs%2D2%2C%2Ecol%2Dxs%2D3%2C%2Ecol%2Dxs%2D4%2C%2Ecol%2Dxs%2D5%2C%2Ecol%2Dxs%2D6%2C%2Ecol%2Dxs%2D7%2C%2Ecol%2Dxs%2D8%2C%2Ecol%2Dxs%2D9%7Bposition%3Arelative%3Bmin%2Dheight%3A1px%3Bpadding%2Dright%3A15px%3Bpadding%2Dleft%3A15px%7D%2Ecol%2Dxs%2D1%2C%2Ecol%2Dxs%2D10%2C%2Ecol%2Dxs%2D11%2C%2Ecol%2Dxs%2D12%2C%2Ecol%2Dxs%2D2%2C%2Ecol%2Dxs%2D3%2C%2Ecol%2Dxs%2D4%2C%2Ecol%2Dxs%2D5%2C%2Ecol%2Dxs%2D6%2C%2Ecol%2Dxs%2D7%2C%2Ecol%2Dxs%2D8%2C%2Ecol%2Dxs%2D9%7Bfloat%3Aleft%7D%2Ecol%2Dxs%2D12%7Bwidth%3A100%25%7D%2Ecol%2Dxs%2D11%7Bwidth%3A91%2E66666667%25%7D%2Ecol%2Dxs%2D10%7Bwidth%3A83%2E33333333%25%7D%2Ecol%2Dxs%2D9%7Bwidth%3A75%25%7D%2Ecol%2Dxs%2D8%7Bwidth%3A66%2E66666667%25%7D%2Ecol%2Dxs%2D7%7Bwidth%3A58%2E33333333%25%7D%2Ecol%2Dxs%2D6%7Bwidth%3A50%25%7D%2Ecol%2Dxs%2D5%7Bwidth%3A41%2E66666667%25%7D%2Ecol%2Dxs%2D4%7Bwidth%3A33%2E33333333%25%7D%2Ecol%2Dxs%2D3%7Bwidth%3A25%25%7D%2Ecol%2Dxs%2D2%7Bwidth%3A16%2E66666667%25%7D%2Ecol%2Dxs%2D1%7Bwidth%3A8%2E33333333%25%7D%2Ecol%2Dxs%2Dpull%2D12%7Bright%3A100%25%7D%2Ecol%2Dxs%2Dpull%2D11%7Bright%3A91%2E66666667%25%7D%2Ecol%2Dxs%2Dpull%2D10%7Bright%3A83%2E33333333%25%7D%2Ecol%2Dxs%2Dpull%2D9%7Bright%3A75%25%7D%2Ecol%2Dxs%2Dpull%2D8%7Bright%3A66%2E66666667%25%7D%2Ecol%2Dxs%2Dpull%2D7%7Bright%3A58%2E33333333%25%7D%2Ecol%2Dxs%2Dpull%2D6%7Bright%3A50%25%7D%2Ecol%2Dxs%2Dpull%2D5%7Bright%3A41%2E66666667%25%7D%2Ecol%2Dxs%2Dpull%2D4%7Bright%3A33%2E33333333%25%7D%2Ecol%2Dxs%2Dpull%2D3%7Bright%3A25%25%7D%2Ecol%2Dxs%2Dpull%2D2%7Bright%3A16%2E66666667%25%7D%2Ecol%2Dxs%2Dpull%2D1%7Bright%3A8%2E33333333%25%7D%2Ecol%2Dxs%2Dpull%2D0%7Bright%3Aauto%7D%2Ecol%2Dxs%2Dpush%2D12%7Bleft%3A100%25%7D%2Ecol%2Dxs%2Dpush%2D11%7Bleft%3A91%2E66666667%25%7D%2Ecol%2Dxs%2Dpush%2D10%7Bleft%3A83%2E33333333%25%7D%2Ecol%2Dxs%2Dpush%2D9%7Bleft%3A75%25%7D%2Ecol%2Dxs%2Dpush%2D8%7Bleft%3A66%2E66666667%25%7D%2Ecol%2Dxs%2Dpush%2D7%7Bleft%3A58%2E33333333%25%7D%2Ecol%2Dxs%2Dpush%2D6%7Bleft%3A50%25%7D%2Ecol%2Dxs%2Dpush%2D5%7Bleft%3A41%2E66666667%25%7D%2Ecol%2Dxs%2Dpush%2D4%7Bleft%3A33%2E33333333%25%7D%2Ecol%2Dxs%2Dpush%2D3%7Bleft%3A25%25%7D%2Ecol%2Dxs%2Dpush%2D2%7Bleft%3A16%2E66666667%25%7D%2Ecol%2Dxs%2Dpush%2D1%7Bleft%3A8%2E33333333%25%7D%2Ecol%2Dxs%2Dpush%2D0%7Bleft%3Aauto%7D%2Ecol%2Dxs%2Doffset%2D12%7Bmargin%2Dleft%3A100%25%7D%2Ecol%2Dxs%2Doffset%2D11%7Bmargin%2Dleft%3A91%2E66666667%25%7D%2Ecol%2Dxs%2Doffset%2D10%7Bmargin%2Dleft%3A83%2E33333333%25%7D%2Ecol%2Dxs%2Doffset%2D9%7Bmargin%2Dleft%3A75%25%7D%2Ecol%2Dxs%2Doffset%2D8%7Bmargin%2Dleft%3A66%2E66666667%25%7D%2Ecol%2Dxs%2Doffset%2D7%7Bmargin%2Dleft%3A58%2E33333333%25%7D%2Ecol%2Dxs%2Doffset%2D6%7Bmargin%2Dleft%3A50%25%7D%2Ecol%2Dxs%2Doffset%2D5%7Bmargin%2Dleft%3A41%2E66666667%25%7D%2Ecol%2Dxs%2Doffset%2D4%7Bmargin%2Dleft%3A33%2E33333333%25%7D%2Ecol%2Dxs%2Doffset%2D3%7Bmargin%2Dleft%3A25%25%7D%2Ecol%2Dxs%2Doffset%2D2%7Bmargin%2Dleft%3A16%2E66666667%25%7D%2Ecol%2Dxs%2Doffset%2D1%7Bmargin%2Dleft%3A8%2E33333333%25%7D%2Ecol%2Dxs%2Doffset%2D0%7Bmargin%2Dleft%3A0%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Ecol%2Dsm%2D1%2C%2Ecol%2Dsm%2D10%2C%2Ecol%2Dsm%2D11%2C%2Ecol%2Dsm%2D12%2C%2Ecol%2Dsm%2D2%2C%2Ecol%2Dsm%2D3%2C%2Ecol%2Dsm%2D4%2C%2Ecol%2Dsm%2D5%2C%2Ecol%2Dsm%2D6%2C%2Ecol%2Dsm%2D7%2C%2Ecol%2Dsm%2D8%2C%2Ecol%2Dsm%2D9%7Bfloat%3Aleft%7D%2Ecol%2Dsm%2D12%7Bwidth%3A100%25%7D%2Ecol%2Dsm%2D11%7Bwidth%3A91%2E66666667%25%7D%2Ecol%2Dsm%2D10%7Bwidth%3A83%2E33333333%25%7D%2Ecol%2Dsm%2D9%7Bwidth%3A75%25%7D%2Ecol%2Dsm%2D8%7Bwidth%3A66%2E66666667%25%7D%2Ecol%2Dsm%2D7%7Bwidth%3A58%2E33333333%25%7D%2Ecol%2Dsm%2D6%7Bwidth%3A50%25%7D%2Ecol%2Dsm%2D5%7Bwidth%3A41%2E66666667%25%7D%2Ecol%2Dsm%2D4%7Bwidth%3A33%2E33333333%25%7D%2Ecol%2Dsm%2D3%7Bwidth%3A25%25%7D%2Ecol%2Dsm%2D2%7Bwidth%3A16%2E66666667%25%7D%2Ecol%2Dsm%2D1%7Bwidth%3A8%2E33333333%25%7D%2Ecol%2Dsm%2Dpull%2D12%7Bright%3A100%25%7D%2Ecol%2Dsm%2Dpull%2D11%7Bright%3A91%2E66666667%25%7D%2Ecol%2Dsm%2Dpull%2D10%7Bright%3A83%2E33333333%25%7D%2Ecol%2Dsm%2Dpull%2D9%7Bright%3A75%25%7D%2Ecol%2Dsm%2Dpull%2D8%7Bright%3A66%2E66666667%25%7D%2Ecol%2Dsm%2Dpull%2D7%7Bright%3A58%2E33333333%25%7D%2Ecol%2Dsm%2Dpull%2D6%7Bright%3A50%25%7D%2Ecol%2Dsm%2Dpull%2D5%7Bright%3A41%2E66666667%25%7D%2Ecol%2Dsm%2Dpull%2D4%7Bright%3A33%2E33333333%25%7D%2Ecol%2Dsm%2Dpull%2D3%7Bright%3A25%25%7D%2Ecol%2Dsm%2Dpull%2D2%7Bright%3A16%2E66666667%25%7D%2Ecol%2Dsm%2Dpull%2D1%7Bright%3A8%2E33333333%25%7D%2Ecol%2Dsm%2Dpull%2D0%7Bright%3Aauto%7D%2Ecol%2Dsm%2Dpush%2D12%7Bleft%3A100%25%7D%2Ecol%2Dsm%2Dpush%2D11%7Bleft%3A91%2E66666667%25%7D%2Ecol%2Dsm%2Dpush%2D10%7Bleft%3A83%2E33333333%25%7D%2Ecol%2Dsm%2Dpush%2D9%7Bleft%3A75%25%7D%2Ecol%2Dsm%2Dpush%2D8%7Bleft%3A66%2E66666667%25%7D%2Ecol%2Dsm%2Dpush%2D7%7Bleft%3A58%2E33333333%25%7D%2Ecol%2Dsm%2Dpush%2D6%7Bleft%3A50%25%7D%2Ecol%2Dsm%2Dpush%2D5%7Bleft%3A41%2E66666667%25%7D%2Ecol%2Dsm%2Dpush%2D4%7Bleft%3A33%2E33333333%25%7D%2Ecol%2Dsm%2Dpush%2D3%7Bleft%3A25%25%7D%2Ecol%2Dsm%2Dpush%2D2%7Bleft%3A16%2E66666667%25%7D%2Ecol%2Dsm%2Dpush%2D1%7Bleft%3A8%2E33333333%25%7D%2Ecol%2Dsm%2Dpush%2D0%7Bleft%3Aauto%7D%2Ecol%2Dsm%2Doffset%2D12%7Bmargin%2Dleft%3A100%25%7D%2Ecol%2Dsm%2Doffset%2D11%7Bmargin%2Dleft%3A91%2E66666667%25%7D%2Ecol%2Dsm%2Doffset%2D10%7Bmargin%2Dleft%3A83%2E33333333%25%7D%2Ecol%2Dsm%2Doffset%2D9%7Bmargin%2Dleft%3A75%25%7D%2Ecol%2Dsm%2Doffset%2D8%7Bmargin%2Dleft%3A66%2E66666667%25%7D%2Ecol%2Dsm%2Doffset%2D7%7Bmargin%2Dleft%3A58%2E33333333%25%7D%2Ecol%2Dsm%2Doffset%2D6%7Bmargin%2Dleft%3A50%25%7D%2Ecol%2Dsm%2Doffset%2D5%7Bmargin%2Dleft%3A41%2E66666667%25%7D%2Ecol%2Dsm%2Doffset%2D4%7Bmargin%2Dleft%3A33%2E33333333%25%7D%2Ecol%2Dsm%2Doffset%2D3%7Bmargin%2Dleft%3A25%25%7D%2Ecol%2Dsm%2Doffset%2D2%7Bmargin%2Dleft%3A16%2E66666667%25%7D%2Ecol%2Dsm%2Doffset%2D1%7Bmargin%2Dleft%3A8%2E33333333%25%7D%2Ecol%2Dsm%2Doffset%2D0%7Bmargin%2Dleft%3A0%7D%7D%40media%20%28min%2Dwidth%3A992px%29%7B%2Ecol%2Dmd%2D1%2C%2Ecol%2Dmd%2D10%2C%2Ecol%2Dmd%2D11%2C%2Ecol%2Dmd%2D12%2C%2Ecol%2Dmd%2D2%2C%2Ecol%2Dmd%2D3%2C%2Ecol%2Dmd%2D4%2C%2Ecol%2Dmd%2D5%2C%2Ecol%2Dmd%2D6%2C%2Ecol%2Dmd%2D7%2C%2Ecol%2Dmd%2D8%2C%2Ecol%2Dmd%2D9%7Bfloat%3Aleft%7D%2Ecol%2Dmd%2D12%7Bwidth%3A100%25%7D%2Ecol%2Dmd%2D11%7Bwidth%3A91%2E66666667%25%7D%2Ecol%2Dmd%2D10%7Bwidth%3A83%2E33333333%25%7D%2Ecol%2Dmd%2D9%7Bwidth%3A75%25%7D%2Ecol%2Dmd%2D8%7Bwidth%3A66%2E66666667%25%7D%2Ecol%2Dmd%2D7%7Bwidth%3A58%2E33333333%25%7D%2Ecol%2Dmd%2D6%7Bwidth%3A50%25%7D%2Ecol%2Dmd%2D5%7Bwidth%3A41%2E66666667%25%7D%2Ecol%2Dmd%2D4%7Bwidth%3A33%2E33333333%25%7D%2Ecol%2Dmd%2D3%7Bwidth%3A25%25%7D%2Ecol%2Dmd%2D2%7Bwidth%3A16%2E66666667%25%7D%2Ecol%2Dmd%2D1%7Bwidth%3A8%2E33333333%25%7D%2Ecol%2Dmd%2Dpull%2D12%7Bright%3A100%25%7D%2Ecol%2Dmd%2Dpull%2D11%7Bright%3A91%2E66666667%25%7D%2Ecol%2Dmd%2Dpull%2D10%7Bright%3A83%2E33333333%25%7D%2Ecol%2Dmd%2Dpull%2D9%7Bright%3A75%25%7D%2Ecol%2Dmd%2Dpull%2D8%7Bright%3A66%2E66666667%25%7D%2Ecol%2Dmd%2Dpull%2D7%7Bright%3A58%2E33333333%25%7D%2Ecol%2Dmd%2Dpull%2D6%7Bright%3A50%25%7D%2Ecol%2Dmd%2Dpull%2D5%7Bright%3A41%2E66666667%25%7D%2Ecol%2Dmd%2Dpull%2D4%7Bright%3A33%2E33333333%25%7D%2Ecol%2Dmd%2Dpull%2D3%7Bright%3A25%25%7D%2Ecol%2Dmd%2Dpull%2D2%7Bright%3A16%2E66666667%25%7D%2Ecol%2Dmd%2Dpull%2D1%7Bright%3A8%2E33333333%25%7D%2Ecol%2Dmd%2Dpull%2D0%7Bright%3Aauto%7D%2Ecol%2Dmd%2Dpush%2D12%7Bleft%3A100%25%7D%2Ecol%2Dmd%2Dpush%2D11%7Bleft%3A91%2E66666667%25%7D%2Ecol%2Dmd%2Dpush%2D10%7Bleft%3A83%2E33333333%25%7D%2Ecol%2Dmd%2Dpush%2D9%7Bleft%3A75%25%7D%2Ecol%2Dmd%2Dpush%2D8%7Bleft%3A66%2E66666667%25%7D%2Ecol%2Dmd%2Dpush%2D7%7Bleft%3A58%2E33333333%25%7D%2Ecol%2Dmd%2Dpush%2D6%7Bleft%3A50%25%7D%2Ecol%2Dmd%2Dpush%2D5%7Bleft%3A41%2E66666667%25%7D%2Ecol%2Dmd%2Dpush%2D4%7Bleft%3A33%2E33333333%25%7D%2Ecol%2Dmd%2Dpush%2D3%7Bleft%3A25%25%7D%2Ecol%2Dmd%2Dpush%2D2%7Bleft%3A16%2E66666667%25%7D%2Ecol%2Dmd%2Dpush%2D1%7Bleft%3A8%2E33333333%25%7D%2Ecol%2Dmd%2Dpush%2D0%7Bleft%3Aauto%7D%2Ecol%2Dmd%2Doffset%2D12%7Bmargin%2Dleft%3A100%25%7D%2Ecol%2Dmd%2Doffset%2D11%7Bmargin%2Dleft%3A91%2E66666667%25%7D%2Ecol%2Dmd%2Doffset%2D10%7Bmargin%2Dleft%3A83%2E33333333%25%7D%2Ecol%2Dmd%2Doffset%2D9%7Bmargin%2Dleft%3A75%25%7D%2Ecol%2Dmd%2Doffset%2D8%7Bmargin%2Dleft%3A66%2E66666667%25%7D%2Ecol%2Dmd%2Doffset%2D7%7Bmargin%2Dleft%3A58%2E33333333%25%7D%2Ecol%2Dmd%2Doffset%2D6%7Bmargin%2Dleft%3A50%25%7D%2Ecol%2Dmd%2Doffset%2D5%7Bmargin%2Dleft%3A41%2E66666667%25%7D%2Ecol%2Dmd%2Doffset%2D4%7Bmargin%2Dleft%3A33%2E33333333%25%7D%2Ecol%2Dmd%2Doffset%2D3%7Bmargin%2Dleft%3A25%25%7D%2Ecol%2Dmd%2Doffset%2D2%7Bmargin%2Dleft%3A16%2E66666667%25%7D%2Ecol%2Dmd%2Doffset%2D1%7Bmargin%2Dleft%3A8%2E33333333%25%7D%2Ecol%2Dmd%2Doffset%2D0%7Bmargin%2Dleft%3A0%7D%7D%40media%20%28min%2Dwidth%3A1200px%29%7B%2Ecol%2Dlg%2D1%2C%2Ecol%2Dlg%2D10%2C%2Ecol%2Dlg%2D11%2C%2Ecol%2Dlg%2D12%2C%2Ecol%2Dlg%2D2%2C%2Ecol%2Dlg%2D3%2C%2Ecol%2Dlg%2D4%2C%2Ecol%2Dlg%2D5%2C%2Ecol%2Dlg%2D6%2C%2Ecol%2Dlg%2D7%2C%2Ecol%2Dlg%2D8%2C%2Ecol%2Dlg%2D9%7Bfloat%3Aleft%7D%2Ecol%2Dlg%2D12%7Bwidth%3A100%25%7D%2Ecol%2Dlg%2D11%7Bwidth%3A91%2E66666667%25%7D%2Ecol%2Dlg%2D10%7Bwidth%3A83%2E33333333%25%7D%2Ecol%2Dlg%2D9%7Bwidth%3A75%25%7D%2Ecol%2Dlg%2D8%7Bwidth%3A66%2E66666667%25%7D%2Ecol%2Dlg%2D7%7Bwidth%3A58%2E33333333%25%7D%2Ecol%2Dlg%2D6%7Bwidth%3A50%25%7D%2Ecol%2Dlg%2D5%7Bwidth%3A41%2E66666667%25%7D%2Ecol%2Dlg%2D4%7Bwidth%3A33%2E33333333%25%7D%2Ecol%2Dlg%2D3%7Bwidth%3A25%25%7D%2Ecol%2Dlg%2D2%7Bwidth%3A16%2E66666667%25%7D%2Ecol%2Dlg%2D1%7Bwidth%3A8%2E33333333%25%7D%2Ecol%2Dlg%2Dpull%2D12%7Bright%3A100%25%7D%2Ecol%2Dlg%2Dpull%2D11%7Bright%3A91%2E66666667%25%7D%2Ecol%2Dlg%2Dpull%2D10%7Bright%3A83%2E33333333%25%7D%2Ecol%2Dlg%2Dpull%2D9%7Bright%3A75%25%7D%2Ecol%2Dlg%2Dpull%2D8%7Bright%3A66%2E66666667%25%7D%2Ecol%2Dlg%2Dpull%2D7%7Bright%3A58%2E33333333%25%7D%2Ecol%2Dlg%2Dpull%2D6%7Bright%3A50%25%7D%2Ecol%2Dlg%2Dpull%2D5%7Bright%3A41%2E66666667%25%7D%2Ecol%2Dlg%2Dpull%2D4%7Bright%3A33%2E33333333%25%7D%2Ecol%2Dlg%2Dpull%2D3%7Bright%3A25%25%7D%2Ecol%2Dlg%2Dpull%2D2%7Bright%3A16%2E66666667%25%7D%2Ecol%2Dlg%2Dpull%2D1%7Bright%3A8%2E33333333%25%7D%2Ecol%2Dlg%2Dpull%2D0%7Bright%3Aauto%7D%2Ecol%2Dlg%2Dpush%2D12%7Bleft%3A100%25%7D%2Ecol%2Dlg%2Dpush%2D11%7Bleft%3A91%2E66666667%25%7D%2Ecol%2Dlg%2Dpush%2D10%7Bleft%3A83%2E33333333%25%7D%2Ecol%2Dlg%2Dpush%2D9%7Bleft%3A75%25%7D%2Ecol%2Dlg%2Dpush%2D8%7Bleft%3A66%2E66666667%25%7D%2Ecol%2Dlg%2Dpush%2D7%7Bleft%3A58%2E33333333%25%7D%2Ecol%2Dlg%2Dpush%2D6%7Bleft%3A50%25%7D%2Ecol%2Dlg%2Dpush%2D5%7Bleft%3A41%2E66666667%25%7D%2Ecol%2Dlg%2Dpush%2D4%7Bleft%3A33%2E33333333%25%7D%2Ecol%2Dlg%2Dpush%2D3%7Bleft%3A25%25%7D%2Ecol%2Dlg%2Dpush%2D2%7Bleft%3A16%2E66666667%25%7D%2Ecol%2Dlg%2Dpush%2D1%7Bleft%3A8%2E33333333%25%7D%2Ecol%2Dlg%2Dpush%2D0%7Bleft%3Aauto%7D%2Ecol%2Dlg%2Doffset%2D12%7Bmargin%2Dleft%3A100%25%7D%2Ecol%2Dlg%2Doffset%2D11%7Bmargin%2Dleft%3A91%2E66666667%25%7D%2Ecol%2Dlg%2Doffset%2D10%7Bmargin%2Dleft%3A83%2E33333333%25%7D%2Ecol%2Dlg%2Doffset%2D9%7Bmargin%2Dleft%3A75%25%7D%2Ecol%2Dlg%2Doffset%2D8%7Bmargin%2Dleft%3A66%2E66666667%25%7D%2Ecol%2Dlg%2Doffset%2D7%7Bmargin%2Dleft%3A58%2E33333333%25%7D%2Ecol%2Dlg%2Doffset%2D6%7Bmargin%2Dleft%3A50%25%7D%2Ecol%2Dlg%2Doffset%2D5%7Bmargin%2Dleft%3A41%2E66666667%25%7D%2Ecol%2Dlg%2Doffset%2D4%7Bmargin%2Dleft%3A33%2E33333333%25%7D%2Ecol%2Dlg%2Doffset%2D3%7Bmargin%2Dleft%3A25%25%7D%2Ecol%2Dlg%2Doffset%2D2%7Bmargin%2Dleft%3A16%2E66666667%25%7D%2Ecol%2Dlg%2Doffset%2D1%7Bmargin%2Dleft%3A8%2E33333333%25%7D%2Ecol%2Dlg%2Doffset%2D0%7Bmargin%2Dleft%3A0%7D%7Dtable%7Bbackground%2Dcolor%3Atransparent%7Dcaption%7Bpadding%2Dtop%3A8px%3Bpadding%2Dbottom%3A8px%3Bcolor%3A%23777%3Btext%2Dalign%3Aleft%7Dth%7B%7D%2Etable%7Bwidth%3A100%25%3Bmax%2Dwidth%3A100%25%3Bmargin%2Dbottom%3A20px%7D%2Etable%3Etbody%3Etr%3Etd%2C%2Etable%3Etbody%3Etr%3Eth%2C%2Etable%3Etfoot%3Etr%3Etd%2C%2Etable%3Etfoot%3Etr%3Eth%2C%2Etable%3Ethead%3Etr%3Etd%2C%2Etable%3Ethead%3Etr%3Eth%7Bpadding%3A8px%3Bline%2Dheight%3A1%2E42857143%3Bvertical%2Dalign%3Atop%3Bborder%2Dtop%3A1px%20solid%20%23ddd%7D%2Etable%3Ethead%3Etr%3Eth%7Bvertical%2Dalign%3Abottom%3Bborder%2Dbottom%3A2px%20solid%20%23ddd%7D%2Etable%3Ecaption%2Bthead%3Etr%3Afirst%2Dchild%3Etd%2C%2Etable%3Ecaption%2Bthead%3Etr%3Afirst%2Dchild%3Eth%2C%2Etable%3Ecolgroup%2Bthead%3Etr%3Afirst%2Dchild%3Etd%2C%2Etable%3Ecolgroup%2Bthead%3Etr%3Afirst%2Dchild%3Eth%2C%2Etable%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%3Etd%2C%2Etable%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%3Eth%7Bborder%2Dtop%3A0%7D%2Etable%3Etbody%2Btbody%7Bborder%2Dtop%3A2px%20solid%20%23ddd%7D%2Etable%20%2Etable%7Bbackground%2Dcolor%3A%23fff%7D%2Etable%2Dcondensed%3Etbody%3Etr%3Etd%2C%2Etable%2Dcondensed%3Etbody%3Etr%3Eth%2C%2Etable%2Dcondensed%3Etfoot%3Etr%3Etd%2C%2Etable%2Dcondensed%3Etfoot%3Etr%3Eth%2C%2Etable%2Dcondensed%3Ethead%3Etr%3Etd%2C%2Etable%2Dcondensed%3Ethead%3Etr%3Eth%7Bpadding%3A5px%7D%2Etable%2Dbordered%7Bborder%3A1px%20solid%20%23ddd%7D%2Etable%2Dbordered%3Etbody%3Etr%3Etd%2C%2Etable%2Dbordered%3Etbody%3Etr%3Eth%2C%2Etable%2Dbordered%3Etfoot%3Etr%3Etd%2C%2Etable%2Dbordered%3Etfoot%3Etr%3Eth%2C%2Etable%2Dbordered%3Ethead%3Etr%3Etd%2C%2Etable%2Dbordered%3Ethead%3Etr%3Eth%7Bborder%3A1px%20solid%20%23ddd%7D%2Etable%2Dbordered%3Ethead%3Etr%3Etd%2C%2Etable%2Dbordered%3Ethead%3Etr%3Eth%7Bborder%2Dbottom%2Dwidth%3A2px%7D%2Etable%2Dstriped%3Etbody%3Etr%3Anth%2Dof%2Dtype%28odd%29%7Bbackground%2Dcolor%3A%23f9f9f9%7D%2Etable%2Dhover%3Etbody%3Etr%3Ahover%7Bbackground%2Dcolor%3A%23f5f5f5%7Dtable%20col%5Bclass%2A%3Dcol%2D%5D%7Bposition%3Astatic%3Bdisplay%3Atable%2Dcolumn%3Bfloat%3Anone%7Dtable%20td%5Bclass%2A%3Dcol%2D%5D%2Ctable%20th%5Bclass%2A%3Dcol%2D%5D%7Bposition%3Astatic%3Bdisplay%3Atable%2Dcell%3Bfloat%3Anone%7D%2Etable%3Etbody%3Etr%2Eactive%3Etd%2C%2Etable%3Etbody%3Etr%2Eactive%3Eth%2C%2Etable%3Etbody%3Etr%3Etd%2Eactive%2C%2Etable%3Etbody%3Etr%3Eth%2Eactive%2C%2Etable%3Etfoot%3Etr%2Eactive%3Etd%2C%2Etable%3Etfoot%3Etr%2Eactive%3Eth%2C%2Etable%3Etfoot%3Etr%3Etd%2Eactive%2C%2Etable%3Etfoot%3Etr%3Eth%2Eactive%2C%2Etable%3Ethead%3Etr%2Eactive%3Etd%2C%2Etable%3Ethead%3Etr%2Eactive%3Eth%2C%2Etable%3Ethead%3Etr%3Etd%2Eactive%2C%2Etable%3Ethead%3Etr%3Eth%2Eactive%7Bbackground%2Dcolor%3A%23f5f5f5%7D%2Etable%2Dhover%3Etbody%3Etr%2Eactive%3Ahover%3Etd%2C%2Etable%2Dhover%3Etbody%3Etr%2Eactive%3Ahover%3Eth%2C%2Etable%2Dhover%3Etbody%3Etr%3Ahover%3E%2Eactive%2C%2Etable%2Dhover%3Etbody%3Etr%3Etd%2Eactive%3Ahover%2C%2Etable%2Dhover%3Etbody%3Etr%3Eth%2Eactive%3Ahover%7Bbackground%2Dcolor%3A%23e8e8e8%7D%2Etable%3Etbody%3Etr%2Esuccess%3Etd%2C%2Etable%3Etbody%3Etr%2Esuccess%3Eth%2C%2Etable%3Etbody%3Etr%3Etd%2Esuccess%2C%2Etable%3Etbody%3Etr%3Eth%2Esuccess%2C%2Etable%3Etfoot%3Etr%2Esuccess%3Etd%2C%2Etable%3Etfoot%3Etr%2Esuccess%3Eth%2C%2Etable%3Etfoot%3Etr%3Etd%2Esuccess%2C%2Etable%3Etfoot%3Etr%3Eth%2Esuccess%2C%2Etable%3Ethead%3Etr%2Esuccess%3Etd%2C%2Etable%3Ethead%3Etr%2Esuccess%3Eth%2C%2Etable%3Ethead%3Etr%3Etd%2Esuccess%2C%2Etable%3Ethead%3Etr%3Eth%2Esuccess%7Bbackground%2Dcolor%3A%23dff0d8%7D%2Etable%2Dhover%3Etbody%3Etr%2Esuccess%3Ahover%3Etd%2C%2Etable%2Dhover%3Etbody%3Etr%2Esuccess%3Ahover%3Eth%2C%2Etable%2Dhover%3Etbody%3Etr%3Ahover%3E%2Esuccess%2C%2Etable%2Dhover%3Etbody%3Etr%3Etd%2Esuccess%3Ahover%2C%2Etable%2Dhover%3Etbody%3Etr%3Eth%2Esuccess%3Ahover%7Bbackground%2Dcolor%3A%23d0e9c6%7D%2Etable%3Etbody%3Etr%2Einfo%3Etd%2C%2Etable%3Etbody%3Etr%2Einfo%3Eth%2C%2Etable%3Etbody%3Etr%3Etd%2Einfo%2C%2Etable%3Etbody%3Etr%3Eth%2Einfo%2C%2Etable%3Etfoot%3Etr%2Einfo%3Etd%2C%2Etable%3Etfoot%3Etr%2Einfo%3Eth%2C%2Etable%3Etfoot%3Etr%3Etd%2Einfo%2C%2Etable%3Etfoot%3Etr%3Eth%2Einfo%2C%2Etable%3Ethead%3Etr%2Einfo%3Etd%2C%2Etable%3Ethead%3Etr%2Einfo%3Eth%2C%2Etable%3Ethead%3Etr%3Etd%2Einfo%2C%2Etable%3Ethead%3Etr%3Eth%2Einfo%7Bbackground%2Dcolor%3A%23d9edf7%7D%2Etable%2Dhover%3Etbody%3Etr%2Einfo%3Ahover%3Etd%2C%2Etable%2Dhover%3Etbody%3Etr%2Einfo%3Ahover%3Eth%2C%2Etable%2Dhover%3Etbody%3Etr%3Ahover%3E%2Einfo%2C%2Etable%2Dhover%3Etbody%3Etr%3Etd%2Einfo%3Ahover%2C%2Etable%2Dhover%3Etbody%3Etr%3Eth%2Einfo%3Ahover%7Bbackground%2Dcolor%3A%23c4e3f3%7D%2Etable%3Etbody%3Etr%2Ewarning%3Etd%2C%2Etable%3Etbody%3Etr%2Ewarning%3Eth%2C%2Etable%3Etbody%3Etr%3Etd%2Ewarning%2C%2Etable%3Etbody%3Etr%3Eth%2Ewarning%2C%2Etable%3Etfoot%3Etr%2Ewarning%3Etd%2C%2Etable%3Etfoot%3Etr%2Ewarning%3Eth%2C%2Etable%3Etfoot%3Etr%3Etd%2Ewarning%2C%2Etable%3Etfoot%3Etr%3Eth%2Ewarning%2C%2Etable%3Ethead%3Etr%2Ewarning%3Etd%2C%2Etable%3Ethead%3Etr%2Ewarning%3Eth%2C%2Etable%3Ethead%3Etr%3Etd%2Ewarning%2C%2Etable%3Ethead%3Etr%3Eth%2Ewarning%7Bbackground%2Dcolor%3A%23fcf8e3%7D%2Etable%2Dhover%3Etbody%3Etr%2Ewarning%3Ahover%3Etd%2C%2Etable%2Dhover%3Etbody%3Etr%2Ewarning%3Ahover%3Eth%2C%2Etable%2Dhover%3Etbody%3Etr%3Ahover%3E%2Ewarning%2C%2Etable%2Dhover%3Etbody%3Etr%3Etd%2Ewarning%3Ahover%2C%2Etable%2Dhover%3Etbody%3Etr%3Eth%2Ewarning%3Ahover%7Bbackground%2Dcolor%3A%23faf2cc%7D%2Etable%3Etbody%3Etr%2Edanger%3Etd%2C%2Etable%3Etbody%3Etr%2Edanger%3Eth%2C%2Etable%3Etbody%3Etr%3Etd%2Edanger%2C%2Etable%3Etbody%3Etr%3Eth%2Edanger%2C%2Etable%3Etfoot%3Etr%2Edanger%3Etd%2C%2Etable%3Etfoot%3Etr%2Edanger%3Eth%2C%2Etable%3Etfoot%3Etr%3Etd%2Edanger%2C%2Etable%3Etfoot%3Etr%3Eth%2Edanger%2C%2Etable%3Ethead%3Etr%2Edanger%3Etd%2C%2Etable%3Ethead%3Etr%2Edanger%3Eth%2C%2Etable%3Ethead%3Etr%3Etd%2Edanger%2C%2Etable%3Ethead%3Etr%3Eth%2Edanger%7Bbackground%2Dcolor%3A%23f2dede%7D%2Etable%2Dhover%3Etbody%3Etr%2Edanger%3Ahover%3Etd%2C%2Etable%2Dhover%3Etbody%3Etr%2Edanger%3Ahover%3Eth%2C%2Etable%2Dhover%3Etbody%3Etr%3Ahover%3E%2Edanger%2C%2Etable%2Dhover%3Etbody%3Etr%3Etd%2Edanger%3Ahover%2C%2Etable%2Dhover%3Etbody%3Etr%3Eth%2Edanger%3Ahover%7Bbackground%2Dcolor%3A%23ebcccc%7D%2Etable%2Dresponsive%7Bmin%2Dheight%3A%2E01%25%3Boverflow%2Dx%3Aauto%7D%40media%20screen%20and%20%28max%2Dwidth%3A767px%29%7B%2Etable%2Dresponsive%7Bwidth%3A100%25%3Bmargin%2Dbottom%3A15px%3Boverflow%2Dy%3Ahidden%3B%2Dms%2Doverflow%2Dstyle%3A%2Dms%2Dautohiding%2Dscrollbar%3Bborder%3A1px%20solid%20%23ddd%7D%2Etable%2Dresponsive%3E%2Etable%7Bmargin%2Dbottom%3A0%7D%2Etable%2Dresponsive%3E%2Etable%3Etbody%3Etr%3Etd%2C%2Etable%2Dresponsive%3E%2Etable%3Etbody%3Etr%3Eth%2C%2Etable%2Dresponsive%3E%2Etable%3Etfoot%3Etr%3Etd%2C%2Etable%2Dresponsive%3E%2Etable%3Etfoot%3Etr%3Eth%2C%2Etable%2Dresponsive%3E%2Etable%3Ethead%3Etr%3Etd%2C%2Etable%2Dresponsive%3E%2Etable%3Ethead%3Etr%3Eth%7Bwhite%2Dspace%3Anowrap%7D%2Etable%2Dresponsive%3E%2Etable%2Dbordered%7Bborder%3A0%7D%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Etd%3Afirst%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Eth%3Afirst%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Etd%3Afirst%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Eth%3Afirst%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Etd%3Afirst%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Eth%3Afirst%2Dchild%7Bborder%2Dleft%3A0%7D%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Etd%3Alast%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Eth%3Alast%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Etd%3Alast%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Eth%3Alast%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Etd%3Alast%2Dchild%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Eth%3Alast%2Dchild%7Bborder%2Dright%3A0%7D%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Alast%2Dchild%3Etd%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Alast%2Dchild%3Eth%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Alast%2Dchild%3Etd%2C%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Alast%2Dchild%3Eth%7Bborder%2Dbottom%3A0%7D%7Dfieldset%7Bmin%2Dwidth%3A0%3Bpadding%3A0%3Bmargin%3A0%3Bborder%3A0%7Dlegend%7Bdisplay%3Ablock%3Bwidth%3A100%25%3Bpadding%3A0%3Bmargin%2Dbottom%3A20px%3Bfont%2Dsize%3A21px%3Bline%2Dheight%3Ainherit%3Bcolor%3A%23333%3Bborder%3A0%3Bborder%2Dbottom%3A1px%20solid%20%23e5e5e5%7Dlabel%7Bdisplay%3Ainline%2Dblock%3Bmax%2Dwidth%3A100%25%3Bmargin%2Dbottom%3A5px%3Bfont%2Dweight%3A700%7Dinput%5Btype%3Dsearch%5D%7B%2Dwebkit%2Dbox%2Dsizing%3Aborder%2Dbox%3B%2Dmoz%2Dbox%2Dsizing%3Aborder%2Dbox%3Bbox%2Dsizing%3Aborder%2Dbox%7Dinput%5Btype%3Dcheckbox%5D%2Cinput%5Btype%3Dradio%5D%7Bmargin%3A4px%200%200%3Bmargin%2Dtop%3A1px%5C9%3Bline%2Dheight%3Anormal%7Dinput%5Btype%3Dfile%5D%7Bdisplay%3Ablock%7Dinput%5Btype%3Drange%5D%7Bdisplay%3Ablock%3Bwidth%3A100%25%7Dselect%5Bmultiple%5D%2Cselect%5Bsize%5D%7Bheight%3Aauto%7Dinput%5Btype%3Dfile%5D%3Afocus%2Cinput%5Btype%3Dcheckbox%5D%3Afocus%2Cinput%5Btype%3Dradio%5D%3Afocus%7Boutline%3Athin%20dotted%3Boutline%3A5px%20auto%20%2Dwebkit%2Dfocus%2Dring%2Dcolor%3Boutline%2Doffset%3A%2D2px%7Doutput%7Bdisplay%3Ablock%3Bpadding%2Dtop%3A7px%3Bfont%2Dsize%3A14px%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23555%7D%2Eform%2Dcontrol%7Bdisplay%3Ablock%3Bwidth%3A100%25%3Bheight%3A34px%3Bpadding%3A6px%2012px%3Bfont%2Dsize%3A14px%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23555%3Bbackground%2Dcolor%3A%23fff%3Bbackground%2Dimage%3Anone%3Bborder%3A1px%20solid%20%23ccc%3Bborder%2Dradius%3A4px%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%3B%2Dwebkit%2Dtransition%3Aborder%2Dcolor%20ease%2Din%2Dout%20%2E15s%2C%2Dwebkit%2Dbox%2Dshadow%20ease%2Din%2Dout%20%2E15s%3B%2Do%2Dtransition%3Aborder%2Dcolor%20ease%2Din%2Dout%20%2E15s%2Cbox%2Dshadow%20ease%2Din%2Dout%20%2E15s%3Btransition%3Aborder%2Dcolor%20ease%2Din%2Dout%20%2E15s%2Cbox%2Dshadow%20ease%2Din%2Dout%20%2E15s%7D%2Eform%2Dcontrol%3Afocus%7Bborder%2Dcolor%3A%2366afe9%3Boutline%3A0%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%208px%20rgba%28102%2C175%2C233%2C%2E6%29%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%208px%20rgba%28102%2C175%2C233%2C%2E6%29%7D%2Eform%2Dcontrol%3A%3A%2Dmoz%2Dplaceholder%7Bcolor%3A%23999%3Bopacity%3A1%7D%2Eform%2Dcontrol%3A%2Dms%2Dinput%2Dplaceholder%7Bcolor%3A%23999%7D%2Eform%2Dcontrol%3A%3A%2Dwebkit%2Dinput%2Dplaceholder%7Bcolor%3A%23999%7D%2Eform%2Dcontrol%5Bdisabled%5D%2C%2Eform%2Dcontrol%5Breadonly%5D%2Cfieldset%5Bdisabled%5D%20%2Eform%2Dcontrol%7Bbackground%2Dcolor%3A%23eee%3Bopacity%3A1%7D%2Eform%2Dcontrol%5Bdisabled%5D%2Cfieldset%5Bdisabled%5D%20%2Eform%2Dcontrol%7Bcursor%3Anot%2Dallowed%7Dtextarea%2Eform%2Dcontrol%7Bheight%3Aauto%7Dinput%5Btype%3Dsearch%5D%7B%2Dwebkit%2Dappearance%3Anone%7D%40media%20screen%20and%20%28%2Dwebkit%2Dmin%2Ddevice%2Dpixel%2Dratio%3A0%29%7Binput%5Btype%3Ddate%5D%2Eform%2Dcontrol%2Cinput%5Btype%3Dtime%5D%2Eform%2Dcontrol%2Cinput%5Btype%3Ddatetime%2Dlocal%5D%2Eform%2Dcontrol%2Cinput%5Btype%3Dmonth%5D%2Eform%2Dcontrol%7Bline%2Dheight%3A34px%7D%2Einput%2Dgroup%2Dsm%20input%5Btype%3Ddate%5D%2C%2Einput%2Dgroup%2Dsm%20input%5Btype%3Dtime%5D%2C%2Einput%2Dgroup%2Dsm%20input%5Btype%3Ddatetime%2Dlocal%5D%2C%2Einput%2Dgroup%2Dsm%20input%5Btype%3Dmonth%5D%2Cinput%5Btype%3Ddate%5D%2Einput%2Dsm%2Cinput%5Btype%3Dtime%5D%2Einput%2Dsm%2Cinput%5Btype%3Ddatetime%2Dlocal%5D%2Einput%2Dsm%2Cinput%5Btype%3Dmonth%5D%2Einput%2Dsm%7Bline%2Dheight%3A30px%7D%2Einput%2Dgroup%2Dlg%20input%5Btype%3Ddate%5D%2C%2Einput%2Dgroup%2Dlg%20input%5Btype%3Dtime%5D%2C%2Einput%2Dgroup%2Dlg%20input%5Btype%3Ddatetime%2Dlocal%5D%2C%2Einput%2Dgroup%2Dlg%20input%5Btype%3Dmonth%5D%2Cinput%5Btype%3Ddate%5D%2Einput%2Dlg%2Cinput%5Btype%3Dtime%5D%2Einput%2Dlg%2Cinput%5Btype%3Ddatetime%2Dlocal%5D%2Einput%2Dlg%2Cinput%5Btype%3Dmonth%5D%2Einput%2Dlg%7Bline%2Dheight%3A46px%7D%7D%2Eform%2Dgroup%7Bmargin%2Dbottom%3A15px%7D%2Echeckbox%2C%2Eradio%7Bposition%3Arelative%3Bdisplay%3Ablock%3Bmargin%2Dtop%3A10px%3Bmargin%2Dbottom%3A10px%7D%2Echeckbox%20label%2C%2Eradio%20label%7Bmin%2Dheight%3A20px%3Bpadding%2Dleft%3A20px%3Bmargin%2Dbottom%3A0%3Bfont%2Dweight%3A400%3Bcursor%3Apointer%7D%2Echeckbox%20input%5Btype%3Dcheckbox%5D%2C%2Echeckbox%2Dinline%20input%5Btype%3Dcheckbox%5D%2C%2Eradio%20input%5Btype%3Dradio%5D%2C%2Eradio%2Dinline%20input%5Btype%3Dradio%5D%7Bposition%3Aabsolute%3Bmargin%2Dtop%3A4px%5C9%3Bmargin%2Dleft%3A%2D20px%7D%2Echeckbox%2B%2Echeckbox%2C%2Eradio%2B%2Eradio%7Bmargin%2Dtop%3A%2D5px%7D%2Echeckbox%2Dinline%2C%2Eradio%2Dinline%7Bposition%3Arelative%3Bdisplay%3Ainline%2Dblock%3Bpadding%2Dleft%3A20px%3Bmargin%2Dbottom%3A0%3Bfont%2Dweight%3A400%3Bvertical%2Dalign%3Amiddle%3Bcursor%3Apointer%7D%2Echeckbox%2Dinline%2B%2Echeckbox%2Dinline%2C%2Eradio%2Dinline%2B%2Eradio%2Dinline%7Bmargin%2Dtop%3A0%3Bmargin%2Dleft%3A10px%7Dfieldset%5Bdisabled%5D%20input%5Btype%3Dcheckbox%5D%2Cfieldset%5Bdisabled%5D%20input%5Btype%3Dradio%5D%2Cinput%5Btype%3Dcheckbox%5D%2Edisabled%2Cinput%5Btype%3Dcheckbox%5D%5Bdisabled%5D%2Cinput%5Btype%3Dradio%5D%2Edisabled%2Cinput%5Btype%3Dradio%5D%5Bdisabled%5D%7Bcursor%3Anot%2Dallowed%7D%2Echeckbox%2Dinline%2Edisabled%2C%2Eradio%2Dinline%2Edisabled%2Cfieldset%5Bdisabled%5D%20%2Echeckbox%2Dinline%2Cfieldset%5Bdisabled%5D%20%2Eradio%2Dinline%7Bcursor%3Anot%2Dallowed%7D%2Echeckbox%2Edisabled%20label%2C%2Eradio%2Edisabled%20label%2Cfieldset%5Bdisabled%5D%20%2Echeckbox%20label%2Cfieldset%5Bdisabled%5D%20%2Eradio%20label%7Bcursor%3Anot%2Dallowed%7D%2Eform%2Dcontrol%2Dstatic%7Bmin%2Dheight%3A34px%3Bpadding%2Dtop%3A7px%3Bpadding%2Dbottom%3A7px%3Bmargin%2Dbottom%3A0%7D%2Eform%2Dcontrol%2Dstatic%2Einput%2Dlg%2C%2Eform%2Dcontrol%2Dstatic%2Einput%2Dsm%7Bpadding%2Dright%3A0%3Bpadding%2Dleft%3A0%7D%2Einput%2Dsm%7Bheight%3A30px%3Bpadding%3A5px%2010px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5%3Bborder%2Dradius%3A3px%7Dselect%2Einput%2Dsm%7Bheight%3A30px%3Bline%2Dheight%3A30px%7Dselect%5Bmultiple%5D%2Einput%2Dsm%2Ctextarea%2Einput%2Dsm%7Bheight%3Aauto%7D%2Eform%2Dgroup%2Dsm%20%2Eform%2Dcontrol%7Bheight%3A30px%3Bpadding%3A5px%2010px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5%3Bborder%2Dradius%3A3px%7D%2Eform%2Dgroup%2Dsm%20select%2Eform%2Dcontrol%7Bheight%3A30px%3Bline%2Dheight%3A30px%7D%2Eform%2Dgroup%2Dsm%20select%5Bmultiple%5D%2Eform%2Dcontrol%2C%2Eform%2Dgroup%2Dsm%20textarea%2Eform%2Dcontrol%7Bheight%3Aauto%7D%2Eform%2Dgroup%2Dsm%20%2Eform%2Dcontrol%2Dstatic%7Bheight%3A30px%3Bmin%2Dheight%3A32px%3Bpadding%3A6px%2010px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5%7D%2Einput%2Dlg%7Bheight%3A46px%3Bpadding%3A10px%2016px%3Bfont%2Dsize%3A18px%3Bline%2Dheight%3A1%2E3333333%3Bborder%2Dradius%3A6px%7Dselect%2Einput%2Dlg%7Bheight%3A46px%3Bline%2Dheight%3A46px%7Dselect%5Bmultiple%5D%2Einput%2Dlg%2Ctextarea%2Einput%2Dlg%7Bheight%3Aauto%7D%2Eform%2Dgroup%2Dlg%20%2Eform%2Dcontrol%7Bheight%3A46px%3Bpadding%3A10px%2016px%3Bfont%2Dsize%3A18px%3Bline%2Dheight%3A1%2E3333333%3Bborder%2Dradius%3A6px%7D%2Eform%2Dgroup%2Dlg%20select%2Eform%2Dcontrol%7Bheight%3A46px%3Bline%2Dheight%3A46px%7D%2Eform%2Dgroup%2Dlg%20select%5Bmultiple%5D%2Eform%2Dcontrol%2C%2Eform%2Dgroup%2Dlg%20textarea%2Eform%2Dcontrol%7Bheight%3Aauto%7D%2Eform%2Dgroup%2Dlg%20%2Eform%2Dcontrol%2Dstatic%7Bheight%3A46px%3Bmin%2Dheight%3A38px%3Bpadding%3A11px%2016px%3Bfont%2Dsize%3A18px%3Bline%2Dheight%3A1%2E3333333%7D%2Ehas%2Dfeedback%7Bposition%3Arelative%7D%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%7Bpadding%2Dright%3A42%2E5px%7D%2Eform%2Dcontrol%2Dfeedback%7Bposition%3Aabsolute%3Btop%3A0%3Bright%3A0%3Bz%2Dindex%3A2%3Bdisplay%3Ablock%3Bwidth%3A34px%3Bheight%3A34px%3Bline%2Dheight%3A34px%3Btext%2Dalign%3Acenter%3Bpointer%2Devents%3Anone%7D%2Eform%2Dgroup%2Dlg%20%2Eform%2Dcontrol%2B%2Eform%2Dcontrol%2Dfeedback%2C%2Einput%2Dgroup%2Dlg%2B%2Eform%2Dcontrol%2Dfeedback%2C%2Einput%2Dlg%2B%2Eform%2Dcontrol%2Dfeedback%7Bwidth%3A46px%3Bheight%3A46px%3Bline%2Dheight%3A46px%7D%2Eform%2Dgroup%2Dsm%20%2Eform%2Dcontrol%2B%2Eform%2Dcontrol%2Dfeedback%2C%2Einput%2Dgroup%2Dsm%2B%2Eform%2Dcontrol%2Dfeedback%2C%2Einput%2Dsm%2B%2Eform%2Dcontrol%2Dfeedback%7Bwidth%3A30px%3Bheight%3A30px%3Bline%2Dheight%3A30px%7D%2Ehas%2Dsuccess%20%2Echeckbox%2C%2Ehas%2Dsuccess%20%2Echeckbox%2Dinline%2C%2Ehas%2Dsuccess%20%2Econtrol%2Dlabel%2C%2Ehas%2Dsuccess%20%2Ehelp%2Dblock%2C%2Ehas%2Dsuccess%20%2Eradio%2C%2Ehas%2Dsuccess%20%2Eradio%2Dinline%2C%2Ehas%2Dsuccess%2Echeckbox%20label%2C%2Ehas%2Dsuccess%2Echeckbox%2Dinline%20label%2C%2Ehas%2Dsuccess%2Eradio%20label%2C%2Ehas%2Dsuccess%2Eradio%2Dinline%20label%7Bcolor%3A%233c763d%7D%2Ehas%2Dsuccess%20%2Eform%2Dcontrol%7Bborder%2Dcolor%3A%233c763d%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%7D%2Ehas%2Dsuccess%20%2Eform%2Dcontrol%3Afocus%7Bborder%2Dcolor%3A%232b542c%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%206px%20%2367b168%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%206px%20%2367b168%7D%2Ehas%2Dsuccess%20%2Einput%2Dgroup%2Daddon%7Bcolor%3A%233c763d%3Bbackground%2Dcolor%3A%23dff0d8%3Bborder%2Dcolor%3A%233c763d%7D%2Ehas%2Dsuccess%20%2Eform%2Dcontrol%2Dfeedback%7Bcolor%3A%233c763d%7D%2Ehas%2Dwarning%20%2Echeckbox%2C%2Ehas%2Dwarning%20%2Echeckbox%2Dinline%2C%2Ehas%2Dwarning%20%2Econtrol%2Dlabel%2C%2Ehas%2Dwarning%20%2Ehelp%2Dblock%2C%2Ehas%2Dwarning%20%2Eradio%2C%2Ehas%2Dwarning%20%2Eradio%2Dinline%2C%2Ehas%2Dwarning%2Echeckbox%20label%2C%2Ehas%2Dwarning%2Echeckbox%2Dinline%20label%2C%2Ehas%2Dwarning%2Eradio%20label%2C%2Ehas%2Dwarning%2Eradio%2Dinline%20label%7Bcolor%3A%238a6d3b%7D%2Ehas%2Dwarning%20%2Eform%2Dcontrol%7Bborder%2Dcolor%3A%238a6d3b%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%7D%2Ehas%2Dwarning%20%2Eform%2Dcontrol%3Afocus%7Bborder%2Dcolor%3A%2366512c%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%206px%20%23c0a16b%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%206px%20%23c0a16b%7D%2Ehas%2Dwarning%20%2Einput%2Dgroup%2Daddon%7Bcolor%3A%238a6d3b%3Bbackground%2Dcolor%3A%23fcf8e3%3Bborder%2Dcolor%3A%238a6d3b%7D%2Ehas%2Dwarning%20%2Eform%2Dcontrol%2Dfeedback%7Bcolor%3A%238a6d3b%7D%2Ehas%2Derror%20%2Echeckbox%2C%2Ehas%2Derror%20%2Echeckbox%2Dinline%2C%2Ehas%2Derror%20%2Econtrol%2Dlabel%2C%2Ehas%2Derror%20%2Ehelp%2Dblock%2C%2Ehas%2Derror%20%2Eradio%2C%2Ehas%2Derror%20%2Eradio%2Dinline%2C%2Ehas%2Derror%2Echeckbox%20label%2C%2Ehas%2Derror%2Echeckbox%2Dinline%20label%2C%2Ehas%2Derror%2Eradio%20label%2C%2Ehas%2Derror%2Eradio%2Dinline%20label%7Bcolor%3A%23a94442%7D%2Ehas%2Derror%20%2Eform%2Dcontrol%7Bborder%2Dcolor%3A%23a94442%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%7D%2Ehas%2Derror%20%2Eform%2Dcontrol%3Afocus%7Bborder%2Dcolor%3A%23843534%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%206px%20%23ce8483%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E075%29%2C0%200%206px%20%23ce8483%7D%2Ehas%2Derror%20%2Einput%2Dgroup%2Daddon%7Bcolor%3A%23a94442%3Bbackground%2Dcolor%3A%23f2dede%3Bborder%2Dcolor%3A%23a94442%7D%2Ehas%2Derror%20%2Eform%2Dcontrol%2Dfeedback%7Bcolor%3A%23a94442%7D%2Ehas%2Dfeedback%20label%7E%2Eform%2Dcontrol%2Dfeedback%7Btop%3A25px%7D%2Ehas%2Dfeedback%20label%2Esr%2Donly%7E%2Eform%2Dcontrol%2Dfeedback%7Btop%3A0%7D%2Ehelp%2Dblock%7Bdisplay%3Ablock%3Bmargin%2Dtop%3A5px%3Bmargin%2Dbottom%3A10px%3Bcolor%3A%23737373%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Eform%2Dinline%20%2Eform%2Dgroup%7Bdisplay%3Ainline%2Dblock%3Bmargin%2Dbottom%3A0%3Bvertical%2Dalign%3Amiddle%7D%2Eform%2Dinline%20%2Eform%2Dcontrol%7Bdisplay%3Ainline%2Dblock%3Bwidth%3Aauto%3Bvertical%2Dalign%3Amiddle%7D%2Eform%2Dinline%20%2Eform%2Dcontrol%2Dstatic%7Bdisplay%3Ainline%2Dblock%7D%2Eform%2Dinline%20%2Einput%2Dgroup%7Bdisplay%3Ainline%2Dtable%3Bvertical%2Dalign%3Amiddle%7D%2Eform%2Dinline%20%2Einput%2Dgroup%20%2Eform%2Dcontrol%2C%2Eform%2Dinline%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Daddon%2C%2Eform%2Dinline%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Dbtn%7Bwidth%3Aauto%7D%2Eform%2Dinline%20%2Einput%2Dgroup%3E%2Eform%2Dcontrol%7Bwidth%3A100%25%7D%2Eform%2Dinline%20%2Econtrol%2Dlabel%7Bmargin%2Dbottom%3A0%3Bvertical%2Dalign%3Amiddle%7D%2Eform%2Dinline%20%2Echeckbox%2C%2Eform%2Dinline%20%2Eradio%7Bdisplay%3Ainline%2Dblock%3Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A0%3Bvertical%2Dalign%3Amiddle%7D%2Eform%2Dinline%20%2Echeckbox%20label%2C%2Eform%2Dinline%20%2Eradio%20label%7Bpadding%2Dleft%3A0%7D%2Eform%2Dinline%20%2Echeckbox%20input%5Btype%3Dcheckbox%5D%2C%2Eform%2Dinline%20%2Eradio%20input%5Btype%3Dradio%5D%7Bposition%3Arelative%3Bmargin%2Dleft%3A0%7D%2Eform%2Dinline%20%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%2Dfeedback%7Btop%3A0%7D%7D%2Eform%2Dhorizontal%20%2Echeckbox%2C%2Eform%2Dhorizontal%20%2Echeckbox%2Dinline%2C%2Eform%2Dhorizontal%20%2Eradio%2C%2Eform%2Dhorizontal%20%2Eradio%2Dinline%7Bpadding%2Dtop%3A7px%3Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A0%7D%2Eform%2Dhorizontal%20%2Echeckbox%2C%2Eform%2Dhorizontal%20%2Eradio%7Bmin%2Dheight%3A27px%7D%2Eform%2Dhorizontal%20%2Eform%2Dgroup%7Bmargin%2Dright%3A%2D15px%3Bmargin%2Dleft%3A%2D15px%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Eform%2Dhorizontal%20%2Econtrol%2Dlabel%7Bpadding%2Dtop%3A7px%3Bmargin%2Dbottom%3A0%3Btext%2Dalign%3Aright%7D%7D%2Eform%2Dhorizontal%20%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%2Dfeedback%7Bright%3A15px%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Eform%2Dhorizontal%20%2Eform%2Dgroup%2Dlg%20%2Econtrol%2Dlabel%7Bpadding%2Dtop%3A14%2E33px%3Bfont%2Dsize%3A18px%7D%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Eform%2Dhorizontal%20%2Eform%2Dgroup%2Dsm%20%2Econtrol%2Dlabel%7Bpadding%2Dtop%3A6px%3Bfont%2Dsize%3A12px%7D%7D%2Ebtn%7Bdisplay%3Ainline%2Dblock%3Bpadding%3A6px%2012px%3Bmargin%2Dbottom%3A0%3Bfont%2Dsize%3A14px%3Bfont%2Dweight%3A400%3Bline%2Dheight%3A1%2E42857143%3Btext%2Dalign%3Acenter%3Bwhite%2Dspace%3Anowrap%3Bvertical%2Dalign%3Amiddle%3B%2Dms%2Dtouch%2Daction%3Amanipulation%3Btouch%2Daction%3Amanipulation%3Bcursor%3Apointer%3B%2Dwebkit%2Duser%2Dselect%3Anone%3B%2Dmoz%2Duser%2Dselect%3Anone%3B%2Dms%2Duser%2Dselect%3Anone%3Buser%2Dselect%3Anone%3Bbackground%2Dimage%3Anone%3Bborder%3A1px%20solid%20transparent%3Bborder%2Dradius%3A4px%7D%2Ebtn%2Eactive%2Efocus%2C%2Ebtn%2Eactive%3Afocus%2C%2Ebtn%2Efocus%2C%2Ebtn%3Aactive%2Efocus%2C%2Ebtn%3Aactive%3Afocus%2C%2Ebtn%3Afocus%7Boutline%3Athin%20dotted%3Boutline%3A5px%20auto%20%2Dwebkit%2Dfocus%2Dring%2Dcolor%3Boutline%2Doffset%3A%2D2px%7D%2Ebtn%2Efocus%2C%2Ebtn%3Afocus%2C%2Ebtn%3Ahover%7Bcolor%3A%23333%3Btext%2Ddecoration%3Anone%7D%2Ebtn%2Eactive%2C%2Ebtn%3Aactive%7Bbackground%2Dimage%3Anone%3Boutline%3A0%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%203px%205px%20rgba%280%2C0%2C0%2C%2E125%29%3Bbox%2Dshadow%3Ainset%200%203px%205px%20rgba%280%2C0%2C0%2C%2E125%29%7D%2Ebtn%2Edisabled%2C%2Ebtn%5Bdisabled%5D%2Cfieldset%5Bdisabled%5D%20%2Ebtn%7Bcursor%3Anot%2Dallowed%3Bfilter%3Aalpha%28opacity%3D65%29%3B%2Dwebkit%2Dbox%2Dshadow%3Anone%3Bbox%2Dshadow%3Anone%3Bopacity%3A%2E65%7Da%2Ebtn%2Edisabled%2Cfieldset%5Bdisabled%5D%20a%2Ebtn%7Bpointer%2Devents%3Anone%7D%2Ebtn%2Ddefault%7Bcolor%3A%23333%3Bbackground%2Dcolor%3A%23fff%3Bborder%2Dcolor%3A%23ccc%7D%2Ebtn%2Ddefault%2Efocus%2C%2Ebtn%2Ddefault%3Afocus%7Bcolor%3A%23333%3Bbackground%2Dcolor%3A%23e6e6e6%3Bborder%2Dcolor%3A%238c8c8c%7D%2Ebtn%2Ddefault%3Ahover%7Bcolor%3A%23333%3Bbackground%2Dcolor%3A%23e6e6e6%3Bborder%2Dcolor%3A%23adadad%7D%2Ebtn%2Ddefault%2Eactive%2C%2Ebtn%2Ddefault%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddefault%7Bcolor%3A%23333%3Bbackground%2Dcolor%3A%23e6e6e6%3Bborder%2Dcolor%3A%23adadad%7D%2Ebtn%2Ddefault%2Eactive%2Efocus%2C%2Ebtn%2Ddefault%2Eactive%3Afocus%2C%2Ebtn%2Ddefault%2Eactive%3Ahover%2C%2Ebtn%2Ddefault%3Aactive%2Efocus%2C%2Ebtn%2Ddefault%3Aactive%3Afocus%2C%2Ebtn%2Ddefault%3Aactive%3Ahover%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddefault%2Efocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddefault%3Afocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddefault%3Ahover%7Bcolor%3A%23333%3Bbackground%2Dcolor%3A%23d4d4d4%3Bborder%2Dcolor%3A%238c8c8c%7D%2Ebtn%2Ddefault%2Eactive%2C%2Ebtn%2Ddefault%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddefault%7Bbackground%2Dimage%3Anone%7D%2Ebtn%2Ddefault%2Edisabled%2C%2Ebtn%2Ddefault%2Edisabled%2Eactive%2C%2Ebtn%2Ddefault%2Edisabled%2Efocus%2C%2Ebtn%2Ddefault%2Edisabled%3Aactive%2C%2Ebtn%2Ddefault%2Edisabled%3Afocus%2C%2Ebtn%2Ddefault%2Edisabled%3Ahover%2C%2Ebtn%2Ddefault%5Bdisabled%5D%2C%2Ebtn%2Ddefault%5Bdisabled%5D%2Eactive%2C%2Ebtn%2Ddefault%5Bdisabled%5D%2Efocus%2C%2Ebtn%2Ddefault%5Bdisabled%5D%3Aactive%2C%2Ebtn%2Ddefault%5Bdisabled%5D%3Afocus%2C%2Ebtn%2Ddefault%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%2Eactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%2Efocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%3Aactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddefault%3Ahover%7Bbackground%2Dcolor%3A%23fff%3Bborder%2Dcolor%3A%23ccc%7D%2Ebtn%2Ddefault%20%2Ebadge%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23333%7D%2Ebtn%2Dprimary%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23337ab7%3Bborder%2Dcolor%3A%232e6da4%7D%2Ebtn%2Dprimary%2Efocus%2C%2Ebtn%2Dprimary%3Afocus%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23286090%3Bborder%2Dcolor%3A%23122b40%7D%2Ebtn%2Dprimary%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23286090%3Bborder%2Dcolor%3A%23204d74%7D%2Ebtn%2Dprimary%2Eactive%2C%2Ebtn%2Dprimary%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dprimary%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23286090%3Bborder%2Dcolor%3A%23204d74%7D%2Ebtn%2Dprimary%2Eactive%2Efocus%2C%2Ebtn%2Dprimary%2Eactive%3Afocus%2C%2Ebtn%2Dprimary%2Eactive%3Ahover%2C%2Ebtn%2Dprimary%3Aactive%2Efocus%2C%2Ebtn%2Dprimary%3Aactive%3Afocus%2C%2Ebtn%2Dprimary%3Aactive%3Ahover%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dprimary%2Efocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dprimary%3Afocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dprimary%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23204d74%3Bborder%2Dcolor%3A%23122b40%7D%2Ebtn%2Dprimary%2Eactive%2C%2Ebtn%2Dprimary%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dprimary%7Bbackground%2Dimage%3Anone%7D%2Ebtn%2Dprimary%2Edisabled%2C%2Ebtn%2Dprimary%2Edisabled%2Eactive%2C%2Ebtn%2Dprimary%2Edisabled%2Efocus%2C%2Ebtn%2Dprimary%2Edisabled%3Aactive%2C%2Ebtn%2Dprimary%2Edisabled%3Afocus%2C%2Ebtn%2Dprimary%2Edisabled%3Ahover%2C%2Ebtn%2Dprimary%5Bdisabled%5D%2C%2Ebtn%2Dprimary%5Bdisabled%5D%2Eactive%2C%2Ebtn%2Dprimary%5Bdisabled%5D%2Efocus%2C%2Ebtn%2Dprimary%5Bdisabled%5D%3Aactive%2C%2Ebtn%2Dprimary%5Bdisabled%5D%3Afocus%2C%2Ebtn%2Dprimary%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%2Eactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%2Efocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%3Aactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dprimary%3Ahover%7Bbackground%2Dcolor%3A%23337ab7%3Bborder%2Dcolor%3A%232e6da4%7D%2Ebtn%2Dprimary%20%2Ebadge%7Bcolor%3A%23337ab7%3Bbackground%2Dcolor%3A%23fff%7D%2Ebtn%2Dsuccess%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%235cb85c%3Bborder%2Dcolor%3A%234cae4c%7D%2Ebtn%2Dsuccess%2Efocus%2C%2Ebtn%2Dsuccess%3Afocus%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23449d44%3Bborder%2Dcolor%3A%23255625%7D%2Ebtn%2Dsuccess%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23449d44%3Bborder%2Dcolor%3A%23398439%7D%2Ebtn%2Dsuccess%2Eactive%2C%2Ebtn%2Dsuccess%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dsuccess%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23449d44%3Bborder%2Dcolor%3A%23398439%7D%2Ebtn%2Dsuccess%2Eactive%2Efocus%2C%2Ebtn%2Dsuccess%2Eactive%3Afocus%2C%2Ebtn%2Dsuccess%2Eactive%3Ahover%2C%2Ebtn%2Dsuccess%3Aactive%2Efocus%2C%2Ebtn%2Dsuccess%3Aactive%3Afocus%2C%2Ebtn%2Dsuccess%3Aactive%3Ahover%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dsuccess%2Efocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dsuccess%3Afocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dsuccess%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23398439%3Bborder%2Dcolor%3A%23255625%7D%2Ebtn%2Dsuccess%2Eactive%2C%2Ebtn%2Dsuccess%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dsuccess%7Bbackground%2Dimage%3Anone%7D%2Ebtn%2Dsuccess%2Edisabled%2C%2Ebtn%2Dsuccess%2Edisabled%2Eactive%2C%2Ebtn%2Dsuccess%2Edisabled%2Efocus%2C%2Ebtn%2Dsuccess%2Edisabled%3Aactive%2C%2Ebtn%2Dsuccess%2Edisabled%3Afocus%2C%2Ebtn%2Dsuccess%2Edisabled%3Ahover%2C%2Ebtn%2Dsuccess%5Bdisabled%5D%2C%2Ebtn%2Dsuccess%5Bdisabled%5D%2Eactive%2C%2Ebtn%2Dsuccess%5Bdisabled%5D%2Efocus%2C%2Ebtn%2Dsuccess%5Bdisabled%5D%3Aactive%2C%2Ebtn%2Dsuccess%5Bdisabled%5D%3Afocus%2C%2Ebtn%2Dsuccess%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%2Eactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%2Efocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%3Aactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dsuccess%3Ahover%7Bbackground%2Dcolor%3A%235cb85c%3Bborder%2Dcolor%3A%234cae4c%7D%2Ebtn%2Dsuccess%20%2Ebadge%7Bcolor%3A%235cb85c%3Bbackground%2Dcolor%3A%23fff%7D%2Ebtn%2Dinfo%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%235bc0de%3Bborder%2Dcolor%3A%2346b8da%7D%2Ebtn%2Dinfo%2Efocus%2C%2Ebtn%2Dinfo%3Afocus%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%2331b0d5%3Bborder%2Dcolor%3A%231b6d85%7D%2Ebtn%2Dinfo%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%2331b0d5%3Bborder%2Dcolor%3A%23269abc%7D%2Ebtn%2Dinfo%2Eactive%2C%2Ebtn%2Dinfo%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dinfo%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%2331b0d5%3Bborder%2Dcolor%3A%23269abc%7D%2Ebtn%2Dinfo%2Eactive%2Efocus%2C%2Ebtn%2Dinfo%2Eactive%3Afocus%2C%2Ebtn%2Dinfo%2Eactive%3Ahover%2C%2Ebtn%2Dinfo%3Aactive%2Efocus%2C%2Ebtn%2Dinfo%3Aactive%3Afocus%2C%2Ebtn%2Dinfo%3Aactive%3Ahover%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dinfo%2Efocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dinfo%3Afocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dinfo%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23269abc%3Bborder%2Dcolor%3A%231b6d85%7D%2Ebtn%2Dinfo%2Eactive%2C%2Ebtn%2Dinfo%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dinfo%7Bbackground%2Dimage%3Anone%7D%2Ebtn%2Dinfo%2Edisabled%2C%2Ebtn%2Dinfo%2Edisabled%2Eactive%2C%2Ebtn%2Dinfo%2Edisabled%2Efocus%2C%2Ebtn%2Dinfo%2Edisabled%3Aactive%2C%2Ebtn%2Dinfo%2Edisabled%3Afocus%2C%2Ebtn%2Dinfo%2Edisabled%3Ahover%2C%2Ebtn%2Dinfo%5Bdisabled%5D%2C%2Ebtn%2Dinfo%5Bdisabled%5D%2Eactive%2C%2Ebtn%2Dinfo%5Bdisabled%5D%2Efocus%2C%2Ebtn%2Dinfo%5Bdisabled%5D%3Aactive%2C%2Ebtn%2Dinfo%5Bdisabled%5D%3Afocus%2C%2Ebtn%2Dinfo%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%2Eactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%2Efocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%3Aactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dinfo%3Ahover%7Bbackground%2Dcolor%3A%235bc0de%3Bborder%2Dcolor%3A%2346b8da%7D%2Ebtn%2Dinfo%20%2Ebadge%7Bcolor%3A%235bc0de%3Bbackground%2Dcolor%3A%23fff%7D%2Ebtn%2Dwarning%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23f0ad4e%3Bborder%2Dcolor%3A%23eea236%7D%2Ebtn%2Dwarning%2Efocus%2C%2Ebtn%2Dwarning%3Afocus%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23ec971f%3Bborder%2Dcolor%3A%23985f0d%7D%2Ebtn%2Dwarning%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23ec971f%3Bborder%2Dcolor%3A%23d58512%7D%2Ebtn%2Dwarning%2Eactive%2C%2Ebtn%2Dwarning%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dwarning%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23ec971f%3Bborder%2Dcolor%3A%23d58512%7D%2Ebtn%2Dwarning%2Eactive%2Efocus%2C%2Ebtn%2Dwarning%2Eactive%3Afocus%2C%2Ebtn%2Dwarning%2Eactive%3Ahover%2C%2Ebtn%2Dwarning%3Aactive%2Efocus%2C%2Ebtn%2Dwarning%3Aactive%3Afocus%2C%2Ebtn%2Dwarning%3Aactive%3Ahover%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dwarning%2Efocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dwarning%3Afocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dwarning%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23d58512%3Bborder%2Dcolor%3A%23985f0d%7D%2Ebtn%2Dwarning%2Eactive%2C%2Ebtn%2Dwarning%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Dwarning%7Bbackground%2Dimage%3Anone%7D%2Ebtn%2Dwarning%2Edisabled%2C%2Ebtn%2Dwarning%2Edisabled%2Eactive%2C%2Ebtn%2Dwarning%2Edisabled%2Efocus%2C%2Ebtn%2Dwarning%2Edisabled%3Aactive%2C%2Ebtn%2Dwarning%2Edisabled%3Afocus%2C%2Ebtn%2Dwarning%2Edisabled%3Ahover%2C%2Ebtn%2Dwarning%5Bdisabled%5D%2C%2Ebtn%2Dwarning%5Bdisabled%5D%2Eactive%2C%2Ebtn%2Dwarning%5Bdisabled%5D%2Efocus%2C%2Ebtn%2Dwarning%5Bdisabled%5D%3Aactive%2C%2Ebtn%2Dwarning%5Bdisabled%5D%3Afocus%2C%2Ebtn%2Dwarning%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%2Eactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%2Efocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%3Aactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dwarning%3Ahover%7Bbackground%2Dcolor%3A%23f0ad4e%3Bborder%2Dcolor%3A%23eea236%7D%2Ebtn%2Dwarning%20%2Ebadge%7Bcolor%3A%23f0ad4e%3Bbackground%2Dcolor%3A%23fff%7D%2Ebtn%2Ddanger%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23d9534f%3Bborder%2Dcolor%3A%23d43f3a%7D%2Ebtn%2Ddanger%2Efocus%2C%2Ebtn%2Ddanger%3Afocus%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23c9302c%3Bborder%2Dcolor%3A%23761c19%7D%2Ebtn%2Ddanger%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23c9302c%3Bborder%2Dcolor%3A%23ac2925%7D%2Ebtn%2Ddanger%2Eactive%2C%2Ebtn%2Ddanger%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddanger%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23c9302c%3Bborder%2Dcolor%3A%23ac2925%7D%2Ebtn%2Ddanger%2Eactive%2Efocus%2C%2Ebtn%2Ddanger%2Eactive%3Afocus%2C%2Ebtn%2Ddanger%2Eactive%3Ahover%2C%2Ebtn%2Ddanger%3Aactive%2Efocus%2C%2Ebtn%2Ddanger%3Aactive%3Afocus%2C%2Ebtn%2Ddanger%3Aactive%3Ahover%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddanger%2Efocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddanger%3Afocus%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddanger%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23ac2925%3Bborder%2Dcolor%3A%23761c19%7D%2Ebtn%2Ddanger%2Eactive%2C%2Ebtn%2Ddanger%3Aactive%2C%2Eopen%3E%2Edropdown%2Dtoggle%2Ebtn%2Ddanger%7Bbackground%2Dimage%3Anone%7D%2Ebtn%2Ddanger%2Edisabled%2C%2Ebtn%2Ddanger%2Edisabled%2Eactive%2C%2Ebtn%2Ddanger%2Edisabled%2Efocus%2C%2Ebtn%2Ddanger%2Edisabled%3Aactive%2C%2Ebtn%2Ddanger%2Edisabled%3Afocus%2C%2Ebtn%2Ddanger%2Edisabled%3Ahover%2C%2Ebtn%2Ddanger%5Bdisabled%5D%2C%2Ebtn%2Ddanger%5Bdisabled%5D%2Eactive%2C%2Ebtn%2Ddanger%5Bdisabled%5D%2Efocus%2C%2Ebtn%2Ddanger%5Bdisabled%5D%3Aactive%2C%2Ebtn%2Ddanger%5Bdisabled%5D%3Afocus%2C%2Ebtn%2Ddanger%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%2Eactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%2Efocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%3Aactive%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Ddanger%3Ahover%7Bbackground%2Dcolor%3A%23d9534f%3Bborder%2Dcolor%3A%23d43f3a%7D%2Ebtn%2Ddanger%20%2Ebadge%7Bcolor%3A%23d9534f%3Bbackground%2Dcolor%3A%23fff%7D%2Ebtn%2Dlink%7Bfont%2Dweight%3A400%3Bcolor%3A%23337ab7%3Bborder%2Dradius%3A0%7D%2Ebtn%2Dlink%2C%2Ebtn%2Dlink%2Eactive%2C%2Ebtn%2Dlink%3Aactive%2C%2Ebtn%2Dlink%5Bdisabled%5D%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dlink%7Bbackground%2Dcolor%3Atransparent%3B%2Dwebkit%2Dbox%2Dshadow%3Anone%3Bbox%2Dshadow%3Anone%7D%2Ebtn%2Dlink%2C%2Ebtn%2Dlink%3Aactive%2C%2Ebtn%2Dlink%3Afocus%2C%2Ebtn%2Dlink%3Ahover%7Bborder%2Dcolor%3Atransparent%7D%2Ebtn%2Dlink%3Afocus%2C%2Ebtn%2Dlink%3Ahover%7Bcolor%3A%2323527c%3Btext%2Ddecoration%3Aunderline%3Bbackground%2Dcolor%3Atransparent%7D%2Ebtn%2Dlink%5Bdisabled%5D%3Afocus%2C%2Ebtn%2Dlink%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dlink%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Ebtn%2Dlink%3Ahover%7Bcolor%3A%23777%3Btext%2Ddecoration%3Anone%7D%2Ebtn%2Dgroup%2Dlg%3E%2Ebtn%2C%2Ebtn%2Dlg%7Bpadding%3A10px%2016px%3Bfont%2Dsize%3A18px%3Bline%2Dheight%3A1%2E3333333%3Bborder%2Dradius%3A6px%7D%2Ebtn%2Dgroup%2Dsm%3E%2Ebtn%2C%2Ebtn%2Dsm%7Bpadding%3A5px%2010px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5%3Bborder%2Dradius%3A3px%7D%2Ebtn%2Dgroup%2Dxs%3E%2Ebtn%2C%2Ebtn%2Dxs%7Bpadding%3A1px%205px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5%3Bborder%2Dradius%3A3px%7D%2Ebtn%2Dblock%7Bdisplay%3Ablock%3Bwidth%3A100%25%7D%2Ebtn%2Dblock%2B%2Ebtn%2Dblock%7Bmargin%2Dtop%3A5px%7Dinput%5Btype%3Dbutton%5D%2Ebtn%2Dblock%2Cinput%5Btype%3Dreset%5D%2Ebtn%2Dblock%2Cinput%5Btype%3Dsubmit%5D%2Ebtn%2Dblock%7Bwidth%3A100%25%7D%2Efade%7Bopacity%3A0%3B%2Dwebkit%2Dtransition%3Aopacity%20%2E15s%20linear%3B%2Do%2Dtransition%3Aopacity%20%2E15s%20linear%3Btransition%3Aopacity%20%2E15s%20linear%7D%2Efade%2Ein%7Bopacity%3A1%7D%2Ecollapse%7Bdisplay%3Anone%7D%2Ecollapse%2Ein%7Bdisplay%3Ablock%7Dtr%2Ecollapse%2Ein%7Bdisplay%3Atable%2Drow%7Dtbody%2Ecollapse%2Ein%7Bdisplay%3Atable%2Drow%2Dgroup%7D%2Ecollapsing%7Bposition%3Arelative%3Bheight%3A0%3Boverflow%3Ahidden%3B%2Dwebkit%2Dtransition%2Dtiming%2Dfunction%3Aease%3B%2Do%2Dtransition%2Dtiming%2Dfunction%3Aease%3Btransition%2Dtiming%2Dfunction%3Aease%3B%2Dwebkit%2Dtransition%2Dduration%3A%2E35s%3B%2Do%2Dtransition%2Dduration%3A%2E35s%3Btransition%2Dduration%3A%2E35s%3B%2Dwebkit%2Dtransition%2Dproperty%3Aheight%2Cvisibility%3B%2Do%2Dtransition%2Dproperty%3Aheight%2Cvisibility%3Btransition%2Dproperty%3Aheight%2Cvisibility%7D%2Ecaret%7Bdisplay%3Ainline%2Dblock%3Bwidth%3A0%3Bheight%3A0%3Bmargin%2Dleft%3A2px%3Bvertical%2Dalign%3Amiddle%3Bborder%2Dtop%3A4px%20dashed%3Bborder%2Dtop%3A4px%20solid%5C9%3Bborder%2Dright%3A4px%20solid%20transparent%3Bborder%2Dleft%3A4px%20solid%20transparent%7D%2Edropdown%2C%2Edropup%7Bposition%3Arelative%7D%2Edropdown%2Dtoggle%3Afocus%7Boutline%3A0%7D%2Edropdown%2Dmenu%7Bposition%3Aabsolute%3Btop%3A100%25%3Bleft%3A0%3Bz%2Dindex%3A1000%3Bdisplay%3Anone%3Bfloat%3Aleft%3Bmin%2Dwidth%3A160px%3Bpadding%3A5px%200%3Bmargin%3A2px%200%200%3Bfont%2Dsize%3A14px%3Btext%2Dalign%3Aleft%3Blist%2Dstyle%3Anone%3Bbackground%2Dcolor%3A%23fff%3B%2Dwebkit%2Dbackground%2Dclip%3Apadding%2Dbox%3Bbackground%2Dclip%3Apadding%2Dbox%3Bborder%3A1px%20solid%20%23ccc%3Bborder%3A1px%20solid%20rgba%280%2C0%2C0%2C%2E15%29%3Bborder%2Dradius%3A4px%3B%2Dwebkit%2Dbox%2Dshadow%3A0%206px%2012px%20rgba%280%2C0%2C0%2C%2E175%29%3Bbox%2Dshadow%3A0%206px%2012px%20rgba%280%2C0%2C0%2C%2E175%29%7D%2Edropdown%2Dmenu%2Epull%2Dright%7Bright%3A0%3Bleft%3Aauto%7D%2Edropdown%2Dmenu%20%2Edivider%7Bheight%3A1px%3Bmargin%3A9px%200%3Boverflow%3Ahidden%3Bbackground%2Dcolor%3A%23e5e5e5%7D%2Edropdown%2Dmenu%3Eli%3Ea%7Bdisplay%3Ablock%3Bpadding%3A3px%2020px%3Bclear%3Aboth%3Bfont%2Dweight%3A400%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23333%3Bwhite%2Dspace%3Anowrap%7D%2Edropdown%2Dmenu%3Eli%3Ea%3Afocus%2C%2Edropdown%2Dmenu%3Eli%3Ea%3Ahover%7Bcolor%3A%23262626%3Btext%2Ddecoration%3Anone%3Bbackground%2Dcolor%3A%23f5f5f5%7D%2Edropdown%2Dmenu%3E%2Eactive%3Ea%2C%2Edropdown%2Dmenu%3E%2Eactive%3Ea%3Afocus%2C%2Edropdown%2Dmenu%3E%2Eactive%3Ea%3Ahover%7Bcolor%3A%23fff%3Btext%2Ddecoration%3Anone%3Bbackground%2Dcolor%3A%23337ab7%3Boutline%3A0%7D%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%2C%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Afocus%2C%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Ahover%7Bcolor%3A%23777%7D%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Afocus%2C%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Ahover%7Btext%2Ddecoration%3Anone%3Bcursor%3Anot%2Dallowed%3Bbackground%2Dcolor%3Atransparent%3Bbackground%2Dimage%3Anone%3Bfilter%3Aprogid%3ADXImageTransform%2EMicrosoft%2Egradient%28enabled%3Dfalse%29%7D%2Eopen%3E%2Edropdown%2Dmenu%7Bdisplay%3Ablock%7D%2Eopen%3Ea%7Boutline%3A0%7D%2Edropdown%2Dmenu%2Dright%7Bright%3A0%3Bleft%3Aauto%7D%2Edropdown%2Dmenu%2Dleft%7Bright%3Aauto%3Bleft%3A0%7D%2Edropdown%2Dheader%7Bdisplay%3Ablock%3Bpadding%3A3px%2020px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23777%3Bwhite%2Dspace%3Anowrap%7D%2Edropdown%2Dbackdrop%7Bposition%3Afixed%3Btop%3A0%3Bright%3A0%3Bbottom%3A0%3Bleft%3A0%3Bz%2Dindex%3A990%7D%2Epull%2Dright%3E%2Edropdown%2Dmenu%7Bright%3A0%3Bleft%3Aauto%7D%2Edropup%20%2Ecaret%2C%2Enavbar%2Dfixed%2Dbottom%20%2Edropdown%20%2Ecaret%7Bcontent%3A%22%22%3Bborder%2Dtop%3A0%3Bborder%2Dbottom%3A4px%20dashed%3Bborder%2Dbottom%3A4px%20solid%5C9%7D%2Edropup%20%2Edropdown%2Dmenu%2C%2Enavbar%2Dfixed%2Dbottom%20%2Edropdown%20%2Edropdown%2Dmenu%7Btop%3Aauto%3Bbottom%3A100%25%3Bmargin%2Dbottom%3A2px%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dright%20%2Edropdown%2Dmenu%7Bright%3A0%3Bleft%3Aauto%7D%2Enavbar%2Dright%20%2Edropdown%2Dmenu%2Dleft%7Bright%3Aauto%3Bleft%3A0%7D%7D%2Ebtn%2Dgroup%2C%2Ebtn%2Dgroup%2Dvertical%7Bposition%3Arelative%3Bdisplay%3Ainline%2Dblock%3Bvertical%2Dalign%3Amiddle%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2C%2Ebtn%2Dgroup%3E%2Ebtn%7Bposition%3Arelative%3Bfloat%3Aleft%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Eactive%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%3Aactive%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%3Afocus%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%3Ahover%2C%2Ebtn%2Dgroup%3E%2Ebtn%2Eactive%2C%2Ebtn%2Dgroup%3E%2Ebtn%3Aactive%2C%2Ebtn%2Dgroup%3E%2Ebtn%3Afocus%2C%2Ebtn%2Dgroup%3E%2Ebtn%3Ahover%7Bz%2Dindex%3A2%7D%2Ebtn%2Dgroup%20%2Ebtn%2B%2Ebtn%2C%2Ebtn%2Dgroup%20%2Ebtn%2B%2Ebtn%2Dgroup%2C%2Ebtn%2Dgroup%20%2Ebtn%2Dgroup%2B%2Ebtn%2C%2Ebtn%2Dgroup%20%2Ebtn%2Dgroup%2B%2Ebtn%2Dgroup%7Bmargin%2Dleft%3A%2D1px%7D%2Ebtn%2Dtoolbar%7Bmargin%2Dleft%3A%2D5px%7D%2Ebtn%2Dtoolbar%20%2Ebtn%2C%2Ebtn%2Dtoolbar%20%2Ebtn%2Dgroup%2C%2Ebtn%2Dtoolbar%20%2Einput%2Dgroup%7Bfloat%3Aleft%7D%2Ebtn%2Dtoolbar%3E%2Ebtn%2C%2Ebtn%2Dtoolbar%3E%2Ebtn%2Dgroup%2C%2Ebtn%2Dtoolbar%3E%2Einput%2Dgroup%7Bmargin%2Dleft%3A5px%7D%2Ebtn%2Dgroup%3E%2Ebtn%3Anot%28%3Afirst%2Dchild%29%3Anot%28%3Alast%2Dchild%29%3Anot%28%2Edropdown%2Dtoggle%29%7Bborder%2Dradius%3A0%7D%2Ebtn%2Dgroup%3E%2Ebtn%3Afirst%2Dchild%7Bmargin%2Dleft%3A0%7D%2Ebtn%2Dgroup%3E%2Ebtn%3Afirst%2Dchild%3Anot%28%3Alast%2Dchild%29%3Anot%28%2Edropdown%2Dtoggle%29%7Bborder%2Dtop%2Dright%2Dradius%3A0%3Bborder%2Dbottom%2Dright%2Dradius%3A0%7D%2Ebtn%2Dgroup%3E%2Ebtn%3Alast%2Dchild%3Anot%28%3Afirst%2Dchild%29%2C%2Ebtn%2Dgroup%3E%2Edropdown%2Dtoggle%3Anot%28%3Afirst%2Dchild%29%7Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dbottom%2Dleft%2Dradius%3A0%7D%2Ebtn%2Dgroup%3E%2Ebtn%2Dgroup%7Bfloat%3Aleft%7D%2Ebtn%2Dgroup%3E%2Ebtn%2Dgroup%3Anot%28%3Afirst%2Dchild%29%3Anot%28%3Alast%2Dchild%29%3E%2Ebtn%7Bborder%2Dradius%3A0%7D%2Ebtn%2Dgroup%3E%2Ebtn%2Dgroup%3Afirst%2Dchild%3Anot%28%3Alast%2Dchild%29%3E%2Ebtn%3Alast%2Dchild%2C%2Ebtn%2Dgroup%3E%2Ebtn%2Dgroup%3Afirst%2Dchild%3Anot%28%3Alast%2Dchild%29%3E%2Edropdown%2Dtoggle%7Bborder%2Dtop%2Dright%2Dradius%3A0%3Bborder%2Dbottom%2Dright%2Dradius%3A0%7D%2Ebtn%2Dgroup%3E%2Ebtn%2Dgroup%3Alast%2Dchild%3Anot%28%3Afirst%2Dchild%29%3E%2Ebtn%3Afirst%2Dchild%7Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dbottom%2Dleft%2Dradius%3A0%7D%2Ebtn%2Dgroup%20%2Edropdown%2Dtoggle%3Aactive%2C%2Ebtn%2Dgroup%2Eopen%20%2Edropdown%2Dtoggle%7Boutline%3A0%7D%2Ebtn%2Dgroup%3E%2Ebtn%2B%2Edropdown%2Dtoggle%7Bpadding%2Dright%3A8px%3Bpadding%2Dleft%3A8px%7D%2Ebtn%2Dgroup%3E%2Ebtn%2Dlg%2B%2Edropdown%2Dtoggle%7Bpadding%2Dright%3A12px%3Bpadding%2Dleft%3A12px%7D%2Ebtn%2Dgroup%2Eopen%20%2Edropdown%2Dtoggle%7B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%203px%205px%20rgba%280%2C0%2C0%2C%2E125%29%3Bbox%2Dshadow%3Ainset%200%203px%205px%20rgba%280%2C0%2C0%2C%2E125%29%7D%2Ebtn%2Dgroup%2Eopen%20%2Edropdown%2Dtoggle%2Ebtn%2Dlink%7B%2Dwebkit%2Dbox%2Dshadow%3Anone%3Bbox%2Dshadow%3Anone%7D%2Ebtn%20%2Ecaret%7Bmargin%2Dleft%3A0%7D%2Ebtn%2Dlg%20%2Ecaret%7Bborder%2Dwidth%3A5px%205px%200%3Bborder%2Dbottom%2Dwidth%3A0%7D%2Edropup%20%2Ebtn%2Dlg%20%2Ecaret%7Bborder%2Dwidth%3A0%205px%205px%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3E%2Ebtn%7Bdisplay%3Ablock%3Bfloat%3Anone%3Bwidth%3A100%25%3Bmax%2Dwidth%3A100%25%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3E%2Ebtn%7Bfloat%3Anone%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2B%2Ebtn%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2B%2Ebtn%2Dgroup%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%2B%2Ebtn%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%2B%2Ebtn%2Dgroup%7Bmargin%2Dtop%3A%2D1px%3Bmargin%2Dleft%3A0%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%3Anot%28%3Afirst%2Dchild%29%3Anot%28%3Alast%2Dchild%29%7Bborder%2Dradius%3A0%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%3Afirst%2Dchild%3Anot%28%3Alast%2Dchild%29%7Bborder%2Dtop%2Dright%2Dradius%3A4px%3Bborder%2Dbottom%2Dright%2Dradius%3A0%3Bborder%2Dbottom%2Dleft%2Dradius%3A0%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%3Alast%2Dchild%3Anot%28%3Afirst%2Dchild%29%7Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dtop%2Dright%2Dradius%3A0%3Bborder%2Dbottom%2Dleft%2Dradius%3A4px%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3Anot%28%3Afirst%2Dchild%29%3Anot%28%3Alast%2Dchild%29%3E%2Ebtn%7Bborder%2Dradius%3A0%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3Afirst%2Dchild%3Anot%28%3Alast%2Dchild%29%3E%2Ebtn%3Alast%2Dchild%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3Afirst%2Dchild%3Anot%28%3Alast%2Dchild%29%3E%2Edropdown%2Dtoggle%7Bborder%2Dbottom%2Dright%2Dradius%3A0%3Bborder%2Dbottom%2Dleft%2Dradius%3A0%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3Alast%2Dchild%3Anot%28%3Afirst%2Dchild%29%3E%2Ebtn%3Afirst%2Dchild%7Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dtop%2Dright%2Dradius%3A0%7D%2Ebtn%2Dgroup%2Djustified%7Bdisplay%3Atable%3Bwidth%3A100%25%3Btable%2Dlayout%3Afixed%3Bborder%2Dcollapse%3Aseparate%7D%2Ebtn%2Dgroup%2Djustified%3E%2Ebtn%2C%2Ebtn%2Dgroup%2Djustified%3E%2Ebtn%2Dgroup%7Bdisplay%3Atable%2Dcell%3Bfloat%3Anone%3Bwidth%3A1%25%7D%2Ebtn%2Dgroup%2Djustified%3E%2Ebtn%2Dgroup%20%2Ebtn%7Bwidth%3A100%25%7D%2Ebtn%2Dgroup%2Djustified%3E%2Ebtn%2Dgroup%20%2Edropdown%2Dmenu%7Bleft%3Aauto%7D%5Bdata%2Dtoggle%3Dbuttons%5D%3E%2Ebtn%20input%5Btype%3Dcheckbox%5D%2C%5Bdata%2Dtoggle%3Dbuttons%5D%3E%2Ebtn%20input%5Btype%3Dradio%5D%2C%5Bdata%2Dtoggle%3Dbuttons%5D%3E%2Ebtn%2Dgroup%3E%2Ebtn%20input%5Btype%3Dcheckbox%5D%2C%5Bdata%2Dtoggle%3Dbuttons%5D%3E%2Ebtn%2Dgroup%3E%2Ebtn%20input%5Btype%3Dradio%5D%7Bposition%3Aabsolute%3Bclip%3Arect%280%2C0%2C0%2C0%29%3Bpointer%2Devents%3Anone%7D%2Einput%2Dgroup%7Bposition%3Arelative%3Bdisplay%3Atable%3Bborder%2Dcollapse%3Aseparate%7D%2Einput%2Dgroup%5Bclass%2A%3Dcol%2D%5D%7Bfloat%3Anone%3Bpadding%2Dright%3A0%3Bpadding%2Dleft%3A0%7D%2Einput%2Dgroup%20%2Eform%2Dcontrol%7Bposition%3Arelative%3Bz%2Dindex%3A2%3Bfloat%3Aleft%3Bwidth%3A100%25%3Bmargin%2Dbottom%3A0%7D%2Einput%2Dgroup%2Dlg%3E%2Eform%2Dcontrol%2C%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Daddon%2C%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%7Bheight%3A46px%3Bpadding%3A10px%2016px%3Bfont%2Dsize%3A18px%3Bline%2Dheight%3A1%2E3333333%3Bborder%2Dradius%3A6px%7Dselect%2Einput%2Dgroup%2Dlg%3E%2Eform%2Dcontrol%2Cselect%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Daddon%2Cselect%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%7Bheight%3A46px%3Bline%2Dheight%3A46px%7Dselect%5Bmultiple%5D%2Einput%2Dgroup%2Dlg%3E%2Eform%2Dcontrol%2Cselect%5Bmultiple%5D%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Daddon%2Cselect%5Bmultiple%5D%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%2Ctextarea%2Einput%2Dgroup%2Dlg%3E%2Eform%2Dcontrol%2Ctextarea%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Daddon%2Ctextarea%2Einput%2Dgroup%2Dlg%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%7Bheight%3Aauto%7D%2Einput%2Dgroup%2Dsm%3E%2Eform%2Dcontrol%2C%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Daddon%2C%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%7Bheight%3A30px%3Bpadding%3A5px%2010px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5%3Bborder%2Dradius%3A3px%7Dselect%2Einput%2Dgroup%2Dsm%3E%2Eform%2Dcontrol%2Cselect%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Daddon%2Cselect%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%7Bheight%3A30px%3Bline%2Dheight%3A30px%7Dselect%5Bmultiple%5D%2Einput%2Dgroup%2Dsm%3E%2Eform%2Dcontrol%2Cselect%5Bmultiple%5D%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Daddon%2Cselect%5Bmultiple%5D%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%2Ctextarea%2Einput%2Dgroup%2Dsm%3E%2Eform%2Dcontrol%2Ctextarea%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Daddon%2Ctextarea%2Einput%2Dgroup%2Dsm%3E%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%7Bheight%3Aauto%7D%2Einput%2Dgroup%20%2Eform%2Dcontrol%2C%2Einput%2Dgroup%2Daddon%2C%2Einput%2Dgroup%2Dbtn%7Bdisplay%3Atable%2Dcell%7D%2Einput%2Dgroup%20%2Eform%2Dcontrol%3Anot%28%3Afirst%2Dchild%29%3Anot%28%3Alast%2Dchild%29%2C%2Einput%2Dgroup%2Daddon%3Anot%28%3Afirst%2Dchild%29%3Anot%28%3Alast%2Dchild%29%2C%2Einput%2Dgroup%2Dbtn%3Anot%28%3Afirst%2Dchild%29%3Anot%28%3Alast%2Dchild%29%7Bborder%2Dradius%3A0%7D%2Einput%2Dgroup%2Daddon%2C%2Einput%2Dgroup%2Dbtn%7Bwidth%3A1%25%3Bwhite%2Dspace%3Anowrap%3Bvertical%2Dalign%3Amiddle%7D%2Einput%2Dgroup%2Daddon%7Bpadding%3A6px%2012px%3Bfont%2Dsize%3A14px%3Bfont%2Dweight%3A400%3Bline%2Dheight%3A1%3Bcolor%3A%23555%3Btext%2Dalign%3Acenter%3Bbackground%2Dcolor%3A%23eee%3Bborder%3A1px%20solid%20%23ccc%3Bborder%2Dradius%3A4px%7D%2Einput%2Dgroup%2Daddon%2Einput%2Dsm%7Bpadding%3A5px%2010px%3Bfont%2Dsize%3A12px%3Bborder%2Dradius%3A3px%7D%2Einput%2Dgroup%2Daddon%2Einput%2Dlg%7Bpadding%3A10px%2016px%3Bfont%2Dsize%3A18px%3Bborder%2Dradius%3A6px%7D%2Einput%2Dgroup%2Daddon%20input%5Btype%3Dcheckbox%5D%2C%2Einput%2Dgroup%2Daddon%20input%5Btype%3Dradio%5D%7Bmargin%2Dtop%3A0%7D%2Einput%2Dgroup%20%2Eform%2Dcontrol%3Afirst%2Dchild%2C%2Einput%2Dgroup%2Daddon%3Afirst%2Dchild%2C%2Einput%2Dgroup%2Dbtn%3Afirst%2Dchild%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Afirst%2Dchild%3E%2Ebtn%2Dgroup%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Afirst%2Dchild%3E%2Edropdown%2Dtoggle%2C%2Einput%2Dgroup%2Dbtn%3Alast%2Dchild%3E%2Ebtn%2Dgroup%3Anot%28%3Alast%2Dchild%29%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Alast%2Dchild%3E%2Ebtn%3Anot%28%3Alast%2Dchild%29%3Anot%28%2Edropdown%2Dtoggle%29%7Bborder%2Dtop%2Dright%2Dradius%3A0%3Bborder%2Dbottom%2Dright%2Dradius%3A0%7D%2Einput%2Dgroup%2Daddon%3Afirst%2Dchild%7Bborder%2Dright%3A0%7D%2Einput%2Dgroup%20%2Eform%2Dcontrol%3Alast%2Dchild%2C%2Einput%2Dgroup%2Daddon%3Alast%2Dchild%2C%2Einput%2Dgroup%2Dbtn%3Afirst%2Dchild%3E%2Ebtn%2Dgroup%3Anot%28%3Afirst%2Dchild%29%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Afirst%2Dchild%3E%2Ebtn%3Anot%28%3Afirst%2Dchild%29%2C%2Einput%2Dgroup%2Dbtn%3Alast%2Dchild%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Alast%2Dchild%3E%2Ebtn%2Dgroup%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Alast%2Dchild%3E%2Edropdown%2Dtoggle%7Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dbottom%2Dleft%2Dradius%3A0%7D%2Einput%2Dgroup%2Daddon%3Alast%2Dchild%7Bborder%2Dleft%3A0%7D%2Einput%2Dgroup%2Dbtn%7Bposition%3Arelative%3Bfont%2Dsize%3A0%3Bwhite%2Dspace%3Anowrap%7D%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%7Bposition%3Arelative%7D%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%2B%2Ebtn%7Bmargin%2Dleft%3A%2D1px%7D%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%3Aactive%2C%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%3Afocus%2C%2Einput%2Dgroup%2Dbtn%3E%2Ebtn%3Ahover%7Bz%2Dindex%3A2%7D%2Einput%2Dgroup%2Dbtn%3Afirst%2Dchild%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Afirst%2Dchild%3E%2Ebtn%2Dgroup%7Bmargin%2Dright%3A%2D1px%7D%2Einput%2Dgroup%2Dbtn%3Alast%2Dchild%3E%2Ebtn%2C%2Einput%2Dgroup%2Dbtn%3Alast%2Dchild%3E%2Ebtn%2Dgroup%7Bz%2Dindex%3A2%3Bmargin%2Dleft%3A%2D1px%7D%2Enav%7Bpadding%2Dleft%3A0%3Bmargin%2Dbottom%3A0%3Blist%2Dstyle%3Anone%7D%2Enav%3Eli%7Bposition%3Arelative%3Bdisplay%3Ablock%7D%2Enav%3Eli%3Ea%7Bposition%3Arelative%3Bdisplay%3Ablock%3Bpadding%3A10px%2015px%7D%2Enav%3Eli%3Ea%3Afocus%2C%2Enav%3Eli%3Ea%3Ahover%7Btext%2Ddecoration%3Anone%3Bbackground%2Dcolor%3A%23eee%7D%2Enav%3Eli%2Edisabled%3Ea%7Bcolor%3A%23777%7D%2Enav%3Eli%2Edisabled%3Ea%3Afocus%2C%2Enav%3Eli%2Edisabled%3Ea%3Ahover%7Bcolor%3A%23777%3Btext%2Ddecoration%3Anone%3Bcursor%3Anot%2Dallowed%3Bbackground%2Dcolor%3Atransparent%7D%2Enav%20%2Eopen%3Ea%2C%2Enav%20%2Eopen%3Ea%3Afocus%2C%2Enav%20%2Eopen%3Ea%3Ahover%7Bbackground%2Dcolor%3A%23eee%3Bborder%2Dcolor%3A%23337ab7%7D%2Enav%20%2Enav%2Ddivider%7Bheight%3A1px%3Bmargin%3A9px%200%3Boverflow%3Ahidden%3Bbackground%2Dcolor%3A%23e5e5e5%7D%2Enav%3Eli%3Ea%3Eimg%7Bmax%2Dwidth%3Anone%7D%2Enav%2Dtabs%7Bborder%2Dbottom%3A1px%20solid%20%23ddd%7D%2Enav%2Dtabs%3Eli%7Bfloat%3Aleft%3Bmargin%2Dbottom%3A%2D1px%7D%2Enav%2Dtabs%3Eli%3Ea%7Bmargin%2Dright%3A2px%3Bline%2Dheight%3A1%2E42857143%3Bborder%3A1px%20solid%20transparent%3Bborder%2Dradius%3A4px%204px%200%200%7D%2Enav%2Dtabs%3Eli%3Ea%3Ahover%7Bborder%2Dcolor%3A%23eee%20%23eee%20%23ddd%7D%2Enav%2Dtabs%3Eli%2Eactive%3Ea%2C%2Enav%2Dtabs%3Eli%2Eactive%3Ea%3Afocus%2C%2Enav%2Dtabs%3Eli%2Eactive%3Ea%3Ahover%7Bcolor%3A%23555%3Bcursor%3Adefault%3Bbackground%2Dcolor%3A%23fff%3Bborder%3A1px%20solid%20%23ddd%3Bborder%2Dbottom%2Dcolor%3Atransparent%7D%2Enav%2Dtabs%2Enav%2Djustified%7Bwidth%3A100%25%3Bborder%2Dbottom%3A0%7D%2Enav%2Dtabs%2Enav%2Djustified%3Eli%7Bfloat%3Anone%7D%2Enav%2Dtabs%2Enav%2Djustified%3Eli%3Ea%7Bmargin%2Dbottom%3A5px%3Btext%2Dalign%3Acenter%7D%2Enav%2Dtabs%2Enav%2Djustified%3E%2Edropdown%20%2Edropdown%2Dmenu%7Btop%3Aauto%3Bleft%3Aauto%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enav%2Dtabs%2Enav%2Djustified%3Eli%7Bdisplay%3Atable%2Dcell%3Bwidth%3A1%25%7D%2Enav%2Dtabs%2Enav%2Djustified%3Eli%3Ea%7Bmargin%2Dbottom%3A0%7D%7D%2Enav%2Dtabs%2Enav%2Djustified%3Eli%3Ea%7Bmargin%2Dright%3A0%3Bborder%2Dradius%3A4px%7D%2Enav%2Dtabs%2Enav%2Djustified%3E%2Eactive%3Ea%2C%2Enav%2Dtabs%2Enav%2Djustified%3E%2Eactive%3Ea%3Afocus%2C%2Enav%2Dtabs%2Enav%2Djustified%3E%2Eactive%3Ea%3Ahover%7Bborder%3A1px%20solid%20%23ddd%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enav%2Dtabs%2Enav%2Djustified%3Eli%3Ea%7Bborder%2Dbottom%3A1px%20solid%20%23ddd%3Bborder%2Dradius%3A4px%204px%200%200%7D%2Enav%2Dtabs%2Enav%2Djustified%3E%2Eactive%3Ea%2C%2Enav%2Dtabs%2Enav%2Djustified%3E%2Eactive%3Ea%3Afocus%2C%2Enav%2Dtabs%2Enav%2Djustified%3E%2Eactive%3Ea%3Ahover%7Bborder%2Dbottom%2Dcolor%3A%23fff%7D%7D%2Enav%2Dpills%3Eli%7Bfloat%3Aleft%7D%2Enav%2Dpills%3Eli%3Ea%7Bborder%2Dradius%3A4px%7D%2Enav%2Dpills%3Eli%2Bli%7Bmargin%2Dleft%3A2px%7D%2Enav%2Dpills%3Eli%2Eactive%3Ea%2C%2Enav%2Dpills%3Eli%2Eactive%3Ea%3Afocus%2C%2Enav%2Dpills%3Eli%2Eactive%3Ea%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23337ab7%7D%2Enav%2Dstacked%3Eli%7Bfloat%3Anone%7D%2Enav%2Dstacked%3Eli%2Bli%7Bmargin%2Dtop%3A2px%3Bmargin%2Dleft%3A0%7D%2Enav%2Djustified%7Bwidth%3A100%25%7D%2Enav%2Djustified%3Eli%7Bfloat%3Anone%7D%2Enav%2Djustified%3Eli%3Ea%7Bmargin%2Dbottom%3A5px%3Btext%2Dalign%3Acenter%7D%2Enav%2Djustified%3E%2Edropdown%20%2Edropdown%2Dmenu%7Btop%3Aauto%3Bleft%3Aauto%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enav%2Djustified%3Eli%7Bdisplay%3Atable%2Dcell%3Bwidth%3A1%25%7D%2Enav%2Djustified%3Eli%3Ea%7Bmargin%2Dbottom%3A0%7D%7D%2Enav%2Dtabs%2Djustified%7Bborder%2Dbottom%3A0%7D%2Enav%2Dtabs%2Djustified%3Eli%3Ea%7Bmargin%2Dright%3A0%3Bborder%2Dradius%3A4px%7D%2Enav%2Dtabs%2Djustified%3E%2Eactive%3Ea%2C%2Enav%2Dtabs%2Djustified%3E%2Eactive%3Ea%3Afocus%2C%2Enav%2Dtabs%2Djustified%3E%2Eactive%3Ea%3Ahover%7Bborder%3A1px%20solid%20%23ddd%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enav%2Dtabs%2Djustified%3Eli%3Ea%7Bborder%2Dbottom%3A1px%20solid%20%23ddd%3Bborder%2Dradius%3A4px%204px%200%200%7D%2Enav%2Dtabs%2Djustified%3E%2Eactive%3Ea%2C%2Enav%2Dtabs%2Djustified%3E%2Eactive%3Ea%3Afocus%2C%2Enav%2Dtabs%2Djustified%3E%2Eactive%3Ea%3Ahover%7Bborder%2Dbottom%2Dcolor%3A%23fff%7D%7D%2Etab%2Dcontent%3E%2Etab%2Dpane%7Bdisplay%3Anone%7D%2Etab%2Dcontent%3E%2Eactive%7Bdisplay%3Ablock%7D%2Enav%2Dtabs%20%2Edropdown%2Dmenu%7Bmargin%2Dtop%3A%2D1px%3Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dtop%2Dright%2Dradius%3A0%7D%2Enavbar%7Bposition%3Arelative%3Bmin%2Dheight%3A50px%3Bmargin%2Dbottom%3A20px%3Bborder%3A1px%20solid%20transparent%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%7Bborder%2Dradius%3A4px%7D%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dheader%7Bfloat%3Aleft%7D%7D%2Enavbar%2Dcollapse%7Bpadding%2Dright%3A15px%3Bpadding%2Dleft%3A15px%3Boverflow%2Dx%3Avisible%3B%2Dwebkit%2Doverflow%2Dscrolling%3Atouch%3Bborder%2Dtop%3A1px%20solid%20transparent%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%200%20rgba%28255%2C255%2C255%2C%2E1%29%3Bbox%2Dshadow%3Ainset%200%201px%200%20rgba%28255%2C255%2C255%2C%2E1%29%7D%2Enavbar%2Dcollapse%2Ein%7Boverflow%2Dy%3Aauto%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dcollapse%7Bwidth%3Aauto%3Bborder%2Dtop%3A0%3B%2Dwebkit%2Dbox%2Dshadow%3Anone%3Bbox%2Dshadow%3Anone%7D%2Enavbar%2Dcollapse%2Ecollapse%7Bdisplay%3Ablock%21important%3Bheight%3Aauto%21important%3Bpadding%2Dbottom%3A0%3Boverflow%3Avisible%21important%7D%2Enavbar%2Dcollapse%2Ein%7Boverflow%2Dy%3Avisible%7D%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dcollapse%2C%2Enavbar%2Dfixed%2Dtop%20%2Enavbar%2Dcollapse%2C%2Enavbar%2Dstatic%2Dtop%20%2Enavbar%2Dcollapse%7Bpadding%2Dright%3A0%3Bpadding%2Dleft%3A0%7D%7D%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dcollapse%2C%2Enavbar%2Dfixed%2Dtop%20%2Enavbar%2Dcollapse%7Bmax%2Dheight%3A340px%7D%40media%20%28max%2Ddevice%2Dwidth%3A480px%29%20and%20%28orientation%3Alandscape%29%7B%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dcollapse%2C%2Enavbar%2Dfixed%2Dtop%20%2Enavbar%2Dcollapse%7Bmax%2Dheight%3A200px%7D%7D%2Econtainer%2Dfluid%3E%2Enavbar%2Dcollapse%2C%2Econtainer%2Dfluid%3E%2Enavbar%2Dheader%2C%2Econtainer%3E%2Enavbar%2Dcollapse%2C%2Econtainer%3E%2Enavbar%2Dheader%7Bmargin%2Dright%3A%2D15px%3Bmargin%2Dleft%3A%2D15px%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Econtainer%2Dfluid%3E%2Enavbar%2Dcollapse%2C%2Econtainer%2Dfluid%3E%2Enavbar%2Dheader%2C%2Econtainer%3E%2Enavbar%2Dcollapse%2C%2Econtainer%3E%2Enavbar%2Dheader%7Bmargin%2Dright%3A0%3Bmargin%2Dleft%3A0%7D%7D%2Enavbar%2Dstatic%2Dtop%7Bz%2Dindex%3A1000%3Bborder%2Dwidth%3A0%200%201px%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dstatic%2Dtop%7Bborder%2Dradius%3A0%7D%7D%2Enavbar%2Dfixed%2Dbottom%2C%2Enavbar%2Dfixed%2Dtop%7Bposition%3Afixed%3Bright%3A0%3Bleft%3A0%3Bz%2Dindex%3A1030%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dfixed%2Dbottom%2C%2Enavbar%2Dfixed%2Dtop%7Bborder%2Dradius%3A0%7D%7D%2Enavbar%2Dfixed%2Dtop%7Btop%3A0%3Bborder%2Dwidth%3A0%200%201px%7D%2Enavbar%2Dfixed%2Dbottom%7Bbottom%3A0%3Bmargin%2Dbottom%3A0%3Bborder%2Dwidth%3A1px%200%200%7D%2Enavbar%2Dbrand%7Bfloat%3Aleft%3Bheight%3A50px%3Bpadding%3A15px%2015px%3Bfont%2Dsize%3A18px%3Bline%2Dheight%3A20px%7D%2Enavbar%2Dbrand%3Afocus%2C%2Enavbar%2Dbrand%3Ahover%7Btext%2Ddecoration%3Anone%7D%2Enavbar%2Dbrand%3Eimg%7Bdisplay%3Ablock%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%3E%2Econtainer%20%2Enavbar%2Dbrand%2C%2Enavbar%3E%2Econtainer%2Dfluid%20%2Enavbar%2Dbrand%7Bmargin%2Dleft%3A%2D15px%7D%7D%2Enavbar%2Dtoggle%7Bposition%3Arelative%3Bfloat%3Aright%3Bpadding%3A9px%2010px%3Bmargin%2Dtop%3A8px%3Bmargin%2Dright%3A15px%3Bmargin%2Dbottom%3A8px%3Bbackground%2Dcolor%3Atransparent%3Bbackground%2Dimage%3Anone%3Bborder%3A1px%20solid%20transparent%3Bborder%2Dradius%3A4px%7D%2Enavbar%2Dtoggle%3Afocus%7Boutline%3A0%7D%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%7Bdisplay%3Ablock%3Bwidth%3A22px%3Bheight%3A2px%3Bborder%2Dradius%3A1px%7D%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%2B%2Eicon%2Dbar%7Bmargin%2Dtop%3A4px%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dtoggle%7Bdisplay%3Anone%7D%7D%2Enavbar%2Dnav%7Bmargin%3A7%2E5px%20%2D15px%7D%2Enavbar%2Dnav%3Eli%3Ea%7Bpadding%2Dtop%3A10px%3Bpadding%2Dbottom%3A10px%3Bline%2Dheight%3A20px%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%7Bposition%3Astatic%3Bfloat%3Anone%3Bwidth%3Aauto%3Bmargin%2Dtop%3A0%3Bbackground%2Dcolor%3Atransparent%3Bborder%3A0%3B%2Dwebkit%2Dbox%2Dshadow%3Anone%3Bbox%2Dshadow%3Anone%7D%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%2Edropdown%2Dheader%2C%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%7Bpadding%3A5px%2015px%205px%2025px%7D%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%7Bline%2Dheight%3A20px%7D%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%3Afocus%2C%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%3Ahover%7Bbackground%2Dimage%3Anone%7D%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dnav%7Bfloat%3Aleft%3Bmargin%3A0%7D%2Enavbar%2Dnav%3Eli%7Bfloat%3Aleft%7D%2Enavbar%2Dnav%3Eli%3Ea%7Bpadding%2Dtop%3A15px%3Bpadding%2Dbottom%3A15px%7D%7D%2Enavbar%2Dform%7Bpadding%3A10px%2015px%3Bmargin%2Dtop%3A8px%3Bmargin%2Dright%3A%2D15px%3Bmargin%2Dbottom%3A8px%3Bmargin%2Dleft%3A%2D15px%3Bborder%2Dtop%3A1px%20solid%20transparent%3Bborder%2Dbottom%3A1px%20solid%20transparent%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%200%20rgba%28255%2C255%2C255%2C%2E1%29%2C0%201px%200%20rgba%28255%2C255%2C255%2C%2E1%29%3Bbox%2Dshadow%3Ainset%200%201px%200%20rgba%28255%2C255%2C255%2C%2E1%29%2C0%201px%200%20rgba%28255%2C255%2C255%2C%2E1%29%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dform%20%2Eform%2Dgroup%7Bdisplay%3Ainline%2Dblock%3Bmargin%2Dbottom%3A0%3Bvertical%2Dalign%3Amiddle%7D%2Enavbar%2Dform%20%2Eform%2Dcontrol%7Bdisplay%3Ainline%2Dblock%3Bwidth%3Aauto%3Bvertical%2Dalign%3Amiddle%7D%2Enavbar%2Dform%20%2Eform%2Dcontrol%2Dstatic%7Bdisplay%3Ainline%2Dblock%7D%2Enavbar%2Dform%20%2Einput%2Dgroup%7Bdisplay%3Ainline%2Dtable%3Bvertical%2Dalign%3Amiddle%7D%2Enavbar%2Dform%20%2Einput%2Dgroup%20%2Eform%2Dcontrol%2C%2Enavbar%2Dform%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Daddon%2C%2Enavbar%2Dform%20%2Einput%2Dgroup%20%2Einput%2Dgroup%2Dbtn%7Bwidth%3Aauto%7D%2Enavbar%2Dform%20%2Einput%2Dgroup%3E%2Eform%2Dcontrol%7Bwidth%3A100%25%7D%2Enavbar%2Dform%20%2Econtrol%2Dlabel%7Bmargin%2Dbottom%3A0%3Bvertical%2Dalign%3Amiddle%7D%2Enavbar%2Dform%20%2Echeckbox%2C%2Enavbar%2Dform%20%2Eradio%7Bdisplay%3Ainline%2Dblock%3Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A0%3Bvertical%2Dalign%3Amiddle%7D%2Enavbar%2Dform%20%2Echeckbox%20label%2C%2Enavbar%2Dform%20%2Eradio%20label%7Bpadding%2Dleft%3A0%7D%2Enavbar%2Dform%20%2Echeckbox%20input%5Btype%3Dcheckbox%5D%2C%2Enavbar%2Dform%20%2Eradio%20input%5Btype%3Dradio%5D%7Bposition%3Arelative%3Bmargin%2Dleft%3A0%7D%2Enavbar%2Dform%20%2Ehas%2Dfeedback%20%2Eform%2Dcontrol%2Dfeedback%7Btop%3A0%7D%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Enavbar%2Dform%20%2Eform%2Dgroup%7Bmargin%2Dbottom%3A5px%7D%2Enavbar%2Dform%20%2Eform%2Dgroup%3Alast%2Dchild%7Bmargin%2Dbottom%3A0%7D%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dform%7Bwidth%3Aauto%3Bpadding%2Dtop%3A0%3Bpadding%2Dbottom%3A0%3Bmargin%2Dright%3A0%3Bmargin%2Dleft%3A0%3Bborder%3A0%3B%2Dwebkit%2Dbox%2Dshadow%3Anone%3Bbox%2Dshadow%3Anone%7D%7D%2Enavbar%2Dnav%3Eli%3E%2Edropdown%2Dmenu%7Bmargin%2Dtop%3A0%3Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dtop%2Dright%2Dradius%3A0%7D%2Enavbar%2Dfixed%2Dbottom%20%2Enavbar%2Dnav%3Eli%3E%2Edropdown%2Dmenu%7Bmargin%2Dbottom%3A0%3Bborder%2Dtop%2Dleft%2Dradius%3A4px%3Bborder%2Dtop%2Dright%2Dradius%3A4px%3Bborder%2Dbottom%2Dright%2Dradius%3A0%3Bborder%2Dbottom%2Dleft%2Dradius%3A0%7D%2Enavbar%2Dbtn%7Bmargin%2Dtop%3A8px%3Bmargin%2Dbottom%3A8px%7D%2Enavbar%2Dbtn%2Ebtn%2Dsm%7Bmargin%2Dtop%3A10px%3Bmargin%2Dbottom%3A10px%7D%2Enavbar%2Dbtn%2Ebtn%2Dxs%7Bmargin%2Dtop%3A14px%3Bmargin%2Dbottom%3A14px%7D%2Enavbar%2Dtext%7Bmargin%2Dtop%3A15px%3Bmargin%2Dbottom%3A15px%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dtext%7Bfloat%3Aleft%3Bmargin%2Dright%3A15px%3Bmargin%2Dleft%3A15px%7D%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Enavbar%2Dleft%7Bfloat%3Aleft%21important%7D%2Enavbar%2Dright%7Bfloat%3Aright%21important%3Bmargin%2Dright%3A%2D15px%7D%2Enavbar%2Dright%7E%2Enavbar%2Dright%7Bmargin%2Dright%3A0%7D%7D%2Enavbar%2Ddefault%7Bbackground%2Dcolor%3A%23f8f8f8%3Bborder%2Dcolor%3A%23e7e7e7%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dbrand%7Bcolor%3A%23777%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dbrand%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dbrand%3Ahover%7Bcolor%3A%235e5e5e%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dtext%7Bcolor%3A%23777%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3Eli%3Ea%7Bcolor%3A%23777%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3Eli%3Ea%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3Eli%3Ea%3Ahover%7Bcolor%3A%23333%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Eactive%3Ea%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Eactive%3Ea%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Eactive%3Ea%3Ahover%7Bcolor%3A%23555%3Bbackground%2Dcolor%3A%23e7e7e7%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Edisabled%3Ea%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Edisabled%3Ea%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Edisabled%3Ea%3Ahover%7Bcolor%3A%23ccc%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%7Bborder%2Dcolor%3A%23ddd%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%3Ahover%7Bbackground%2Dcolor%3A%23ddd%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%7Bbackground%2Dcolor%3A%23888%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dcollapse%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dform%7Bborder%2Dcolor%3A%23e7e7e7%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Eopen%3Ea%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Eopen%3Ea%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%3E%2Eopen%3Ea%3Ahover%7Bcolor%3A%23555%3Bbackground%2Dcolor%3A%23e7e7e7%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%7Bcolor%3A%23777%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%3Ahover%7Bcolor%3A%23333%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Eactive%3Ea%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Eactive%3Ea%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Eactive%3Ea%3Ahover%7Bcolor%3A%23555%3Bbackground%2Dcolor%3A%23e7e7e7%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Afocus%2C%2Enavbar%2Ddefault%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Ahover%7Bcolor%3A%23ccc%3Bbackground%2Dcolor%3Atransparent%7D%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dlink%7Bcolor%3A%23777%7D%2Enavbar%2Ddefault%20%2Enavbar%2Dlink%3Ahover%7Bcolor%3A%23333%7D%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%7Bcolor%3A%23777%7D%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Afocus%2C%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Ahover%7Bcolor%3A%23333%7D%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%5Bdisabled%5D%3Afocus%2C%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Enavbar%2Ddefault%20%2Ebtn%2Dlink%3Ahover%7Bcolor%3A%23ccc%7D%2Enavbar%2Dinverse%7Bbackground%2Dcolor%3A%23222%3Bborder%2Dcolor%3A%23080808%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dbrand%7Bcolor%3A%239d9d9d%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dbrand%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dbrand%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dtext%7Bcolor%3A%239d9d9d%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3Eli%3Ea%7Bcolor%3A%239d9d9d%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3Eli%3Ea%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3Eli%3Ea%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Eactive%3Ea%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Eactive%3Ea%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Eactive%3Ea%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23080808%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Edisabled%3Ea%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Edisabled%3Ea%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Edisabled%3Ea%3Ahover%7Bcolor%3A%23444%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%7Bborder%2Dcolor%3A%23333%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%3Ahover%7Bbackground%2Dcolor%3A%23333%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dtoggle%20%2Eicon%2Dbar%7Bbackground%2Dcolor%3A%23fff%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dcollapse%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dform%7Bborder%2Dcolor%3A%23101010%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Eopen%3Ea%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Eopen%3Ea%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%3E%2Eopen%3Ea%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23080808%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Edropdown%2Dheader%7Bborder%2Dcolor%3A%23080808%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%20%2Edivider%7Bbackground%2Dcolor%3A%23080808%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%7Bcolor%3A%239d9d9d%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3Eli%3Ea%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3Atransparent%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Eactive%3Ea%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Eactive%3Ea%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Eactive%3Ea%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23080808%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Afocus%2C%2Enavbar%2Dinverse%20%2Enavbar%2Dnav%20%2Eopen%20%2Edropdown%2Dmenu%3E%2Edisabled%3Ea%3Ahover%7Bcolor%3A%23444%3Bbackground%2Dcolor%3Atransparent%7D%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dlink%7Bcolor%3A%239d9d9d%7D%2Enavbar%2Dinverse%20%2Enavbar%2Dlink%3Ahover%7Bcolor%3A%23fff%7D%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%7Bcolor%3A%239d9d9d%7D%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Afocus%2C%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Ahover%7Bcolor%3A%23fff%7D%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%5Bdisabled%5D%3Afocus%2C%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%5Bdisabled%5D%3Ahover%2Cfieldset%5Bdisabled%5D%20%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Afocus%2Cfieldset%5Bdisabled%5D%20%2Enavbar%2Dinverse%20%2Ebtn%2Dlink%3Ahover%7Bcolor%3A%23444%7D%2Ebreadcrumb%7Bpadding%3A8px%2015px%3Bmargin%2Dbottom%3A20px%3Blist%2Dstyle%3Anone%3Bbackground%2Dcolor%3A%23f5f5f5%3Bborder%2Dradius%3A4px%7D%2Ebreadcrumb%3Eli%7Bdisplay%3Ainline%2Dblock%7D%2Ebreadcrumb%3Eli%2Bli%3Abefore%7Bpadding%3A0%205px%3Bcolor%3A%23ccc%3Bcontent%3A%22%2F%5C00a0%22%7D%2Ebreadcrumb%3E%2Eactive%7Bcolor%3A%23777%7D%2Epagination%7Bdisplay%3Ainline%2Dblock%3Bpadding%2Dleft%3A0%3Bmargin%3A20px%200%3Bborder%2Dradius%3A4px%7D%2Epagination%3Eli%7Bdisplay%3Ainline%7D%2Epagination%3Eli%3Ea%2C%2Epagination%3Eli%3Espan%7Bposition%3Arelative%3Bfloat%3Aleft%3Bpadding%3A6px%2012px%3Bmargin%2Dleft%3A%2D1px%3Bline%2Dheight%3A1%2E42857143%3Bcolor%3A%23337ab7%3Btext%2Ddecoration%3Anone%3Bbackground%2Dcolor%3A%23fff%3Bborder%3A1px%20solid%20%23ddd%7D%2Epagination%3Eli%3Afirst%2Dchild%3Ea%2C%2Epagination%3Eli%3Afirst%2Dchild%3Espan%7Bmargin%2Dleft%3A0%3Bborder%2Dtop%2Dleft%2Dradius%3A4px%3Bborder%2Dbottom%2Dleft%2Dradius%3A4px%7D%2Epagination%3Eli%3Alast%2Dchild%3Ea%2C%2Epagination%3Eli%3Alast%2Dchild%3Espan%7Bborder%2Dtop%2Dright%2Dradius%3A4px%3Bborder%2Dbottom%2Dright%2Dradius%3A4px%7D%2Epagination%3Eli%3Ea%3Afocus%2C%2Epagination%3Eli%3Ea%3Ahover%2C%2Epagination%3Eli%3Espan%3Afocus%2C%2Epagination%3Eli%3Espan%3Ahover%7Bz%2Dindex%3A3%3Bcolor%3A%2323527c%3Bbackground%2Dcolor%3A%23eee%3Bborder%2Dcolor%3A%23ddd%7D%2Epagination%3E%2Eactive%3Ea%2C%2Epagination%3E%2Eactive%3Ea%3Afocus%2C%2Epagination%3E%2Eactive%3Ea%3Ahover%2C%2Epagination%3E%2Eactive%3Espan%2C%2Epagination%3E%2Eactive%3Espan%3Afocus%2C%2Epagination%3E%2Eactive%3Espan%3Ahover%7Bz%2Dindex%3A2%3Bcolor%3A%23fff%3Bcursor%3Adefault%3Bbackground%2Dcolor%3A%23337ab7%3Bborder%2Dcolor%3A%23337ab7%7D%2Epagination%3E%2Edisabled%3Ea%2C%2Epagination%3E%2Edisabled%3Ea%3Afocus%2C%2Epagination%3E%2Edisabled%3Ea%3Ahover%2C%2Epagination%3E%2Edisabled%3Espan%2C%2Epagination%3E%2Edisabled%3Espan%3Afocus%2C%2Epagination%3E%2Edisabled%3Espan%3Ahover%7Bcolor%3A%23777%3Bcursor%3Anot%2Dallowed%3Bbackground%2Dcolor%3A%23fff%3Bborder%2Dcolor%3A%23ddd%7D%2Epagination%2Dlg%3Eli%3Ea%2C%2Epagination%2Dlg%3Eli%3Espan%7Bpadding%3A10px%2016px%3Bfont%2Dsize%3A18px%3Bline%2Dheight%3A1%2E3333333%7D%2Epagination%2Dlg%3Eli%3Afirst%2Dchild%3Ea%2C%2Epagination%2Dlg%3Eli%3Afirst%2Dchild%3Espan%7Bborder%2Dtop%2Dleft%2Dradius%3A6px%3Bborder%2Dbottom%2Dleft%2Dradius%3A6px%7D%2Epagination%2Dlg%3Eli%3Alast%2Dchild%3Ea%2C%2Epagination%2Dlg%3Eli%3Alast%2Dchild%3Espan%7Bborder%2Dtop%2Dright%2Dradius%3A6px%3Bborder%2Dbottom%2Dright%2Dradius%3A6px%7D%2Epagination%2Dsm%3Eli%3Ea%2C%2Epagination%2Dsm%3Eli%3Espan%7Bpadding%3A5px%2010px%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A1%2E5%7D%2Epagination%2Dsm%3Eli%3Afirst%2Dchild%3Ea%2C%2Epagination%2Dsm%3Eli%3Afirst%2Dchild%3Espan%7Bborder%2Dtop%2Dleft%2Dradius%3A3px%3Bborder%2Dbottom%2Dleft%2Dradius%3A3px%7D%2Epagination%2Dsm%3Eli%3Alast%2Dchild%3Ea%2C%2Epagination%2Dsm%3Eli%3Alast%2Dchild%3Espan%7Bborder%2Dtop%2Dright%2Dradius%3A3px%3Bborder%2Dbottom%2Dright%2Dradius%3A3px%7D%2Epager%7Bpadding%2Dleft%3A0%3Bmargin%3A20px%200%3Btext%2Dalign%3Acenter%3Blist%2Dstyle%3Anone%7D%2Epager%20li%7Bdisplay%3Ainline%7D%2Epager%20li%3Ea%2C%2Epager%20li%3Espan%7Bdisplay%3Ainline%2Dblock%3Bpadding%3A5px%2014px%3Bbackground%2Dcolor%3A%23fff%3Bborder%3A1px%20solid%20%23ddd%3Bborder%2Dradius%3A15px%7D%2Epager%20li%3Ea%3Afocus%2C%2Epager%20li%3Ea%3Ahover%7Btext%2Ddecoration%3Anone%3Bbackground%2Dcolor%3A%23eee%7D%2Epager%20%2Enext%3Ea%2C%2Epager%20%2Enext%3Espan%7Bfloat%3Aright%7D%2Epager%20%2Eprevious%3Ea%2C%2Epager%20%2Eprevious%3Espan%7Bfloat%3Aleft%7D%2Epager%20%2Edisabled%3Ea%2C%2Epager%20%2Edisabled%3Ea%3Afocus%2C%2Epager%20%2Edisabled%3Ea%3Ahover%2C%2Epager%20%2Edisabled%3Espan%7Bcolor%3A%23777%3Bcursor%3Anot%2Dallowed%3Bbackground%2Dcolor%3A%23fff%7D%2Elabel%7Bdisplay%3Ainline%3Bpadding%3A%2E2em%20%2E6em%20%2E3em%3Bfont%2Dsize%3A75%25%3Bfont%2Dweight%3A700%3Bline%2Dheight%3A1%3Bcolor%3A%23fff%3Btext%2Dalign%3Acenter%3Bwhite%2Dspace%3Anowrap%3Bvertical%2Dalign%3Abaseline%3Bborder%2Dradius%3A%2E25em%7Da%2Elabel%3Afocus%2Ca%2Elabel%3Ahover%7Bcolor%3A%23fff%3Btext%2Ddecoration%3Anone%3Bcursor%3Apointer%7D%2Elabel%3Aempty%7Bdisplay%3Anone%7D%2Ebtn%20%2Elabel%7Bposition%3Arelative%3Btop%3A%2D1px%7D%2Elabel%2Ddefault%7Bbackground%2Dcolor%3A%23777%7D%2Elabel%2Ddefault%5Bhref%5D%3Afocus%2C%2Elabel%2Ddefault%5Bhref%5D%3Ahover%7Bbackground%2Dcolor%3A%235e5e5e%7D%2Elabel%2Dprimary%7Bbackground%2Dcolor%3A%23337ab7%7D%2Elabel%2Dprimary%5Bhref%5D%3Afocus%2C%2Elabel%2Dprimary%5Bhref%5D%3Ahover%7Bbackground%2Dcolor%3A%23286090%7D%2Elabel%2Dsuccess%7Bbackground%2Dcolor%3A%235cb85c%7D%2Elabel%2Dsuccess%5Bhref%5D%3Afocus%2C%2Elabel%2Dsuccess%5Bhref%5D%3Ahover%7Bbackground%2Dcolor%3A%23449d44%7D%2Elabel%2Dinfo%7Bbackground%2Dcolor%3A%235bc0de%7D%2Elabel%2Dinfo%5Bhref%5D%3Afocus%2C%2Elabel%2Dinfo%5Bhref%5D%3Ahover%7Bbackground%2Dcolor%3A%2331b0d5%7D%2Elabel%2Dwarning%7Bbackground%2Dcolor%3A%23f0ad4e%7D%2Elabel%2Dwarning%5Bhref%5D%3Afocus%2C%2Elabel%2Dwarning%5Bhref%5D%3Ahover%7Bbackground%2Dcolor%3A%23ec971f%7D%2Elabel%2Ddanger%7Bbackground%2Dcolor%3A%23d9534f%7D%2Elabel%2Ddanger%5Bhref%5D%3Afocus%2C%2Elabel%2Ddanger%5Bhref%5D%3Ahover%7Bbackground%2Dcolor%3A%23c9302c%7D%2Ebadge%7Bdisplay%3Ainline%2Dblock%3Bmin%2Dwidth%3A10px%3Bpadding%3A3px%207px%3Bfont%2Dsize%3A12px%3Bfont%2Dweight%3A700%3Bline%2Dheight%3A1%3Bcolor%3A%23fff%3Btext%2Dalign%3Acenter%3Bwhite%2Dspace%3Anowrap%3Bvertical%2Dalign%3Amiddle%3Bbackground%2Dcolor%3A%23777%3Bborder%2Dradius%3A10px%7D%2Ebadge%3Aempty%7Bdisplay%3Anone%7D%2Ebtn%20%2Ebadge%7Bposition%3Arelative%3Btop%3A%2D1px%7D%2Ebtn%2Dgroup%2Dxs%3E%2Ebtn%20%2Ebadge%2C%2Ebtn%2Dxs%20%2Ebadge%7Btop%3A0%3Bpadding%3A1px%205px%7Da%2Ebadge%3Afocus%2Ca%2Ebadge%3Ahover%7Bcolor%3A%23fff%3Btext%2Ddecoration%3Anone%3Bcursor%3Apointer%7D%2Elist%2Dgroup%2Ditem%2Eactive%3E%2Ebadge%2C%2Enav%2Dpills%3E%2Eactive%3Ea%3E%2Ebadge%7Bcolor%3A%23337ab7%3Bbackground%2Dcolor%3A%23fff%7D%2Elist%2Dgroup%2Ditem%3E%2Ebadge%7Bfloat%3Aright%7D%2Elist%2Dgroup%2Ditem%3E%2Ebadge%2B%2Ebadge%7Bmargin%2Dright%3A5px%7D%2Enav%2Dpills%3Eli%3Ea%3E%2Ebadge%7Bmargin%2Dleft%3A3px%7D%2Ejumbotron%7Bpadding%2Dtop%3A30px%3Bpadding%2Dbottom%3A30px%3Bmargin%2Dbottom%3A30px%3Bcolor%3Ainherit%3Bbackground%2Dcolor%3A%23eee%7D%2Ejumbotron%20%2Eh1%2C%2Ejumbotron%20h1%7Bcolor%3Ainherit%7D%2Ejumbotron%20p%7Bmargin%2Dbottom%3A15px%3Bfont%2Dsize%3A21px%3Bfont%2Dweight%3A200%7D%2Ejumbotron%3Ehr%7Bborder%2Dtop%2Dcolor%3A%23d5d5d5%7D%2Econtainer%20%2Ejumbotron%2C%2Econtainer%2Dfluid%20%2Ejumbotron%7Bborder%2Dradius%3A6px%7D%2Ejumbotron%20%2Econtainer%7Bmax%2Dwidth%3A100%25%7D%40media%20screen%20and%20%28min%2Dwidth%3A768px%29%7B%2Ejumbotron%7Bpadding%2Dtop%3A48px%3Bpadding%2Dbottom%3A48px%7D%2Econtainer%20%2Ejumbotron%2C%2Econtainer%2Dfluid%20%2Ejumbotron%7Bpadding%2Dright%3A60px%3Bpadding%2Dleft%3A60px%7D%2Ejumbotron%20%2Eh1%2C%2Ejumbotron%20h1%7Bfont%2Dsize%3A63px%7D%7D%2Ethumbnail%7Bdisplay%3Ablock%3Bpadding%3A4px%3Bmargin%2Dbottom%3A20px%3Bline%2Dheight%3A1%2E42857143%3Bbackground%2Dcolor%3A%23fff%3Bborder%3A1px%20solid%20%23ddd%3Bborder%2Dradius%3A4px%3B%2Dwebkit%2Dtransition%3Aborder%20%2E2s%20ease%2Din%2Dout%3B%2Do%2Dtransition%3Aborder%20%2E2s%20ease%2Din%2Dout%3Btransition%3Aborder%20%2E2s%20ease%2Din%2Dout%7D%2Ethumbnail%20a%3Eimg%2C%2Ethumbnail%3Eimg%7Bmargin%2Dright%3Aauto%3Bmargin%2Dleft%3Aauto%7Da%2Ethumbnail%2Eactive%2Ca%2Ethumbnail%3Afocus%2Ca%2Ethumbnail%3Ahover%7Bborder%2Dcolor%3A%23337ab7%7D%2Ethumbnail%20%2Ecaption%7Bpadding%3A9px%3Bcolor%3A%23333%7D%2Ealert%7Bpadding%3A15px%3Bmargin%2Dbottom%3A20px%3Bborder%3A1px%20solid%20transparent%3Bborder%2Dradius%3A4px%7D%2Ealert%20h4%7Bmargin%2Dtop%3A0%3Bcolor%3Ainherit%7D%2Ealert%20%2Ealert%2Dlink%7Bfont%2Dweight%3A700%7D%2Ealert%3Ep%2C%2Ealert%3Eul%7Bmargin%2Dbottom%3A0%7D%2Ealert%3Ep%2Bp%7Bmargin%2Dtop%3A5px%7D%2Ealert%2Ddismissable%2C%2Ealert%2Ddismissible%7Bpadding%2Dright%3A35px%7D%2Ealert%2Ddismissable%20%2Eclose%2C%2Ealert%2Ddismissible%20%2Eclose%7Bposition%3Arelative%3Btop%3A%2D2px%3Bright%3A%2D21px%3Bcolor%3Ainherit%7D%2Ealert%2Dsuccess%7Bcolor%3A%233c763d%3Bbackground%2Dcolor%3A%23dff0d8%3Bborder%2Dcolor%3A%23d6e9c6%7D%2Ealert%2Dsuccess%20hr%7Bborder%2Dtop%2Dcolor%3A%23c9e2b3%7D%2Ealert%2Dsuccess%20%2Ealert%2Dlink%7Bcolor%3A%232b542c%7D%2Ealert%2Dinfo%7Bcolor%3A%2331708f%3Bbackground%2Dcolor%3A%23d9edf7%3Bborder%2Dcolor%3A%23bce8f1%7D%2Ealert%2Dinfo%20hr%7Bborder%2Dtop%2Dcolor%3A%23a6e1ec%7D%2Ealert%2Dinfo%20%2Ealert%2Dlink%7Bcolor%3A%23245269%7D%2Ealert%2Dwarning%7Bcolor%3A%238a6d3b%3Bbackground%2Dcolor%3A%23fcf8e3%3Bborder%2Dcolor%3A%23faebcc%7D%2Ealert%2Dwarning%20hr%7Bborder%2Dtop%2Dcolor%3A%23f7e1b5%7D%2Ealert%2Dwarning%20%2Ealert%2Dlink%7Bcolor%3A%2366512c%7D%2Ealert%2Ddanger%7Bcolor%3A%23a94442%3Bbackground%2Dcolor%3A%23f2dede%3Bborder%2Dcolor%3A%23ebccd1%7D%2Ealert%2Ddanger%20hr%7Bborder%2Dtop%2Dcolor%3A%23e4b9c0%7D%2Ealert%2Ddanger%20%2Ealert%2Dlink%7Bcolor%3A%23843534%7D%40%2Dwebkit%2Dkeyframes%20progress%2Dbar%2Dstripes%7Bfrom%7Bbackground%2Dposition%3A40px%200%7Dto%7Bbackground%2Dposition%3A0%200%7D%7D%40%2Do%2Dkeyframes%20progress%2Dbar%2Dstripes%7Bfrom%7Bbackground%2Dposition%3A40px%200%7Dto%7Bbackground%2Dposition%3A0%200%7D%7D%40keyframes%20progress%2Dbar%2Dstripes%7Bfrom%7Bbackground%2Dposition%3A40px%200%7Dto%7Bbackground%2Dposition%3A0%200%7D%7D%2Eprogress%7Bheight%3A20px%3Bmargin%2Dbottom%3A20px%3Boverflow%3Ahidden%3Bbackground%2Dcolor%3A%23f5f5f5%3Bborder%2Dradius%3A4px%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%202px%20rgba%280%2C0%2C0%2C%2E1%29%3Bbox%2Dshadow%3Ainset%200%201px%202px%20rgba%280%2C0%2C0%2C%2E1%29%7D%2Eprogress%2Dbar%7Bfloat%3Aleft%3Bwidth%3A0%3Bheight%3A100%25%3Bfont%2Dsize%3A12px%3Bline%2Dheight%3A20px%3Bcolor%3A%23fff%3Btext%2Dalign%3Acenter%3Bbackground%2Dcolor%3A%23337ab7%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%20%2D1px%200%20rgba%280%2C0%2C0%2C%2E15%29%3Bbox%2Dshadow%3Ainset%200%20%2D1px%200%20rgba%280%2C0%2C0%2C%2E15%29%3B%2Dwebkit%2Dtransition%3Awidth%20%2E6s%20ease%3B%2Do%2Dtransition%3Awidth%20%2E6s%20ease%3Btransition%3Awidth%20%2E6s%20ease%7D%2Eprogress%2Dbar%2Dstriped%2C%2Eprogress%2Dstriped%20%2Eprogress%2Dbar%7Bbackground%2Dimage%3A%2Dwebkit%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3A%2Do%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3Alinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3B%2Dwebkit%2Dbackground%2Dsize%3A40px%2040px%3Bbackground%2Dsize%3A40px%2040px%7D%2Eprogress%2Dbar%2Eactive%2C%2Eprogress%2Eactive%20%2Eprogress%2Dbar%7B%2Dwebkit%2Danimation%3Aprogress%2Dbar%2Dstripes%202s%20linear%20infinite%3B%2Do%2Danimation%3Aprogress%2Dbar%2Dstripes%202s%20linear%20infinite%3Banimation%3Aprogress%2Dbar%2Dstripes%202s%20linear%20infinite%7D%2Eprogress%2Dbar%2Dsuccess%7Bbackground%2Dcolor%3A%235cb85c%7D%2Eprogress%2Dstriped%20%2Eprogress%2Dbar%2Dsuccess%7Bbackground%2Dimage%3A%2Dwebkit%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3A%2Do%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3Alinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%7D%2Eprogress%2Dbar%2Dinfo%7Bbackground%2Dcolor%3A%235bc0de%7D%2Eprogress%2Dstriped%20%2Eprogress%2Dbar%2Dinfo%7Bbackground%2Dimage%3A%2Dwebkit%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3A%2Do%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3Alinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%7D%2Eprogress%2Dbar%2Dwarning%7Bbackground%2Dcolor%3A%23f0ad4e%7D%2Eprogress%2Dstriped%20%2Eprogress%2Dbar%2Dwarning%7Bbackground%2Dimage%3A%2Dwebkit%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3A%2Do%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3Alinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%7D%2Eprogress%2Dbar%2Ddanger%7Bbackground%2Dcolor%3A%23d9534f%7D%2Eprogress%2Dstriped%20%2Eprogress%2Dbar%2Ddanger%7Bbackground%2Dimage%3A%2Dwebkit%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3A%2Do%2Dlinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%3Bbackground%2Dimage%3Alinear%2Dgradient%2845deg%2Crgba%28255%2C255%2C255%2C%2E15%29%2025%25%2Ctransparent%2025%25%2Ctransparent%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2050%25%2Crgba%28255%2C255%2C255%2C%2E15%29%2075%25%2Ctransparent%2075%25%2Ctransparent%29%7D%2Emedia%7Bmargin%2Dtop%3A15px%7D%2Emedia%3Afirst%2Dchild%7Bmargin%2Dtop%3A0%7D%2Emedia%2C%2Emedia%2Dbody%7Boverflow%3Ahidden%3Bzoom%3A1%7D%2Emedia%2Dbody%7Bwidth%3A10000px%7D%2Emedia%2Dobject%7Bdisplay%3Ablock%7D%2Emedia%2Dobject%2Eimg%2Dthumbnail%7Bmax%2Dwidth%3Anone%7D%2Emedia%2Dright%2C%2Emedia%3E%2Epull%2Dright%7Bpadding%2Dleft%3A10px%7D%2Emedia%2Dleft%2C%2Emedia%3E%2Epull%2Dleft%7Bpadding%2Dright%3A10px%7D%2Emedia%2Dbody%2C%2Emedia%2Dleft%2C%2Emedia%2Dright%7Bdisplay%3Atable%2Dcell%3Bvertical%2Dalign%3Atop%7D%2Emedia%2Dmiddle%7Bvertical%2Dalign%3Amiddle%7D%2Emedia%2Dbottom%7Bvertical%2Dalign%3Abottom%7D%2Emedia%2Dheading%7Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A5px%7D%2Emedia%2Dlist%7Bpadding%2Dleft%3A0%3Blist%2Dstyle%3Anone%7D%2Elist%2Dgroup%7Bpadding%2Dleft%3A0%3Bmargin%2Dbottom%3A20px%7D%2Elist%2Dgroup%2Ditem%7Bposition%3Arelative%3Bdisplay%3Ablock%3Bpadding%3A10px%2015px%3Bmargin%2Dbottom%3A%2D1px%3Bbackground%2Dcolor%3A%23fff%3Bborder%3A1px%20solid%20%23ddd%7D%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%7Bborder%2Dtop%2Dleft%2Dradius%3A4px%3Bborder%2Dtop%2Dright%2Dradius%3A4px%7D%2Elist%2Dgroup%2Ditem%3Alast%2Dchild%7Bmargin%2Dbottom%3A0%3Bborder%2Dbottom%2Dright%2Dradius%3A4px%3Bborder%2Dbottom%2Dleft%2Dradius%3A4px%7Da%2Elist%2Dgroup%2Ditem%2Cbutton%2Elist%2Dgroup%2Ditem%7Bcolor%3A%23555%7Da%2Elist%2Dgroup%2Ditem%20%2Elist%2Dgroup%2Ditem%2Dheading%2Cbutton%2Elist%2Dgroup%2Ditem%20%2Elist%2Dgroup%2Ditem%2Dheading%7Bcolor%3A%23333%7Da%2Elist%2Dgroup%2Ditem%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%3Ahover%7Bcolor%3A%23555%3Btext%2Ddecoration%3Anone%3Bbackground%2Dcolor%3A%23f5f5f5%7Dbutton%2Elist%2Dgroup%2Ditem%7Bwidth%3A100%25%3Btext%2Dalign%3Aleft%7D%2Elist%2Dgroup%2Ditem%2Edisabled%2C%2Elist%2Dgroup%2Ditem%2Edisabled%3Afocus%2C%2Elist%2Dgroup%2Ditem%2Edisabled%3Ahover%7Bcolor%3A%23777%3Bcursor%3Anot%2Dallowed%3Bbackground%2Dcolor%3A%23eee%7D%2Elist%2Dgroup%2Ditem%2Edisabled%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%2Elist%2Dgroup%2Ditem%2Edisabled%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%2Elist%2Dgroup%2Ditem%2Edisabled%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%7Bcolor%3Ainherit%7D%2Elist%2Dgroup%2Ditem%2Edisabled%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%2Elist%2Dgroup%2Ditem%2Edisabled%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%2Elist%2Dgroup%2Ditem%2Edisabled%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dtext%7Bcolor%3A%23777%7D%2Elist%2Dgroup%2Ditem%2Eactive%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%7Bz%2Dindex%3A2%3Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23337ab7%3Bborder%2Dcolor%3A%23337ab7%7D%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dheading%3E%2Esmall%2C%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dheading%3Esmall%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%3E%2Esmall%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dheading%3Esmall%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%3E%2Esmall%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dheading%3Esmall%7Bcolor%3Ainherit%7D%2Elist%2Dgroup%2Ditem%2Eactive%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Afocus%20%2Elist%2Dgroup%2Ditem%2Dtext%2C%2Elist%2Dgroup%2Ditem%2Eactive%3Ahover%20%2Elist%2Dgroup%2Ditem%2Dtext%7Bcolor%3A%23c7ddef%7D%2Elist%2Dgroup%2Ditem%2Dsuccess%7Bcolor%3A%233c763d%3Bbackground%2Dcolor%3A%23dff0d8%7Da%2Elist%2Dgroup%2Ditem%2Dsuccess%2Cbutton%2Elist%2Dgroup%2Ditem%2Dsuccess%7Bcolor%3A%233c763d%7Da%2Elist%2Dgroup%2Ditem%2Dsuccess%20%2Elist%2Dgroup%2Ditem%2Dheading%2Cbutton%2Elist%2Dgroup%2Ditem%2Dsuccess%20%2Elist%2Dgroup%2Ditem%2Dheading%7Bcolor%3Ainherit%7Da%2Elist%2Dgroup%2Ditem%2Dsuccess%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Dsuccess%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Dsuccess%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Dsuccess%3Ahover%7Bcolor%3A%233c763d%3Bbackground%2Dcolor%3A%23d0e9c6%7Da%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%2Ca%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%2Cbutton%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Dsuccess%2Eactive%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%233c763d%3Bborder%2Dcolor%3A%233c763d%7D%2Elist%2Dgroup%2Ditem%2Dinfo%7Bcolor%3A%2331708f%3Bbackground%2Dcolor%3A%23d9edf7%7Da%2Elist%2Dgroup%2Ditem%2Dinfo%2Cbutton%2Elist%2Dgroup%2Ditem%2Dinfo%7Bcolor%3A%2331708f%7Da%2Elist%2Dgroup%2Ditem%2Dinfo%20%2Elist%2Dgroup%2Ditem%2Dheading%2Cbutton%2Elist%2Dgroup%2Ditem%2Dinfo%20%2Elist%2Dgroup%2Ditem%2Dheading%7Bcolor%3Ainherit%7Da%2Elist%2Dgroup%2Ditem%2Dinfo%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Dinfo%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Dinfo%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Dinfo%3Ahover%7Bcolor%3A%2331708f%3Bbackground%2Dcolor%3A%23c4e3f3%7Da%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%2Ca%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%2Cbutton%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Dinfo%2Eactive%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%2331708f%3Bborder%2Dcolor%3A%2331708f%7D%2Elist%2Dgroup%2Ditem%2Dwarning%7Bcolor%3A%238a6d3b%3Bbackground%2Dcolor%3A%23fcf8e3%7Da%2Elist%2Dgroup%2Ditem%2Dwarning%2Cbutton%2Elist%2Dgroup%2Ditem%2Dwarning%7Bcolor%3A%238a6d3b%7Da%2Elist%2Dgroup%2Ditem%2Dwarning%20%2Elist%2Dgroup%2Ditem%2Dheading%2Cbutton%2Elist%2Dgroup%2Ditem%2Dwarning%20%2Elist%2Dgroup%2Ditem%2Dheading%7Bcolor%3Ainherit%7Da%2Elist%2Dgroup%2Ditem%2Dwarning%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Dwarning%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Dwarning%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Dwarning%3Ahover%7Bcolor%3A%238a6d3b%3Bbackground%2Dcolor%3A%23faf2cc%7Da%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%2Ca%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%2Cbutton%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Dwarning%2Eactive%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%238a6d3b%3Bborder%2Dcolor%3A%238a6d3b%7D%2Elist%2Dgroup%2Ditem%2Ddanger%7Bcolor%3A%23a94442%3Bbackground%2Dcolor%3A%23f2dede%7Da%2Elist%2Dgroup%2Ditem%2Ddanger%2Cbutton%2Elist%2Dgroup%2Ditem%2Ddanger%7Bcolor%3A%23a94442%7Da%2Elist%2Dgroup%2Ditem%2Ddanger%20%2Elist%2Dgroup%2Ditem%2Dheading%2Cbutton%2Elist%2Dgroup%2Ditem%2Ddanger%20%2Elist%2Dgroup%2Ditem%2Dheading%7Bcolor%3Ainherit%7Da%2Elist%2Dgroup%2Ditem%2Ddanger%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Ddanger%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Ddanger%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Ddanger%3Ahover%7Bcolor%3A%23a94442%3Bbackground%2Dcolor%3A%23ebcccc%7Da%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%2Ca%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%3Afocus%2Ca%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%3Ahover%2Cbutton%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%2Cbutton%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%3Afocus%2Cbutton%2Elist%2Dgroup%2Ditem%2Ddanger%2Eactive%3Ahover%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23a94442%3Bborder%2Dcolor%3A%23a94442%7D%2Elist%2Dgroup%2Ditem%2Dheading%7Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A5px%7D%2Elist%2Dgroup%2Ditem%2Dtext%7Bmargin%2Dbottom%3A0%3Bline%2Dheight%3A1%2E3%7D%2Epanel%7Bmargin%2Dbottom%3A20px%3Bbackground%2Dcolor%3A%23fff%3Bborder%3A1px%20solid%20transparent%3Bborder%2Dradius%3A4px%3B%2Dwebkit%2Dbox%2Dshadow%3A0%201px%201px%20rgba%280%2C0%2C0%2C%2E05%29%3Bbox%2Dshadow%3A0%201px%201px%20rgba%280%2C0%2C0%2C%2E05%29%7D%2Epanel%2Dbody%7Bpadding%3A15px%7D%2Epanel%2Dheading%7Bpadding%3A10px%2015px%3Bborder%2Dbottom%3A1px%20solid%20transparent%3Bborder%2Dtop%2Dleft%2Dradius%3A3px%3Bborder%2Dtop%2Dright%2Dradius%3A3px%7D%2Epanel%2Dheading%3E%2Edropdown%20%2Edropdown%2Dtoggle%7Bcolor%3Ainherit%7D%2Epanel%2Dtitle%7Bmargin%2Dtop%3A0%3Bmargin%2Dbottom%3A0%3Bfont%2Dsize%3A16px%3Bcolor%3Ainherit%7D%2Epanel%2Dtitle%3E%2Esmall%2C%2Epanel%2Dtitle%3E%2Esmall%3Ea%2C%2Epanel%2Dtitle%3Ea%2C%2Epanel%2Dtitle%3Esmall%2C%2Epanel%2Dtitle%3Esmall%3Ea%7Bcolor%3Ainherit%7D%2Epanel%2Dfooter%7Bpadding%3A10px%2015px%3Bbackground%2Dcolor%3A%23f5f5f5%3Bborder%2Dtop%3A1px%20solid%20%23ddd%3Bborder%2Dbottom%2Dright%2Dradius%3A3px%3Bborder%2Dbottom%2Dleft%2Dradius%3A3px%7D%2Epanel%3E%2Elist%2Dgroup%2C%2Epanel%3E%2Epanel%2Dcollapse%3E%2Elist%2Dgroup%7Bmargin%2Dbottom%3A0%7D%2Epanel%3E%2Elist%2Dgroup%20%2Elist%2Dgroup%2Ditem%2C%2Epanel%3E%2Epanel%2Dcollapse%3E%2Elist%2Dgroup%20%2Elist%2Dgroup%2Ditem%7Bborder%2Dwidth%3A1px%200%3Bborder%2Dradius%3A0%7D%2Epanel%3E%2Elist%2Dgroup%3Afirst%2Dchild%20%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%2C%2Epanel%3E%2Epanel%2Dcollapse%3E%2Elist%2Dgroup%3Afirst%2Dchild%20%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%7Bborder%2Dtop%3A0%3Bborder%2Dtop%2Dleft%2Dradius%3A3px%3Bborder%2Dtop%2Dright%2Dradius%3A3px%7D%2Epanel%3E%2Elist%2Dgroup%3Alast%2Dchild%20%2Elist%2Dgroup%2Ditem%3Alast%2Dchild%2C%2Epanel%3E%2Epanel%2Dcollapse%3E%2Elist%2Dgroup%3Alast%2Dchild%20%2Elist%2Dgroup%2Ditem%3Alast%2Dchild%7Bborder%2Dbottom%3A0%3Bborder%2Dbottom%2Dright%2Dradius%3A3px%3Bborder%2Dbottom%2Dleft%2Dradius%3A3px%7D%2Epanel%3E%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Elist%2Dgroup%20%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%7Bborder%2Dtop%2Dleft%2Dradius%3A0%3Bborder%2Dtop%2Dright%2Dradius%3A0%7D%2Epanel%2Dheading%2B%2Elist%2Dgroup%20%2Elist%2Dgroup%2Ditem%3Afirst%2Dchild%7Bborder%2Dtop%2Dwidth%3A0%7D%2Elist%2Dgroup%2B%2Epanel%2Dfooter%7Bborder%2Dtop%2Dwidth%3A0%7D%2Epanel%3E%2Epanel%2Dcollapse%3E%2Etable%2C%2Epanel%3E%2Etable%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%7Bmargin%2Dbottom%3A0%7D%2Epanel%3E%2Epanel%2Dcollapse%3E%2Etable%20caption%2C%2Epanel%3E%2Etable%20caption%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%20caption%7Bpadding%2Dright%3A15px%3Bpadding%2Dleft%3A15px%7D%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%7Bborder%2Dtop%2Dleft%2Dradius%3A3px%3Bborder%2Dtop%2Dright%2Dradius%3A3px%7D%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%7Bborder%2Dtop%2Dleft%2Dradius%3A3px%3Bborder%2Dtop%2Dright%2Dradius%3A3px%7D%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Afirst%2Dchild%7Bborder%2Dtop%2Dleft%2Dradius%3A3px%7D%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Afirst%2Dchild%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Afirst%2Dchild%3Ethead%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%3Alast%2Dchild%7Bborder%2Dtop%2Dright%2Dradius%3A3px%7D%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%7Bborder%2Dbottom%2Dright%2Dradius%3A3px%3Bborder%2Dbottom%2Dleft%2Dradius%3A3px%7D%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%7Bborder%2Dbottom%2Dright%2Dradius%3A3px%3Bborder%2Dbottom%2Dleft%2Dradius%3A3px%7D%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Afirst%2Dchild%7Bborder%2Dbottom%2Dleft%2Dradius%3A3px%7D%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3Alast%2Dchild%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etbody%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20td%3Alast%2Dchild%2C%2Epanel%3E%2Etable%3Alast%2Dchild%3Etfoot%3Alast%2Dchild%3Etr%3Alast%2Dchild%20th%3Alast%2Dchild%7Bborder%2Dbottom%2Dright%2Dradius%3A3px%7D%2Epanel%3E%2Epanel%2Dbody%2B%2Etable%2C%2Epanel%3E%2Epanel%2Dbody%2B%2Etable%2Dresponsive%2C%2Epanel%3E%2Etable%2B%2Epanel%2Dbody%2C%2Epanel%3E%2Etable%2Dresponsive%2B%2Epanel%2Dbody%7Bborder%2Dtop%3A1px%20solid%20%23ddd%7D%2Epanel%3E%2Etable%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20td%2C%2Epanel%3E%2Etable%3Etbody%3Afirst%2Dchild%3Etr%3Afirst%2Dchild%20th%7Bborder%2Dtop%3A0%7D%2Epanel%3E%2Etable%2Dbordered%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%7Bborder%3A0%7D%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Etd%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Eth%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Etd%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Eth%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Ethead%3Etr%3Etd%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Ethead%3Etr%3Eth%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Etd%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Eth%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Etd%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Eth%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Etd%3Afirst%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Eth%3Afirst%2Dchild%7Bborder%2Dleft%3A0%7D%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Etd%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Eth%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Etd%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Eth%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Ethead%3Etr%3Etd%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dbordered%3Ethead%3Etr%3Eth%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Etd%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Eth%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Etd%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Eth%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Etd%3Alast%2Dchild%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Eth%3Alast%2Dchild%7Bborder%2Dright%3A0%7D%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Afirst%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Afirst%2Dchild%3Eth%2C%2Epanel%3E%2Etable%2Dbordered%3Ethead%3Etr%3Afirst%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dbordered%3Ethead%3Etr%3Afirst%2Dchild%3Eth%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Afirst%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Afirst%2Dchild%3Eth%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Afirst%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Ethead%3Etr%3Afirst%2Dchild%3Eth%7Bborder%2Dbottom%3A0%7D%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Alast%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dbordered%3Etbody%3Etr%3Alast%2Dchild%3Eth%2C%2Epanel%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Alast%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Alast%2Dchild%3Eth%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Alast%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etbody%3Etr%3Alast%2Dchild%3Eth%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Alast%2Dchild%3Etd%2C%2Epanel%3E%2Etable%2Dresponsive%3E%2Etable%2Dbordered%3Etfoot%3Etr%3Alast%2Dchild%3Eth%7Bborder%2Dbottom%3A0%7D%2Epanel%3E%2Etable%2Dresponsive%7Bmargin%2Dbottom%3A0%3Bborder%3A0%7D%2Epanel%2Dgroup%7Bmargin%2Dbottom%3A20px%7D%2Epanel%2Dgroup%20%2Epanel%7Bmargin%2Dbottom%3A0%3Bborder%2Dradius%3A4px%7D%2Epanel%2Dgroup%20%2Epanel%2B%2Epanel%7Bmargin%2Dtop%3A5px%7D%2Epanel%2Dgroup%20%2Epanel%2Dheading%7Bborder%2Dbottom%3A0%7D%2Epanel%2Dgroup%20%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Elist%2Dgroup%2C%2Epanel%2Dgroup%20%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dtop%3A1px%20solid%20%23ddd%7D%2Epanel%2Dgroup%20%2Epanel%2Dfooter%7Bborder%2Dtop%3A0%7D%2Epanel%2Dgroup%20%2Epanel%2Dfooter%2B%2Epanel%2Dcollapse%20%2Epanel%2Dbody%7Bborder%2Dbottom%3A1px%20solid%20%23ddd%7D%2Epanel%2Ddefault%7Bborder%2Dcolor%3A%23ddd%7D%2Epanel%2Ddefault%3E%2Epanel%2Dheading%7Bcolor%3A%23333%3Bbackground%2Dcolor%3A%23f5f5f5%3Bborder%2Dcolor%3A%23ddd%7D%2Epanel%2Ddefault%3E%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dtop%2Dcolor%3A%23ddd%7D%2Epanel%2Ddefault%3E%2Epanel%2Dheading%20%2Ebadge%7Bcolor%3A%23f5f5f5%3Bbackground%2Dcolor%3A%23333%7D%2Epanel%2Ddefault%3E%2Epanel%2Dfooter%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dbottom%2Dcolor%3A%23ddd%7D%2Epanel%2Dprimary%7Bborder%2Dcolor%3A%23337ab7%7D%2Epanel%2Dprimary%3E%2Epanel%2Dheading%7Bcolor%3A%23fff%3Bbackground%2Dcolor%3A%23337ab7%3Bborder%2Dcolor%3A%23337ab7%7D%2Epanel%2Dprimary%3E%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dtop%2Dcolor%3A%23337ab7%7D%2Epanel%2Dprimary%3E%2Epanel%2Dheading%20%2Ebadge%7Bcolor%3A%23337ab7%3Bbackground%2Dcolor%3A%23fff%7D%2Epanel%2Dprimary%3E%2Epanel%2Dfooter%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dbottom%2Dcolor%3A%23337ab7%7D%2Epanel%2Dsuccess%7Bborder%2Dcolor%3A%23d6e9c6%7D%2Epanel%2Dsuccess%3E%2Epanel%2Dheading%7Bcolor%3A%233c763d%3Bbackground%2Dcolor%3A%23dff0d8%3Bborder%2Dcolor%3A%23d6e9c6%7D%2Epanel%2Dsuccess%3E%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dtop%2Dcolor%3A%23d6e9c6%7D%2Epanel%2Dsuccess%3E%2Epanel%2Dheading%20%2Ebadge%7Bcolor%3A%23dff0d8%3Bbackground%2Dcolor%3A%233c763d%7D%2Epanel%2Dsuccess%3E%2Epanel%2Dfooter%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dbottom%2Dcolor%3A%23d6e9c6%7D%2Epanel%2Dinfo%7Bborder%2Dcolor%3A%23bce8f1%7D%2Epanel%2Dinfo%3E%2Epanel%2Dheading%7Bcolor%3A%2331708f%3Bbackground%2Dcolor%3A%23d9edf7%3Bborder%2Dcolor%3A%23bce8f1%7D%2Epanel%2Dinfo%3E%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dtop%2Dcolor%3A%23bce8f1%7D%2Epanel%2Dinfo%3E%2Epanel%2Dheading%20%2Ebadge%7Bcolor%3A%23d9edf7%3Bbackground%2Dcolor%3A%2331708f%7D%2Epanel%2Dinfo%3E%2Epanel%2Dfooter%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dbottom%2Dcolor%3A%23bce8f1%7D%2Epanel%2Dwarning%7Bborder%2Dcolor%3A%23faebcc%7D%2Epanel%2Dwarning%3E%2Epanel%2Dheading%7Bcolor%3A%238a6d3b%3Bbackground%2Dcolor%3A%23fcf8e3%3Bborder%2Dcolor%3A%23faebcc%7D%2Epanel%2Dwarning%3E%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dtop%2Dcolor%3A%23faebcc%7D%2Epanel%2Dwarning%3E%2Epanel%2Dheading%20%2Ebadge%7Bcolor%3A%23fcf8e3%3Bbackground%2Dcolor%3A%238a6d3b%7D%2Epanel%2Dwarning%3E%2Epanel%2Dfooter%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dbottom%2Dcolor%3A%23faebcc%7D%2Epanel%2Ddanger%7Bborder%2Dcolor%3A%23ebccd1%7D%2Epanel%2Ddanger%3E%2Epanel%2Dheading%7Bcolor%3A%23a94442%3Bbackground%2Dcolor%3A%23f2dede%3Bborder%2Dcolor%3A%23ebccd1%7D%2Epanel%2Ddanger%3E%2Epanel%2Dheading%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dtop%2Dcolor%3A%23ebccd1%7D%2Epanel%2Ddanger%3E%2Epanel%2Dheading%20%2Ebadge%7Bcolor%3A%23f2dede%3Bbackground%2Dcolor%3A%23a94442%7D%2Epanel%2Ddanger%3E%2Epanel%2Dfooter%2B%2Epanel%2Dcollapse%3E%2Epanel%2Dbody%7Bborder%2Dbottom%2Dcolor%3A%23ebccd1%7D%2Eembed%2Dresponsive%7Bposition%3Arelative%3Bdisplay%3Ablock%3Bheight%3A0%3Bpadding%3A0%3Boverflow%3Ahidden%7D%2Eembed%2Dresponsive%20%2Eembed%2Dresponsive%2Ditem%2C%2Eembed%2Dresponsive%20embed%2C%2Eembed%2Dresponsive%20iframe%2C%2Eembed%2Dresponsive%20object%2C%2Eembed%2Dresponsive%20video%7Bposition%3Aabsolute%3Btop%3A0%3Bbottom%3A0%3Bleft%3A0%3Bwidth%3A100%25%3Bheight%3A100%25%3Bborder%3A0%7D%2Eembed%2Dresponsive%2D16by9%7Bpadding%2Dbottom%3A56%2E25%25%7D%2Eembed%2Dresponsive%2D4by3%7Bpadding%2Dbottom%3A75%25%7D%2Ewell%7Bmin%2Dheight%3A20px%3Bpadding%3A19px%3Bmargin%2Dbottom%3A20px%3Bbackground%2Dcolor%3A%23f5f5f5%3Bborder%3A1px%20solid%20%23e3e3e3%3Bborder%2Dradius%3A4px%3B%2Dwebkit%2Dbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E05%29%3Bbox%2Dshadow%3Ainset%200%201px%201px%20rgba%280%2C0%2C0%2C%2E05%29%7D%2Ewell%20blockquote%7Bborder%2Dcolor%3A%23ddd%3Bborder%2Dcolor%3Argba%280%2C0%2C0%2C%2E15%29%7D%2Ewell%2Dlg%7Bpadding%3A24px%3Bborder%2Dradius%3A6px%7D%2Ewell%2Dsm%7Bpadding%3A9px%3Bborder%2Dradius%3A3px%7D%2Eclose%7Bfloat%3Aright%3Bfont%2Dsize%3A21px%3Bfont%2Dweight%3A700%3Bline%2Dheight%3A1%3Bcolor%3A%23000%3Btext%2Dshadow%3A0%201px%200%20%23fff%3Bfilter%3Aalpha%28opacity%3D20%29%3Bopacity%3A%2E2%7D%2Eclose%3Afocus%2C%2Eclose%3Ahover%7Bcolor%3A%23000%3Btext%2Ddecoration%3Anone%3Bcursor%3Apointer%3Bfilter%3Aalpha%28opacity%3D50%29%3Bopacity%3A%2E5%7Dbutton%2Eclose%7B%2Dwebkit%2Dappearance%3Anone%3Bpadding%3A0%3Bcursor%3Apointer%3Bbackground%3A0%200%3Bborder%3A0%7D%2Emodal%2Dopen%7Boverflow%3Ahidden%7D%2Emodal%7Bposition%3Afixed%3Btop%3A0%3Bright%3A0%3Bbottom%3A0%3Bleft%3A0%3Bz%2Dindex%3A1050%3Bdisplay%3Anone%3Boverflow%3Ahidden%3B%2Dwebkit%2Doverflow%2Dscrolling%3Atouch%3Boutline%3A0%7D%2Emodal%2Efade%20%2Emodal%2Ddialog%7B%2Dwebkit%2Dtransition%3A%2Dwebkit%2Dtransform%20%2E3s%20ease%2Dout%3B%2Do%2Dtransition%3A%2Do%2Dtransform%20%2E3s%20ease%2Dout%3Btransition%3Atransform%20%2E3s%20ease%2Dout%3B%2Dwebkit%2Dtransform%3Atranslate%280%2C%2D25%25%29%3B%2Dms%2Dtransform%3Atranslate%280%2C%2D25%25%29%3B%2Do%2Dtransform%3Atranslate%280%2C%2D25%25%29%3Btransform%3Atranslate%280%2C%2D25%25%29%7D%2Emodal%2Ein%20%2Emodal%2Ddialog%7B%2Dwebkit%2Dtransform%3Atranslate%280%2C0%29%3B%2Dms%2Dtransform%3Atranslate%280%2C0%29%3B%2Do%2Dtransform%3Atranslate%280%2C0%29%3Btransform%3Atranslate%280%2C0%29%7D%2Emodal%2Dopen%20%2Emodal%7Boverflow%2Dx%3Ahidden%3Boverflow%2Dy%3Aauto%7D%2Emodal%2Ddialog%7Bposition%3Arelative%3Bwidth%3Aauto%3Bmargin%3A10px%7D%2Emodal%2Dcontent%7Bposition%3Arelative%3Bbackground%2Dcolor%3A%23fff%3B%2Dwebkit%2Dbackground%2Dclip%3Apadding%2Dbox%3Bbackground%2Dclip%3Apadding%2Dbox%3Bborder%3A1px%20solid%20%23999%3Bborder%3A1px%20solid%20rgba%280%2C0%2C0%2C%2E2%29%3Bborder%2Dradius%3A6px%3Boutline%3A0%3B%2Dwebkit%2Dbox%2Dshadow%3A0%203px%209px%20rgba%280%2C0%2C0%2C%2E5%29%3Bbox%2Dshadow%3A0%203px%209px%20rgba%280%2C0%2C0%2C%2E5%29%7D%2Emodal%2Dbackdrop%7Bposition%3Afixed%3Btop%3A0%3Bright%3A0%3Bbottom%3A0%3Bleft%3A0%3Bz%2Dindex%3A1040%3Bbackground%2Dcolor%3A%23000%7D%2Emodal%2Dbackdrop%2Efade%7Bfilter%3Aalpha%28opacity%3D0%29%3Bopacity%3A0%7D%2Emodal%2Dbackdrop%2Ein%7Bfilter%3Aalpha%28opacity%3D50%29%3Bopacity%3A%2E5%7D%2Emodal%2Dheader%7Bmin%2Dheight%3A16%2E43px%3Bpadding%3A15px%3Bborder%2Dbottom%3A1px%20solid%20%23e5e5e5%7D%2Emodal%2Dheader%20%2Eclose%7Bmargin%2Dtop%3A%2D2px%7D%2Emodal%2Dtitle%7Bmargin%3A0%3Bline%2Dheight%3A1%2E42857143%7D%2Emodal%2Dbody%7Bposition%3Arelative%3Bpadding%3A15px%7D%2Emodal%2Dfooter%7Bpadding%3A15px%3Btext%2Dalign%3Aright%3Bborder%2Dtop%3A1px%20solid%20%23e5e5e5%7D%2Emodal%2Dfooter%20%2Ebtn%2B%2Ebtn%7Bmargin%2Dbottom%3A0%3Bmargin%2Dleft%3A5px%7D%2Emodal%2Dfooter%20%2Ebtn%2Dgroup%20%2Ebtn%2B%2Ebtn%7Bmargin%2Dleft%3A%2D1px%7D%2Emodal%2Dfooter%20%2Ebtn%2Dblock%2B%2Ebtn%2Dblock%7Bmargin%2Dleft%3A0%7D%2Emodal%2Dscrollbar%2Dmeasure%7Bposition%3Aabsolute%3Btop%3A%2D9999px%3Bwidth%3A50px%3Bheight%3A50px%3Boverflow%3Ascroll%7D%40media%20%28min%2Dwidth%3A768px%29%7B%2Emodal%2Ddialog%7Bwidth%3A600px%3Bmargin%3A30px%20auto%7D%2Emodal%2Dcontent%7B%2Dwebkit%2Dbox%2Dshadow%3A0%205px%2015px%20rgba%280%2C0%2C0%2C%2E5%29%3Bbox%2Dshadow%3A0%205px%2015px%20rgba%280%2C0%2C0%2C%2E5%29%7D%2Emodal%2Dsm%7Bwidth%3A300px%7D%7D%40media%20%28min%2Dwidth%3A992px%29%7B%2Emodal%2Dlg%7Bwidth%3A900px%7D%7D%2Etooltip%7Bposition%3Aabsolute%3Bz%2Dindex%3A1070%3Bdisplay%3Ablock%3Bfont%2Dfamily%3A%22Helvetica%20Neue%22%2CHelvetica%2CArial%2Csans%2Dserif%3Bfont%2Dsize%3A12px%3Bfont%2Dstyle%3Anormal%3Bfont%2Dweight%3A400%3Bline%2Dheight%3A1%2E42857143%3Btext%2Dalign%3Aleft%3Btext%2Dalign%3Astart%3Btext%2Ddecoration%3Anone%3Btext%2Dshadow%3Anone%3Btext%2Dtransform%3Anone%3Bletter%2Dspacing%3Anormal%3Bword%2Dbreak%3Anormal%3Bword%2Dspacing%3Anormal%3Bword%2Dwrap%3Anormal%3Bwhite%2Dspace%3Anormal%3Bfilter%3Aalpha%28opacity%3D0%29%3Bopacity%3A0%3Bline%2Dbreak%3Aauto%7D%2Etooltip%2Ein%7Bfilter%3Aalpha%28opacity%3D90%29%3Bopacity%3A%2E9%7D%2Etooltip%2Etop%7Bpadding%3A5px%200%3Bmargin%2Dtop%3A%2D3px%7D%2Etooltip%2Eright%7Bpadding%3A0%205px%3Bmargin%2Dleft%3A3px%7D%2Etooltip%2Ebottom%7Bpadding%3A5px%200%3Bmargin%2Dtop%3A3px%7D%2Etooltip%2Eleft%7Bpadding%3A0%205px%3Bmargin%2Dleft%3A%2D3px%7D%2Etooltip%2Dinner%7Bmax%2Dwidth%3A200px%3Bpadding%3A3px%208px%3Bcolor%3A%23fff%3Btext%2Dalign%3Acenter%3Bbackground%2Dcolor%3A%23000%3Bborder%2Dradius%3A4px%7D%2Etooltip%2Darrow%7Bposition%3Aabsolute%3Bwidth%3A0%3Bheight%3A0%3Bborder%2Dcolor%3Atransparent%3Bborder%2Dstyle%3Asolid%7D%2Etooltip%2Etop%20%2Etooltip%2Darrow%7Bbottom%3A0%3Bleft%3A50%25%3Bmargin%2Dleft%3A%2D5px%3Bborder%2Dwidth%3A5px%205px%200%3Bborder%2Dtop%2Dcolor%3A%23000%7D%2Etooltip%2Etop%2Dleft%20%2Etooltip%2Darrow%7Bright%3A5px%3Bbottom%3A0%3Bmargin%2Dbottom%3A%2D5px%3Bborder%2Dwidth%3A5px%205px%200%3Bborder%2Dtop%2Dcolor%3A%23000%7D%2Etooltip%2Etop%2Dright%20%2Etooltip%2Darrow%7Bbottom%3A0%3Bleft%3A5px%3Bmargin%2Dbottom%3A%2D5px%3Bborder%2Dwidth%3A5px%205px%200%3Bborder%2Dtop%2Dcolor%3A%23000%7D%2Etooltip%2Eright%20%2Etooltip%2Darrow%7Btop%3A50%25%3Bleft%3A0%3Bmargin%2Dtop%3A%2D5px%3Bborder%2Dwidth%3A5px%205px%205px%200%3Bborder%2Dright%2Dcolor%3A%23000%7D%2Etooltip%2Eleft%20%2Etooltip%2Darrow%7Btop%3A50%25%3Bright%3A0%3Bmargin%2Dtop%3A%2D5px%3Bborder%2Dwidth%3A5px%200%205px%205px%3Bborder%2Dleft%2Dcolor%3A%23000%7D%2Etooltip%2Ebottom%20%2Etooltip%2Darrow%7Btop%3A0%3Bleft%3A50%25%3Bmargin%2Dleft%3A%2D5px%3Bborder%2Dwidth%3A0%205px%205px%3Bborder%2Dbottom%2Dcolor%3A%23000%7D%2Etooltip%2Ebottom%2Dleft%20%2Etooltip%2Darrow%7Btop%3A0%3Bright%3A5px%3Bmargin%2Dtop%3A%2D5px%3Bborder%2Dwidth%3A0%205px%205px%3Bborder%2Dbottom%2Dcolor%3A%23000%7D%2Etooltip%2Ebottom%2Dright%20%2Etooltip%2Darrow%7Btop%3A0%3Bleft%3A5px%3Bmargin%2Dtop%3A%2D5px%3Bborder%2Dwidth%3A0%205px%205px%3Bborder%2Dbottom%2Dcolor%3A%23000%7D%2Epopover%7Bposition%3Aabsolute%3Btop%3A0%3Bleft%3A0%3Bz%2Dindex%3A1060%3Bdisplay%3Anone%3Bmax%2Dwidth%3A276px%3Bpadding%3A1px%3Bfont%2Dfamily%3A%22Helvetica%20Neue%22%2CHelvetica%2CArial%2Csans%2Dserif%3Bfont%2Dsize%3A14px%3Bfont%2Dstyle%3Anormal%3Bfont%2Dweight%3A400%3Bline%2Dheight%3A1%2E42857143%3Btext%2Dalign%3Aleft%3Btext%2Dalign%3Astart%3Btext%2Ddecoration%3Anone%3Btext%2Dshadow%3Anone%3Btext%2Dtransform%3Anone%3Bletter%2Dspacing%3Anormal%3Bword%2Dbreak%3Anormal%3Bword%2Dspacing%3Anormal%3Bword%2Dwrap%3Anormal%3Bwhite%2Dspace%3Anormal%3Bbackground%2Dcolor%3A%23fff%3B%2Dwebkit%2Dbackground%2Dclip%3Apadding%2Dbox%3Bbackground%2Dclip%3Apadding%2Dbox%3Bborder%3A1px%20solid%20%23ccc%3Bborder%3A1px%20solid%20rgba%280%2C0%2C0%2C%2E2%29%3Bborder%2Dradius%3A6px%3B%2Dwebkit%2Dbox%2Dshadow%3A0%205px%2010px%20rgba%280%2C0%2C0%2C%2E2%29%3Bbox%2Dshadow%3A0%205px%2010px%20rgba%280%2C0%2C0%2C%2E2%29%3Bline%2Dbreak%3Aauto%7D%2Epopover%2Etop%7Bmargin%2Dtop%3A%2D10px%7D%2Epopover%2Eright%7Bmargin%2Dleft%3A10px%7D%2Epopover%2Ebottom%7Bmargin%2Dtop%3A10px%7D%2Epopover%2Eleft%7Bmargin%2Dleft%3A%2D10px%7D%2Epopover%2Dtitle%7Bpadding%3A8px%2014px%3Bmargin%3A0%3Bfont%2Dsize%3A14px%3Bbackground%2Dcolor%3A%23f7f7f7%3Bborder%2Dbottom%3A1px%20solid%20%23ebebeb%3Bborder%2Dradius%3A5px%205px%200%200%7D%2Epopover%2Dcontent%7Bpadding%3A9px%2014px%7D%2Epopover%3E%2Earrow%2C%2Epopover%3E%2Earrow%3Aafter%7Bposition%3Aabsolute%3Bdisplay%3Ablock%3Bwidth%3A0%3Bheight%3A0%3Bborder%2Dcolor%3Atransparent%3Bborder%2Dstyle%3Asolid%7D%2Epopover%3E%2Earrow%7Bborder%2Dwidth%3A11px%7D%2Epopover%3E%2Earrow%3Aafter%7Bcontent%3A%22%22%3Bborder%2Dwidth%3A10px%7D%2Epopover%2Etop%3E%2Earrow%7Bbottom%3A%2D11px%3Bleft%3A50%25%3Bmargin%2Dleft%3A%2D11px%3Bborder%2Dtop%2Dcolor%3A%23999%3Bborder%2Dtop%2Dcolor%3Argba%280%2C0%2C0%2C%2E25%29%3Bborder%2Dbottom%2Dwidth%3A0%7D%2Epopover%2Etop%3E%2Earrow%3Aafter%7Bbottom%3A1px%3Bmargin%2Dleft%3A%2D10px%3Bcontent%3A%22%20%22%3Bborder%2Dtop%2Dcolor%3A%23fff%3Bborder%2Dbottom%2Dwidth%3A0%7D%2Epopover%2Eright%3E%2Earrow%7Btop%3A50%25%3Bleft%3A%2D11px%3Bmargin%2Dtop%3A%2D11px%3Bborder%2Dright%2Dcolor%3A%23999%3Bborder%2Dright%2Dcolor%3Argba%280%2C0%2C0%2C%2E25%29%3Bborder%2Dleft%2Dwidth%3A0%7D%2Epopover%2Eright%3E%2Earrow%3Aafter%7Bbottom%3A%2D10px%3Bleft%3A1px%3Bcontent%3A%22%20%22%3Bborder%2Dright%2Dcolor%3A%23fff%3Bborder%2Dleft%2Dwidth%3A0%7D%2Epopover%2Ebottom%3E%2Earrow%7Btop%3A%2D11px%3Bleft%3A50%25%3Bmargin%2Dleft%3A%2D11px%3Bborder%2Dtop%2Dwidth%3A0%3Bborder%2Dbottom%2Dcolor%3A%23999%3Bborder%2Dbottom%2Dcolor%3Argba%280%2C0%2C0%2C%2E25%29%7D%2Epopover%2Ebottom%3E%2Earrow%3Aafter%7Btop%3A1px%3Bmargin%2Dleft%3A%2D10px%3Bcontent%3A%22%20%22%3Bborder%2Dtop%2Dwidth%3A0%3Bborder%2Dbottom%2Dcolor%3A%23fff%7D%2Epopover%2Eleft%3E%2Earrow%7Btop%3A50%25%3Bright%3A%2D11px%3Bmargin%2Dtop%3A%2D11px%3Bborder%2Dright%2Dwidth%3A0%3Bborder%2Dleft%2Dcolor%3A%23999%3Bborder%2Dleft%2Dcolor%3Argba%280%2C0%2C0%2C%2E25%29%7D%2Epopover%2Eleft%3E%2Earrow%3Aafter%7Bright%3A1px%3Bbottom%3A%2D10px%3Bcontent%3A%22%20%22%3Bborder%2Dright%2Dwidth%3A0%3Bborder%2Dleft%2Dcolor%3A%23fff%7D%2Ecarousel%7Bposition%3Arelative%7D%2Ecarousel%2Dinner%7Bposition%3Arelative%3Bwidth%3A100%25%3Boverflow%3Ahidden%7D%2Ecarousel%2Dinner%3E%2Eitem%7Bposition%3Arelative%3Bdisplay%3Anone%3B%2Dwebkit%2Dtransition%3A%2E6s%20ease%2Din%2Dout%20left%3B%2Do%2Dtransition%3A%2E6s%20ease%2Din%2Dout%20left%3Btransition%3A%2E6s%20ease%2Din%2Dout%20left%7D%2Ecarousel%2Dinner%3E%2Eitem%3Ea%3Eimg%2C%2Ecarousel%2Dinner%3E%2Eitem%3Eimg%7Bline%2Dheight%3A1%7D%40media%20all%20and%20%28transform%2D3d%29%2C%28%2Dwebkit%2Dtransform%2D3d%29%7B%2Ecarousel%2Dinner%3E%2Eitem%7B%2Dwebkit%2Dtransition%3A%2Dwebkit%2Dtransform%20%2E6s%20ease%2Din%2Dout%3B%2Do%2Dtransition%3A%2Do%2Dtransform%20%2E6s%20ease%2Din%2Dout%3Btransition%3Atransform%20%2E6s%20ease%2Din%2Dout%3B%2Dwebkit%2Dbackface%2Dvisibility%3Ahidden%3Bbackface%2Dvisibility%3Ahidden%3B%2Dwebkit%2Dperspective%3A1000px%3Bperspective%3A1000px%7D%2Ecarousel%2Dinner%3E%2Eitem%2Eactive%2Eright%2C%2Ecarousel%2Dinner%3E%2Eitem%2Enext%7Bleft%3A0%3B%2Dwebkit%2Dtransform%3Atranslate3d%28100%25%2C0%2C0%29%3Btransform%3Atranslate3d%28100%25%2C0%2C0%29%7D%2Ecarousel%2Dinner%3E%2Eitem%2Eactive%2Eleft%2C%2Ecarousel%2Dinner%3E%2Eitem%2Eprev%7Bleft%3A0%3B%2Dwebkit%2Dtransform%3Atranslate3d%28%2D100%25%2C0%2C0%29%3Btransform%3Atranslate3d%28%2D100%25%2C0%2C0%29%7D%2Ecarousel%2Dinner%3E%2Eitem%2Eactive%2C%2Ecarousel%2Dinner%3E%2Eitem%2Enext%2Eleft%2C%2Ecarousel%2Dinner%3E%2Eitem%2Eprev%2Eright%7Bleft%3A0%3B%2Dwebkit%2Dtransform%3Atranslate3d%280%2C0%2C0%29%3Btransform%3Atranslate3d%280%2C0%2C0%29%7D%7D%2Ecarousel%2Dinner%3E%2Eactive%2C%2Ecarousel%2Dinner%3E%2Enext%2C%2Ecarousel%2Dinner%3E%2Eprev%7Bdisplay%3Ablock%7D%2Ecarousel%2Dinner%3E%2Eactive%7Bleft%3A0%7D%2Ecarousel%2Dinner%3E%2Enext%2C%2Ecarousel%2Dinner%3E%2Eprev%7Bposition%3Aabsolute%3Btop%3A0%3Bwidth%3A100%25%7D%2Ecarousel%2Dinner%3E%2Enext%7Bleft%3A100%25%7D%2Ecarousel%2Dinner%3E%2Eprev%7Bleft%3A%2D100%25%7D%2Ecarousel%2Dinner%3E%2Enext%2Eleft%2C%2Ecarousel%2Dinner%3E%2Eprev%2Eright%7Bleft%3A0%7D%2Ecarousel%2Dinner%3E%2Eactive%2Eleft%7Bleft%3A%2D100%25%7D%2Ecarousel%2Dinner%3E%2Eactive%2Eright%7Bleft%3A100%25%7D%2Ecarousel%2Dcontrol%7Bposition%3Aabsolute%3Btop%3A0%3Bbottom%3A0%3Bleft%3A0%3Bwidth%3A15%25%3Bfont%2Dsize%3A20px%3Bcolor%3A%23fff%3Btext%2Dalign%3Acenter%3Btext%2Dshadow%3A0%201px%202px%20rgba%280%2C0%2C0%2C%2E6%29%3Bfilter%3Aalpha%28opacity%3D50%29%3Bopacity%3A%2E5%7D%2Ecarousel%2Dcontrol%2Eleft%7Bbackground%2Dimage%3A%2Dwebkit%2Dlinear%2Dgradient%28left%2Crgba%280%2C0%2C0%2C%2E5%29%200%2Crgba%280%2C0%2C0%2C%2E0001%29%20100%25%29%3Bbackground%2Dimage%3A%2Do%2Dlinear%2Dgradient%28left%2Crgba%280%2C0%2C0%2C%2E5%29%200%2Crgba%280%2C0%2C0%2C%2E0001%29%20100%25%29%3Bbackground%2Dimage%3A%2Dwebkit%2Dgradient%28linear%2Cleft%20top%2Cright%20top%2Cfrom%28rgba%280%2C0%2C0%2C%2E5%29%29%2Cto%28rgba%280%2C0%2C0%2C%2E0001%29%29%29%3Bbackground%2Dimage%3Alinear%2Dgradient%28to%20right%2Crgba%280%2C0%2C0%2C%2E5%29%200%2Crgba%280%2C0%2C0%2C%2E0001%29%20100%25%29%3Bfilter%3Aprogid%3ADXImageTransform%2EMicrosoft%2Egradient%28startColorstr%3D%27%2380000000%27%2C%20endColorstr%3D%27%2300000000%27%2C%20GradientType%3D1%29%3Bbackground%2Drepeat%3Arepeat%2Dx%7D%2Ecarousel%2Dcontrol%2Eright%7Bright%3A0%3Bleft%3Aauto%3Bbackground%2Dimage%3A%2Dwebkit%2Dlinear%2Dgradient%28left%2Crgba%280%2C0%2C0%2C%2E0001%29%200%2Crgba%280%2C0%2C0%2C%2E5%29%20100%25%29%3Bbackground%2Dimage%3A%2Do%2Dlinear%2Dgradient%28left%2Crgba%280%2C0%2C0%2C%2E0001%29%200%2Crgba%280%2C0%2C0%2C%2E5%29%20100%25%29%3Bbackground%2Dimage%3A%2Dwebkit%2Dgradient%28linear%2Cleft%20top%2Cright%20top%2Cfrom%28rgba%280%2C0%2C0%2C%2E0001%29%29%2Cto%28rgba%280%2C0%2C0%2C%2E5%29%29%29%3Bbackground%2Dimage%3Alinear%2Dgradient%28to%20right%2Crgba%280%2C0%2C0%2C%2E0001%29%200%2Crgba%280%2C0%2C0%2C%2E5%29%20100%25%29%3Bfilter%3Aprogid%3ADXImageTransform%2EMicrosoft%2Egradient%28startColorstr%3D%27%2300000000%27%2C%20endColorstr%3D%27%2380000000%27%2C%20GradientType%3D1%29%3Bbackground%2Drepeat%3Arepeat%2Dx%7D%2Ecarousel%2Dcontrol%3Afocus%2C%2Ecarousel%2Dcontrol%3Ahover%7Bcolor%3A%23fff%3Btext%2Ddecoration%3Anone%3Bfilter%3Aalpha%28opacity%3D90%29%3Boutline%3A0%3Bopacity%3A%2E9%7D%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dleft%2C%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dright%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dnext%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dprev%7Bposition%3Aabsolute%3Btop%3A50%25%3Bz%2Dindex%3A5%3Bdisplay%3Ainline%2Dblock%3Bmargin%2Dtop%3A%2D10px%7D%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dleft%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dprev%7Bleft%3A50%25%3Bmargin%2Dleft%3A%2D10px%7D%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dright%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dnext%7Bright%3A50%25%3Bmargin%2Dright%3A%2D10px%7D%2Ecarousel%2Dcontrol%20%2Eicon%2Dnext%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dprev%7Bwidth%3A20px%3Bheight%3A20px%3Bfont%2Dfamily%3Aserif%3Bline%2Dheight%3A1%7D%2Ecarousel%2Dcontrol%20%2Eicon%2Dprev%3Abefore%7Bcontent%3A%27%5C2039%27%7D%2Ecarousel%2Dcontrol%20%2Eicon%2Dnext%3Abefore%7Bcontent%3A%27%5C203a%27%7D%2Ecarousel%2Dindicators%7Bposition%3Aabsolute%3Bbottom%3A10px%3Bleft%3A50%25%3Bz%2Dindex%3A15%3Bwidth%3A60%25%3Bpadding%2Dleft%3A0%3Bmargin%2Dleft%3A%2D30%25%3Btext%2Dalign%3Acenter%3Blist%2Dstyle%3Anone%7D%2Ecarousel%2Dindicators%20li%7Bdisplay%3Ainline%2Dblock%3Bwidth%3A10px%3Bheight%3A10px%3Bmargin%3A1px%3Btext%2Dindent%3A%2D999px%3Bcursor%3Apointer%3Bbackground%2Dcolor%3A%23000%5C9%3Bbackground%2Dcolor%3Argba%280%2C0%2C0%2C0%29%3Bborder%3A1px%20solid%20%23fff%3Bborder%2Dradius%3A10px%7D%2Ecarousel%2Dindicators%20%2Eactive%7Bwidth%3A12px%3Bheight%3A12px%3Bmargin%3A0%3Bbackground%2Dcolor%3A%23fff%7D%2Ecarousel%2Dcaption%7Bposition%3Aabsolute%3Bright%3A15%25%3Bbottom%3A20px%3Bleft%3A15%25%3Bz%2Dindex%3A10%3Bpadding%2Dtop%3A20px%3Bpadding%2Dbottom%3A20px%3Bcolor%3A%23fff%3Btext%2Dalign%3Acenter%3Btext%2Dshadow%3A0%201px%202px%20rgba%280%2C0%2C0%2C%2E6%29%7D%2Ecarousel%2Dcaption%20%2Ebtn%7Btext%2Dshadow%3Anone%7D%40media%20screen%20and%20%28min%2Dwidth%3A768px%29%7B%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dleft%2C%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dright%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dnext%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dprev%7Bwidth%3A30px%3Bheight%3A30px%3Bmargin%2Dtop%3A%2D15px%3Bfont%2Dsize%3A30px%7D%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dleft%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dprev%7Bmargin%2Dleft%3A%2D15px%7D%2Ecarousel%2Dcontrol%20%2Eglyphicon%2Dchevron%2Dright%2C%2Ecarousel%2Dcontrol%20%2Eicon%2Dnext%7Bmargin%2Dright%3A%2D15px%7D%2Ecarousel%2Dcaption%7Bright%3A20%25%3Bleft%3A20%25%3Bpadding%2Dbottom%3A30px%7D%2Ecarousel%2Dindicators%7Bbottom%3A20px%7D%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3Aafter%2C%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3Abefore%2C%2Ebtn%2Dtoolbar%3Aafter%2C%2Ebtn%2Dtoolbar%3Abefore%2C%2Eclearfix%3Aafter%2C%2Eclearfix%3Abefore%2C%2Econtainer%2Dfluid%3Aafter%2C%2Econtainer%2Dfluid%3Abefore%2C%2Econtainer%3Aafter%2C%2Econtainer%3Abefore%2C%2Edl%2Dhorizontal%20dd%3Aafter%2C%2Edl%2Dhorizontal%20dd%3Abefore%2C%2Eform%2Dhorizontal%20%2Eform%2Dgroup%3Aafter%2C%2Eform%2Dhorizontal%20%2Eform%2Dgroup%3Abefore%2C%2Emodal%2Dfooter%3Aafter%2C%2Emodal%2Dfooter%3Abefore%2C%2Enav%3Aafter%2C%2Enav%3Abefore%2C%2Enavbar%2Dcollapse%3Aafter%2C%2Enavbar%2Dcollapse%3Abefore%2C%2Enavbar%2Dheader%3Aafter%2C%2Enavbar%2Dheader%3Abefore%2C%2Enavbar%3Aafter%2C%2Enavbar%3Abefore%2C%2Epager%3Aafter%2C%2Epager%3Abefore%2C%2Epanel%2Dbody%3Aafter%2C%2Epanel%2Dbody%3Abefore%2C%2Erow%3Aafter%2C%2Erow%3Abefore%7Bdisplay%3Atable%3Bcontent%3A%22%20%22%7D%2Ebtn%2Dgroup%2Dvertical%3E%2Ebtn%2Dgroup%3Aafter%2C%2Ebtn%2Dtoolbar%3Aafter%2C%2Eclearfix%3Aafter%2C%2Econtainer%2Dfluid%3Aafter%2C%2Econtainer%3Aafter%2C%2Edl%2Dhorizontal%20dd%3Aafter%2C%2Eform%2Dhorizontal%20%2Eform%2Dgroup%3Aafter%2C%2Emodal%2Dfooter%3Aafter%2C%2Enav%3Aafter%2C%2Enavbar%2Dcollapse%3Aafter%2C%2Enavbar%2Dheader%3Aafter%2C%2Enavbar%3Aafter%2C%2Epager%3Aafter%2C%2Epanel%2Dbody%3Aafter%2C%2Erow%3Aafter%7Bclear%3Aboth%7D%2Ecenter%2Dblock%7Bdisplay%3Ablock%3Bmargin%2Dright%3Aauto%3Bmargin%2Dleft%3Aauto%7D%2Epull%2Dright%7Bfloat%3Aright%21important%7D%2Epull%2Dleft%7Bfloat%3Aleft%21important%7D%2Ehide%7Bdisplay%3Anone%21important%7D%2Eshow%7Bdisplay%3Ablock%21important%7D%2Einvisible%7Bvisibility%3Ahidden%7D%2Etext%2Dhide%7Bfont%3A0%2F0%20a%3Bcolor%3Atransparent%3Btext%2Dshadow%3Anone%3Bbackground%2Dcolor%3Atransparent%3Bborder%3A0%7D%2Ehidden%7Bdisplay%3Anone%21important%7D%2Eaffix%7Bposition%3Afixed%7D%40%2Dms%2Dviewport%7Bwidth%3Adevice%2Dwidth%7D%2Evisible%2Dlg%2C%2Evisible%2Dmd%2C%2Evisible%2Dsm%2C%2Evisible%2Dxs%7Bdisplay%3Anone%21important%7D%2Evisible%2Dlg%2Dblock%2C%2Evisible%2Dlg%2Dinline%2C%2Evisible%2Dlg%2Dinline%2Dblock%2C%2Evisible%2Dmd%2Dblock%2C%2Evisible%2Dmd%2Dinline%2C%2Evisible%2Dmd%2Dinline%2Dblock%2C%2Evisible%2Dsm%2Dblock%2C%2Evisible%2Dsm%2Dinline%2C%2Evisible%2Dsm%2Dinline%2Dblock%2C%2Evisible%2Dxs%2Dblock%2C%2Evisible%2Dxs%2Dinline%2C%2Evisible%2Dxs%2Dinline%2Dblock%7Bdisplay%3Anone%21important%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Evisible%2Dxs%7Bdisplay%3Ablock%21important%7Dtable%2Evisible%2Dxs%7Bdisplay%3Atable%21important%7Dtr%2Evisible%2Dxs%7Bdisplay%3Atable%2Drow%21important%7Dtd%2Evisible%2Dxs%2Cth%2Evisible%2Dxs%7Bdisplay%3Atable%2Dcell%21important%7D%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Evisible%2Dxs%2Dblock%7Bdisplay%3Ablock%21important%7D%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Evisible%2Dxs%2Dinline%7Bdisplay%3Ainline%21important%7D%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Evisible%2Dxs%2Dinline%2Dblock%7Bdisplay%3Ainline%2Dblock%21important%7D%7D%40media%20%28min%2Dwidth%3A768px%29%20and%20%28max%2Dwidth%3A991px%29%7B%2Evisible%2Dsm%7Bdisplay%3Ablock%21important%7Dtable%2Evisible%2Dsm%7Bdisplay%3Atable%21important%7Dtr%2Evisible%2Dsm%7Bdisplay%3Atable%2Drow%21important%7Dtd%2Evisible%2Dsm%2Cth%2Evisible%2Dsm%7Bdisplay%3Atable%2Dcell%21important%7D%7D%40media%20%28min%2Dwidth%3A768px%29%20and%20%28max%2Dwidth%3A991px%29%7B%2Evisible%2Dsm%2Dblock%7Bdisplay%3Ablock%21important%7D%7D%40media%20%28min%2Dwidth%3A768px%29%20and%20%28max%2Dwidth%3A991px%29%7B%2Evisible%2Dsm%2Dinline%7Bdisplay%3Ainline%21important%7D%7D%40media%20%28min%2Dwidth%3A768px%29%20and%20%28max%2Dwidth%3A991px%29%7B%2Evisible%2Dsm%2Dinline%2Dblock%7Bdisplay%3Ainline%2Dblock%21important%7D%7D%40media%20%28min%2Dwidth%3A992px%29%20and%20%28max%2Dwidth%3A1199px%29%7B%2Evisible%2Dmd%7Bdisplay%3Ablock%21important%7Dtable%2Evisible%2Dmd%7Bdisplay%3Atable%21important%7Dtr%2Evisible%2Dmd%7Bdisplay%3Atable%2Drow%21important%7Dtd%2Evisible%2Dmd%2Cth%2Evisible%2Dmd%7Bdisplay%3Atable%2Dcell%21important%7D%7D%40media%20%28min%2Dwidth%3A992px%29%20and%20%28max%2Dwidth%3A1199px%29%7B%2Evisible%2Dmd%2Dblock%7Bdisplay%3Ablock%21important%7D%7D%40media%20%28min%2Dwidth%3A992px%29%20and%20%28max%2Dwidth%3A1199px%29%7B%2Evisible%2Dmd%2Dinline%7Bdisplay%3Ainline%21important%7D%7D%40media%20%28min%2Dwidth%3A992px%29%20and%20%28max%2Dwidth%3A1199px%29%7B%2Evisible%2Dmd%2Dinline%2Dblock%7Bdisplay%3Ainline%2Dblock%21important%7D%7D%40media%20%28min%2Dwidth%3A1200px%29%7B%2Evisible%2Dlg%7Bdisplay%3Ablock%21important%7Dtable%2Evisible%2Dlg%7Bdisplay%3Atable%21important%7Dtr%2Evisible%2Dlg%7Bdisplay%3Atable%2Drow%21important%7Dtd%2Evisible%2Dlg%2Cth%2Evisible%2Dlg%7Bdisplay%3Atable%2Dcell%21important%7D%7D%40media%20%28min%2Dwidth%3A1200px%29%7B%2Evisible%2Dlg%2Dblock%7Bdisplay%3Ablock%21important%7D%7D%40media%20%28min%2Dwidth%3A1200px%29%7B%2Evisible%2Dlg%2Dinline%7Bdisplay%3Ainline%21important%7D%7D%40media%20%28min%2Dwidth%3A1200px%29%7B%2Evisible%2Dlg%2Dinline%2Dblock%7Bdisplay%3Ainline%2Dblock%21important%7D%7D%40media%20%28max%2Dwidth%3A767px%29%7B%2Ehidden%2Dxs%7Bdisplay%3Anone%21important%7D%7D%40media%20%28min%2Dwidth%3A768px%29%20and%20%28max%2Dwidth%3A991px%29%7B%2Ehidden%2Dsm%7Bdisplay%3Anone%21important%7D%7D%40media%20%28min%2Dwidth%3A992px%29%20and%20%28max%2Dwidth%3A1199px%29%7B%2Ehidden%2Dmd%7Bdisplay%3Anone%21important%7D%7D%40media%20%28min%2Dwidth%3A1200px%29%7B%2Ehidden%2Dlg%7Bdisplay%3Anone%21important%7D%7D%2Evisible%2Dprint%7Bdisplay%3Anone%21important%7D%40media%20print%7B%2Evisible%2Dprint%7Bdisplay%3Ablock%21important%7Dtable%2Evisible%2Dprint%7Bdisplay%3Atable%21important%7Dtr%2Evisible%2Dprint%7Bdisplay%3Atable%2Drow%21important%7Dtd%2Evisible%2Dprint%2Cth%2Evisible%2Dprint%7Bdisplay%3Atable%2Dcell%21important%7D%7D%2Evisible%2Dprint%2Dblock%7Bdisplay%3Anone%21important%7D%40media%20print%7B%2Evisible%2Dprint%2Dblock%7Bdisplay%3Ablock%21important%7D%7D%2Evisible%2Dprint%2Dinline%7Bdisplay%3Anone%21important%7D%40media%20print%7B%2Evisible%2Dprint%2Dinline%7Bdisplay%3Ainline%21important%7D%7D%2Evisible%2Dprint%2Dinline%2Dblock%7Bdisplay%3Anone%21important%7D%40media%20print%7B%2Evisible%2Dprint%2Dinline%2Dblock%7Bdisplay%3Ainline%2Dblock%21important%7D%7D%40media%20print%7B%2Ehidden%2Dprint%7Bdisplay%3Anone%21important%7D%7D%0A" rel="stylesheet" />
<script src="data:application/x-javascript;base64,LyohCiAqIEJvb3RzdHJhcCB2My4zLjUgKGh0dHA6Ly9nZXRib290c3RyYXAuY29tKQogKiBDb3B5cmlnaHQgMjAxMS0yMDE1IFR3aXR0ZXIsIEluYy4KICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlCiAqLwppZigidW5kZWZpbmVkIj09dHlwZW9mIGpRdWVyeSl0aHJvdyBuZXcgRXJyb3IoIkJvb3RzdHJhcCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5Iik7K2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0Ijt2YXIgYj1hLmZuLmpxdWVyeS5zcGxpdCgiICIpWzBdLnNwbGl0KCIuIik7aWYoYlswXTwyJiZiWzFdPDl8fDE9PWJbMF0mJjk9PWJbMV0mJmJbMl08MSl0aHJvdyBuZXcgRXJyb3IoIkJvb3RzdHJhcCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5IHZlcnNpb24gMS45LjEgb3IgaGlnaGVyIil9KGpRdWVyeSksK2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBiKCl7dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYm9vdHN0cmFwIiksYj17V2Via2l0VHJhbnNpdGlvbjoid2Via2l0VHJhbnNpdGlvbkVuZCIsTW96VHJhbnNpdGlvbjoidHJhbnNpdGlvbmVuZCIsT1RyYW5zaXRpb246Im9UcmFuc2l0aW9uRW5kIG90cmFuc2l0aW9uZW5kIix0cmFuc2l0aW9uOiJ0cmFuc2l0aW9uZW5kIn07Zm9yKHZhciBjIGluIGIpaWYodm9pZCAwIT09YS5zdHlsZVtjXSlyZXR1cm57ZW5kOmJbY119O3JldHVybiExfWEuZm4uZW11bGF0ZVRyYW5zaXRpb25FbmQ9ZnVuY3Rpb24oYil7dmFyIGM9ITEsZD10aGlzO2EodGhpcykub25lKCJic1RyYW5zaXRpb25FbmQiLGZ1bmN0aW9uKCl7Yz0hMH0pO3ZhciBlPWZ1bmN0aW9uKCl7Y3x8YShkKS50cmlnZ2VyKGEuc3VwcG9ydC50cmFuc2l0aW9uLmVuZCl9O3JldHVybiBzZXRUaW1lb3V0KGUsYiksdGhpc30sYShmdW5jdGlvbigpe2Euc3VwcG9ydC50cmFuc2l0aW9uPWIoKSxhLnN1cHBvcnQudHJhbnNpdGlvbiYmKGEuZXZlbnQuc3BlY2lhbC5ic1RyYW5zaXRpb25FbmQ9e2JpbmRUeXBlOmEuc3VwcG9ydC50cmFuc2l0aW9uLmVuZCxkZWxlZ2F0ZVR5cGU6YS5zdXBwb3J0LnRyYW5zaXRpb24uZW5kLGhhbmRsZTpmdW5jdGlvbihiKXtyZXR1cm4gYShiLnRhcmdldCkuaXModGhpcyk/Yi5oYW5kbGVPYmouaGFuZGxlci5hcHBseSh0aGlzLGFyZ3VtZW50cyk6dm9pZCAwfX0pfSl9KGpRdWVyeSksK2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBiKGIpe3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXt2YXIgYz1hKHRoaXMpLGU9Yy5kYXRhKCJicy5hbGVydCIpO2V8fGMuZGF0YSgiYnMuYWxlcnQiLGU9bmV3IGQodGhpcykpLCJzdHJpbmciPT10eXBlb2YgYiYmZVtiXS5jYWxsKGMpfSl9dmFyIGM9J1tkYXRhLWRpc21pc3M9ImFsZXJ0Il0nLGQ9ZnVuY3Rpb24oYil7YShiKS5vbigiY2xpY2siLGMsdGhpcy5jbG9zZSl9O2QuVkVSU0lPTj0iMy4zLjUiLGQuVFJBTlNJVElPTl9EVVJBVElPTj0xNTAsZC5wcm90b3R5cGUuY2xvc2U9ZnVuY3Rpb24oYil7ZnVuY3Rpb24gYygpe2cuZGV0YWNoKCkudHJpZ2dlcigiY2xvc2VkLmJzLmFsZXJ0IikucmVtb3ZlKCl9dmFyIGU9YSh0aGlzKSxmPWUuYXR0cigiZGF0YS10YXJnZXQiKTtmfHwoZj1lLmF0dHIoImhyZWYiKSxmPWYmJmYucmVwbGFjZSgvLiooPz0jW15cc10qJCkvLCIiKSk7dmFyIGc9YShmKTtiJiZiLnByZXZlbnREZWZhdWx0KCksZy5sZW5ndGh8fChnPWUuY2xvc2VzdCgiLmFsZXJ0IikpLGcudHJpZ2dlcihiPWEuRXZlbnQoImNsb3NlLmJzLmFsZXJ0IikpLGIuaXNEZWZhdWx0UHJldmVudGVkKCl8fChnLnJlbW92ZUNsYXNzKCJpbiIpLGEuc3VwcG9ydC50cmFuc2l0aW9uJiZnLmhhc0NsYXNzKCJmYWRlIik/Zy5vbmUoImJzVHJhbnNpdGlvbkVuZCIsYykuZW11bGF0ZVRyYW5zaXRpb25FbmQoZC5UUkFOU0lUSU9OX0RVUkFUSU9OKTpjKCkpfTt2YXIgZT1hLmZuLmFsZXJ0O2EuZm4uYWxlcnQ9YixhLmZuLmFsZXJ0LkNvbnN0cnVjdG9yPWQsYS5mbi5hbGVydC5ub0NvbmZsaWN0PWZ1bmN0aW9uKCl7cmV0dXJuIGEuZm4uYWxlcnQ9ZSx0aGlzfSxhKGRvY3VtZW50KS5vbigiY2xpY2suYnMuYWxlcnQuZGF0YS1hcGkiLGMsZC5wcm90b3R5cGUuY2xvc2UpfShqUXVlcnkpLCtmdW5jdGlvbihhKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gYihiKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGQ9YSh0aGlzKSxlPWQuZGF0YSgiYnMuYnV0dG9uIiksZj0ib2JqZWN0Ij09dHlwZW9mIGImJmI7ZXx8ZC5kYXRhKCJicy5idXR0b24iLGU9bmV3IGModGhpcyxmKSksInRvZ2dsZSI9PWI/ZS50b2dnbGUoKTpiJiZlLnNldFN0YXRlKGIpfSl9dmFyIGM9ZnVuY3Rpb24oYixkKXt0aGlzLiRlbGVtZW50PWEoYiksdGhpcy5vcHRpb25zPWEuZXh0ZW5kKHt9LGMuREVGQVVMVFMsZCksdGhpcy5pc0xvYWRpbmc9ITF9O2MuVkVSU0lPTj0iMy4zLjUiLGMuREVGQVVMVFM9e2xvYWRpbmdUZXh0OiJsb2FkaW5nLi4uIn0sYy5wcm90b3R5cGUuc2V0U3RhdGU9ZnVuY3Rpb24oYil7dmFyIGM9ImRpc2FibGVkIixkPXRoaXMuJGVsZW1lbnQsZT1kLmlzKCJpbnB1dCIpPyJ2YWwiOiJodG1sIixmPWQuZGF0YSgpO2IrPSJUZXh0IixudWxsPT1mLnJlc2V0VGV4dCYmZC5kYXRhKCJyZXNldFRleHQiLGRbZV0oKSksc2V0VGltZW91dChhLnByb3h5KGZ1bmN0aW9uKCl7ZFtlXShudWxsPT1mW2JdP3RoaXMub3B0aW9uc1tiXTpmW2JdKSwibG9hZGluZ1RleHQiPT1iPyh0aGlzLmlzTG9hZGluZz0hMCxkLmFkZENsYXNzKGMpLmF0dHIoYyxjKSk6dGhpcy5pc0xvYWRpbmcmJih0aGlzLmlzTG9hZGluZz0hMSxkLnJlbW92ZUNsYXNzKGMpLnJlbW92ZUF0dHIoYykpfSx0aGlzKSwwKX0sYy5wcm90b3R5cGUudG9nZ2xlPWZ1bmN0aW9uKCl7dmFyIGE9ITAsYj10aGlzLiRlbGVtZW50LmNsb3Nlc3QoJ1tkYXRhLXRvZ2dsZT0iYnV0dG9ucyJdJyk7aWYoYi5sZW5ndGgpe3ZhciBjPXRoaXMuJGVsZW1lbnQuZmluZCgiaW5wdXQiKTsicmFkaW8iPT1jLnByb3AoInR5cGUiKT8oYy5wcm9wKCJjaGVja2VkIikmJihhPSExKSxiLmZpbmQoIi5hY3RpdmUiKS5yZW1vdmVDbGFzcygiYWN0aXZlIiksdGhpcy4kZWxlbWVudC5hZGRDbGFzcygiYWN0aXZlIikpOiJjaGVja2JveCI9PWMucHJvcCgidHlwZSIpJiYoYy5wcm9wKCJjaGVja2VkIikhPT10aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCJhY3RpdmUiKSYmKGE9ITEpLHRoaXMuJGVsZW1lbnQudG9nZ2xlQ2xhc3MoImFjdGl2ZSIpKSxjLnByb3AoImNoZWNrZWQiLHRoaXMuJGVsZW1lbnQuaGFzQ2xhc3MoImFjdGl2ZSIpKSxhJiZjLnRyaWdnZXIoImNoYW5nZSIpfWVsc2UgdGhpcy4kZWxlbWVudC5hdHRyKCJhcmlhLXByZXNzZWQiLCF0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCJhY3RpdmUiKSksdGhpcy4kZWxlbWVudC50b2dnbGVDbGFzcygiYWN0aXZlIil9O3ZhciBkPWEuZm4uYnV0dG9uO2EuZm4uYnV0dG9uPWIsYS5mbi5idXR0b24uQ29uc3RydWN0b3I9YyxhLmZuLmJ1dHRvbi5ub0NvbmZsaWN0PWZ1bmN0aW9uKCl7cmV0dXJuIGEuZm4uYnV0dG9uPWQsdGhpc30sYShkb2N1bWVudCkub24oImNsaWNrLmJzLmJ1dHRvbi5kYXRhLWFwaSIsJ1tkYXRhLXRvZ2dsZV49ImJ1dHRvbiJdJyxmdW5jdGlvbihjKXt2YXIgZD1hKGMudGFyZ2V0KTtkLmhhc0NsYXNzKCJidG4iKXx8KGQ9ZC5jbG9zZXN0KCIuYnRuIikpLGIuY2FsbChkLCJ0b2dnbGUiKSxhKGMudGFyZ2V0KS5pcygnaW5wdXRbdHlwZT0icmFkaW8iXScpfHxhKGMudGFyZ2V0KS5pcygnaW5wdXRbdHlwZT0iY2hlY2tib3giXScpfHxjLnByZXZlbnREZWZhdWx0KCl9KS5vbigiZm9jdXMuYnMuYnV0dG9uLmRhdGEtYXBpIGJsdXIuYnMuYnV0dG9uLmRhdGEtYXBpIiwnW2RhdGEtdG9nZ2xlXj0iYnV0dG9uIl0nLGZ1bmN0aW9uKGIpe2EoYi50YXJnZXQpLmNsb3Nlc3QoIi5idG4iKS50b2dnbGVDbGFzcygiZm9jdXMiLC9eZm9jdXMoaW4pPyQvLnRlc3QoYi50eXBlKSl9KX0oalF1ZXJ5KSwrZnVuY3Rpb24oYSl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIGIoYil7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBkPWEodGhpcyksZT1kLmRhdGEoImJzLmNhcm91c2VsIiksZj1hLmV4dGVuZCh7fSxjLkRFRkFVTFRTLGQuZGF0YSgpLCJvYmplY3QiPT10eXBlb2YgYiYmYiksZz0ic3RyaW5nIj09dHlwZW9mIGI/YjpmLnNsaWRlO2V8fGQuZGF0YSgiYnMuY2Fyb3VzZWwiLGU9bmV3IGModGhpcyxmKSksIm51bWJlciI9PXR5cGVvZiBiP2UudG8oYik6Zz9lW2ddKCk6Zi5pbnRlcnZhbCYmZS5wYXVzZSgpLmN5Y2xlKCl9KX12YXIgYz1mdW5jdGlvbihiLGMpe3RoaXMuJGVsZW1lbnQ9YShiKSx0aGlzLiRpbmRpY2F0b3JzPXRoaXMuJGVsZW1lbnQuZmluZCgiLmNhcm91c2VsLWluZGljYXRvcnMiKSx0aGlzLm9wdGlvbnM9Yyx0aGlzLnBhdXNlZD1udWxsLHRoaXMuc2xpZGluZz1udWxsLHRoaXMuaW50ZXJ2YWw9bnVsbCx0aGlzLiRhY3RpdmU9bnVsbCx0aGlzLiRpdGVtcz1udWxsLHRoaXMub3B0aW9ucy5rZXlib2FyZCYmdGhpcy4kZWxlbWVudC5vbigia2V5ZG93bi5icy5jYXJvdXNlbCIsYS5wcm94eSh0aGlzLmtleWRvd24sdGhpcykpLCJob3ZlciI9PXRoaXMub3B0aW9ucy5wYXVzZSYmISgib250b3VjaHN0YXJ0ImluIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCkmJnRoaXMuJGVsZW1lbnQub24oIm1vdXNlZW50ZXIuYnMuY2Fyb3VzZWwiLGEucHJveHkodGhpcy5wYXVzZSx0aGlzKSkub24oIm1vdXNlbGVhdmUuYnMuY2Fyb3VzZWwiLGEucHJveHkodGhpcy5jeWNsZSx0aGlzKSl9O2MuVkVSU0lPTj0iMy4zLjUiLGMuVFJBTlNJVElPTl9EVVJBVElPTj02MDAsYy5ERUZBVUxUUz17aW50ZXJ2YWw6NWUzLHBhdXNlOiJob3ZlciIsd3JhcDohMCxrZXlib2FyZDohMH0sYy5wcm90b3R5cGUua2V5ZG93bj1mdW5jdGlvbihhKXtpZighL2lucHV0fHRleHRhcmVhL2kudGVzdChhLnRhcmdldC50YWdOYW1lKSl7c3dpdGNoKGEud2hpY2gpe2Nhc2UgMzc6dGhpcy5wcmV2KCk7YnJlYWs7Y2FzZSAzOTp0aGlzLm5leHQoKTticmVhaztkZWZhdWx0OnJldHVybn1hLnByZXZlbnREZWZhdWx0KCl9fSxjLnByb3RvdHlwZS5jeWNsZT1mdW5jdGlvbihiKXtyZXR1cm4gYnx8KHRoaXMucGF1c2VkPSExKSx0aGlzLmludGVydmFsJiZjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWwpLHRoaXMub3B0aW9ucy5pbnRlcnZhbCYmIXRoaXMucGF1c2VkJiYodGhpcy5pbnRlcnZhbD1zZXRJbnRlcnZhbChhLnByb3h5KHRoaXMubmV4dCx0aGlzKSx0aGlzLm9wdGlvbnMuaW50ZXJ2YWwpKSx0aGlzfSxjLnByb3RvdHlwZS5nZXRJdGVtSW5kZXg9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuJGl0ZW1zPWEucGFyZW50KCkuY2hpbGRyZW4oIi5pdGVtIiksdGhpcy4kaXRlbXMuaW5kZXgoYXx8dGhpcy4kYWN0aXZlKX0sYy5wcm90b3R5cGUuZ2V0SXRlbUZvckRpcmVjdGlvbj1mdW5jdGlvbihhLGIpe3ZhciBjPXRoaXMuZ2V0SXRlbUluZGV4KGIpLGQ9InByZXYiPT1hJiYwPT09Y3x8Im5leHQiPT1hJiZjPT10aGlzLiRpdGVtcy5sZW5ndGgtMTtpZihkJiYhdGhpcy5vcHRpb25zLndyYXApcmV0dXJuIGI7dmFyIGU9InByZXYiPT1hPy0xOjEsZj0oYytlKSV0aGlzLiRpdGVtcy5sZW5ndGg7cmV0dXJuIHRoaXMuJGl0ZW1zLmVxKGYpfSxjLnByb3RvdHlwZS50bz1mdW5jdGlvbihhKXt2YXIgYj10aGlzLGM9dGhpcy5nZXRJdGVtSW5kZXgodGhpcy4kYWN0aXZlPXRoaXMuJGVsZW1lbnQuZmluZCgiLml0ZW0uYWN0aXZlIikpO3JldHVybiBhPnRoaXMuJGl0ZW1zLmxlbmd0aC0xfHwwPmE/dm9pZCAwOnRoaXMuc2xpZGluZz90aGlzLiRlbGVtZW50Lm9uZSgic2xpZC5icy5jYXJvdXNlbCIsZnVuY3Rpb24oKXtiLnRvKGEpfSk6Yz09YT90aGlzLnBhdXNlKCkuY3ljbGUoKTp0aGlzLnNsaWRlKGE+Yz8ibmV4dCI6InByZXYiLHRoaXMuJGl0ZW1zLmVxKGEpKX0sYy5wcm90b3R5cGUucGF1c2U9ZnVuY3Rpb24oYil7cmV0dXJuIGJ8fCh0aGlzLnBhdXNlZD0hMCksdGhpcy4kZWxlbWVudC5maW5kKCIubmV4dCwgLnByZXYiKS5sZW5ndGgmJmEuc3VwcG9ydC50cmFuc2l0aW9uJiYodGhpcy4kZWxlbWVudC50cmlnZ2VyKGEuc3VwcG9ydC50cmFuc2l0aW9uLmVuZCksdGhpcy5jeWNsZSghMCkpLHRoaXMuaW50ZXJ2YWw9Y2xlYXJJbnRlcnZhbCh0aGlzLmludGVydmFsKSx0aGlzfSxjLnByb3RvdHlwZS5uZXh0PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc2xpZGluZz92b2lkIDA6dGhpcy5zbGlkZSgibmV4dCIpfSxjLnByb3RvdHlwZS5wcmV2PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc2xpZGluZz92b2lkIDA6dGhpcy5zbGlkZSgicHJldiIpfSxjLnByb3RvdHlwZS5zbGlkZT1mdW5jdGlvbihiLGQpe3ZhciBlPXRoaXMuJGVsZW1lbnQuZmluZCgiLml0ZW0uYWN0aXZlIiksZj1kfHx0aGlzLmdldEl0ZW1Gb3JEaXJlY3Rpb24oYixlKSxnPXRoaXMuaW50ZXJ2YWwsaD0ibmV4dCI9PWI/ImxlZnQiOiJyaWdodCIsaT10aGlzO2lmKGYuaGFzQ2xhc3MoImFjdGl2ZSIpKXJldHVybiB0aGlzLnNsaWRpbmc9ITE7dmFyIGo9ZlswXSxrPWEuRXZlbnQoInNsaWRlLmJzLmNhcm91c2VsIix7cmVsYXRlZFRhcmdldDpqLGRpcmVjdGlvbjpofSk7aWYodGhpcy4kZWxlbWVudC50cmlnZ2VyKGspLCFrLmlzRGVmYXVsdFByZXZlbnRlZCgpKXtpZih0aGlzLnNsaWRpbmc9ITAsZyYmdGhpcy5wYXVzZSgpLHRoaXMuJGluZGljYXRvcnMubGVuZ3RoKXt0aGlzLiRpbmRpY2F0b3JzLmZpbmQoIi5hY3RpdmUiKS5yZW1vdmVDbGFzcygiYWN0aXZlIik7dmFyIGw9YSh0aGlzLiRpbmRpY2F0b3JzLmNoaWxkcmVuKClbdGhpcy5nZXRJdGVtSW5kZXgoZildKTtsJiZsLmFkZENsYXNzKCJhY3RpdmUiKX12YXIgbT1hLkV2ZW50KCJzbGlkLmJzLmNhcm91c2VsIix7cmVsYXRlZFRhcmdldDpqLGRpcmVjdGlvbjpofSk7cmV0dXJuIGEuc3VwcG9ydC50cmFuc2l0aW9uJiZ0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCJzbGlkZSIpPyhmLmFkZENsYXNzKGIpLGZbMF0ub2Zmc2V0V2lkdGgsZS5hZGRDbGFzcyhoKSxmLmFkZENsYXNzKGgpLGUub25lKCJic1RyYW5zaXRpb25FbmQiLGZ1bmN0aW9uKCl7Zi5yZW1vdmVDbGFzcyhbYixoXS5qb2luKCIgIikpLmFkZENsYXNzKCJhY3RpdmUiKSxlLnJlbW92ZUNsYXNzKFsiYWN0aXZlIixoXS5qb2luKCIgIikpLGkuc2xpZGluZz0hMSxzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7aS4kZWxlbWVudC50cmlnZ2VyKG0pfSwwKX0pLmVtdWxhdGVUcmFuc2l0aW9uRW5kKGMuVFJBTlNJVElPTl9EVVJBVElPTikpOihlLnJlbW92ZUNsYXNzKCJhY3RpdmUiKSxmLmFkZENsYXNzKCJhY3RpdmUiKSx0aGlzLnNsaWRpbmc9ITEsdGhpcy4kZWxlbWVudC50cmlnZ2VyKG0pKSxnJiZ0aGlzLmN5Y2xlKCksdGhpc319O3ZhciBkPWEuZm4uY2Fyb3VzZWw7YS5mbi5jYXJvdXNlbD1iLGEuZm4uY2Fyb3VzZWwuQ29uc3RydWN0b3I9YyxhLmZuLmNhcm91c2VsLm5vQ29uZmxpY3Q9ZnVuY3Rpb24oKXtyZXR1cm4gYS5mbi5jYXJvdXNlbD1kLHRoaXN9O3ZhciBlPWZ1bmN0aW9uKGMpe3ZhciBkLGU9YSh0aGlzKSxmPWEoZS5hdHRyKCJkYXRhLXRhcmdldCIpfHwoZD1lLmF0dHIoImhyZWYiKSkmJmQucmVwbGFjZSgvLiooPz0jW15cc10rJCkvLCIiKSk7aWYoZi5oYXNDbGFzcygiY2Fyb3VzZWwiKSl7dmFyIGc9YS5leHRlbmQoe30sZi5kYXRhKCksZS5kYXRhKCkpLGg9ZS5hdHRyKCJkYXRhLXNsaWRlLXRvIik7aCYmKGcuaW50ZXJ2YWw9ITEpLGIuY2FsbChmLGcpLGgmJmYuZGF0YSgiYnMuY2Fyb3VzZWwiKS50byhoKSxjLnByZXZlbnREZWZhdWx0KCl9fTthKGRvY3VtZW50KS5vbigiY2xpY2suYnMuY2Fyb3VzZWwuZGF0YS1hcGkiLCJbZGF0YS1zbGlkZV0iLGUpLm9uKCJjbGljay5icy5jYXJvdXNlbC5kYXRhLWFwaSIsIltkYXRhLXNsaWRlLXRvXSIsZSksYSh3aW5kb3cpLm9uKCJsb2FkIixmdW5jdGlvbigpe2EoJ1tkYXRhLXJpZGU9ImNhcm91c2VsIl0nKS5lYWNoKGZ1bmN0aW9uKCl7dmFyIGM9YSh0aGlzKTtiLmNhbGwoYyxjLmRhdGEoKSl9KX0pfShqUXVlcnkpLCtmdW5jdGlvbihhKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gYihiKXt2YXIgYyxkPWIuYXR0cigiZGF0YS10YXJnZXQiKXx8KGM9Yi5hdHRyKCJocmVmIikpJiZjLnJlcGxhY2UoLy4qKD89I1teXHNdKyQpLywiIik7cmV0dXJuIGEoZCl9ZnVuY3Rpb24gYyhiKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGM9YSh0aGlzKSxlPWMuZGF0YSgiYnMuY29sbGFwc2UiKSxmPWEuZXh0ZW5kKHt9LGQuREVGQVVMVFMsYy5kYXRhKCksIm9iamVjdCI9PXR5cGVvZiBiJiZiKTshZSYmZi50b2dnbGUmJi9zaG93fGhpZGUvLnRlc3QoYikmJihmLnRvZ2dsZT0hMSksZXx8Yy5kYXRhKCJicy5jb2xsYXBzZSIsZT1uZXcgZCh0aGlzLGYpKSwic3RyaW5nIj09dHlwZW9mIGImJmVbYl0oKX0pfXZhciBkPWZ1bmN0aW9uKGIsYyl7dGhpcy4kZWxlbWVudD1hKGIpLHRoaXMub3B0aW9ucz1hLmV4dGVuZCh7fSxkLkRFRkFVTFRTLGMpLHRoaXMuJHRyaWdnZXI9YSgnW2RhdGEtdG9nZ2xlPSJjb2xsYXBzZSJdW2hyZWY9IiMnK2IuaWQrJyJdLFtkYXRhLXRvZ2dsZT0iY29sbGFwc2UiXVtkYXRhLXRhcmdldD0iIycrYi5pZCsnIl0nKSx0aGlzLnRyYW5zaXRpb25pbmc9bnVsbCx0aGlzLm9wdGlvbnMucGFyZW50P3RoaXMuJHBhcmVudD10aGlzLmdldFBhcmVudCgpOnRoaXMuYWRkQXJpYUFuZENvbGxhcHNlZENsYXNzKHRoaXMuJGVsZW1lbnQsdGhpcy4kdHJpZ2dlciksdGhpcy5vcHRpb25zLnRvZ2dsZSYmdGhpcy50b2dnbGUoKX07ZC5WRVJTSU9OPSIzLjMuNSIsZC5UUkFOU0lUSU9OX0RVUkFUSU9OPTM1MCxkLkRFRkFVTFRTPXt0b2dnbGU6ITB9LGQucHJvdG90eXBlLmRpbWVuc2lvbj1mdW5jdGlvbigpe3ZhciBhPXRoaXMuJGVsZW1lbnQuaGFzQ2xhc3MoIndpZHRoIik7cmV0dXJuIGE/IndpZHRoIjoiaGVpZ2h0In0sZC5wcm90b3R5cGUuc2hvdz1mdW5jdGlvbigpe2lmKCF0aGlzLnRyYW5zaXRpb25pbmcmJiF0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCJpbiIpKXt2YXIgYixlPXRoaXMuJHBhcmVudCYmdGhpcy4kcGFyZW50LmNoaWxkcmVuKCIucGFuZWwiKS5jaGlsZHJlbigiLmluLCAuY29sbGFwc2luZyIpO2lmKCEoZSYmZS5sZW5ndGgmJihiPWUuZGF0YSgiYnMuY29sbGFwc2UiKSxiJiZiLnRyYW5zaXRpb25pbmcpKSl7dmFyIGY9YS5FdmVudCgic2hvdy5icy5jb2xsYXBzZSIpO2lmKHRoaXMuJGVsZW1lbnQudHJpZ2dlcihmKSwhZi5pc0RlZmF1bHRQcmV2ZW50ZWQoKSl7ZSYmZS5sZW5ndGgmJihjLmNhbGwoZSwiaGlkZSIpLGJ8fGUuZGF0YSgiYnMuY29sbGFwc2UiLG51bGwpKTt2YXIgZz10aGlzLmRpbWVuc2lvbigpO3RoaXMuJGVsZW1lbnQucmVtb3ZlQ2xhc3MoImNvbGxhcHNlIikuYWRkQ2xhc3MoImNvbGxhcHNpbmciKVtnXSgwKS5hdHRyKCJhcmlhLWV4cGFuZGVkIiwhMCksdGhpcy4kdHJpZ2dlci5yZW1vdmVDbGFzcygiY29sbGFwc2VkIikuYXR0cigiYXJpYS1leHBhbmRlZCIsITApLHRoaXMudHJhbnNpdGlvbmluZz0xO3ZhciBoPWZ1bmN0aW9uKCl7dGhpcy4kZWxlbWVudC5yZW1vdmVDbGFzcygiY29sbGFwc2luZyIpLmFkZENsYXNzKCJjb2xsYXBzZSBpbiIpW2ddKCIiKSx0aGlzLnRyYW5zaXRpb25pbmc9MCx0aGlzLiRlbGVtZW50LnRyaWdnZXIoInNob3duLmJzLmNvbGxhcHNlIil9O2lmKCFhLnN1cHBvcnQudHJhbnNpdGlvbilyZXR1cm4gaC5jYWxsKHRoaXMpO3ZhciBpPWEuY2FtZWxDYXNlKFsic2Nyb2xsIixnXS5qb2luKCItIikpO3RoaXMuJGVsZW1lbnQub25lKCJic1RyYW5zaXRpb25FbmQiLGEucHJveHkoaCx0aGlzKSkuZW11bGF0ZVRyYW5zaXRpb25FbmQoZC5UUkFOU0lUSU9OX0RVUkFUSU9OKVtnXSh0aGlzLiRlbGVtZW50WzBdW2ldKX19fX0sZC5wcm90b3R5cGUuaGlkZT1mdW5jdGlvbigpe2lmKCF0aGlzLnRyYW5zaXRpb25pbmcmJnRoaXMuJGVsZW1lbnQuaGFzQ2xhc3MoImluIikpe3ZhciBiPWEuRXZlbnQoImhpZGUuYnMuY29sbGFwc2UiKTtpZih0aGlzLiRlbGVtZW50LnRyaWdnZXIoYiksIWIuaXNEZWZhdWx0UHJldmVudGVkKCkpe3ZhciBjPXRoaXMuZGltZW5zaW9uKCk7dGhpcy4kZWxlbWVudFtjXSh0aGlzLiRlbGVtZW50W2NdKCkpWzBdLm9mZnNldEhlaWdodCx0aGlzLiRlbGVtZW50LmFkZENsYXNzKCJjb2xsYXBzaW5nIikucmVtb3ZlQ2xhc3MoImNvbGxhcHNlIGluIikuYXR0cigiYXJpYS1leHBhbmRlZCIsITEpLHRoaXMuJHRyaWdnZXIuYWRkQ2xhc3MoImNvbGxhcHNlZCIpLmF0dHIoImFyaWEtZXhwYW5kZWQiLCExKSx0aGlzLnRyYW5zaXRpb25pbmc9MTt2YXIgZT1mdW5jdGlvbigpe3RoaXMudHJhbnNpdGlvbmluZz0wLHRoaXMuJGVsZW1lbnQucmVtb3ZlQ2xhc3MoImNvbGxhcHNpbmciKS5hZGRDbGFzcygiY29sbGFwc2UiKS50cmlnZ2VyKCJoaWRkZW4uYnMuY29sbGFwc2UiKX07cmV0dXJuIGEuc3VwcG9ydC50cmFuc2l0aW9uP3ZvaWQgdGhpcy4kZWxlbWVudFtjXSgwKS5vbmUoImJzVHJhbnNpdGlvbkVuZCIsYS5wcm94eShlLHRoaXMpKS5lbXVsYXRlVHJhbnNpdGlvbkVuZChkLlRSQU5TSVRJT05fRFVSQVRJT04pOmUuY2FsbCh0aGlzKX19fSxkLnByb3RvdHlwZS50b2dnbGU9ZnVuY3Rpb24oKXt0aGlzW3RoaXMuJGVsZW1lbnQuaGFzQ2xhc3MoImluIik/ImhpZGUiOiJzaG93Il0oKX0sZC5wcm90b3R5cGUuZ2V0UGFyZW50PWZ1bmN0aW9uKCl7cmV0dXJuIGEodGhpcy5vcHRpb25zLnBhcmVudCkuZmluZCgnW2RhdGEtdG9nZ2xlPSJjb2xsYXBzZSJdW2RhdGEtcGFyZW50PSInK3RoaXMub3B0aW9ucy5wYXJlbnQrJyJdJykuZWFjaChhLnByb3h5KGZ1bmN0aW9uKGMsZCl7dmFyIGU9YShkKTt0aGlzLmFkZEFyaWFBbmRDb2xsYXBzZWRDbGFzcyhiKGUpLGUpfSx0aGlzKSkuZW5kKCl9LGQucHJvdG90eXBlLmFkZEFyaWFBbmRDb2xsYXBzZWRDbGFzcz1mdW5jdGlvbihhLGIpe3ZhciBjPWEuaGFzQ2xhc3MoImluIik7YS5hdHRyKCJhcmlhLWV4cGFuZGVkIixjKSxiLnRvZ2dsZUNsYXNzKCJjb2xsYXBzZWQiLCFjKS5hdHRyKCJhcmlhLWV4cGFuZGVkIixjKX07dmFyIGU9YS5mbi5jb2xsYXBzZTthLmZuLmNvbGxhcHNlPWMsYS5mbi5jb2xsYXBzZS5Db25zdHJ1Y3Rvcj1kLGEuZm4uY29sbGFwc2Uubm9Db25mbGljdD1mdW5jdGlvbigpe3JldHVybiBhLmZuLmNvbGxhcHNlPWUsdGhpc30sYShkb2N1bWVudCkub24oImNsaWNrLmJzLmNvbGxhcHNlLmRhdGEtYXBpIiwnW2RhdGEtdG9nZ2xlPSJjb2xsYXBzZSJdJyxmdW5jdGlvbihkKXt2YXIgZT1hKHRoaXMpO2UuYXR0cigiZGF0YS10YXJnZXQiKXx8ZC5wcmV2ZW50RGVmYXVsdCgpO3ZhciBmPWIoZSksZz1mLmRhdGEoImJzLmNvbGxhcHNlIiksaD1nPyJ0b2dnbGUiOmUuZGF0YSgpO2MuY2FsbChmLGgpfSl9KGpRdWVyeSksK2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBiKGIpe3ZhciBjPWIuYXR0cigiZGF0YS10YXJnZXQiKTtjfHwoYz1iLmF0dHIoImhyZWYiKSxjPWMmJi8jW0EtWmEtel0vLnRlc3QoYykmJmMucmVwbGFjZSgvLiooPz0jW15cc10qJCkvLCIiKSk7dmFyIGQ9YyYmYShjKTtyZXR1cm4gZCYmZC5sZW5ndGg/ZDpiLnBhcmVudCgpfWZ1bmN0aW9uIGMoYyl7YyYmMz09PWMud2hpY2h8fChhKGUpLnJlbW92ZSgpLGEoZikuZWFjaChmdW5jdGlvbigpe3ZhciBkPWEodGhpcyksZT1iKGQpLGY9e3JlbGF0ZWRUYXJnZXQ6dGhpc307ZS5oYXNDbGFzcygib3BlbiIpJiYoYyYmImNsaWNrIj09Yy50eXBlJiYvaW5wdXR8dGV4dGFyZWEvaS50ZXN0KGMudGFyZ2V0LnRhZ05hbWUpJiZhLmNvbnRhaW5zKGVbMF0sYy50YXJnZXQpfHwoZS50cmlnZ2VyKGM9YS5FdmVudCgiaGlkZS5icy5kcm9wZG93biIsZikpLGMuaXNEZWZhdWx0UHJldmVudGVkKCl8fChkLmF0dHIoImFyaWEtZXhwYW5kZWQiLCJmYWxzZSIpLGUucmVtb3ZlQ2xhc3MoIm9wZW4iKS50cmlnZ2VyKCJoaWRkZW4uYnMuZHJvcGRvd24iLGYpKSkpfSkpfWZ1bmN0aW9uIGQoYil7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBjPWEodGhpcyksZD1jLmRhdGEoImJzLmRyb3Bkb3duIik7ZHx8Yy5kYXRhKCJicy5kcm9wZG93biIsZD1uZXcgZyh0aGlzKSksInN0cmluZyI9PXR5cGVvZiBiJiZkW2JdLmNhbGwoYyl9KX12YXIgZT0iLmRyb3Bkb3duLWJhY2tkcm9wIixmPSdbZGF0YS10b2dnbGU9ImRyb3Bkb3duIl0nLGc9ZnVuY3Rpb24oYil7YShiKS5vbigiY2xpY2suYnMuZHJvcGRvd24iLHRoaXMudG9nZ2xlKX07Zy5WRVJTSU9OPSIzLjMuNSIsZy5wcm90b3R5cGUudG9nZ2xlPWZ1bmN0aW9uKGQpe3ZhciBlPWEodGhpcyk7aWYoIWUuaXMoIi5kaXNhYmxlZCwgOmRpc2FibGVkIikpe3ZhciBmPWIoZSksZz1mLmhhc0NsYXNzKCJvcGVuIik7aWYoYygpLCFnKXsib250b3VjaHN0YXJ0ImluIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCYmIWYuY2xvc2VzdCgiLm5hdmJhci1uYXYiKS5sZW5ndGgmJmEoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2IikpLmFkZENsYXNzKCJkcm9wZG93bi1iYWNrZHJvcCIpLmluc2VydEFmdGVyKGEodGhpcykpLm9uKCJjbGljayIsYyk7dmFyIGg9e3JlbGF0ZWRUYXJnZXQ6dGhpc307aWYoZi50cmlnZ2VyKGQ9YS5FdmVudCgic2hvdy5icy5kcm9wZG93biIsaCkpLGQuaXNEZWZhdWx0UHJldmVudGVkKCkpcmV0dXJuO2UudHJpZ2dlcigiZm9jdXMiKS5hdHRyKCJhcmlhLWV4cGFuZGVkIiwidHJ1ZSIpLGYudG9nZ2xlQ2xhc3MoIm9wZW4iKS50cmlnZ2VyKCJzaG93bi5icy5kcm9wZG93biIsaCl9cmV0dXJuITF9fSxnLnByb3RvdHlwZS5rZXlkb3duPWZ1bmN0aW9uKGMpe2lmKC8oMzh8NDB8Mjd8MzIpLy50ZXN0KGMud2hpY2gpJiYhL2lucHV0fHRleHRhcmVhL2kudGVzdChjLnRhcmdldC50YWdOYW1lKSl7dmFyIGQ9YSh0aGlzKTtpZihjLnByZXZlbnREZWZhdWx0KCksYy5zdG9wUHJvcGFnYXRpb24oKSwhZC5pcygiLmRpc2FibGVkLCA6ZGlzYWJsZWQiKSl7dmFyIGU9YihkKSxnPWUuaGFzQ2xhc3MoIm9wZW4iKTtpZighZyYmMjchPWMud2hpY2h8fGcmJjI3PT1jLndoaWNoKXJldHVybiAyNz09Yy53aGljaCYmZS5maW5kKGYpLnRyaWdnZXIoImZvY3VzIiksZC50cmlnZ2VyKCJjbGljayIpO3ZhciBoPSIgbGk6bm90KC5kaXNhYmxlZCk6dmlzaWJsZSBhIixpPWUuZmluZCgiLmRyb3Bkb3duLW1lbnUiK2gpO2lmKGkubGVuZ3RoKXt2YXIgaj1pLmluZGV4KGMudGFyZ2V0KTszOD09Yy53aGljaCYmaj4wJiZqLS0sNDA9PWMud2hpY2gmJmo8aS5sZW5ndGgtMSYmaisrLH5qfHwoaj0wKSxpLmVxKGopLnRyaWdnZXIoImZvY3VzIil9fX19O3ZhciBoPWEuZm4uZHJvcGRvd247YS5mbi5kcm9wZG93bj1kLGEuZm4uZHJvcGRvd24uQ29uc3RydWN0b3I9ZyxhLmZuLmRyb3Bkb3duLm5vQ29uZmxpY3Q9ZnVuY3Rpb24oKXtyZXR1cm4gYS5mbi5kcm9wZG93bj1oLHRoaXN9LGEoZG9jdW1lbnQpLm9uKCJjbGljay5icy5kcm9wZG93bi5kYXRhLWFwaSIsYykub24oImNsaWNrLmJzLmRyb3Bkb3duLmRhdGEtYXBpIiwiLmRyb3Bkb3duIGZvcm0iLGZ1bmN0aW9uKGEpe2Euc3RvcFByb3BhZ2F0aW9uKCl9KS5vbigiY2xpY2suYnMuZHJvcGRvd24uZGF0YS1hcGkiLGYsZy5wcm90b3R5cGUudG9nZ2xlKS5vbigia2V5ZG93bi5icy5kcm9wZG93bi5kYXRhLWFwaSIsZixnLnByb3RvdHlwZS5rZXlkb3duKS5vbigia2V5ZG93bi5icy5kcm9wZG93bi5kYXRhLWFwaSIsIi5kcm9wZG93bi1tZW51IixnLnByb3RvdHlwZS5rZXlkb3duKX0oalF1ZXJ5KSwrZnVuY3Rpb24oYSl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIGIoYixkKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGU9YSh0aGlzKSxmPWUuZGF0YSgiYnMubW9kYWwiKSxnPWEuZXh0ZW5kKHt9LGMuREVGQVVMVFMsZS5kYXRhKCksIm9iamVjdCI9PXR5cGVvZiBiJiZiKTtmfHxlLmRhdGEoImJzLm1vZGFsIixmPW5ldyBjKHRoaXMsZykpLCJzdHJpbmciPT10eXBlb2YgYj9mW2JdKGQpOmcuc2hvdyYmZi5zaG93KGQpfSl9dmFyIGM9ZnVuY3Rpb24oYixjKXt0aGlzLm9wdGlvbnM9Yyx0aGlzLiRib2R5PWEoZG9jdW1lbnQuYm9keSksdGhpcy4kZWxlbWVudD1hKGIpLHRoaXMuJGRpYWxvZz10aGlzLiRlbGVtZW50LmZpbmQoIi5tb2RhbC1kaWFsb2ciKSx0aGlzLiRiYWNrZHJvcD1udWxsLHRoaXMuaXNTaG93bj1udWxsLHRoaXMub3JpZ2luYWxCb2R5UGFkPW51bGwsdGhpcy5zY3JvbGxiYXJXaWR0aD0wLHRoaXMuaWdub3JlQmFja2Ryb3BDbGljaz0hMSx0aGlzLm9wdGlvbnMucmVtb3RlJiZ0aGlzLiRlbGVtZW50LmZpbmQoIi5tb2RhbC1jb250ZW50IikubG9hZCh0aGlzLm9wdGlvbnMucmVtb3RlLGEucHJveHkoZnVuY3Rpb24oKXt0aGlzLiRlbGVtZW50LnRyaWdnZXIoImxvYWRlZC5icy5tb2RhbCIpfSx0aGlzKSl9O2MuVkVSU0lPTj0iMy4zLjUiLGMuVFJBTlNJVElPTl9EVVJBVElPTj0zMDAsYy5CQUNLRFJPUF9UUkFOU0lUSU9OX0RVUkFUSU9OPTE1MCxjLkRFRkFVTFRTPXtiYWNrZHJvcDohMCxrZXlib2FyZDohMCxzaG93OiEwfSxjLnByb3RvdHlwZS50b2dnbGU9ZnVuY3Rpb24oYSl7cmV0dXJuIHRoaXMuaXNTaG93bj90aGlzLmhpZGUoKTp0aGlzLnNob3coYSl9LGMucHJvdG90eXBlLnNob3c9ZnVuY3Rpb24oYil7dmFyIGQ9dGhpcyxlPWEuRXZlbnQoInNob3cuYnMubW9kYWwiLHtyZWxhdGVkVGFyZ2V0OmJ9KTt0aGlzLiRlbGVtZW50LnRyaWdnZXIoZSksdGhpcy5pc1Nob3dufHxlLmlzRGVmYXVsdFByZXZlbnRlZCgpfHwodGhpcy5pc1Nob3duPSEwLHRoaXMuY2hlY2tTY3JvbGxiYXIoKSx0aGlzLnNldFNjcm9sbGJhcigpLHRoaXMuJGJvZHkuYWRkQ2xhc3MoIm1vZGFsLW9wZW4iKSx0aGlzLmVzY2FwZSgpLHRoaXMucmVzaXplKCksdGhpcy4kZWxlbWVudC5vbigiY2xpY2suZGlzbWlzcy5icy5tb2RhbCIsJ1tkYXRhLWRpc21pc3M9Im1vZGFsIl0nLGEucHJveHkodGhpcy5oaWRlLHRoaXMpKSx0aGlzLiRkaWFsb2cub24oIm1vdXNlZG93bi5kaXNtaXNzLmJzLm1vZGFsIixmdW5jdGlvbigpe2QuJGVsZW1lbnQub25lKCJtb3VzZXVwLmRpc21pc3MuYnMubW9kYWwiLGZ1bmN0aW9uKGIpe2EoYi50YXJnZXQpLmlzKGQuJGVsZW1lbnQpJiYoZC5pZ25vcmVCYWNrZHJvcENsaWNrPSEwKX0pfSksdGhpcy5iYWNrZHJvcChmdW5jdGlvbigpe3ZhciBlPWEuc3VwcG9ydC50cmFuc2l0aW9uJiZkLiRlbGVtZW50Lmhhc0NsYXNzKCJmYWRlIik7ZC4kZWxlbWVudC5wYXJlbnQoKS5sZW5ndGh8fGQuJGVsZW1lbnQuYXBwZW5kVG8oZC4kYm9keSksZC4kZWxlbWVudC5zaG93KCkuc2Nyb2xsVG9wKDApLGQuYWRqdXN0RGlhbG9nKCksZSYmZC4kZWxlbWVudFswXS5vZmZzZXRXaWR0aCxkLiRlbGVtZW50LmFkZENsYXNzKCJpbiIpLGQuZW5mb3JjZUZvY3VzKCk7dmFyIGY9YS5FdmVudCgic2hvd24uYnMubW9kYWwiLHtyZWxhdGVkVGFyZ2V0OmJ9KTtlP2QuJGRpYWxvZy5vbmUoImJzVHJhbnNpdGlvbkVuZCIsZnVuY3Rpb24oKXtkLiRlbGVtZW50LnRyaWdnZXIoImZvY3VzIikudHJpZ2dlcihmKX0pLmVtdWxhdGVUcmFuc2l0aW9uRW5kKGMuVFJBTlNJVElPTl9EVVJBVElPTik6ZC4kZWxlbWVudC50cmlnZ2VyKCJmb2N1cyIpLnRyaWdnZXIoZil9KSl9LGMucHJvdG90eXBlLmhpZGU9ZnVuY3Rpb24oYil7YiYmYi5wcmV2ZW50RGVmYXVsdCgpLGI9YS5FdmVudCgiaGlkZS5icy5tb2RhbCIpLHRoaXMuJGVsZW1lbnQudHJpZ2dlcihiKSx0aGlzLmlzU2hvd24mJiFiLmlzRGVmYXVsdFByZXZlbnRlZCgpJiYodGhpcy5pc1Nob3duPSExLHRoaXMuZXNjYXBlKCksdGhpcy5yZXNpemUoKSxhKGRvY3VtZW50KS5vZmYoImZvY3VzaW4uYnMubW9kYWwiKSx0aGlzLiRlbGVtZW50LnJlbW92ZUNsYXNzKCJpbiIpLm9mZigiY2xpY2suZGlzbWlzcy5icy5tb2RhbCIpLm9mZigibW91c2V1cC5kaXNtaXNzLmJzLm1vZGFsIiksdGhpcy4kZGlhbG9nLm9mZigibW91c2Vkb3duLmRpc21pc3MuYnMubW9kYWwiKSxhLnN1cHBvcnQudHJhbnNpdGlvbiYmdGhpcy4kZWxlbWVudC5oYXNDbGFzcygiZmFkZSIpP3RoaXMuJGVsZW1lbnQub25lKCJic1RyYW5zaXRpb25FbmQiLGEucHJveHkodGhpcy5oaWRlTW9kYWwsdGhpcykpLmVtdWxhdGVUcmFuc2l0aW9uRW5kKGMuVFJBTlNJVElPTl9EVVJBVElPTik6dGhpcy5oaWRlTW9kYWwoKSl9LGMucHJvdG90eXBlLmVuZm9yY2VGb2N1cz1mdW5jdGlvbigpe2EoZG9jdW1lbnQpLm9mZigiZm9jdXNpbi5icy5tb2RhbCIpLm9uKCJmb2N1c2luLmJzLm1vZGFsIixhLnByb3h5KGZ1bmN0aW9uKGEpe3RoaXMuJGVsZW1lbnRbMF09PT1hLnRhcmdldHx8dGhpcy4kZWxlbWVudC5oYXMoYS50YXJnZXQpLmxlbmd0aHx8dGhpcy4kZWxlbWVudC50cmlnZ2VyKCJmb2N1cyIpfSx0aGlzKSl9LGMucHJvdG90eXBlLmVzY2FwZT1mdW5jdGlvbigpe3RoaXMuaXNTaG93biYmdGhpcy5vcHRpb25zLmtleWJvYXJkP3RoaXMuJGVsZW1lbnQub24oImtleWRvd24uZGlzbWlzcy5icy5tb2RhbCIsYS5wcm94eShmdW5jdGlvbihhKXsyNz09YS53aGljaCYmdGhpcy5oaWRlKCl9LHRoaXMpKTp0aGlzLmlzU2hvd258fHRoaXMuJGVsZW1lbnQub2ZmKCJrZXlkb3duLmRpc21pc3MuYnMubW9kYWwiKX0sYy5wcm90b3R5cGUucmVzaXplPWZ1bmN0aW9uKCl7dGhpcy5pc1Nob3duP2Eod2luZG93KS5vbigicmVzaXplLmJzLm1vZGFsIixhLnByb3h5KHRoaXMuaGFuZGxlVXBkYXRlLHRoaXMpKTphKHdpbmRvdykub2ZmKCJyZXNpemUuYnMubW9kYWwiKX0sYy5wcm90b3R5cGUuaGlkZU1vZGFsPWZ1bmN0aW9uKCl7dmFyIGE9dGhpczt0aGlzLiRlbGVtZW50LmhpZGUoKSx0aGlzLmJhY2tkcm9wKGZ1bmN0aW9uKCl7YS4kYm9keS5yZW1vdmVDbGFzcygibW9kYWwtb3BlbiIpLGEucmVzZXRBZGp1c3RtZW50cygpLGEucmVzZXRTY3JvbGxiYXIoKSxhLiRlbGVtZW50LnRyaWdnZXIoImhpZGRlbi5icy5tb2RhbCIpfSl9LGMucHJvdG90eXBlLnJlbW92ZUJhY2tkcm9wPWZ1bmN0aW9uKCl7dGhpcy4kYmFja2Ryb3AmJnRoaXMuJGJhY2tkcm9wLnJlbW92ZSgpLHRoaXMuJGJhY2tkcm9wPW51bGx9LGMucHJvdG90eXBlLmJhY2tkcm9wPWZ1bmN0aW9uKGIpe3ZhciBkPXRoaXMsZT10aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCJmYWRlIik/ImZhZGUiOiIiO2lmKHRoaXMuaXNTaG93biYmdGhpcy5vcHRpb25zLmJhY2tkcm9wKXt2YXIgZj1hLnN1cHBvcnQudHJhbnNpdGlvbiYmZTtpZih0aGlzLiRiYWNrZHJvcD1hKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImRpdiIpKS5hZGRDbGFzcygibW9kYWwtYmFja2Ryb3AgIitlKS5hcHBlbmRUbyh0aGlzLiRib2R5KSx0aGlzLiRlbGVtZW50Lm9uKCJjbGljay5kaXNtaXNzLmJzLm1vZGFsIixhLnByb3h5KGZ1bmN0aW9uKGEpe3JldHVybiB0aGlzLmlnbm9yZUJhY2tkcm9wQ2xpY2s/dm9pZCh0aGlzLmlnbm9yZUJhY2tkcm9wQ2xpY2s9ITEpOnZvaWQoYS50YXJnZXQ9PT1hLmN1cnJlbnRUYXJnZXQmJigic3RhdGljIj09dGhpcy5vcHRpb25zLmJhY2tkcm9wP3RoaXMuJGVsZW1lbnRbMF0uZm9jdXMoKTp0aGlzLmhpZGUoKSkpfSx0aGlzKSksZiYmdGhpcy4kYmFja2Ryb3BbMF0ub2Zmc2V0V2lkdGgsdGhpcy4kYmFja2Ryb3AuYWRkQ2xhc3MoImluIiksIWIpcmV0dXJuO2Y/dGhpcy4kYmFja2Ryb3Aub25lKCJic1RyYW5zaXRpb25FbmQiLGIpLmVtdWxhdGVUcmFuc2l0aW9uRW5kKGMuQkFDS0RST1BfVFJBTlNJVElPTl9EVVJBVElPTik6YigpfWVsc2UgaWYoIXRoaXMuaXNTaG93biYmdGhpcy4kYmFja2Ryb3Ape3RoaXMuJGJhY2tkcm9wLnJlbW92ZUNsYXNzKCJpbiIpO3ZhciBnPWZ1bmN0aW9uKCl7ZC5yZW1vdmVCYWNrZHJvcCgpLGImJmIoKX07YS5zdXBwb3J0LnRyYW5zaXRpb24mJnRoaXMuJGVsZW1lbnQuaGFzQ2xhc3MoImZhZGUiKT90aGlzLiRiYWNrZHJvcC5vbmUoImJzVHJhbnNpdGlvbkVuZCIsZykuZW11bGF0ZVRyYW5zaXRpb25FbmQoYy5CQUNLRFJPUF9UUkFOU0lUSU9OX0RVUkFUSU9OKTpnKCl9ZWxzZSBiJiZiKCl9LGMucHJvdG90eXBlLmhhbmRsZVVwZGF0ZT1mdW5jdGlvbigpe3RoaXMuYWRqdXN0RGlhbG9nKCl9LGMucHJvdG90eXBlLmFkanVzdERpYWxvZz1mdW5jdGlvbigpe3ZhciBhPXRoaXMuJGVsZW1lbnRbMF0uc2Nyb2xsSGVpZ2h0PmRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQ7dGhpcy4kZWxlbWVudC5jc3Moe3BhZGRpbmdMZWZ0OiF0aGlzLmJvZHlJc092ZXJmbG93aW5nJiZhP3RoaXMuc2Nyb2xsYmFyV2lkdGg6IiIscGFkZGluZ1JpZ2h0OnRoaXMuYm9keUlzT3ZlcmZsb3dpbmcmJiFhP3RoaXMuc2Nyb2xsYmFyV2lkdGg6IiJ9KX0sYy5wcm90b3R5cGUucmVzZXRBZGp1c3RtZW50cz1mdW5jdGlvbigpe3RoaXMuJGVsZW1lbnQuY3NzKHtwYWRkaW5nTGVmdDoiIixwYWRkaW5nUmlnaHQ6IiJ9KX0sYy5wcm90b3R5cGUuY2hlY2tTY3JvbGxiYXI9ZnVuY3Rpb24oKXt2YXIgYT13aW5kb3cuaW5uZXJXaWR0aDtpZighYSl7dmFyIGI9ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO2E9Yi5yaWdodC1NYXRoLmFicyhiLmxlZnQpfXRoaXMuYm9keUlzT3ZlcmZsb3dpbmc9ZG9jdW1lbnQuYm9keS5jbGllbnRXaWR0aDxhLHRoaXMuc2Nyb2xsYmFyV2lkdGg9dGhpcy5tZWFzdXJlU2Nyb2xsYmFyKCl9LGMucHJvdG90eXBlLnNldFNjcm9sbGJhcj1mdW5jdGlvbigpe3ZhciBhPXBhcnNlSW50KHRoaXMuJGJvZHkuY3NzKCJwYWRkaW5nLXJpZ2h0Iil8fDAsMTApO3RoaXMub3JpZ2luYWxCb2R5UGFkPWRvY3VtZW50LmJvZHkuc3R5bGUucGFkZGluZ1JpZ2h0fHwiIix0aGlzLmJvZHlJc092ZXJmbG93aW5nJiZ0aGlzLiRib2R5LmNzcygicGFkZGluZy1yaWdodCIsYSt0aGlzLnNjcm9sbGJhcldpZHRoKX0sYy5wcm90b3R5cGUucmVzZXRTY3JvbGxiYXI9ZnVuY3Rpb24oKXt0aGlzLiRib2R5LmNzcygicGFkZGluZy1yaWdodCIsdGhpcy5vcmlnaW5hbEJvZHlQYWQpfSxjLnByb3RvdHlwZS5tZWFzdXJlU2Nyb2xsYmFyPWZ1bmN0aW9uKCl7dmFyIGE9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7YS5jbGFzc05hbWU9Im1vZGFsLXNjcm9sbGJhci1tZWFzdXJlIix0aGlzLiRib2R5LmFwcGVuZChhKTt2YXIgYj1hLm9mZnNldFdpZHRoLWEuY2xpZW50V2lkdGg7cmV0dXJuIHRoaXMuJGJvZHlbMF0ucmVtb3ZlQ2hpbGQoYSksYn07dmFyIGQ9YS5mbi5tb2RhbDthLmZuLm1vZGFsPWIsYS5mbi5tb2RhbC5Db25zdHJ1Y3Rvcj1jLGEuZm4ubW9kYWwubm9Db25mbGljdD1mdW5jdGlvbigpe3JldHVybiBhLmZuLm1vZGFsPWQsdGhpc30sYShkb2N1bWVudCkub24oImNsaWNrLmJzLm1vZGFsLmRhdGEtYXBpIiwnW2RhdGEtdG9nZ2xlPSJtb2RhbCJdJyxmdW5jdGlvbihjKXt2YXIgZD1hKHRoaXMpLGU9ZC5hdHRyKCJocmVmIiksZj1hKGQuYXR0cigiZGF0YS10YXJnZXQiKXx8ZSYmZS5yZXBsYWNlKC8uKig/PSNbXlxzXSskKS8sIiIpKSxnPWYuZGF0YSgiYnMubW9kYWwiKT8idG9nZ2xlIjphLmV4dGVuZCh7cmVtb3RlOiEvIy8udGVzdChlKSYmZX0sZi5kYXRhKCksZC5kYXRhKCkpO2QuaXMoImEiKSYmYy5wcmV2ZW50RGVmYXVsdCgpLGYub25lKCJzaG93LmJzLm1vZGFsIixmdW5jdGlvbihhKXthLmlzRGVmYXVsdFByZXZlbnRlZCgpfHxmLm9uZSgiaGlkZGVuLmJzLm1vZGFsIixmdW5jdGlvbigpe2QuaXMoIjp2aXNpYmxlIikmJmQudHJpZ2dlcigiZm9jdXMiKX0pfSksYi5jYWxsKGYsZyx0aGlzKX0pfShqUXVlcnkpLCtmdW5jdGlvbihhKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gYihiKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGQ9YSh0aGlzKSxlPWQuZGF0YSgiYnMudG9vbHRpcCIpLGY9Im9iamVjdCI9PXR5cGVvZiBiJiZiOyhlfHwhL2Rlc3Ryb3l8aGlkZS8udGVzdChiKSkmJihlfHxkLmRhdGEoImJzLnRvb2x0aXAiLGU9bmV3IGModGhpcyxmKSksInN0cmluZyI9PXR5cGVvZiBiJiZlW2JdKCkpfSl9dmFyIGM9ZnVuY3Rpb24oYSxiKXt0aGlzLnR5cGU9bnVsbCx0aGlzLm9wdGlvbnM9bnVsbCx0aGlzLmVuYWJsZWQ9bnVsbCx0aGlzLnRpbWVvdXQ9bnVsbCx0aGlzLmhvdmVyU3RhdGU9bnVsbCx0aGlzLiRlbGVtZW50PW51bGwsdGhpcy5pblN0YXRlPW51bGwsdGhpcy5pbml0KCJ0b29sdGlwIixhLGIpfTtjLlZFUlNJT049IjMuMy41IixjLlRSQU5TSVRJT05fRFVSQVRJT049MTUwLGMuREVGQVVMVFM9e2FuaW1hdGlvbjohMCxwbGFjZW1lbnQ6InRvcCIsc2VsZWN0b3I6ITEsdGVtcGxhdGU6JzxkaXYgY2xhc3M9InRvb2x0aXAiIHJvbGU9InRvb2x0aXAiPjxkaXYgY2xhc3M9InRvb2x0aXAtYXJyb3ciPjwvZGl2PjxkaXYgY2xhc3M9InRvb2x0aXAtaW5uZXIiPjwvZGl2PjwvZGl2PicsdHJpZ2dlcjoiaG92ZXIgZm9jdXMiLHRpdGxlOiIiLGRlbGF5OjAsaHRtbDohMSxjb250YWluZXI6ITEsdmlld3BvcnQ6e3NlbGVjdG9yOiJib2R5IixwYWRkaW5nOjB9fSxjLnByb3RvdHlwZS5pbml0PWZ1bmN0aW9uKGIsYyxkKXtpZih0aGlzLmVuYWJsZWQ9ITAsdGhpcy50eXBlPWIsdGhpcy4kZWxlbWVudD1hKGMpLHRoaXMub3B0aW9ucz10aGlzLmdldE9wdGlvbnMoZCksdGhpcy4kdmlld3BvcnQ9dGhpcy5vcHRpb25zLnZpZXdwb3J0JiZhKGEuaXNGdW5jdGlvbih0aGlzLm9wdGlvbnMudmlld3BvcnQpP3RoaXMub3B0aW9ucy52aWV3cG9ydC5jYWxsKHRoaXMsdGhpcy4kZWxlbWVudCk6dGhpcy5vcHRpb25zLnZpZXdwb3J0LnNlbGVjdG9yfHx0aGlzLm9wdGlvbnMudmlld3BvcnQpLHRoaXMuaW5TdGF0ZT17Y2xpY2s6ITEsaG92ZXI6ITEsZm9jdXM6ITF9LHRoaXMuJGVsZW1lbnRbMF1pbnN0YW5jZW9mIGRvY3VtZW50LmNvbnN0cnVjdG9yJiYhdGhpcy5vcHRpb25zLnNlbGVjdG9yKXRocm93IG5ldyBFcnJvcigiYHNlbGVjdG9yYCBvcHRpb24gbXVzdCBiZSBzcGVjaWZpZWQgd2hlbiBpbml0aWFsaXppbmcgIit0aGlzLnR5cGUrIiBvbiB0aGUgd2luZG93LmRvY3VtZW50IG9iamVjdCEiKTtmb3IodmFyIGU9dGhpcy5vcHRpb25zLnRyaWdnZXIuc3BsaXQoIiAiKSxmPWUubGVuZ3RoO2YtLTspe3ZhciBnPWVbZl07aWYoImNsaWNrIj09Zyl0aGlzLiRlbGVtZW50Lm9uKCJjbGljay4iK3RoaXMudHlwZSx0aGlzLm9wdGlvbnMuc2VsZWN0b3IsYS5wcm94eSh0aGlzLnRvZ2dsZSx0aGlzKSk7ZWxzZSBpZigibWFudWFsIiE9Zyl7dmFyIGg9ImhvdmVyIj09Zz8ibW91c2VlbnRlciI6ImZvY3VzaW4iLGk9ImhvdmVyIj09Zz8ibW91c2VsZWF2ZSI6ImZvY3Vzb3V0Ijt0aGlzLiRlbGVtZW50Lm9uKGgrIi4iK3RoaXMudHlwZSx0aGlzLm9wdGlvbnMuc2VsZWN0b3IsYS5wcm94eSh0aGlzLmVudGVyLHRoaXMpKSx0aGlzLiRlbGVtZW50Lm9uKGkrIi4iK3RoaXMudHlwZSx0aGlzLm9wdGlvbnMuc2VsZWN0b3IsYS5wcm94eSh0aGlzLmxlYXZlLHRoaXMpKX19dGhpcy5vcHRpb25zLnNlbGVjdG9yP3RoaXMuX29wdGlvbnM9YS5leHRlbmQoe30sdGhpcy5vcHRpb25zLHt0cmlnZ2VyOiJtYW51YWwiLHNlbGVjdG9yOiIifSk6dGhpcy5maXhUaXRsZSgpfSxjLnByb3RvdHlwZS5nZXREZWZhdWx0cz1mdW5jdGlvbigpe3JldHVybiBjLkRFRkFVTFRTfSxjLnByb3RvdHlwZS5nZXRPcHRpb25zPWZ1bmN0aW9uKGIpe3JldHVybiBiPWEuZXh0ZW5kKHt9LHRoaXMuZ2V0RGVmYXVsdHMoKSx0aGlzLiRlbGVtZW50LmRhdGEoKSxiKSxiLmRlbGF5JiYibnVtYmVyIj09dHlwZW9mIGIuZGVsYXkmJihiLmRlbGF5PXtzaG93OmIuZGVsYXksaGlkZTpiLmRlbGF5fSksYn0sYy5wcm90b3R5cGUuZ2V0RGVsZWdhdGVPcHRpb25zPWZ1bmN0aW9uKCl7dmFyIGI9e30sYz10aGlzLmdldERlZmF1bHRzKCk7cmV0dXJuIHRoaXMuX29wdGlvbnMmJmEuZWFjaCh0aGlzLl9vcHRpb25zLGZ1bmN0aW9uKGEsZCl7Y1thXSE9ZCYmKGJbYV09ZCl9KSxifSxjLnByb3RvdHlwZS5lbnRlcj1mdW5jdGlvbihiKXt2YXIgYz1iIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9iOmEoYi5jdXJyZW50VGFyZ2V0KS5kYXRhKCJicy4iK3RoaXMudHlwZSk7cmV0dXJuIGN8fChjPW5ldyB0aGlzLmNvbnN0cnVjdG9yKGIuY3VycmVudFRhcmdldCx0aGlzLmdldERlbGVnYXRlT3B0aW9ucygpKSxhKGIuY3VycmVudFRhcmdldCkuZGF0YSgiYnMuIit0aGlzLnR5cGUsYykpLGIgaW5zdGFuY2VvZiBhLkV2ZW50JiYoYy5pblN0YXRlWyJmb2N1c2luIj09Yi50eXBlPyJmb2N1cyI6ImhvdmVyIl09ITApLGMudGlwKCkuaGFzQ2xhc3MoImluIil8fCJpbiI9PWMuaG92ZXJTdGF0ZT92b2lkKGMuaG92ZXJTdGF0ZT0iaW4iKTooY2xlYXJUaW1lb3V0KGMudGltZW91dCksYy5ob3ZlclN0YXRlPSJpbiIsYy5vcHRpb25zLmRlbGF5JiZjLm9wdGlvbnMuZGVsYXkuc2hvdz92b2lkKGMudGltZW91dD1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7ImluIj09Yy5ob3ZlclN0YXRlJiZjLnNob3coKX0sYy5vcHRpb25zLmRlbGF5LnNob3cpKTpjLnNob3coKSl9LGMucHJvdG90eXBlLmlzSW5TdGF0ZVRydWU9ZnVuY3Rpb24oKXtmb3IodmFyIGEgaW4gdGhpcy5pblN0YXRlKWlmKHRoaXMuaW5TdGF0ZVthXSlyZXR1cm4hMDtyZXR1cm4hMX0sYy5wcm90b3R5cGUubGVhdmU9ZnVuY3Rpb24oYil7dmFyIGM9YiBpbnN0YW5jZW9mIHRoaXMuY29uc3RydWN0b3I/YjphKGIuY3VycmVudFRhcmdldCkuZGF0YSgiYnMuIit0aGlzLnR5cGUpO3JldHVybiBjfHwoYz1uZXcgdGhpcy5jb25zdHJ1Y3RvcihiLmN1cnJlbnRUYXJnZXQsdGhpcy5nZXREZWxlZ2F0ZU9wdGlvbnMoKSksYShiLmN1cnJlbnRUYXJnZXQpLmRhdGEoImJzLiIrdGhpcy50eXBlLGMpKSxiIGluc3RhbmNlb2YgYS5FdmVudCYmKGMuaW5TdGF0ZVsiZm9jdXNvdXQiPT1iLnR5cGU/ImZvY3VzIjoiaG92ZXIiXT0hMSksYy5pc0luU3RhdGVUcnVlKCk/dm9pZCAwOihjbGVhclRpbWVvdXQoYy50aW1lb3V0KSxjLmhvdmVyU3RhdGU9Im91dCIsYy5vcHRpb25zLmRlbGF5JiZjLm9wdGlvbnMuZGVsYXkuaGlkZT92b2lkKGMudGltZW91dD1zZXRUaW1lb3V0KGZ1bmN0aW9uKCl7Im91dCI9PWMuaG92ZXJTdGF0ZSYmYy5oaWRlKCl9LGMub3B0aW9ucy5kZWxheS5oaWRlKSk6Yy5oaWRlKCkpfSxjLnByb3RvdHlwZS5zaG93PWZ1bmN0aW9uKCl7dmFyIGI9YS5FdmVudCgic2hvdy5icy4iK3RoaXMudHlwZSk7aWYodGhpcy5oYXNDb250ZW50KCkmJnRoaXMuZW5hYmxlZCl7dGhpcy4kZWxlbWVudC50cmlnZ2VyKGIpO3ZhciBkPWEuY29udGFpbnModGhpcy4kZWxlbWVudFswXS5vd25lckRvY3VtZW50LmRvY3VtZW50RWxlbWVudCx0aGlzLiRlbGVtZW50WzBdKTtpZihiLmlzRGVmYXVsdFByZXZlbnRlZCgpfHwhZClyZXR1cm47dmFyIGU9dGhpcyxmPXRoaXMudGlwKCksZz10aGlzLmdldFVJRCh0aGlzLnR5cGUpO3RoaXMuc2V0Q29udGVudCgpLGYuYXR0cigiaWQiLGcpLHRoaXMuJGVsZW1lbnQuYXR0cigiYXJpYS1kZXNjcmliZWRieSIsZyksdGhpcy5vcHRpb25zLmFuaW1hdGlvbiYmZi5hZGRDbGFzcygiZmFkZSIpO3ZhciBoPSJmdW5jdGlvbiI9PXR5cGVvZiB0aGlzLm9wdGlvbnMucGxhY2VtZW50P3RoaXMub3B0aW9ucy5wbGFjZW1lbnQuY2FsbCh0aGlzLGZbMF0sdGhpcy4kZWxlbWVudFswXSk6dGhpcy5vcHRpb25zLnBsYWNlbWVudCxpPS9ccz9hdXRvP1xzPy9pLGo9aS50ZXN0KGgpO2omJihoPWgucmVwbGFjZShpLCIiKXx8InRvcCIpLGYuZGV0YWNoKCkuY3NzKHt0b3A6MCxsZWZ0OjAsZGlzcGxheToiYmxvY2sifSkuYWRkQ2xhc3MoaCkuZGF0YSgiYnMuIit0aGlzLnR5cGUsdGhpcyksdGhpcy5vcHRpb25zLmNvbnRhaW5lcj9mLmFwcGVuZFRvKHRoaXMub3B0aW9ucy5jb250YWluZXIpOmYuaW5zZXJ0QWZ0ZXIodGhpcy4kZWxlbWVudCksdGhpcy4kZWxlbWVudC50cmlnZ2VyKCJpbnNlcnRlZC5icy4iK3RoaXMudHlwZSk7dmFyIGs9dGhpcy5nZXRQb3NpdGlvbigpLGw9ZlswXS5vZmZzZXRXaWR0aCxtPWZbMF0ub2Zmc2V0SGVpZ2h0O2lmKGope3ZhciBuPWgsbz10aGlzLmdldFBvc2l0aW9uKHRoaXMuJHZpZXdwb3J0KTtoPSJib3R0b20iPT1oJiZrLmJvdHRvbSttPm8uYm90dG9tPyJ0b3AiOiJ0b3AiPT1oJiZrLnRvcC1tPG8udG9wPyJib3R0b20iOiJyaWdodCI9PWgmJmsucmlnaHQrbD5vLndpZHRoPyJsZWZ0IjoibGVmdCI9PWgmJmsubGVmdC1sPG8ubGVmdD8icmlnaHQiOmgsZi5yZW1vdmVDbGFzcyhuKS5hZGRDbGFzcyhoKX12YXIgcD10aGlzLmdldENhbGN1bGF0ZWRPZmZzZXQoaCxrLGwsbSk7dGhpcy5hcHBseVBsYWNlbWVudChwLGgpO3ZhciBxPWZ1bmN0aW9uKCl7dmFyIGE9ZS5ob3ZlclN0YXRlO2UuJGVsZW1lbnQudHJpZ2dlcigic2hvd24uYnMuIitlLnR5cGUpLGUuaG92ZXJTdGF0ZT1udWxsLCJvdXQiPT1hJiZlLmxlYXZlKGUpfTthLnN1cHBvcnQudHJhbnNpdGlvbiYmdGhpcy4kdGlwLmhhc0NsYXNzKCJmYWRlIik/Zi5vbmUoImJzVHJhbnNpdGlvbkVuZCIscSkuZW11bGF0ZVRyYW5zaXRpb25FbmQoYy5UUkFOU0lUSU9OX0RVUkFUSU9OKTpxKCl9fSxjLnByb3RvdHlwZS5hcHBseVBsYWNlbWVudD1mdW5jdGlvbihiLGMpe3ZhciBkPXRoaXMudGlwKCksZT1kWzBdLm9mZnNldFdpZHRoLGY9ZFswXS5vZmZzZXRIZWlnaHQsZz1wYXJzZUludChkLmNzcygibWFyZ2luLXRvcCIpLDEwKSxoPXBhcnNlSW50KGQuY3NzKCJtYXJnaW4tbGVmdCIpLDEwKTtpc05hTihnKSYmKGc9MCksaXNOYU4oaCkmJihoPTApLGIudG9wKz1nLGIubGVmdCs9aCxhLm9mZnNldC5zZXRPZmZzZXQoZFswXSxhLmV4dGVuZCh7dXNpbmc6ZnVuY3Rpb24oYSl7ZC5jc3Moe3RvcDpNYXRoLnJvdW5kKGEudG9wKSxsZWZ0Ok1hdGgucm91bmQoYS5sZWZ0KX0pfX0sYiksMCksZC5hZGRDbGFzcygiaW4iKTt2YXIgaT1kWzBdLm9mZnNldFdpZHRoLGo9ZFswXS5vZmZzZXRIZWlnaHQ7InRvcCI9PWMmJmohPWYmJihiLnRvcD1iLnRvcCtmLWopO3ZhciBrPXRoaXMuZ2V0Vmlld3BvcnRBZGp1c3RlZERlbHRhKGMsYixpLGopO2subGVmdD9iLmxlZnQrPWsubGVmdDpiLnRvcCs9ay50b3A7dmFyIGw9L3RvcHxib3R0b20vLnRlc3QoYyksbT1sPzIqay5sZWZ0LWUraToyKmsudG9wLWYraixuPWw/Im9mZnNldFdpZHRoIjoib2Zmc2V0SGVpZ2h0IjtkLm9mZnNldChiKSx0aGlzLnJlcGxhY2VBcnJvdyhtLGRbMF1bbl0sbCl9LGMucHJvdG90eXBlLnJlcGxhY2VBcnJvdz1mdW5jdGlvbihhLGIsYyl7dGhpcy5hcnJvdygpLmNzcyhjPyJsZWZ0IjoidG9wIiw1MCooMS1hL2IpKyIlIikuY3NzKGM/InRvcCI6ImxlZnQiLCIiKX0sYy5wcm90b3R5cGUuc2V0Q29udGVudD1mdW5jdGlvbigpe3ZhciBhPXRoaXMudGlwKCksYj10aGlzLmdldFRpdGxlKCk7YS5maW5kKCIudG9vbHRpcC1pbm5lciIpW3RoaXMub3B0aW9ucy5odG1sPyJodG1sIjoidGV4dCJdKGIpLGEucmVtb3ZlQ2xhc3MoImZhZGUgaW4gdG9wIGJvdHRvbSBsZWZ0IHJpZ2h0Iil9LGMucHJvdG90eXBlLmhpZGU9ZnVuY3Rpb24oYil7ZnVuY3Rpb24gZCgpeyJpbiIhPWUuaG92ZXJTdGF0ZSYmZi5kZXRhY2goKSxlLiRlbGVtZW50LnJlbW92ZUF0dHIoImFyaWEtZGVzY3JpYmVkYnkiKS50cmlnZ2VyKCJoaWRkZW4uYnMuIitlLnR5cGUpLGImJmIoKX12YXIgZT10aGlzLGY9YSh0aGlzLiR0aXApLGc9YS5FdmVudCgiaGlkZS5icy4iK3RoaXMudHlwZSk7cmV0dXJuIHRoaXMuJGVsZW1lbnQudHJpZ2dlcihnKSxnLmlzRGVmYXVsdFByZXZlbnRlZCgpP3ZvaWQgMDooZi5yZW1vdmVDbGFzcygiaW4iKSxhLnN1cHBvcnQudHJhbnNpdGlvbiYmZi5oYXNDbGFzcygiZmFkZSIpP2Yub25lKCJic1RyYW5zaXRpb25FbmQiLGQpLmVtdWxhdGVUcmFuc2l0aW9uRW5kKGMuVFJBTlNJVElPTl9EVVJBVElPTik6ZCgpLHRoaXMuaG92ZXJTdGF0ZT1udWxsLHRoaXMpfSxjLnByb3RvdHlwZS5maXhUaXRsZT1mdW5jdGlvbigpe3ZhciBhPXRoaXMuJGVsZW1lbnQ7KGEuYXR0cigidGl0bGUiKXx8InN0cmluZyIhPXR5cGVvZiBhLmF0dHIoImRhdGEtb3JpZ2luYWwtdGl0bGUiKSkmJmEuYXR0cigiZGF0YS1vcmlnaW5hbC10aXRsZSIsYS5hdHRyKCJ0aXRsZSIpfHwiIikuYXR0cigidGl0bGUiLCIiKX0sYy5wcm90b3R5cGUuaGFzQ29udGVudD1mdW5jdGlvbigpe3JldHVybiB0aGlzLmdldFRpdGxlKCl9LGMucHJvdG90eXBlLmdldFBvc2l0aW9uPWZ1bmN0aW9uKGIpe2I9Ynx8dGhpcy4kZWxlbWVudDt2YXIgYz1iWzBdLGQ9IkJPRFkiPT1jLnRhZ05hbWUsZT1jLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO251bGw9PWUud2lkdGgmJihlPWEuZXh0ZW5kKHt9LGUse3dpZHRoOmUucmlnaHQtZS5sZWZ0LGhlaWdodDplLmJvdHRvbS1lLnRvcH0pKTt2YXIgZj1kP3t0b3A6MCxsZWZ0OjB9OmIub2Zmc2V0KCksZz17c2Nyb2xsOmQ/ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcHx8ZG9jdW1lbnQuYm9keS5zY3JvbGxUb3A6Yi5zY3JvbGxUb3AoKX0saD1kP3t3aWR0aDphKHdpbmRvdykud2lkdGgoKSxoZWlnaHQ6YSh3aW5kb3cpLmhlaWdodCgpfTpudWxsO3JldHVybiBhLmV4dGVuZCh7fSxlLGcsaCxmKX0sYy5wcm90b3R5cGUuZ2V0Q2FsY3VsYXRlZE9mZnNldD1mdW5jdGlvbihhLGIsYyxkKXtyZXR1cm4iYm90dG9tIj09YT97dG9wOmIudG9wK2IuaGVpZ2h0LGxlZnQ6Yi5sZWZ0K2Iud2lkdGgvMi1jLzJ9OiJ0b3AiPT1hP3t0b3A6Yi50b3AtZCxsZWZ0OmIubGVmdCtiLndpZHRoLzItYy8yfToibGVmdCI9PWE/e3RvcDpiLnRvcCtiLmhlaWdodC8yLWQvMixsZWZ0OmIubGVmdC1jfTp7dG9wOmIudG9wK2IuaGVpZ2h0LzItZC8yLGxlZnQ6Yi5sZWZ0K2Iud2lkdGh9fSxjLnByb3RvdHlwZS5nZXRWaWV3cG9ydEFkanVzdGVkRGVsdGE9ZnVuY3Rpb24oYSxiLGMsZCl7dmFyIGU9e3RvcDowLGxlZnQ6MH07aWYoIXRoaXMuJHZpZXdwb3J0KXJldHVybiBlO3ZhciBmPXRoaXMub3B0aW9ucy52aWV3cG9ydCYmdGhpcy5vcHRpb25zLnZpZXdwb3J0LnBhZGRpbmd8fDAsZz10aGlzLmdldFBvc2l0aW9uKHRoaXMuJHZpZXdwb3J0KTtpZigvcmlnaHR8bGVmdC8udGVzdChhKSl7dmFyIGg9Yi50b3AtZi1nLnNjcm9sbCxpPWIudG9wK2YtZy5zY3JvbGwrZDtoPGcudG9wP2UudG9wPWcudG9wLWg6aT5nLnRvcCtnLmhlaWdodCYmKGUudG9wPWcudG9wK2cuaGVpZ2h0LWkpfWVsc2V7dmFyIGo9Yi5sZWZ0LWYsaz1iLmxlZnQrZitjO2o8Zy5sZWZ0P2UubGVmdD1nLmxlZnQtajprPmcucmlnaHQmJihlLmxlZnQ9Zy5sZWZ0K2cud2lkdGgtayl9cmV0dXJuIGV9LGMucHJvdG90eXBlLmdldFRpdGxlPWZ1bmN0aW9uKCl7dmFyIGEsYj10aGlzLiRlbGVtZW50LGM9dGhpcy5vcHRpb25zO3JldHVybiBhPWIuYXR0cigiZGF0YS1vcmlnaW5hbC10aXRsZSIpfHwoImZ1bmN0aW9uIj09dHlwZW9mIGMudGl0bGU/Yy50aXRsZS5jYWxsKGJbMF0pOmMudGl0bGUpfSxjLnByb3RvdHlwZS5nZXRVSUQ9ZnVuY3Rpb24oYSl7ZG8gYSs9fn4oMWU2Kk1hdGgucmFuZG9tKCkpO3doaWxlKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGEpKTtyZXR1cm4gYX0sYy5wcm90b3R5cGUudGlwPWZ1bmN0aW9uKCl7aWYoIXRoaXMuJHRpcCYmKHRoaXMuJHRpcD1hKHRoaXMub3B0aW9ucy50ZW1wbGF0ZSksMSE9dGhpcy4kdGlwLmxlbmd0aCkpdGhyb3cgbmV3IEVycm9yKHRoaXMudHlwZSsiIGB0ZW1wbGF0ZWAgb3B0aW9uIG11c3QgY29uc2lzdCBvZiBleGFjdGx5IDEgdG9wLWxldmVsIGVsZW1lbnQhIik7cmV0dXJuIHRoaXMuJHRpcH0sYy5wcm90b3R5cGUuYXJyb3c9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy4kYXJyb3c9dGhpcy4kYXJyb3d8fHRoaXMudGlwKCkuZmluZCgiLnRvb2x0aXAtYXJyb3ciKX0sYy5wcm90b3R5cGUuZW5hYmxlPWZ1bmN0aW9uKCl7dGhpcy5lbmFibGVkPSEwfSxjLnByb3RvdHlwZS5kaXNhYmxlPWZ1bmN0aW9uKCl7dGhpcy5lbmFibGVkPSExfSxjLnByb3RvdHlwZS50b2dnbGVFbmFibGVkPWZ1bmN0aW9uKCl7dGhpcy5lbmFibGVkPSF0aGlzLmVuYWJsZWR9LGMucHJvdG90eXBlLnRvZ2dsZT1mdW5jdGlvbihiKXt2YXIgYz10aGlzO2ImJihjPWEoYi5jdXJyZW50VGFyZ2V0KS5kYXRhKCJicy4iK3RoaXMudHlwZSksY3x8KGM9bmV3IHRoaXMuY29uc3RydWN0b3IoYi5jdXJyZW50VGFyZ2V0LHRoaXMuZ2V0RGVsZWdhdGVPcHRpb25zKCkpLGEoYi5jdXJyZW50VGFyZ2V0KS5kYXRhKCJicy4iK3RoaXMudHlwZSxjKSkpLGI/KGMuaW5TdGF0ZS5jbGljaz0hYy5pblN0YXRlLmNsaWNrLGMuaXNJblN0YXRlVHJ1ZSgpP2MuZW50ZXIoYyk6Yy5sZWF2ZShjKSk6Yy50aXAoKS5oYXNDbGFzcygiaW4iKT9jLmxlYXZlKGMpOmMuZW50ZXIoYyl9LGMucHJvdG90eXBlLmRlc3Ryb3k9ZnVuY3Rpb24oKXt2YXIgYT10aGlzO2NsZWFyVGltZW91dCh0aGlzLnRpbWVvdXQpLHRoaXMuaGlkZShmdW5jdGlvbigpe2EuJGVsZW1lbnQub2ZmKCIuIithLnR5cGUpLnJlbW92ZURhdGEoImJzLiIrYS50eXBlKSxhLiR0aXAmJmEuJHRpcC5kZXRhY2goKSxhLiR0aXA9bnVsbCxhLiRhcnJvdz1udWxsLGEuJHZpZXdwb3J0PW51bGx9KX07dmFyIGQ9YS5mbi50b29sdGlwO2EuZm4udG9vbHRpcD1iLGEuZm4udG9vbHRpcC5Db25zdHJ1Y3Rvcj1jLGEuZm4udG9vbHRpcC5ub0NvbmZsaWN0PWZ1bmN0aW9uKCl7cmV0dXJuIGEuZm4udG9vbHRpcD1kLHRoaXN9fShqUXVlcnkpLCtmdW5jdGlvbihhKXsidXNlIHN0cmljdCI7ZnVuY3Rpb24gYihiKXtyZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCl7dmFyIGQ9YSh0aGlzKSxlPWQuZGF0YSgiYnMucG9wb3ZlciIpLGY9Im9iamVjdCI9PXR5cGVvZiBiJiZiOyhlfHwhL2Rlc3Ryb3l8aGlkZS8udGVzdChiKSkmJihlfHxkLmRhdGEoImJzLnBvcG92ZXIiLGU9bmV3IGModGhpcyxmKSksInN0cmluZyI9PXR5cGVvZiBiJiZlW2JdKCkpfSl9dmFyIGM9ZnVuY3Rpb24oYSxiKXt0aGlzLmluaXQoInBvcG92ZXIiLGEsYil9O2lmKCFhLmZuLnRvb2x0aXApdGhyb3cgbmV3IEVycm9yKCJQb3BvdmVyIHJlcXVpcmVzIHRvb2x0aXAuanMiKTtjLlZFUlNJT049IjMuMy41IixjLkRFRkFVTFRTPWEuZXh0ZW5kKHt9LGEuZm4udG9vbHRpcC5Db25zdHJ1Y3Rvci5ERUZBVUxUUyx7cGxhY2VtZW50OiJyaWdodCIsdHJpZ2dlcjoiY2xpY2siLGNvbnRlbnQ6IiIsdGVtcGxhdGU6JzxkaXYgY2xhc3M9InBvcG92ZXIiIHJvbGU9InRvb2x0aXAiPjxkaXYgY2xhc3M9ImFycm93Ij48L2Rpdj48aDMgY2xhc3M9InBvcG92ZXItdGl0bGUiPjwvaDM+PGRpdiBjbGFzcz0icG9wb3Zlci1jb250ZW50Ij48L2Rpdj48L2Rpdj4nfSksYy5wcm90b3R5cGU9YS5leHRlbmQoe30sYS5mbi50b29sdGlwLkNvbnN0cnVjdG9yLnByb3RvdHlwZSksYy5wcm90b3R5cGUuY29uc3RydWN0b3I9YyxjLnByb3RvdHlwZS5nZXREZWZhdWx0cz1mdW5jdGlvbigpe3JldHVybiBjLkRFRkFVTFRTfSxjLnByb3RvdHlwZS5zZXRDb250ZW50PWZ1bmN0aW9uKCl7dmFyIGE9dGhpcy50aXAoKSxiPXRoaXMuZ2V0VGl0bGUoKSxjPXRoaXMuZ2V0Q29udGVudCgpO2EuZmluZCgiLnBvcG92ZXItdGl0bGUiKVt0aGlzLm9wdGlvbnMuaHRtbD8iaHRtbCI6InRleHQiXShiKSxhLmZpbmQoIi5wb3BvdmVyLWNvbnRlbnQiKS5jaGlsZHJlbigpLmRldGFjaCgpLmVuZCgpW3RoaXMub3B0aW9ucy5odG1sPyJzdHJpbmciPT10eXBlb2YgYz8iaHRtbCI6ImFwcGVuZCI6InRleHQiXShjKSxhLnJlbW92ZUNsYXNzKCJmYWRlIHRvcCBib3R0b20gbGVmdCByaWdodCBpbiIpLGEuZmluZCgiLnBvcG92ZXItdGl0bGUiKS5odG1sKCl8fGEuZmluZCgiLnBvcG92ZXItdGl0bGUiKS5oaWRlKCl9LGMucHJvdG90eXBlLmhhc0NvbnRlbnQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5nZXRUaXRsZSgpfHx0aGlzLmdldENvbnRlbnQoKX0sYy5wcm90b3R5cGUuZ2V0Q29udGVudD1mdW5jdGlvbigpe3ZhciBhPXRoaXMuJGVsZW1lbnQsYj10aGlzLm9wdGlvbnM7cmV0dXJuIGEuYXR0cigiZGF0YS1jb250ZW50Iil8fCgiZnVuY3Rpb24iPT10eXBlb2YgYi5jb250ZW50P2IuY29udGVudC5jYWxsKGFbMF0pOmIuY29udGVudCl9LGMucHJvdG90eXBlLmFycm93PWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuJGFycm93PXRoaXMuJGFycm93fHx0aGlzLnRpcCgpLmZpbmQoIi5hcnJvdyIpfTt2YXIgZD1hLmZuLnBvcG92ZXI7YS5mbi5wb3BvdmVyPWIsYS5mbi5wb3BvdmVyLkNvbnN0cnVjdG9yPWMsYS5mbi5wb3BvdmVyLm5vQ29uZmxpY3Q9ZnVuY3Rpb24oKXtyZXR1cm4gYS5mbi5wb3BvdmVyPWQsdGhpc319KGpRdWVyeSksK2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBiKGMsZCl7dGhpcy4kYm9keT1hKGRvY3VtZW50LmJvZHkpLHRoaXMuJHNjcm9sbEVsZW1lbnQ9YShhKGMpLmlzKGRvY3VtZW50LmJvZHkpP3dpbmRvdzpjKSx0aGlzLm9wdGlvbnM9YS5leHRlbmQoe30sYi5ERUZBVUxUUyxkKSx0aGlzLnNlbGVjdG9yPSh0aGlzLm9wdGlvbnMudGFyZ2V0fHwiIikrIiAubmF2IGxpID4gYSIsdGhpcy5vZmZzZXRzPVtdLHRoaXMudGFyZ2V0cz1bXSx0aGlzLmFjdGl2ZVRhcmdldD1udWxsLHRoaXMuc2Nyb2xsSGVpZ2h0PTAsdGhpcy4kc2Nyb2xsRWxlbWVudC5vbigic2Nyb2xsLmJzLnNjcm9sbHNweSIsYS5wcm94eSh0aGlzLnByb2Nlc3MsdGhpcykpLHRoaXMucmVmcmVzaCgpLHRoaXMucHJvY2VzcygpfWZ1bmN0aW9uIGMoYyl7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBkPWEodGhpcyksZT1kLmRhdGEoImJzLnNjcm9sbHNweSIpLGY9Im9iamVjdCI9PXR5cGVvZiBjJiZjO2V8fGQuZGF0YSgiYnMuc2Nyb2xsc3B5IixlPW5ldyBiKHRoaXMsZikpLCJzdHJpbmciPT10eXBlb2YgYyYmZVtjXSgpfSl9Yi5WRVJTSU9OPSIzLjMuNSIsYi5ERUZBVUxUUz17b2Zmc2V0OjEwfSxiLnByb3RvdHlwZS5nZXRTY3JvbGxIZWlnaHQ9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy4kc2Nyb2xsRWxlbWVudFswXS5zY3JvbGxIZWlnaHR8fE1hdGgubWF4KHRoaXMuJGJvZHlbMF0uc2Nyb2xsSGVpZ2h0LGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxIZWlnaHQpfSxiLnByb3RvdHlwZS5yZWZyZXNoPWZ1bmN0aW9uKCl7dmFyIGI9dGhpcyxjPSJvZmZzZXQiLGQ9MDt0aGlzLm9mZnNldHM9W10sdGhpcy50YXJnZXRzPVtdLHRoaXMuc2Nyb2xsSGVpZ2h0PXRoaXMuZ2V0U2Nyb2xsSGVpZ2h0KCksYS5pc1dpbmRvdyh0aGlzLiRzY3JvbGxFbGVtZW50WzBdKXx8KGM9InBvc2l0aW9uIixkPXRoaXMuJHNjcm9sbEVsZW1lbnQuc2Nyb2xsVG9wKCkpLHRoaXMuJGJvZHkuZmluZCh0aGlzLnNlbGVjdG9yKS5tYXAoZnVuY3Rpb24oKXt2YXIgYj1hKHRoaXMpLGU9Yi5kYXRhKCJ0YXJnZXQiKXx8Yi5hdHRyKCJocmVmIiksZj0vXiMuLy50ZXN0KGUpJiZhKGUpO3JldHVybiBmJiZmLmxlbmd0aCYmZi5pcygiOnZpc2libGUiKSYmW1tmW2NdKCkudG9wK2QsZV1dfHxudWxsfSkuc29ydChmdW5jdGlvbihhLGIpe3JldHVybiBhWzBdLWJbMF19KS5lYWNoKGZ1bmN0aW9uKCl7Yi5vZmZzZXRzLnB1c2godGhpc1swXSksYi50YXJnZXRzLnB1c2godGhpc1sxXSl9KX0sYi5wcm90b3R5cGUucHJvY2Vzcz1mdW5jdGlvbigpe3ZhciBhLGI9dGhpcy4kc2Nyb2xsRWxlbWVudC5zY3JvbGxUb3AoKSt0aGlzLm9wdGlvbnMub2Zmc2V0LGM9dGhpcy5nZXRTY3JvbGxIZWlnaHQoKSxkPXRoaXMub3B0aW9ucy5vZmZzZXQrYy10aGlzLiRzY3JvbGxFbGVtZW50LmhlaWdodCgpLGU9dGhpcy5vZmZzZXRzLGY9dGhpcy50YXJnZXRzLGc9dGhpcy5hY3RpdmVUYXJnZXQ7aWYodGhpcy5zY3JvbGxIZWlnaHQhPWMmJnRoaXMucmVmcmVzaCgpLGI+PWQpcmV0dXJuIGchPShhPWZbZi5sZW5ndGgtMV0pJiZ0aGlzLmFjdGl2YXRlKGEpO2lmKGcmJmI8ZVswXSlyZXR1cm4gdGhpcy5hY3RpdmVUYXJnZXQ9bnVsbCx0aGlzLmNsZWFyKCk7Zm9yKGE9ZS5sZW5ndGg7YS0tOylnIT1mW2FdJiZiPj1lW2FdJiYodm9pZCAwPT09ZVthKzFdfHxiPGVbYSsxXSkmJnRoaXMuYWN0aXZhdGUoZlthXSl9LGIucHJvdG90eXBlLmFjdGl2YXRlPWZ1bmN0aW9uKGIpe3RoaXMuYWN0aXZlVGFyZ2V0PWIsdGhpcy5jbGVhcigpO3ZhciBjPXRoaXMuc2VsZWN0b3IrJ1tkYXRhLXRhcmdldD0iJytiKyciXSwnK3RoaXMuc2VsZWN0b3IrJ1tocmVmPSInK2IrJyJdJyxkPWEoYykucGFyZW50cygibGkiKS5hZGRDbGFzcygiYWN0aXZlIik7ZC5wYXJlbnQoIi5kcm9wZG93bi1tZW51IikubGVuZ3RoJiYoZD1kLmNsb3Nlc3QoImxpLmRyb3Bkb3duIikuYWRkQ2xhc3MoImFjdGl2ZSIpKSwKZC50cmlnZ2VyKCJhY3RpdmF0ZS5icy5zY3JvbGxzcHkiKX0sYi5wcm90b3R5cGUuY2xlYXI9ZnVuY3Rpb24oKXthKHRoaXMuc2VsZWN0b3IpLnBhcmVudHNVbnRpbCh0aGlzLm9wdGlvbnMudGFyZ2V0LCIuYWN0aXZlIikucmVtb3ZlQ2xhc3MoImFjdGl2ZSIpfTt2YXIgZD1hLmZuLnNjcm9sbHNweTthLmZuLnNjcm9sbHNweT1jLGEuZm4uc2Nyb2xsc3B5LkNvbnN0cnVjdG9yPWIsYS5mbi5zY3JvbGxzcHkubm9Db25mbGljdD1mdW5jdGlvbigpe3JldHVybiBhLmZuLnNjcm9sbHNweT1kLHRoaXN9LGEod2luZG93KS5vbigibG9hZC5icy5zY3JvbGxzcHkuZGF0YS1hcGkiLGZ1bmN0aW9uKCl7YSgnW2RhdGEtc3B5PSJzY3JvbGwiXScpLmVhY2goZnVuY3Rpb24oKXt2YXIgYj1hKHRoaXMpO2MuY2FsbChiLGIuZGF0YSgpKX0pfSl9KGpRdWVyeSksK2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBiKGIpe3JldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKXt2YXIgZD1hKHRoaXMpLGU9ZC5kYXRhKCJicy50YWIiKTtlfHxkLmRhdGEoImJzLnRhYiIsZT1uZXcgYyh0aGlzKSksInN0cmluZyI9PXR5cGVvZiBiJiZlW2JdKCl9KX12YXIgYz1mdW5jdGlvbihiKXt0aGlzLmVsZW1lbnQ9YShiKX07Yy5WRVJTSU9OPSIzLjMuNSIsYy5UUkFOU0lUSU9OX0RVUkFUSU9OPTE1MCxjLnByb3RvdHlwZS5zaG93PWZ1bmN0aW9uKCl7dmFyIGI9dGhpcy5lbGVtZW50LGM9Yi5jbG9zZXN0KCJ1bDpub3QoLmRyb3Bkb3duLW1lbnUpIiksZD1iLmRhdGEoInRhcmdldCIpO2lmKGR8fChkPWIuYXR0cigiaHJlZiIpLGQ9ZCYmZC5yZXBsYWNlKC8uKig/PSNbXlxzXSokKS8sIiIpKSwhYi5wYXJlbnQoImxpIikuaGFzQ2xhc3MoImFjdGl2ZSIpKXt2YXIgZT1jLmZpbmQoIi5hY3RpdmU6bGFzdCBhIiksZj1hLkV2ZW50KCJoaWRlLmJzLnRhYiIse3JlbGF0ZWRUYXJnZXQ6YlswXX0pLGc9YS5FdmVudCgic2hvdy5icy50YWIiLHtyZWxhdGVkVGFyZ2V0OmVbMF19KTtpZihlLnRyaWdnZXIoZiksYi50cmlnZ2VyKGcpLCFnLmlzRGVmYXVsdFByZXZlbnRlZCgpJiYhZi5pc0RlZmF1bHRQcmV2ZW50ZWQoKSl7dmFyIGg9YShkKTt0aGlzLmFjdGl2YXRlKGIuY2xvc2VzdCgibGkiKSxjKSx0aGlzLmFjdGl2YXRlKGgsaC5wYXJlbnQoKSxmdW5jdGlvbigpe2UudHJpZ2dlcih7dHlwZToiaGlkZGVuLmJzLnRhYiIscmVsYXRlZFRhcmdldDpiWzBdfSksYi50cmlnZ2VyKHt0eXBlOiJzaG93bi5icy50YWIiLHJlbGF0ZWRUYXJnZXQ6ZVswXX0pfSl9fX0sYy5wcm90b3R5cGUuYWN0aXZhdGU9ZnVuY3Rpb24oYixkLGUpe2Z1bmN0aW9uIGYoKXtnLnJlbW92ZUNsYXNzKCJhY3RpdmUiKS5maW5kKCI+IC5kcm9wZG93bi1tZW51ID4gLmFjdGl2ZSIpLnJlbW92ZUNsYXNzKCJhY3RpdmUiKS5lbmQoKS5maW5kKCdbZGF0YS10b2dnbGU9InRhYiJdJykuYXR0cigiYXJpYS1leHBhbmRlZCIsITEpLGIuYWRkQ2xhc3MoImFjdGl2ZSIpLmZpbmQoJ1tkYXRhLXRvZ2dsZT0idGFiIl0nKS5hdHRyKCJhcmlhLWV4cGFuZGVkIiwhMCksaD8oYlswXS5vZmZzZXRXaWR0aCxiLmFkZENsYXNzKCJpbiIpKTpiLnJlbW92ZUNsYXNzKCJmYWRlIiksYi5wYXJlbnQoIi5kcm9wZG93bi1tZW51IikubGVuZ3RoJiZiLmNsb3Nlc3QoImxpLmRyb3Bkb3duIikuYWRkQ2xhc3MoImFjdGl2ZSIpLmVuZCgpLmZpbmQoJ1tkYXRhLXRvZ2dsZT0idGFiIl0nKS5hdHRyKCJhcmlhLWV4cGFuZGVkIiwhMCksZSYmZSgpfXZhciBnPWQuZmluZCgiPiAuYWN0aXZlIiksaD1lJiZhLnN1cHBvcnQudHJhbnNpdGlvbiYmKGcubGVuZ3RoJiZnLmhhc0NsYXNzKCJmYWRlIil8fCEhZC5maW5kKCI+IC5mYWRlIikubGVuZ3RoKTtnLmxlbmd0aCYmaD9nLm9uZSgiYnNUcmFuc2l0aW9uRW5kIixmKS5lbXVsYXRlVHJhbnNpdGlvbkVuZChjLlRSQU5TSVRJT05fRFVSQVRJT04pOmYoKSxnLnJlbW92ZUNsYXNzKCJpbiIpfTt2YXIgZD1hLmZuLnRhYjthLmZuLnRhYj1iLGEuZm4udGFiLkNvbnN0cnVjdG9yPWMsYS5mbi50YWIubm9Db25mbGljdD1mdW5jdGlvbigpe3JldHVybiBhLmZuLnRhYj1kLHRoaXN9O3ZhciBlPWZ1bmN0aW9uKGMpe2MucHJldmVudERlZmF1bHQoKSxiLmNhbGwoYSh0aGlzKSwic2hvdyIpfTthKGRvY3VtZW50KS5vbigiY2xpY2suYnMudGFiLmRhdGEtYXBpIiwnW2RhdGEtdG9nZ2xlPSJ0YWIiXScsZSkub24oImNsaWNrLmJzLnRhYi5kYXRhLWFwaSIsJ1tkYXRhLXRvZ2dsZT0icGlsbCJdJyxlKX0oalF1ZXJ5KSwrZnVuY3Rpb24oYSl7InVzZSBzdHJpY3QiO2Z1bmN0aW9uIGIoYil7cmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe3ZhciBkPWEodGhpcyksZT1kLmRhdGEoImJzLmFmZml4IiksZj0ib2JqZWN0Ij09dHlwZW9mIGImJmI7ZXx8ZC5kYXRhKCJicy5hZmZpeCIsZT1uZXcgYyh0aGlzLGYpKSwic3RyaW5nIj09dHlwZW9mIGImJmVbYl0oKX0pfXZhciBjPWZ1bmN0aW9uKGIsZCl7dGhpcy5vcHRpb25zPWEuZXh0ZW5kKHt9LGMuREVGQVVMVFMsZCksdGhpcy4kdGFyZ2V0PWEodGhpcy5vcHRpb25zLnRhcmdldCkub24oInNjcm9sbC5icy5hZmZpeC5kYXRhLWFwaSIsYS5wcm94eSh0aGlzLmNoZWNrUG9zaXRpb24sdGhpcykpLm9uKCJjbGljay5icy5hZmZpeC5kYXRhLWFwaSIsYS5wcm94eSh0aGlzLmNoZWNrUG9zaXRpb25XaXRoRXZlbnRMb29wLHRoaXMpKSx0aGlzLiRlbGVtZW50PWEoYiksdGhpcy5hZmZpeGVkPW51bGwsdGhpcy51bnBpbj1udWxsLHRoaXMucGlubmVkT2Zmc2V0PW51bGwsdGhpcy5jaGVja1Bvc2l0aW9uKCl9O2MuVkVSU0lPTj0iMy4zLjUiLGMuUkVTRVQ9ImFmZml4IGFmZml4LXRvcCBhZmZpeC1ib3R0b20iLGMuREVGQVVMVFM9e29mZnNldDowLHRhcmdldDp3aW5kb3d9LGMucHJvdG90eXBlLmdldFN0YXRlPWZ1bmN0aW9uKGEsYixjLGQpe3ZhciBlPXRoaXMuJHRhcmdldC5zY3JvbGxUb3AoKSxmPXRoaXMuJGVsZW1lbnQub2Zmc2V0KCksZz10aGlzLiR0YXJnZXQuaGVpZ2h0KCk7aWYobnVsbCE9YyYmInRvcCI9PXRoaXMuYWZmaXhlZClyZXR1cm4gYz5lPyJ0b3AiOiExO2lmKCJib3R0b20iPT10aGlzLmFmZml4ZWQpcmV0dXJuIG51bGwhPWM/ZSt0aGlzLnVucGluPD1mLnRvcD8hMToiYm90dG9tIjphLWQ+PWUrZz8hMToiYm90dG9tIjt2YXIgaD1udWxsPT10aGlzLmFmZml4ZWQsaT1oP2U6Zi50b3Asaj1oP2c6YjtyZXR1cm4gbnVsbCE9YyYmYz49ZT8idG9wIjpudWxsIT1kJiZpK2o+PWEtZD8iYm90dG9tIjohMX0sYy5wcm90b3R5cGUuZ2V0UGlubmVkT2Zmc2V0PWZ1bmN0aW9uKCl7aWYodGhpcy5waW5uZWRPZmZzZXQpcmV0dXJuIHRoaXMucGlubmVkT2Zmc2V0O3RoaXMuJGVsZW1lbnQucmVtb3ZlQ2xhc3MoYy5SRVNFVCkuYWRkQ2xhc3MoImFmZml4Iik7dmFyIGE9dGhpcy4kdGFyZ2V0LnNjcm9sbFRvcCgpLGI9dGhpcy4kZWxlbWVudC5vZmZzZXQoKTtyZXR1cm4gdGhpcy5waW5uZWRPZmZzZXQ9Yi50b3AtYX0sYy5wcm90b3R5cGUuY2hlY2tQb3NpdGlvbldpdGhFdmVudExvb3A9ZnVuY3Rpb24oKXtzZXRUaW1lb3V0KGEucHJveHkodGhpcy5jaGVja1Bvc2l0aW9uLHRoaXMpLDEpfSxjLnByb3RvdHlwZS5jaGVja1Bvc2l0aW9uPWZ1bmN0aW9uKCl7aWYodGhpcy4kZWxlbWVudC5pcygiOnZpc2libGUiKSl7dmFyIGI9dGhpcy4kZWxlbWVudC5oZWlnaHQoKSxkPXRoaXMub3B0aW9ucy5vZmZzZXQsZT1kLnRvcCxmPWQuYm90dG9tLGc9TWF0aC5tYXgoYShkb2N1bWVudCkuaGVpZ2h0KCksYShkb2N1bWVudC5ib2R5KS5oZWlnaHQoKSk7Im9iamVjdCIhPXR5cGVvZiBkJiYoZj1lPWQpLCJmdW5jdGlvbiI9PXR5cGVvZiBlJiYoZT1kLnRvcCh0aGlzLiRlbGVtZW50KSksImZ1bmN0aW9uIj09dHlwZW9mIGYmJihmPWQuYm90dG9tKHRoaXMuJGVsZW1lbnQpKTt2YXIgaD10aGlzLmdldFN0YXRlKGcsYixlLGYpO2lmKHRoaXMuYWZmaXhlZCE9aCl7bnVsbCE9dGhpcy51bnBpbiYmdGhpcy4kZWxlbWVudC5jc3MoInRvcCIsIiIpO3ZhciBpPSJhZmZpeCIrKGg/Ii0iK2g6IiIpLGo9YS5FdmVudChpKyIuYnMuYWZmaXgiKTtpZih0aGlzLiRlbGVtZW50LnRyaWdnZXIoaiksai5pc0RlZmF1bHRQcmV2ZW50ZWQoKSlyZXR1cm47dGhpcy5hZmZpeGVkPWgsdGhpcy51bnBpbj0iYm90dG9tIj09aD90aGlzLmdldFBpbm5lZE9mZnNldCgpOm51bGwsdGhpcy4kZWxlbWVudC5yZW1vdmVDbGFzcyhjLlJFU0VUKS5hZGRDbGFzcyhpKS50cmlnZ2VyKGkucmVwbGFjZSgiYWZmaXgiLCJhZmZpeGVkIikrIi5icy5hZmZpeCIpfSJib3R0b20iPT1oJiZ0aGlzLiRlbGVtZW50Lm9mZnNldCh7dG9wOmctYi1mfSl9fTt2YXIgZD1hLmZuLmFmZml4O2EuZm4uYWZmaXg9YixhLmZuLmFmZml4LkNvbnN0cnVjdG9yPWMsYS5mbi5hZmZpeC5ub0NvbmZsaWN0PWZ1bmN0aW9uKCl7cmV0dXJuIGEuZm4uYWZmaXg9ZCx0aGlzfSxhKHdpbmRvdykub24oImxvYWQiLGZ1bmN0aW9uKCl7YSgnW2RhdGEtc3B5PSJhZmZpeCJdJykuZWFjaChmdW5jdGlvbigpe3ZhciBjPWEodGhpcyksZD1jLmRhdGEoKTtkLm9mZnNldD1kLm9mZnNldHx8e30sbnVsbCE9ZC5vZmZzZXRCb3R0b20mJihkLm9mZnNldC5ib3R0b209ZC5vZmZzZXRCb3R0b20pLG51bGwhPWQub2Zmc2V0VG9wJiYoZC5vZmZzZXQudG9wPWQub2Zmc2V0VG9wKSxiLmNhbGwoYyxkKX0pfSl9KGpRdWVyeSk7"></script>
<script src="data:application/x-javascript;base64,LyoqCiogQHByZXNlcnZlIEhUTUw1IFNoaXYgMy43LjIgfCBAYWZhcmthcyBAamRhbHRvbiBAam9uX25lYWwgQHJlbSB8IE1JVC9HUEwyIExpY2Vuc2VkCiovCi8vIE9ubHkgcnVuIHRoaXMgY29kZSBpbiBJRSA4CmlmICghIXdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKCJNU0lFIDgiKSkgewohZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7dmFyIGM9YS5jcmVhdGVFbGVtZW50KCJwIiksZD1hLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF18fGEuZG9jdW1lbnRFbGVtZW50O3JldHVybiBjLmlubmVySFRNTD0ieDxzdHlsZT4iK2IrIjwvc3R5bGU+IixkLmluc2VydEJlZm9yZShjLmxhc3RDaGlsZCxkLmZpcnN0Q2hpbGQpfWZ1bmN0aW9uIGQoKXt2YXIgYT10LmVsZW1lbnRzO3JldHVybiJzdHJpbmciPT10eXBlb2YgYT9hLnNwbGl0KCIgIik6YX1mdW5jdGlvbiBlKGEsYil7dmFyIGM9dC5lbGVtZW50czsic3RyaW5nIiE9dHlwZW9mIGMmJihjPWMuam9pbigiICIpKSwic3RyaW5nIiE9dHlwZW9mIGEmJihhPWEuam9pbigiICIpKSx0LmVsZW1lbnRzPWMrIiAiK2EsaihiKX1mdW5jdGlvbiBmKGEpe3ZhciBiPXNbYVtxXV07cmV0dXJuIGJ8fChiPXt9LHIrKyxhW3FdPXIsc1tyXT1iKSxifWZ1bmN0aW9uIGcoYSxjLGQpe2lmKGN8fChjPWIpLGwpcmV0dXJuIGMuY3JlYXRlRWxlbWVudChhKTtkfHwoZD1mKGMpKTt2YXIgZTtyZXR1cm4gZT1kLmNhY2hlW2FdP2QuY2FjaGVbYV0uY2xvbmVOb2RlKCk6cC50ZXN0KGEpPyhkLmNhY2hlW2FdPWQuY3JlYXRlRWxlbShhKSkuY2xvbmVOb2RlKCk6ZC5jcmVhdGVFbGVtKGEpLCFlLmNhbkhhdmVDaGlsZHJlbnx8by50ZXN0KGEpfHxlLnRhZ1Vybj9lOmQuZnJhZy5hcHBlbmRDaGlsZChlKX1mdW5jdGlvbiBoKGEsYyl7aWYoYXx8KGE9YiksbClyZXR1cm4gYS5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7Yz1jfHxmKGEpO2Zvcih2YXIgZT1jLmZyYWcuY2xvbmVOb2RlKCksZz0wLGg9ZCgpLGk9aC5sZW5ndGg7aT5nO2crKyllLmNyZWF0ZUVsZW1lbnQoaFtnXSk7cmV0dXJuIGV9ZnVuY3Rpb24gaShhLGIpe2IuY2FjaGV8fChiLmNhY2hlPXt9LGIuY3JlYXRlRWxlbT1hLmNyZWF0ZUVsZW1lbnQsYi5jcmVhdGVGcmFnPWEuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCxiLmZyYWc9Yi5jcmVhdGVGcmFnKCkpLGEuY3JlYXRlRWxlbWVudD1mdW5jdGlvbihjKXtyZXR1cm4gdC5zaGl2TWV0aG9kcz9nKGMsYSxiKTpiLmNyZWF0ZUVsZW0oYyl9LGEuY3JlYXRlRG9jdW1lbnRGcmFnbWVudD1GdW5jdGlvbigiaCxmIiwicmV0dXJuIGZ1bmN0aW9uKCl7dmFyIG49Zi5jbG9uZU5vZGUoKSxjPW4uY3JlYXRlRWxlbWVudDtoLnNoaXZNZXRob2RzJiYoIitkKCkuam9pbigpLnJlcGxhY2UoL1tcd1wtOl0rL2csZnVuY3Rpb24oYSl7cmV0dXJuIGIuY3JlYXRlRWxlbShhKSxiLmZyYWcuY3JlYXRlRWxlbWVudChhKSwnYygiJythKyciKSd9KSsiKTtyZXR1cm4gbn0iKSh0LGIuZnJhZyl9ZnVuY3Rpb24gaihhKXthfHwoYT1iKTt2YXIgZD1mKGEpO3JldHVybiF0LnNoaXZDU1N8fGt8fGQuaGFzQ1NTfHwoZC5oYXNDU1M9ISFjKGEsImFydGljbGUsYXNpZGUsZGlhbG9nLGZpZ2NhcHRpb24sZmlndXJlLGZvb3RlcixoZWFkZXIsaGdyb3VwLG1haW4sbmF2LHNlY3Rpb257ZGlzcGxheTpibG9ja31tYXJre2JhY2tncm91bmQ6I0ZGMDtjb2xvcjojMDAwfXRlbXBsYXRle2Rpc3BsYXk6bm9uZX0iKSksbHx8aShhLGQpLGF9dmFyIGssbCxtPSIzLjcuMiIsbj1hLmh0bWw1fHx7fSxvPS9ePHxeKD86YnV0dG9ufG1hcHxzZWxlY3R8dGV4dGFyZWF8b2JqZWN0fGlmcmFtZXxvcHRpb258b3B0Z3JvdXApJC9pLHA9L14oPzphfGJ8Y29kZXxkaXZ8ZmllbGRzZXR8aDF8aDJ8aDN8aDR8aDV8aDZ8aXxsYWJlbHxsaXxvbHxwfHF8c3BhbnxzdHJvbmd8c3R5bGV8dGFibGV8dGJvZHl8dGR8dGh8dHJ8dWwpJC9pLHE9Il9odG1sNXNoaXYiLHI9MCxzPXt9OyFmdW5jdGlvbigpe3RyeXt2YXIgYT1iLmNyZWF0ZUVsZW1lbnQoImEiKTthLmlubmVySFRNTD0iPHh5ej48L3h5ej4iLGs9ImhpZGRlbiJpbiBhLGw9MT09YS5jaGlsZE5vZGVzLmxlbmd0aHx8ZnVuY3Rpb24oKXtiLmNyZWF0ZUVsZW1lbnQoImEiKTt2YXIgYT1iLmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtyZXR1cm4idW5kZWZpbmVkIj09dHlwZW9mIGEuY2xvbmVOb2RlfHwidW5kZWZpbmVkIj09dHlwZW9mIGEuY3JlYXRlRG9jdW1lbnRGcmFnbWVudHx8InVuZGVmaW5lZCI9PXR5cGVvZiBhLmNyZWF0ZUVsZW1lbnR9KCl9Y2F0Y2goYyl7az0hMCxsPSEwfX0oKTt2YXIgdD17ZWxlbWVudHM6bi5lbGVtZW50c3x8ImFiYnIgYXJ0aWNsZSBhc2lkZSBhdWRpbyBiZGkgY2FudmFzIGRhdGEgZGF0YWxpc3QgZGV0YWlscyBkaWFsb2cgZmlnY2FwdGlvbiBmaWd1cmUgZm9vdGVyIGhlYWRlciBoZ3JvdXAgbWFpbiBtYXJrIG1ldGVyIG5hdiBvdXRwdXQgcGljdHVyZSBwcm9ncmVzcyBzZWN0aW9uIHN1bW1hcnkgdGVtcGxhdGUgdGltZSB2aWRlbyIsdmVyc2lvbjptLHNoaXZDU1M6bi5zaGl2Q1NTIT09ITEsc3VwcG9ydHNVbmtub3duRWxlbWVudHM6bCxzaGl2TWV0aG9kczpuLnNoaXZNZXRob2RzIT09ITEsdHlwZToiZGVmYXVsdCIsc2hpdkRvY3VtZW50OmosY3JlYXRlRWxlbWVudDpnLGNyZWF0ZURvY3VtZW50RnJhZ21lbnQ6aCxhZGRFbGVtZW50czplfTthLmh0bWw1PXQsaihiKX0odGhpcyxkb2N1bWVudCk7Cn07Cg=="></script>
<script src="data:application/x-javascript;base64,LyohIFJlc3BvbmQuanMgdjEuNC4yOiBtaW4vbWF4LXdpZHRoIG1lZGlhIHF1ZXJ5IHBvbHlmaWxsICogQ29weXJpZ2h0IDIwMTMgU2NvdHQgSmVobAogKiBMaWNlbnNlZCB1bmRlciBodHRwczovL2dpdGh1Yi5jb20vc2NvdHRqZWhsL1Jlc3BvbmQvYmxvYi9tYXN0ZXIvTElDRU5TRS1NSVQKICogICovCgovLyBPbmx5IHJ1biB0aGlzIGNvZGUgaW4gSUUgOAppZiAoISF3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgiTVNJRSA4IikpIHsKIWZ1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjthLm1hdGNoTWVkaWE9YS5tYXRjaE1lZGlhfHxmdW5jdGlvbihhKXt2YXIgYixjPWEuZG9jdW1lbnRFbGVtZW50LGQ9Yy5maXJzdEVsZW1lbnRDaGlsZHx8Yy5maXJzdENoaWxkLGU9YS5jcmVhdGVFbGVtZW50KCJib2R5IiksZj1hLmNyZWF0ZUVsZW1lbnQoImRpdiIpO3JldHVybiBmLmlkPSJtcS10ZXN0LTEiLGYuc3R5bGUuY3NzVGV4dD0icG9zaXRpb246YWJzb2x1dGU7dG9wOi0xMDBlbSIsZS5zdHlsZS5iYWNrZ3JvdW5kPSJub25lIixlLmFwcGVuZENoaWxkKGYpLGZ1bmN0aW9uKGEpe3JldHVybiBmLmlubmVySFRNTD0nJnNoeTs8c3R5bGUgbWVkaWE9IicrYSsnIj4gI21xLXRlc3QtMSB7IHdpZHRoOiA0MnB4OyB9PC9zdHlsZT4nLGMuaW5zZXJ0QmVmb3JlKGUsZCksYj00Mj09PWYub2Zmc2V0V2lkdGgsYy5yZW1vdmVDaGlsZChlKSx7bWF0Y2hlczpiLG1lZGlhOmF9fX0oYS5kb2N1bWVudCl9KHRoaXMpLGZ1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjtmdW5jdGlvbiBiKCl7dSghMCl9dmFyIGM9e307YS5yZXNwb25kPWMsYy51cGRhdGU9ZnVuY3Rpb24oKXt9O3ZhciBkPVtdLGU9ZnVuY3Rpb24oKXt2YXIgYj0hMTt0cnl7Yj1uZXcgYS5YTUxIdHRwUmVxdWVzdH1jYXRjaChjKXtiPW5ldyBhLkFjdGl2ZVhPYmplY3QoIk1pY3Jvc29mdC5YTUxIVFRQIil9cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGJ9fSgpLGY9ZnVuY3Rpb24oYSxiKXt2YXIgYz1lKCk7YyYmKGMub3BlbigiR0VUIixhLCEwKSxjLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpezQhPT1jLnJlYWR5U3RhdGV8fDIwMCE9PWMuc3RhdHVzJiYzMDQhPT1jLnN0YXR1c3x8YihjLnJlc3BvbnNlVGV4dCl9LDQhPT1jLnJlYWR5U3RhdGUmJmMuc2VuZChudWxsKSl9O2lmKGMuYWpheD1mLGMucXVldWU9ZCxjLnJlZ2V4PXttZWRpYTovQG1lZGlhW15ce10rXHsoW15ce1x9XSpce1teXH1ce10qXH0pKy9naSxrZXlmcmFtZXM6L0AoPzpcLSg/Om98bW96fHdlYmtpdClcLSk/a2V5ZnJhbWVzW15ce10rXHsoPzpbXlx7XH1dKlx7W15cfVx7XSpcfSkrW15cfV0qXH0vZ2ksdXJsczovKHVybFwoKVsnIl0/KFteXC9cKSciXVteOlwpJyJdKylbJyJdPyhcKSkvZyxmaW5kU3R5bGVzOi9AbWVkaWEgKihbXlx7XSspXHsoW1xTXHNdKz8pJC8sb25seTovKG9ubHlccyspPyhbYS16QS1aXSspXHM/LyxtaW53Oi9cKFtcc10qbWluXC13aWR0aFxzKjpbXHNdKihbXHNdKlswLTlcLl0rKShweHxlbSlbXHNdKlwpLyxtYXh3Oi9cKFtcc10qbWF4XC13aWR0aFxzKjpbXHNdKihbXHNdKlswLTlcLl0rKShweHxlbSlbXHNdKlwpL30sYy5tZWRpYVF1ZXJpZXNTdXBwb3J0ZWQ9YS5tYXRjaE1lZGlhJiZudWxsIT09YS5tYXRjaE1lZGlhKCJvbmx5IGFsbCIpJiZhLm1hdGNoTWVkaWEoIm9ubHkgYWxsIikubWF0Y2hlcywhYy5tZWRpYVF1ZXJpZXNTdXBwb3J0ZWQpe3ZhciBnLGgsaSxqPWEuZG9jdW1lbnQsaz1qLmRvY3VtZW50RWxlbWVudCxsPVtdLG09W10sbj1bXSxvPXt9LHA9MzAscT1qLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF18fGsscj1qLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJiYXNlIilbMF0scz1xLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJsaW5rIiksdD1mdW5jdGlvbigpe3ZhciBhLGI9ai5jcmVhdGVFbGVtZW50KCJkaXYiKSxjPWouYm9keSxkPWsuc3R5bGUuZm9udFNpemUsZT1jJiZjLnN0eWxlLmZvbnRTaXplLGY9ITE7cmV0dXJuIGIuc3R5bGUuY3NzVGV4dD0icG9zaXRpb246YWJzb2x1dGU7Zm9udC1zaXplOjFlbTt3aWR0aDoxZW0iLGN8fChjPWY9ai5jcmVhdGVFbGVtZW50KCJib2R5IiksYy5zdHlsZS5iYWNrZ3JvdW5kPSJub25lIiksay5zdHlsZS5mb250U2l6ZT0iMTAwJSIsYy5zdHlsZS5mb250U2l6ZT0iMTAwJSIsYy5hcHBlbmRDaGlsZChiKSxmJiZrLmluc2VydEJlZm9yZShjLGsuZmlyc3RDaGlsZCksYT1iLm9mZnNldFdpZHRoLGY/ay5yZW1vdmVDaGlsZChjKTpjLnJlbW92ZUNoaWxkKGIpLGsuc3R5bGUuZm9udFNpemU9ZCxlJiYoYy5zdHlsZS5mb250U2l6ZT1lKSxhPWk9cGFyc2VGbG9hdChhKX0sdT1mdW5jdGlvbihiKXt2YXIgYz0iY2xpZW50V2lkdGgiLGQ9a1tjXSxlPSJDU1MxQ29tcGF0Ij09PWouY29tcGF0TW9kZSYmZHx8ai5ib2R5W2NdfHxkLGY9e30sbz1zW3MubGVuZ3RoLTFdLHI9KG5ldyBEYXRlKS5nZXRUaW1lKCk7aWYoYiYmZyYmcD5yLWcpcmV0dXJuIGEuY2xlYXJUaW1lb3V0KGgpLGg9YS5zZXRUaW1lb3V0KHUscCksdm9pZCAwO2c9cjtmb3IodmFyIHYgaW4gbClpZihsLmhhc093blByb3BlcnR5KHYpKXt2YXIgdz1sW3ZdLHg9dy5taW53LHk9dy5tYXh3LHo9bnVsbD09PXgsQT1udWxsPT09eSxCPSJlbSI7eCYmKHg9cGFyc2VGbG9hdCh4KSooeC5pbmRleE9mKEIpPi0xP2l8fHQoKToxKSkseSYmKHk9cGFyc2VGbG9hdCh5KSooeS5pbmRleE9mKEIpPi0xP2l8fHQoKToxKSksdy5oYXNxdWVyeSYmKHomJkF8fCEoenx8ZT49eCl8fCEoQXx8eT49ZSkpfHwoZlt3Lm1lZGlhXXx8KGZbdy5tZWRpYV09W10pLGZbdy5tZWRpYV0ucHVzaChtW3cucnVsZXNdKSl9Zm9yKHZhciBDIGluIG4pbi5oYXNPd25Qcm9wZXJ0eShDKSYmbltDXSYmbltDXS5wYXJlbnROb2RlPT09cSYmcS5yZW1vdmVDaGlsZChuW0NdKTtuLmxlbmd0aD0wO2Zvcih2YXIgRCBpbiBmKWlmKGYuaGFzT3duUHJvcGVydHkoRCkpe3ZhciBFPWouY3JlYXRlRWxlbWVudCgic3R5bGUiKSxGPWZbRF0uam9pbigiXG4iKTtFLnR5cGU9InRleHQvY3NzIixFLm1lZGlhPUQscS5pbnNlcnRCZWZvcmUoRSxvLm5leHRTaWJsaW5nKSxFLnN0eWxlU2hlZXQ/RS5zdHlsZVNoZWV0LmNzc1RleHQ9RjpFLmFwcGVuZENoaWxkKGouY3JlYXRlVGV4dE5vZGUoRikpLG4ucHVzaChFKX19LHY9ZnVuY3Rpb24oYSxiLGQpe3ZhciBlPWEucmVwbGFjZShjLnJlZ2V4LmtleWZyYW1lcywiIikubWF0Y2goYy5yZWdleC5tZWRpYSksZj1lJiZlLmxlbmd0aHx8MDtiPWIuc3Vic3RyaW5nKDAsYi5sYXN0SW5kZXhPZigiLyIpKTt2YXIgZz1mdW5jdGlvbihhKXtyZXR1cm4gYS5yZXBsYWNlKGMucmVnZXgudXJscywiJDEiK2IrIiQyJDMiKX0saD0hZiYmZDtiLmxlbmd0aCYmKGIrPSIvIiksaCYmKGY9MSk7Zm9yKHZhciBpPTA7Zj5pO2krKyl7dmFyIGosayxuLG87aD8oaj1kLG0ucHVzaChnKGEpKSk6KGo9ZVtpXS5tYXRjaChjLnJlZ2V4LmZpbmRTdHlsZXMpJiZSZWdFeHAuJDEsbS5wdXNoKFJlZ0V4cC4kMiYmZyhSZWdFeHAuJDIpKSksbj1qLnNwbGl0KCIsIiksbz1uLmxlbmd0aDtmb3IodmFyIHA9MDtvPnA7cCsrKWs9bltwXSxsLnB1c2goe21lZGlhOmsuc3BsaXQoIigiKVswXS5tYXRjaChjLnJlZ2V4Lm9ubHkpJiZSZWdFeHAuJDJ8fCJhbGwiLHJ1bGVzOm0ubGVuZ3RoLTEsaGFzcXVlcnk6ay5pbmRleE9mKCIoIik+LTEsbWludzprLm1hdGNoKGMucmVnZXgubWludykmJnBhcnNlRmxvYXQoUmVnRXhwLiQxKSsoUmVnRXhwLiQyfHwiIiksbWF4dzprLm1hdGNoKGMucmVnZXgubWF4dykmJnBhcnNlRmxvYXQoUmVnRXhwLiQxKSsoUmVnRXhwLiQyfHwiIil9KX11KCl9LHc9ZnVuY3Rpb24oKXtpZihkLmxlbmd0aCl7dmFyIGI9ZC5zaGlmdCgpO2YoYi5ocmVmLGZ1bmN0aW9uKGMpe3YoYyxiLmhyZWYsYi5tZWRpYSksb1tiLmhyZWZdPSEwLGEuc2V0VGltZW91dChmdW5jdGlvbigpe3coKX0sMCl9KX19LHg9ZnVuY3Rpb24oKXtmb3IodmFyIGI9MDtiPHMubGVuZ3RoO2IrKyl7dmFyIGM9c1tiXSxlPWMuaHJlZixmPWMubWVkaWEsZz1jLnJlbCYmInN0eWxlc2hlZXQiPT09Yy5yZWwudG9Mb3dlckNhc2UoKTtlJiZnJiYhb1tlXSYmKGMuc3R5bGVTaGVldCYmYy5zdHlsZVNoZWV0LnJhd0Nzc1RleHQ/KHYoYy5zdHlsZVNoZWV0LnJhd0Nzc1RleHQsZSxmKSxvW2VdPSEwKTooIS9eKFthLXpBLVo6XSpcL1wvKS8udGVzdChlKSYmIXJ8fGUucmVwbGFjZShSZWdFeHAuJDEsIiIpLnNwbGl0KCIvIilbMF09PT1hLmxvY2F0aW9uLmhvc3QpJiYoIi8vIj09PWUuc3Vic3RyaW5nKDAsMikmJihlPWEubG9jYXRpb24ucHJvdG9jb2wrZSksZC5wdXNoKHtocmVmOmUsbWVkaWE6Zn0pKSl9dygpfTt4KCksYy51cGRhdGU9eCxjLmdldEVtVmFsdWU9dCxhLmFkZEV2ZW50TGlzdGVuZXI/YS5hZGRFdmVudExpc3RlbmVyKCJyZXNpemUiLGIsITEpOmEuYXR0YWNoRXZlbnQmJmEuYXR0YWNoRXZlbnQoIm9ucmVzaXplIixiKX19KHRoaXMpOwp9Owo="></script>
<script src="data:application/x-javascript;base64,Cgp3aW5kb3cuYnVpbGRUYWJzZXRzID0gZnVuY3Rpb24odG9jSUQpIHsKCiAgLy8gYnVpbGQgYSB0YWJzZXQgZnJvbSBhIHNlY3Rpb24gZGl2IHdpdGggdGhlIC50YWJzZXQgY2xhc3MKICBmdW5jdGlvbiBidWlsZFRhYnNldCh0YWJzZXQpIHsKCiAgICAvLyBjaGVjayBmb3IgZmFkZSBhbmQgcGlsbHMgb3B0aW9ucwogICAgdmFyIGZhZGUgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1mYWRlIik7CiAgICB2YXIgcGlsbHMgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1waWxscyIpOwogICAgdmFyIG5hdkNsYXNzID0gcGlsbHMgPyAibmF2LXBpbGxzIiA6ICJuYXYtdGFicyI7CgogICAgLy8gZGV0ZXJtaW5lIHRoZSBoZWFkaW5nIGxldmVsIG9mIHRoZSB0YWJzZXQgYW5kIHRhYnMKICAgIHZhciBtYXRjaCA9IHRhYnNldC5hdHRyKCdjbGFzcycpLm1hdGNoKC9sZXZlbChcZCkgLyk7CiAgICBpZiAobWF0Y2ggPT09IG51bGwpCiAgICAgIHJldHVybjsKICAgIHZhciB0YWJzZXRMZXZlbCA9IE51bWJlcihtYXRjaFsxXSk7CiAgICB2YXIgdGFiTGV2ZWwgPSB0YWJzZXRMZXZlbCArIDE7CgogICAgLy8gZmluZCBhbGwgc3ViaGVhZGluZ3MgaW1tZWRpYXRlbHkgYmVsb3cKICAgIHZhciB0YWJzID0gdGFic2V0LmZpbmQoImRpdi5zZWN0aW9uLmxldmVsIiArIHRhYkxldmVsKTsKICAgIGlmICghdGFicy5sZW5ndGgpCiAgICAgIHJldHVybjsKCiAgICAvLyBjcmVhdGUgdGFibGlzdCBhbmQgdGFiLWNvbnRlbnQgZWxlbWVudHMKICAgIHZhciB0YWJMaXN0ID0gJCgnPHVsIGNsYXNzPSJuYXYgJyArIG5hdkNsYXNzICsgJyIgcm9sZT0idGFibGlzdCI+PC91bD4nKTsKICAgICQodGFic1swXSkuYmVmb3JlKHRhYkxpc3QpOwogICAgdmFyIHRhYkNvbnRlbnQgPSAkKCc8ZGl2IGNsYXNzPSJ0YWItY29udGVudCI+PC9kaXY+Jyk7CiAgICAkKHRhYnNbMF0pLmJlZm9yZSh0YWJDb250ZW50KTsKCiAgICAvLyBidWlsZCB0aGUgdGFic2V0CiAgICB2YXIgYWN0aXZlVGFiID0gMDsKICAgIHRhYnMuZWFjaChmdW5jdGlvbihpKSB7CgogICAgICAvLyBnZXQgdGhlIHRhYiBkaXYKICAgICAgdmFyIHRhYiA9ICQodGFic1tpXSk7CgogICAgICAvLyBnZXQgdGhlIGlkIHRoZW4gc2FuaXRpemUgaXQgZm9yIHVzZSB3aXRoIGJvb3RzdHJhcCB0YWJzCiAgICAgIHZhciBpZCA9IHRhYi5hdHRyKCdpZCcpOwoKICAgICAgLy8gc2VlIGlmIHRoaXMgaXMgbWFya2VkIGFzIHRoZSBhY3RpdmUgdGFiCiAgICAgIGlmICh0YWIuaGFzQ2xhc3MoJ2FjdGl2ZScpKQogICAgICAgIGFjdGl2ZVRhYiA9IGk7CgogICAgICAvLyByZW1vdmUgYW55IHRhYmxlIG9mIGNvbnRlbnRzIGVudHJpZXMgYXNzb2NpYXRlZCB3aXRoCiAgICAgIC8vIHRoaXMgSUQgKHNpbmNlIHdlJ2xsIGJlIHJlbW92aW5nIHRoZSBoZWFkaW5nIGVsZW1lbnQpCiAgICAgICQoImRpdiMiICsgdG9jSUQgKyAiIGxpIGFbaHJlZj0nIyIgKyBpZCArICInXSIpLnBhcmVudCgpLnJlbW92ZSgpOwoKICAgICAgLy8gc2FuaXRpemUgdGhlIGlkIGZvciB1c2Ugd2l0aCBib290c3RyYXAgdGFicwogICAgICBpZCA9IGlkLnJlcGxhY2UoL1suXC8/JiEjPD5dL2csICcnKS5yZXBsYWNlKC9ccy9nLCAnXycpOwogICAgICB0YWIuYXR0cignaWQnLCBpZCk7CgogICAgICAvLyBnZXQgdGhlIGhlYWRpbmcgZWxlbWVudCB3aXRoaW4gaXQsIGdyYWIgaXQncyB0ZXh0LCB0aGVuIHJlbW92ZSBpdAogICAgICB2YXIgaGVhZGluZyA9IHRhYi5maW5kKCdoJyArIHRhYkxldmVsICsgJzpmaXJzdCcpOwogICAgICB2YXIgaGVhZGluZ1RleHQgPSBoZWFkaW5nLmh0bWwoKTsKICAgICAgaGVhZGluZy5yZW1vdmUoKTsKCiAgICAgIC8vIGJ1aWxkIGFuZCBhcHBlbmQgdGhlIHRhYiBsaXN0IGl0ZW0KICAgICAgdmFyIGEgPSAkKCc8YSByb2xlPSJ0YWIiIGRhdGEtdG9nZ2xlPSJ0YWIiPicgKyBoZWFkaW5nVGV4dCArICc8L2E+Jyk7CiAgICAgIGEuYXR0cignaHJlZicsICcjJyArIGlkKTsKICAgICAgYS5hdHRyKCdhcmlhLWNvbnRyb2xzJywgaWQpOwogICAgICB2YXIgbGkgPSAkKCc8bGkgcm9sZT0icHJlc2VudGF0aW9uIj48L2xpPicpOwogICAgICBsaS5hcHBlbmQoYSk7CiAgICAgIHRhYkxpc3QuYXBwZW5kKGxpKTsKCiAgICAgIC8vIHNldCBpdCdzIGF0dHJpYnV0ZXMKICAgICAgdGFiLmF0dHIoJ3JvbGUnLCAndGFicGFuZWwnKTsKICAgICAgdGFiLmFkZENsYXNzKCd0YWItcGFuZScpOwogICAgICB0YWIuYWRkQ2xhc3MoJ3RhYmJlZC1wYW5lJyk7CiAgICAgIGlmIChmYWRlKQogICAgICAgIHRhYi5hZGRDbGFzcygnZmFkZScpOwoKICAgICAgLy8gbW92ZSBpdCBpbnRvIHRoZSB0YWIgY29udGVudCBkaXYKICAgICAgdGFiLmRldGFjaCgpLmFwcGVuZFRvKHRhYkNvbnRlbnQpOwogICAgfSk7CgogICAgLy8gc2V0IGFjdGl2ZSB0YWIKICAgICQodGFiTGlzdC5jaGlsZHJlbignbGknKVthY3RpdmVUYWJdKS5hZGRDbGFzcygnYWN0aXZlJyk7CiAgICB2YXIgYWN0aXZlID0gJCh0YWJDb250ZW50LmNoaWxkcmVuKCdkaXYuc2VjdGlvbicpW2FjdGl2ZVRhYl0pOwogICAgYWN0aXZlLmFkZENsYXNzKCdhY3RpdmUnKTsKICAgIGlmIChmYWRlKQogICAgICBhY3RpdmUuYWRkQ2xhc3MoJ2luJyk7CiAgfQoKICAvLyBjb252ZXJ0IHNlY3Rpb24gZGl2cyB3aXRoIHRoZSAudGFic2V0IGNsYXNzIHRvIHRhYnNldHMKICB2YXIgdGFic2V0cyA9ICQoImRpdi5zZWN0aW9uLnRhYnNldCIpOwogIHRhYnNldHMuZWFjaChmdW5jdGlvbihpKSB7CiAgICBidWlsZFRhYnNldCgkKHRhYnNldHNbaV0pKTsKICB9KTsKfTsKCg=="></script>
<link href="data:text/css;charset=utf-8,pre%20%2Eoperator%2C%0Apre%20%2Eparen%20%7B%0Acolor%3A%20rgb%28104%2C%20118%2C%20135%29%0A%7D%0Apre%20%2Eliteral%20%7B%0Acolor%3A%20%23990073%0A%7D%0Apre%20%2Enumber%20%7B%0Acolor%3A%20%23099%3B%0A%7D%0Apre%20%2Ecomment%20%7B%0Acolor%3A%20%23998%3B%0Afont%2Dstyle%3A%20italic%0A%7D%0Apre%20%2Ekeyword%20%7B%0Acolor%3A%20%23900%3B%0Afont%2Dweight%3A%20bold%0A%7D%0Apre%20%2Eidentifier%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%200%29%3B%0A%7D%0Apre%20%2Estring%20%7B%0Acolor%3A%20%23d14%3B%0A%7D%0A" rel="stylesheet" />
<script src="data:application/x-javascript;base64,dmFyIGhsanM9bmV3IGZ1bmN0aW9uKCl7ZnVuY3Rpb24gbShwKXtyZXR1cm4gcC5yZXBsYWNlKC8mL2dtLCImYW1wOyIpLnJlcGxhY2UoLzwvZ20sIiZsdDsiKX1mdW5jdGlvbiBmKHIscSxwKXtyZXR1cm4gUmVnRXhwKHEsIm0iKyhyLmNJPyJpIjoiIikrKHA/ImciOiIiKSl9ZnVuY3Rpb24gYihyKXtmb3IodmFyIHA9MDtwPHIuY2hpbGROb2Rlcy5sZW5ndGg7cCsrKXt2YXIgcT1yLmNoaWxkTm9kZXNbcF07aWYocS5ub2RlTmFtZT09IkNPREUiKXtyZXR1cm4gcX1pZighKHEubm9kZVR5cGU9PTMmJnEubm9kZVZhbHVlLm1hdGNoKC9ccysvKSkpe2JyZWFrfX19ZnVuY3Rpb24gaCh0LHMpe3ZhciBwPSIiO2Zvcih2YXIgcj0wO3I8dC5jaGlsZE5vZGVzLmxlbmd0aDtyKyspe2lmKHQuY2hpbGROb2Rlc1tyXS5ub2RlVHlwZT09Myl7dmFyIHE9dC5jaGlsZE5vZGVzW3JdLm5vZGVWYWx1ZTtpZihzKXtxPXEucmVwbGFjZSgvXG4vZywiIil9cCs9cX1lbHNle2lmKHQuY2hpbGROb2Rlc1tyXS5ub2RlTmFtZT09IkJSIil7cCs9IlxuIn1lbHNle3ArPWgodC5jaGlsZE5vZGVzW3JdKX19fWlmKC9NU0lFIFs2NzhdLy50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpKXtwPXAucmVwbGFjZSgvXHIvZywiXG4iKX1yZXR1cm4gcH1mdW5jdGlvbiBhKHMpe3ZhciByPXMuY2xhc3NOYW1lLnNwbGl0KC9ccysvKTtyPXIuY29uY2F0KHMucGFyZW50Tm9kZS5jbGFzc05hbWUuc3BsaXQoL1xzKy8pKTtmb3IodmFyIHE9MDtxPHIubGVuZ3RoO3ErKyl7dmFyIHA9cltxXS5yZXBsYWNlKC9ebGFuZ3VhZ2UtLywiIik7aWYoZVtwXSl7cmV0dXJuIHB9fX1mdW5jdGlvbiBjKHEpe3ZhciBwPVtdOyhmdW5jdGlvbihzLHQpe2Zvcih2YXIgcj0wO3I8cy5jaGlsZE5vZGVzLmxlbmd0aDtyKyspe2lmKHMuY2hpbGROb2Rlc1tyXS5ub2RlVHlwZT09Myl7dCs9cy5jaGlsZE5vZGVzW3JdLm5vZGVWYWx1ZS5sZW5ndGh9ZWxzZXtpZihzLmNoaWxkTm9kZXNbcl0ubm9kZU5hbWU9PSJCUiIpe3QrPTF9ZWxzZXtpZihzLmNoaWxkTm9kZXNbcl0ubm9kZVR5cGU9PTEpe3AucHVzaCh7ZXZlbnQ6InN0YXJ0IixvZmZzZXQ6dCxub2RlOnMuY2hpbGROb2Rlc1tyXX0pO3Q9YXJndW1lbnRzLmNhbGxlZShzLmNoaWxkTm9kZXNbcl0sdCk7cC5wdXNoKHtldmVudDoic3RvcCIsb2Zmc2V0OnQsbm9kZTpzLmNoaWxkTm9kZXNbcl19KX19fX1yZXR1cm4gdH0pKHEsMCk7cmV0dXJuIHB9ZnVuY3Rpb24gayh5LHcseCl7dmFyIHE9MDt2YXIgej0iIjt2YXIgcz1bXTtmdW5jdGlvbiB1KCl7aWYoeS5sZW5ndGgmJncubGVuZ3RoKXtpZih5WzBdLm9mZnNldCE9d1swXS5vZmZzZXQpe3JldHVybih5WzBdLm9mZnNldDx3WzBdLm9mZnNldCk/eTp3fWVsc2V7cmV0dXJuIHdbMF0uZXZlbnQ9PSJzdGFydCI/eTp3fX1lbHNle3JldHVybiB5Lmxlbmd0aD95Ond9fWZ1bmN0aW9uIHQoRCl7dmFyIEE9IjwiK0Qubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtmb3IodmFyIEI9MDtCPEQuYXR0cmlidXRlcy5sZW5ndGg7QisrKXt2YXIgQz1ELmF0dHJpYnV0ZXNbQl07QSs9IiAiK0Mubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtpZihDLnZhbHVlIT09dW5kZWZpbmVkJiZDLnZhbHVlIT09ZmFsc2UmJkMudmFsdWUhPT1udWxsKXtBKz0nPSInK20oQy52YWx1ZSkrJyInfX1yZXR1cm4gQSsiPiJ9d2hpbGUoeS5sZW5ndGh8fHcubGVuZ3RoKXt2YXIgdj11KCkuc3BsaWNlKDAsMSlbMF07eis9bSh4LnN1YnN0cihxLHYub2Zmc2V0LXEpKTtxPXYub2Zmc2V0O2lmKHYuZXZlbnQ9PSJzdGFydCIpe3orPXQodi5ub2RlKTtzLnB1c2godi5ub2RlKX1lbHNle2lmKHYuZXZlbnQ9PSJzdG9wIil7dmFyIHAscj1zLmxlbmd0aDtkb3tyLS07cD1zW3JdO3orPSgiPC8iK3Aubm9kZU5hbWUudG9Mb3dlckNhc2UoKSsiPiIpfXdoaWxlKHAhPXYubm9kZSk7cy5zcGxpY2UociwxKTt3aGlsZShyPHMubGVuZ3RoKXt6Kz10KHNbcl0pO3IrK319fX1yZXR1cm4geittKHguc3Vic3RyKHEpKX1mdW5jdGlvbiBqKCl7ZnVuY3Rpb24gcSh4LHksdil7aWYoeC5jb21waWxlZCl7cmV0dXJufXZhciB1O3ZhciBzPVtdO2lmKHguayl7eC5sUj1mKHkseC5sfHxobGpzLklSLHRydWUpO2Zvcih2YXIgdyBpbiB4Lmspe2lmKCF4LmsuaGFzT3duUHJvcGVydHkodykpe2NvbnRpbnVlfWlmKHgua1t3XSBpbnN0YW5jZW9mIE9iamVjdCl7dT14Lmtbd119ZWxzZXt1PXguazt3PSJrZXl3b3JkIn1mb3IodmFyIHIgaW4gdSl7aWYoIXUuaGFzT3duUHJvcGVydHkocikpe2NvbnRpbnVlfXgua1tyXT1bdyx1W3JdXTtzLnB1c2gocil9fX1pZighdil7aWYoeC5iV0spe3guYj0iXFxiKCIrcy5qb2luKCJ8IikrIilcXHMifXguYlI9Zih5LHguYj94LmI6IlxcQnxcXGIiKTtpZigheC5lJiYheC5lVyl7eC5lPSJcXEJ8XFxiIn1pZih4LmUpe3guZVI9Zih5LHguZSl9fWlmKHguaSl7eC5pUj1mKHkseC5pKX1pZih4LnI9PT11bmRlZmluZWQpe3gucj0xfWlmKCF4LmMpe3guYz1bXX14LmNvbXBpbGVkPXRydWU7Zm9yKHZhciB0PTA7dDx4LmMubGVuZ3RoO3QrKyl7aWYoeC5jW3RdPT0ic2VsZiIpe3guY1t0XT14fXEoeC5jW3RdLHksZmFsc2UpfWlmKHguc3RhcnRzKXtxKHguc3RhcnRzLHksZmFsc2UpfX1mb3IodmFyIHAgaW4gZSl7aWYoIWUuaGFzT3duUHJvcGVydHkocCkpe2NvbnRpbnVlfXEoZVtwXS5kTSxlW3BdLHRydWUpfX1mdW5jdGlvbiBkKEIsQyl7aWYoIWouY2FsbGVkKXtqKCk7ai5jYWxsZWQ9dHJ1ZX1mdW5jdGlvbiBxKHIsTSl7Zm9yKHZhciBMPTA7TDxNLmMubGVuZ3RoO0wrKyl7aWYoKE0uY1tMXS5iUi5leGVjKHIpfHxbbnVsbF0pWzBdPT1yKXtyZXR1cm4gTS5jW0xdfX19ZnVuY3Rpb24gdihMLHIpe2lmKERbTF0uZSYmRFtMXS5lUi50ZXN0KHIpKXtyZXR1cm4gMX1pZihEW0xdLmVXKXt2YXIgTT12KEwtMSxyKTtyZXR1cm4gTT9NKzE6MH1yZXR1cm4gMH1mdW5jdGlvbiB3KHIsTCl7cmV0dXJuIEwuaSYmTC5pUi50ZXN0KHIpfWZ1bmN0aW9uIEsoTixPKXt2YXIgTT1bXTtmb3IodmFyIEw9MDtMPE4uYy5sZW5ndGg7TCsrKXtNLnB1c2goTi5jW0xdLmIpfXZhciByPUQubGVuZ3RoLTE7ZG97aWYoRFtyXS5lKXtNLnB1c2goRFtyXS5lKX1yLS19d2hpbGUoRFtyKzFdLmVXKTtpZihOLmkpe00ucHVzaChOLmkpfXJldHVybiBmKE8sTS5qb2luKCJ8IiksdHJ1ZSl9ZnVuY3Rpb24gcChNLEwpe3ZhciBOPURbRC5sZW5ndGgtMV07aWYoIU4udCl7Ti50PUsoTixFKX1OLnQubGFzdEluZGV4PUw7dmFyIHI9Ti50LmV4ZWMoTSk7cmV0dXJuIHI/W00uc3Vic3RyKEwsci5pbmRleC1MKSxyWzBdLGZhbHNlXTpbTS5zdWJzdHIoTCksIiIsdHJ1ZV19ZnVuY3Rpb24geihOLHIpe3ZhciBMPUUuY0k/clswXS50b0xvd2VyQ2FzZSgpOnJbMF07dmFyIE09Ti5rW0xdO2lmKE0mJk0gaW5zdGFuY2VvZiBBcnJheSl7cmV0dXJuIE19cmV0dXJuIGZhbHNlfWZ1bmN0aW9uIEYoTCxQKXtMPW0oTCk7aWYoIVAuayl7cmV0dXJuIEx9dmFyIHI9IiI7dmFyIE89MDtQLmxSLmxhc3RJbmRleD0wO3ZhciBNPVAubFIuZXhlYyhMKTt3aGlsZShNKXtyKz1MLnN1YnN0cihPLE0uaW5kZXgtTyk7dmFyIE49eihQLE0pO2lmKE4pe3grPU5bMV07cis9JzxzcGFuIGNsYXNzPSInK05bMF0rJyI+JytNWzBdKyI8L3NwYW4+In1lbHNle3IrPU1bMF19Tz1QLmxSLmxhc3RJbmRleDtNPVAubFIuZXhlYyhMKX1yZXR1cm4gcitMLnN1YnN0cihPLEwubGVuZ3RoLU8pfWZ1bmN0aW9uIEooTCxNKXtpZihNLnNMJiZlW00uc0xdKXt2YXIgcj1kKE0uc0wsTCk7eCs9ci5rZXl3b3JkX2NvdW50O3JldHVybiByLnZhbHVlfWVsc2V7cmV0dXJuIEYoTCxNKX19ZnVuY3Rpb24gSShNLHIpe3ZhciBMPU0uY04/JzxzcGFuIGNsYXNzPSInK00uY04rJyI+JzoiIjtpZihNLnJCKXt5Kz1MO00uYnVmZmVyPSIifWVsc2V7aWYoTS5lQil7eSs9bShyKStMO00uYnVmZmVyPSIifWVsc2V7eSs9TDtNLmJ1ZmZlcj1yfX1ELnB1c2goTSk7QSs9TS5yfWZ1bmN0aW9uIEcoTixNLFEpe3ZhciBSPURbRC5sZW5ndGgtMV07aWYoUSl7eSs9SihSLmJ1ZmZlcitOLFIpO3JldHVybiBmYWxzZX12YXIgUD1xKE0sUik7aWYoUCl7eSs9SihSLmJ1ZmZlcitOLFIpO0koUCxNKTtyZXR1cm4gUC5yQn12YXIgTD12KEQubGVuZ3RoLTEsTSk7aWYoTCl7dmFyIE89Ui5jTj8iPC9zcGFuPiI6IiI7aWYoUi5yRSl7eSs9SihSLmJ1ZmZlcitOLFIpK099ZWxzZXtpZihSLmVFKXt5Kz1KKFIuYnVmZmVyK04sUikrTyttKE0pfWVsc2V7eSs9SihSLmJ1ZmZlcitOK00sUikrT319d2hpbGUoTD4xKXtPPURbRC5sZW5ndGgtMl0uY04/Ijwvc3Bhbj4iOiIiO3krPU87TC0tO0QubGVuZ3RoLS19dmFyIHI9RFtELmxlbmd0aC0xXTtELmxlbmd0aC0tO0RbRC5sZW5ndGgtMV0uYnVmZmVyPSIiO2lmKHIuc3RhcnRzKXtJKHIuc3RhcnRzLCIiKX1yZXR1cm4gUi5yRX1pZih3KE0sUikpe3Rocm93IklsbGVnYWwifX12YXIgRT1lW0JdO3ZhciBEPVtFLmRNXTt2YXIgQT0wO3ZhciB4PTA7dmFyIHk9IiI7dHJ5e3ZhciBzLHU9MDtFLmRNLmJ1ZmZlcj0iIjtkb3tzPXAoQyx1KTt2YXIgdD1HKHNbMF0sc1sxXSxzWzJdKTt1Kz1zWzBdLmxlbmd0aDtpZighdCl7dSs9c1sxXS5sZW5ndGh9fXdoaWxlKCFzWzJdKTtpZihELmxlbmd0aD4xKXt0aHJvdyJJbGxlZ2FsIn1yZXR1cm57cjpBLGtleXdvcmRfY291bnQ6eCx2YWx1ZTp5fX1jYXRjaChIKXtpZihIPT0iSWxsZWdhbCIpe3JldHVybntyOjAsa2V5d29yZF9jb3VudDowLHZhbHVlOm0oQyl9fWVsc2V7dGhyb3cgSH19fWZ1bmN0aW9uIGcodCl7dmFyIHA9e2tleXdvcmRfY291bnQ6MCxyOjAsdmFsdWU6bSh0KX07dmFyIHI9cDtmb3IodmFyIHEgaW4gZSl7aWYoIWUuaGFzT3duUHJvcGVydHkocSkpe2NvbnRpbnVlfXZhciBzPWQocSx0KTtzLmxhbmd1YWdlPXE7aWYocy5rZXl3b3JkX2NvdW50K3Mucj5yLmtleXdvcmRfY291bnQrci5yKXtyPXN9aWYocy5rZXl3b3JkX2NvdW50K3Mucj5wLmtleXdvcmRfY291bnQrcC5yKXtyPXA7cD1zfX1pZihyLmxhbmd1YWdlKXtwLnNlY29uZF9iZXN0PXJ9cmV0dXJuIHB9ZnVuY3Rpb24gaShyLHEscCl7aWYocSl7cj1yLnJlcGxhY2UoL14oKDxbXj5dKz58XHQpKykvZ20sZnVuY3Rpb24odCx3LHYsdSl7cmV0dXJuIHcucmVwbGFjZSgvXHQvZyxxKX0pfWlmKHApe3I9ci5yZXBsYWNlKC9cbi9nLCI8YnI+Iil9cmV0dXJuIHJ9ZnVuY3Rpb24gbih0LHcscil7dmFyIHg9aCh0LHIpO3ZhciB2PWEodCk7dmFyIHkscztpZih2KXt5PWQodix4KX1lbHNle3JldHVybn12YXIgcT1jKHQpO2lmKHEubGVuZ3RoKXtzPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoInByZSIpO3MuaW5uZXJIVE1MPXkudmFsdWU7eS52YWx1ZT1rKHEsYyhzKSx4KX15LnZhbHVlPWkoeS52YWx1ZSx3LHIpO3ZhciB1PXQuY2xhc3NOYW1lO2lmKCF1Lm1hdGNoKCIoXFxzfF4pKGxhbmd1YWdlLSk/Iit2KyIoXFxzfCQpIikpe3U9dT8odSsiICIrdik6dn1pZigvTVNJRSBbNjc4XS8udGVzdChuYXZpZ2F0b3IudXNlckFnZW50KSYmdC50YWdOYW1lPT0iQ09ERSImJnQucGFyZW50Tm9kZS50YWdOYW1lPT0iUFJFIil7cz10LnBhcmVudE5vZGU7dmFyIHA9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiZGl2Iik7cC5pbm5lckhUTUw9IjxwcmU+PGNvZGU+Iit5LnZhbHVlKyI8L2NvZGU+PC9wcmU+Ijt0PXAuZmlyc3RDaGlsZC5maXJzdENoaWxkO3AuZmlyc3RDaGlsZC5jTj1zLmNOO3MucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQocC5maXJzdENoaWxkLHMpfWVsc2V7dC5pbm5lckhUTUw9eS52YWx1ZX10LmNsYXNzTmFtZT11O3QucmVzdWx0PXtsYW5ndWFnZTp2LGt3Onkua2V5d29yZF9jb3VudCxyZTp5LnJ9O2lmKHkuc2Vjb25kX2Jlc3Qpe3Quc2Vjb25kX2Jlc3Q9e2xhbmd1YWdlOnkuc2Vjb25kX2Jlc3QubGFuZ3VhZ2Usa3c6eS5zZWNvbmRfYmVzdC5rZXl3b3JkX2NvdW50LHJlOnkuc2Vjb25kX2Jlc3Qucn19fWZ1bmN0aW9uIG8oKXtpZihvLmNhbGxlZCl7cmV0dXJufW8uY2FsbGVkPXRydWU7dmFyIHI9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoInByZSIpO2Zvcih2YXIgcD0wO3A8ci5sZW5ndGg7cCsrKXt2YXIgcT1iKHJbcF0pO2lmKHEpe24ocSxobGpzLnRhYlJlcGxhY2UpfX19ZnVuY3Rpb24gbCgpe2lmKHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKXt3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcigiRE9NQ29udGVudExvYWRlZCIsbyxmYWxzZSk7d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoImxvYWQiLG8sZmFsc2UpfWVsc2V7aWYod2luZG93LmF0dGFjaEV2ZW50KXt3aW5kb3cuYXR0YWNoRXZlbnQoIm9ubG9hZCIsbyl9ZWxzZXt3aW5kb3cub25sb2FkPW99fX12YXIgZT17fTt0aGlzLkxBTkdVQUdFUz1lO3RoaXMuaGlnaGxpZ2h0PWQ7dGhpcy5oaWdobGlnaHRBdXRvPWc7dGhpcy5maXhNYXJrdXA9aTt0aGlzLmhpZ2hsaWdodEJsb2NrPW47dGhpcy5pbml0SGlnaGxpZ2h0aW5nPW87dGhpcy5pbml0SGlnaGxpZ2h0aW5nT25Mb2FkPWw7dGhpcy5JUj0iW2EtekEtWl1bYS16QS1aMC05X10qIjt0aGlzLlVJUj0iW2EtekEtWl9dW2EtekEtWjAtOV9dKiI7dGhpcy5OUj0iXFxiXFxkKyhcXC5cXGQrKT8iO3RoaXMuQ05SPSJcXGIoMFt4WF1bYS1mQS1GMC05XSt8KFxcZCsoXFwuXFxkKik/fFxcLlxcZCspKFtlRV1bLStdP1xcZCspPykiO3RoaXMuQk5SPSJcXGIoMGJbMDFdKykiO3RoaXMuUlNSPSIhfCE9fCE9PXwlfCU9fCZ8JiZ8Jj18XFwqfFxcKj18XFwrfFxcKz18LHxcXC58LXwtPXwvfC89fDp8O3w8fDw8fDw8PXw8PXw9fD09fD09PXw+fD49fD4+fD4+PXw+Pj58Pj4+PXxcXD98XFxbfFxce3xcXCh8XFxefFxcXj18XFx8fFxcfD18XFx8XFx8fH4iO3RoaXMuRVI9Iig/IVtcXHNcXFNdKSI7dGhpcy5CRT17YjoiXFxcXC4iLHI6MH07dGhpcy5BU009e2NOOiJzdHJpbmciLGI6IiciLGU6IiciLGk6IlxcbiIsYzpbdGhpcy5CRV0scjowfTt0aGlzLlFTTT17Y046InN0cmluZyIsYjonIicsZTonIicsaToiXFxuIixjOlt0aGlzLkJFXSxyOjB9O3RoaXMuQ0xDTT17Y046ImNvbW1lbnQiLGI6Ii8vIixlOiIkIn07dGhpcy5DQkxDTE09e2NOOiJjb21tZW50IixiOiIvXFwqIixlOiJcXCovIn07dGhpcy5IQ009e2NOOiJjb21tZW50IixiOiIjIixlOiIkIn07dGhpcy5OTT17Y046Im51bWJlciIsYjp0aGlzLk5SLHI6MH07dGhpcy5DTk09e2NOOiJudW1iZXIiLGI6dGhpcy5DTlIscjowfTt0aGlzLkJOTT17Y046Im51bWJlciIsYjp0aGlzLkJOUixyOjB9O3RoaXMuaW5oZXJpdD1mdW5jdGlvbihyLHMpe3ZhciBwPXt9O2Zvcih2YXIgcSBpbiByKXtwW3FdPXJbcV19aWYocyl7Zm9yKHZhciBxIGluIHMpe3BbcV09c1txXX19cmV0dXJuIHB9fSgpO2hsanMuTEFOR1VBR0VTLmJhc2g9ZnVuY3Rpb24oKXt2YXIgZT17InRydWUiOjEsImZhbHNlIjoxfTt2YXIgYj17Y046InZhcmlhYmxlIixiOiJcXCQoW2EtekEtWjAtOV9dKylcXGIifTt2YXIgYT17Y046InZhcmlhYmxlIixiOiJcXCRcXHsoKFtefV0pfChcXFxcfSkpK1xcfSIsYzpbaGxqcy5DTk1dfTt2YXIgZj17Y046InN0cmluZyIsYjonIicsZTonIicsaToiXFxuIixjOltobGpzLkJFLGIsYV0scjowfTt2YXIgYz17Y046InN0cmluZyIsYjoiJyIsZToiJyIsYzpbe2I6IicnIn1dLHI6MH07dmFyIGQ9e2NOOiJ0ZXN0X2NvbmRpdGlvbiIsYjoiIixlOiIiLGM6W2YsYyxiLGEsaGxqcy5DTk1dLGs6e2xpdGVyYWw6ZX0scjowfTtyZXR1cm57ZE06e2s6e2tleXdvcmQ6eyJpZiI6MSx0aGVuOjEsImVsc2UiOjEsZmk6MSwiZm9yIjoxLCJicmVhayI6MSwiY29udGludWUiOjEsIndoaWxlIjoxLCJpbiI6MSwiZG8iOjEsZG9uZToxLGVjaG86MSxleGl0OjEsInJldHVybiI6MSxzZXQ6MSxkZWNsYXJlOjF9LGxpdGVyYWw6ZX0sYzpbe2NOOiJzaGViYW5nIixiOiIoIyFcXC9iaW5cXC9iYXNoKXwoIyFcXC9iaW5cXC9zaCkiLHI6MTB9LGIsYSxobGpzLkhDTSxobGpzLkNOTSxmLGMsaGxqcy5pbmhlcml0KGQse2I6IlxcWyAiLGU6IiBcXF0iLHI6MH0pLGhsanMuaW5oZXJpdChkLHtiOiJcXFtcXFsgIixlOiIgXFxdXFxdIn0pXX19fSgpO2hsanMuTEFOR1VBR0VTLmNwcD1mdW5jdGlvbigpe3ZhciBhPXtrZXl3b3JkOnsiZmFsc2UiOjEsImludCI6MSwiZmxvYXQiOjEsIndoaWxlIjoxLCJwcml2YXRlIjoxLCJjaGFyIjoxLCJjYXRjaCI6MSwiZXhwb3J0IjoxLHZpcnR1YWw6MSxvcGVyYXRvcjoyLHNpemVvZjoyLGR5bmFtaWNfY2FzdDoyLHR5cGVkZWY6Mixjb25zdF9jYXN0OjIsImNvbnN0IjoxLHN0cnVjdDoxLCJmb3IiOjEsc3RhdGljX2Nhc3Q6Mix1bmlvbjoxLG5hbWVzcGFjZToxLHVuc2lnbmVkOjEsImxvbmciOjEsInRocm93IjoxLCJ2b2xhdGlsZSI6Miwic3RhdGljIjoxLCJwcm90ZWN0ZWQiOjEsYm9vbDoxLHRlbXBsYXRlOjEsbXV0YWJsZToxLCJpZiI6MSwicHVibGljIjoxLGZyaWVuZDoyLCJkbyI6MSwicmV0dXJuIjoxLCJnb3RvIjoxLGF1dG86MSwidm9pZCI6MiwiZW51bSI6MSwiZWxzZSI6MSwiYnJlYWsiOjEsIm5ldyI6MSxleHRlcm46MSx1c2luZzoxLCJ0cnVlIjoxLCJjbGFzcyI6MSxhc206MSwiY2FzZSI6MSx0eXBlaWQ6MSwic2hvcnQiOjEscmVpbnRlcnByZXRfY2FzdDoyLCJkZWZhdWx0IjoxLCJkb3VibGUiOjEscmVnaXN0ZXI6MSxleHBsaWNpdDoxLHNpZ25lZDoxLHR5cGVuYW1lOjEsInRyeSI6MSwidGhpcyI6MSwic3dpdGNoIjoxLCJjb250aW51ZSI6MSx3Y2hhcl90OjEsaW5saW5lOjEsImRlbGV0ZSI6MSxhbGlnbm9mOjEsY2hhcjE2X3Q6MSxjaGFyMzJfdDoxLGNvbnN0ZXhwcjoxLGRlY2x0eXBlOjEsbm9leGNlcHQ6MSxudWxscHRyOjEsc3RhdGljX2Fzc2VydDoxLHRocmVhZF9sb2NhbDoxLHJlc3RyaWN0OjEsX0Jvb2w6MSxjb21wbGV4OjF9LGJ1aWx0X2luOntzdGQ6MSxzdHJpbmc6MSxjaW46MSxjb3V0OjEsY2VycjoxLGNsb2c6MSxzdHJpbmdzdHJlYW06MSxpc3RyaW5nc3RyZWFtOjEsb3N0cmluZ3N0cmVhbToxLGF1dG9fcHRyOjEsZGVxdWU6MSxsaXN0OjEscXVldWU6MSxzdGFjazoxLHZlY3RvcjoxLG1hcDoxLHNldDoxLGJpdHNldDoxLG11bHRpc2V0OjEsbXVsdGltYXA6MSx1bm9yZGVyZWRfc2V0OjEsdW5vcmRlcmVkX21hcDoxLHVub3JkZXJlZF9tdWx0aXNldDoxLHVub3JkZXJlZF9tdWx0aW1hcDoxLGFycmF5OjEsc2hhcmVkX3B0cjoxfX07cmV0dXJue2RNOntrOmEsaToiPC8iLGM6W2hsanMuQ0xDTSxobGpzLkNCTENMTSxobGpzLlFTTSx7Y046InN0cmluZyIsYjoiJ1xcXFw/LiIsZToiJyIsaToiLiJ9LHtjTjoibnVtYmVyIixiOiJcXGIoXFxkKyhcXC5cXGQqKT98XFwuXFxkKykodXxVfGx8THx1bHxVTHxmfEYpIn0saGxqcy5DTk0se2NOOiJwcmVwcm9jZXNzb3IiLGI6IiMiLGU6IiQifSx7Y046InN0bF9jb250YWluZXIiLGI6IlxcYihkZXF1ZXxsaXN0fHF1ZXVlfHN0YWNrfHZlY3RvcnxtYXB8c2V0fGJpdHNldHxtdWx0aXNldHxtdWx0aW1hcHx1bm9yZGVyZWRfbWFwfHVub3JkZXJlZF9zZXR8dW5vcmRlcmVkX211bHRpc2V0fHVub3JkZXJlZF9tdWx0aW1hcHxhcnJheSlcXHMqPCIsZToiPiIsazphLHI6MTAsYzpbInNlbGYiXX1dfX19KCk7aGxqcy5MQU5HVUFHRVMuY3NzPWZ1bmN0aW9uKCl7dmFyIGE9e2NOOiJmdW5jdGlvbiIsYjpobGpzLklSKyJcXCgiLGU6IlxcKSIsYzpbe2VXOnRydWUsZUU6dHJ1ZSxjOltobGpzLk5NLGhsanMuQVNNLGhsanMuUVNNXX1dfTtyZXR1cm57Y0k6dHJ1ZSxkTTp7aToiWz0vfCddIixjOltobGpzLkNCTENMTSx7Y046ImlkIixiOiJcXCNbQS1aYS16MC05Xy1dKyJ9LHtjTjoiY2xhc3MiLGI6IlxcLltBLVphLXowLTlfLV0rIixyOjB9LHtjTjoiYXR0cl9zZWxlY3RvciIsYjoiXFxbIixlOiJcXF0iLGk6IiQifSx7Y046InBzZXVkbyIsYjoiOig6KT9bYS16QS1aMC05XFxfXFwtXFwrXFwoXFwpXFxcIlxcJ10rIn0se2NOOiJhdF9ydWxlIixiOiJAKGZvbnQtZmFjZXxwYWdlKSIsbDoiW2Etei1dKyIsazp7ImZvbnQtZmFjZSI6MSxwYWdlOjF9fSx7Y046ImF0X3J1bGUiLGI6IkAiLGU6Ilt7O10iLGVFOnRydWUsazp7ImltcG9ydCI6MSxwYWdlOjEsbWVkaWE6MSxjaGFyc2V0OjF9LGM6W2EsaGxqcy5BU00saGxqcy5RU00saGxqcy5OTV19LHtjTjoidGFnIixiOmhsanMuSVIscjowfSx7Y046InJ1bGVzIixiOiJ7IixlOiJ9IixpOiJbXlxcc10iLHI6MCxjOltobGpzLkNCTENMTSx7Y046InJ1bGUiLGI6IlteXFxzXSIsckI6dHJ1ZSxlOiI7IixlVzp0cnVlLGM6W3tjTjoiYXR0cmlidXRlIixiOiJbQS1aXFxfXFwuXFwtXSsiLGU6IjoiLGVFOnRydWUsaToiW15cXHNdIixzdGFydHM6e2NOOiJ2YWx1ZSIsZVc6dHJ1ZSxlRTp0cnVlLGM6W2EsaGxqcy5OTSxobGpzLlFTTSxobGpzLkFTTSxobGpzLkNCTENMTSx7Y046ImhleGNvbG9yIixiOiJcXCNbMC05QS1GXSsifSx7Y046ImltcG9ydGFudCIsYjoiIWltcG9ydGFudCJ9XX19XX1dfV19fX0oKTtobGpzLkxBTkdVQUdFUy5pbmk9e2NJOnRydWUsZE06e2k6IlteXFxzXSIsYzpbe2NOOiJjb21tZW50IixiOiI7IixlOiIkIn0se2NOOiJ0aXRsZSIsYjoiXlxcWyIsZToiXFxdIn0se2NOOiJzZXR0aW5nIixiOiJeW2EtejAtOV9cXFtcXF1dK1sgXFx0XSo9WyBcXHRdKiIsZToiJCIsYzpbe2NOOiJ2YWx1ZSIsZVc6dHJ1ZSxrOntvbjoxLG9mZjoxLCJ0cnVlIjoxLCJmYWxzZSI6MSx5ZXM6MSxubzoxfSxjOltobGpzLlFTTSxobGpzLk5NXX1dfV19fTtobGpzLkxBTkdVQUdFUy5wZXJsPWZ1bmN0aW9uKCl7dmFyIGQ9e2dldHB3ZW50OjEsZ2V0c2VydmVudDoxLHF1b3RlbWV0YToxLG1zZ3JjdjoxLHNjYWxhcjoxLGtpbGw6MSxkYm1jbG9zZToxLHVuZGVmOjEsbGM6MSxtYToxLHN5c3dyaXRlOjEsdHI6MSxzZW5kOjEsdW1hc2s6MSxzeXNvcGVuOjEsc2htd3JpdGU6MSx2ZWM6MSxxeDoxLHV0aW1lOjEsbG9jYWw6MSxvY3Q6MSxzZW1jdGw6MSxsb2NhbHRpbWU6MSxyZWFkcGlwZToxLCJkbyI6MSwicmV0dXJuIjoxLGZvcm1hdDoxLHJlYWQ6MSxzcHJpbnRmOjEsZGJtb3BlbjoxLHBvcDoxLGdldHBncnA6MSxub3Q6MSxnZXRwd25hbToxLHJld2luZGRpcjoxLHFxOjEsZmlsZW5vOjEscXc6MSxlbmRwcm90b2VudDoxLHdhaXQ6MSxzZXRob3N0ZW50OjEsYmxlc3M6MSxzOjAsb3BlbmRpcjoxLCJjb250aW51ZSI6MSxlYWNoOjEsc2xlZXA6MSxlbmRncmVudDoxLHNodXRkb3duOjEsZHVtcDoxLGNob21wOjEsY29ubmVjdDoxLGdldHNvY2tuYW1lOjEsZGllOjEsc29ja2V0cGFpcjoxLGNsb3NlOjEsZmxvY2s6MSxleGlzdHM6MSxpbmRleDoxLHNobWdldDoxLHN1YjoxLCJmb3IiOjEsZW5kcHdlbnQ6MSxyZWRvOjEsbHN0YXQ6MSxtc2djdGw6MSxzZXRwZ3JwOjEsYWJzOjEsZXhpdDoxLHNlbGVjdDoxLHByaW50OjEscmVmOjEsZ2V0aG9zdGJ5YWRkcjoxLHVuc2hpZnQ6MSxmY250bDoxLHN5c2NhbGw6MSwiZ290byI6MSxnZXRuZXRieWFkZHI6MSxqb2luOjEsZ210aW1lOjEsc3ltbGluazoxLHNlbWdldDoxLHNwbGljZToxLHg6MCxnZXRwZWVybmFtZToxLHJlY3Y6MSxsb2c6MSxzZXRzb2Nrb3B0OjEsY29zOjEsbGFzdDoxLHJldmVyc2U6MSxnZXRob3N0YnluYW1lOjEsZ2V0Z3JuYW06MSxzdHVkeToxLGZvcm1saW5lOjEsZW5kaG9zdGVudDoxLHRpbWVzOjEsY2hvcDoxLGxlbmd0aDoxLGdldGhvc3RlbnQ6MSxnZXRuZXRlbnQ6MSxwYWNrOjEsZ2V0cHJvdG9lbnQ6MSxnZXRzZXJ2YnluYW1lOjEscmFuZDoxLG1rZGlyOjEscG9zOjEsY2htb2Q6MSx5OjAsc3Vic3RyOjEsZW5kbmV0ZW50OjEscHJpbnRmOjEsbmV4dDoxLG9wZW46MSxtc2dzbmQ6MSxyZWFkZGlyOjEsdXNlOjEsdW5saW5rOjEsZ2V0c29ja29wdDoxLGdldHByaW9yaXR5OjEscmluZGV4OjEsd2FudGFycmF5OjEsaGV4OjEsc3lzdGVtOjEsZ2V0c2VydmJ5cG9ydDoxLGVuZHNlcnZlbnQ6MSwiaW50IjoxLGNocjoxLHVudGllOjEscm1kaXI6MSxwcm90b3R5cGU6MSx0ZWxsOjEsbGlzdGVuOjEsZm9yazoxLHNobXJlYWQ6MSx1Y2ZpcnN0OjEsc2V0cHJvdG9lbnQ6MSwiZWxzZSI6MSxzeXNzZWVrOjEsbGluazoxLGdldGdyZ2lkOjEsc2htY3RsOjEsd2FpdHBpZDoxLHVucGFjazoxLGdldG5ldGJ5bmFtZToxLHJlc2V0OjEsY2hkaXI6MSxncmVwOjEsc3BsaXQ6MSxyZXF1aXJlOjEsY2FsbGVyOjEsbGNmaXJzdDoxLHVudGlsOjEsd2FybjoxLCJ3aGlsZSI6MSx2YWx1ZXM6MSxzaGlmdDoxLHRlbGxkaXI6MSxnZXRwd3VpZDoxLG15OjEsZ2V0cHJvdG9ieW51bWJlcjoxLCJkZWxldGUiOjEsYW5kOjEsc29ydDoxLHVjOjEsZGVmaW5lZDoxLHNyYW5kOjEsYWNjZXB0OjEsInBhY2thZ2UiOjEsc2Vla2RpcjoxLGdldHByb3RvYnluYW1lOjEsc2Vtb3A6MSxvdXI6MSxyZW5hbWU6MSxzZWVrOjEsImlmIjoxLHE6MCxjaHJvb3Q6MSxzeXNyZWFkOjEsc2V0cHdlbnQ6MSxubzoxLGNyeXB0OjEsZ2V0YzoxLGNob3duOjEsc3FydDoxLHdyaXRlOjEsc2V0bmV0ZW50OjEsc2V0cHJpb3JpdHk6MSxmb3JlYWNoOjEsdGllOjEsc2luOjEsbXNnZ2V0OjEsbWFwOjEsc3RhdDoxLGdldGxvZ2luOjEsdW5sZXNzOjEsZWxzaWY6MSx0cnVuY2F0ZToxLGV4ZWM6MSxrZXlzOjEsZ2xvYjoxLHRpZWQ6MSxjbG9zZWRpcjoxLGlvY3RsOjEsc29ja2V0OjEscmVhZGxpbms6MSwiZXZhbCI6MSx4b3I6MSxyZWFkbGluZToxLGJpbm1vZGU6MSxzZXRzZXJ2ZW50OjEsZW9mOjEsb3JkOjEsYmluZDoxLGFsYXJtOjEscGlwZToxLGF0YW4yOjEsZ2V0Z3JlbnQ6MSxleHA6MSx0aW1lOjEscHVzaDoxLHNldGdyZW50OjEsZ3Q6MSxsdDoxLG9yOjEsbmU6MSxtOjB9O3ZhciBmPXtjTjoic3Vic3QiLGI6IlskQF1cXHsiLGU6IlxcfSIsazpkLHI6MTB9O3ZhciBjPXtjTjoidmFyaWFibGUiLGI6IlxcJFxcZCJ9O3ZhciBiPXtjTjoidmFyaWFibGUiLGI6IltcXCRcXCVcXEBcXCpdKFxcXlxcd1xcYnwjXFx3KyhcXDpcXDpcXHcrKSp8W15cXHNcXHd7XXx7XFx3K318XFx3KyhcXDpcXDpcXHcqKSopIn07dmFyIGg9W2hsanMuQkUsZixjLGJdO3ZhciBnPXtiOiItPiIsYzpbe2I6aGxqcy5JUn0se2I6InsiLGU6In0ifV19O3ZhciBlPXtjTjoiY29tbWVudCIsYjoiXihfX0VORF9ffF9fREFUQV9fKSIsZToiXFxuJCIscjo1fTt2YXIgYT1bYyxiLGhsanMuSENNLGUsZyx7Y046InN0cmluZyIsYjoicVtxd3hyXT9cXHMqXFwoIixlOiJcXCkiLGM6aCxyOjV9LHtjTjoic3RyaW5nIixiOiJxW3F3eHJdP1xccypcXFsiLGU6IlxcXSIsYzpoLHI6NX0se2NOOiJzdHJpbmciLGI6InFbcXd4cl0/XFxzKlxceyIsZToiXFx9IixjOmgscjo1fSx7Y046InN0cmluZyIsYjoicVtxd3hyXT9cXHMqXFx8IixlOiJcXHwiLGM6aCxyOjV9LHtjTjoic3RyaW5nIixiOiJxW3F3eHJdP1xccypcXDwiLGU6IlxcPiIsYzpoLHI6NX0se2NOOiJzdHJpbmciLGI6InF3XFxzK3EiLGU6InEiLGM6aCxyOjV9LHtjTjoic3RyaW5nIixiOiInIixlOiInIixjOltobGpzLkJFXSxyOjB9LHtjTjoic3RyaW5nIixiOiciJyxlOiciJyxjOmgscjowfSx7Y046InN0cmluZyIsYjoiYCIsZToiYCIsYzpbaGxqcy5CRV19LHtjTjoic3RyaW5nIixiOiJ7XFx3K30iLHI6MH0se2NOOiJzdHJpbmciLGI6Ii0/XFx3K1xccypcXD1cXD4iLHI6MH0se2NOOiJudW1iZXIiLGI6IihcXGIwWzAtN19dKyl8KFxcYjB4WzAtOWEtZkEtRl9dKyl8KFxcYlsxLTldWzAtOV9dKihcXC5bMC05X10rKT8pfFswX11cXGIiLHI6MH0se2I6IigiK2hsanMuUlNSKyJ8XFxiKHNwbGl0fHJldHVybnxwcmludHxyZXZlcnNlfGdyZXApXFxiKVxccyoiLGs6e3NwbGl0OjEsInJldHVybiI6MSxwcmludDoxLHJldmVyc2U6MSxncmVwOjF9LHI6MCxjOltobGpzLkhDTSxlLHtjTjoicmVnZXhwIixiOiIoc3x0cnx5KS8oXFxcXC58W14vXSkqLyhcXFxcLnxbXi9dKSovW2Etel0qIixyOjEwfSx7Y046InJlZ2V4cCIsYjoiKG18cXIpPy8iLGU6Ii9bYS16XSoiLGM6W2hsanMuQkVdLHI6MH1dfSx7Y046InN1YiIsYjoiXFxic3ViXFxiIixlOiIoXFxzKlxcKC4qP1xcKSk/Wzt7XSIsazp7c3ViOjF9LHI6NX0se2NOOiJvcGVyYXRvciIsYjoiLVxcd1xcYiIscjowfSx7Y046InBvZCIsYjoiXFw9XFx3IixlOiJcXD1jdXQifV07Zi5jPWE7Zy5jWzFdLmM9YTtyZXR1cm57ZE06e2s6ZCxjOmF9fX0oKTtobGpzLkxBTkdVQUdFUy5weXRob249ZnVuY3Rpb24oKXt2YXIgYj1be2NOOiJzdHJpbmciLGI6Iih1fGIpP3I/JycnIixlOiInJyciLHI6MTB9LHtjTjoic3RyaW5nIixiOicodXxiKT9yPyIiIicsZTonIiIiJyxyOjEwfSx7Y046InN0cmluZyIsYjoiKHV8cnx1ciknIixlOiInIixjOltobGpzLkJFXSxyOjEwfSx7Y046InN0cmluZyIsYjonKHV8cnx1cikiJyxlOiciJyxjOltobGpzLkJFXSxyOjEwfSx7Y046InN0cmluZyIsYjoiKGJ8YnIpJyIsZToiJyIsYzpbaGxqcy5CRV19LHtjTjoic3RyaW5nIixiOicoYnxicikiJyxlOiciJyxjOltobGpzLkJFXX1dLmNvbmNhdChbaGxqcy5BU00saGxqcy5RU01dKTt2YXIgZD17Y046InRpdGxlIixiOmhsanMuVUlSfTt2YXIgYz17Y046InBhcmFtcyIsYjoiXFwoIixlOiJcXCkiLGM6Yi5jb25jYXQoW2hsanMuQ05NXSl9O3ZhciBhPXtiV0s6dHJ1ZSxlOiI6IixpOiJbJHtdIixjOltkLGNdLHI6MTB9O3JldHVybntkTTp7azp7a2V5d29yZDp7YW5kOjEsZWxpZjoxLGlzOjEsZ2xvYmFsOjEsYXM6MSwiaW4iOjEsImlmIjoxLGZyb206MSxyYWlzZToxLCJmb3IiOjEsZXhjZXB0OjEsImZpbmFsbHkiOjEscHJpbnQ6MSwiaW1wb3J0IjoxLHBhc3M6MSwicmV0dXJuIjoxLGV4ZWM6MSwiZWxzZSI6MSwiYnJlYWsiOjEsbm90OjEsIndpdGgiOjEsImNsYXNzIjoxLGFzc2VydDoxLHlpZWxkOjEsInRyeSI6MSwid2hpbGUiOjEsImNvbnRpbnVlIjoxLGRlbDoxLG9yOjEsZGVmOjEsbGFtYmRhOjEsbm9ubG9jYWw6MTB9LGJ1aWx0X2luOntOb25lOjEsVHJ1ZToxLEZhbHNlOjEsRWxsaXBzaXM6MSxOb3RJbXBsZW1lbnRlZDoxfX0saToiKDwvfC0+fFxcPykiLGM6Yi5jb25jYXQoW2hsanMuSENNLGhsanMuaW5oZXJpdChhLHtjTjoiZnVuY3Rpb24iLGs6e2RlZjoxfX0pLGhsanMuaW5oZXJpdChhLHtjTjoiY2xhc3MiLGs6eyJjbGFzcyI6MX19KSxobGpzLkNOTSx7Y046ImRlY29yYXRvciIsYjoiQCIsZToiJCJ9XSl9fX0oKTtobGpzLkxBTkdVQUdFUy5yPXtkTTp7YzpbaGxqcy5IQ00se2NOOiJudW1iZXIiLGI6IlxcYjBbeFhdWzAtOWEtZkEtRl0rW0xpXT9cXGIiLGU6aGxqcy5JTU1FRElBVEVfUkUscjowfSx7Y046Im51bWJlciIsYjoiXFxiXFxkKyg/OltlRV1bK1xcLV0/XFxkKik/TFxcYiIsZTpobGpzLklNTUVESUFURV9SRSxyOjB9LHtjTjoibnVtYmVyIixiOiJcXGJcXGQrXFwuKD8hXFxkKSg/OmlcXGIpPyIsZTpobGpzLklNTUVESUFURV9SRSxyOjF9LHtjTjoibnVtYmVyIixiOiJcXGJcXGQrKD86XFwuXFxkKik/KD86W2VFXVsrXFwtXT9cXGQqKT9pP1xcYiIsZTpobGpzLklNTUVESUFURV9SRSxyOjB9LHtjTjoibnVtYmVyIixiOiJcXC5cXGQrKD86W2VFXVsrXFwtXT9cXGQqKT9pP1xcYiIsZTpobGpzLklNTUVESUFURV9SRSxyOjF9LHtjTjoia2V5d29yZCIsYjoiKD86dHJ5Q2F0Y2h8bGlicmFyeXxzZXRHZW5lcmljfHNldEdyb3VwR2VuZXJpYylcXGIiLGU6aGxqcy5JTU1FRElBVEVfUkUscjoxMH0se2NOOiJrZXl3b3JkIixiOiJcXC5cXC5cXC4iLGU6aGxqcy5JTU1FRElBVEVfUkUscjoxMH0se2NOOiJrZXl3b3JkIixiOiJcXC5cXC5cXGQrKD8hW1xcdy5dKSIsZTpobGpzLklNTUVESUFURV9SRSxyOjEwfSx7Y046ImtleXdvcmQiLGI6IlxcYig/OmZ1bmN0aW9uKSIsZTpobGpzLklNTUVESUFURV9SRSxyOjJ9LHtjTjoia2V5d29yZCIsYjoiKD86aWZ8aW58YnJlYWt8bmV4dHxyZXBlYXR8ZWxzZXxmb3J8cmV0dXJufHN3aXRjaHx3aGlsZXx0cnl8c3RvcHx3YXJuaW5nfHJlcXVpcmV8YXR0YWNofGRldGFjaHxzb3VyY2V8c2V0TWV0aG9kfHNldENsYXNzKVxcYiIsZTpobGpzLklNTUVESUFURV9SRSxyOjF9LHtjTjoibGl0ZXJhbCIsYjoiKD86TkF8TkFfaW50ZWdlcl98TkFfcmVhbF98TkFfY2hhcmFjdGVyX3xOQV9jb21wbGV4XylcXGIiLGU6aGxqcy5JTU1FRElBVEVfUkUscjoxMH0se2NOOiJsaXRlcmFsIixiOiIoPzpOVUxMfFRSVUV8RkFMU0V8VHxGfEluZnxOYU4pXFxiIixlOmhsanMuSU1NRURJQVRFX1JFLHI6MX0se2NOOiJpZGVudGlmaWVyIixiOiJbYS16QS1aLl1bYS16QS1aMC05Ll9dKlxcYiIsZTpobGpzLklNTUVESUFURV9SRSxyOjB9LHtjTjoib3BlcmF0b3IiLGI6IjxcXC0oPyFcXHMqXFxkKSIsZTpobGpzLklNTUVESUFURV9SRSxyOjJ9LHtjTjoib3BlcmF0b3IiLGI6IlxcLT58PFxcLSIsZTpobGpzLklNTUVESUFURV9SRSxyOjF9LHtjTjoib3BlcmF0b3IiLGI6IiUlfH4iLGU6aGxqcy5JTU1FRElBVEVfUkV9LHtjTjoib3BlcmF0b3IiLGI6Ij49fDw9fD09fCE9fFxcfFxcfHwmJnw9fFxcK3xcXC18XFwqfC98XFxefD58PHwhfCZ8XFx8fFxcJHw6IixlOmhsanMuSU1NRURJQVRFX1JFLHI6MH0se2NOOiJvcGVyYXRvciIsYjoiJSIsZToiJSIsaToiXFxuIixyOjF9LHtjTjoiaWRlbnRpZmllciIsYjoiYCIsZToiYCIscjowfSx7Y046InN0cmluZyIsYjonIicsZTonIicsYzpbaGxqcy5CRV0scjowfSx7Y046InN0cmluZyIsYjoiJyIsZToiJyIsYzpbaGxqcy5CRV0scjowfSx7Y046InBhcmVuIixiOiJbWyh7XFxdKX1dIixlOmhsanMuSU1NRURJQVRFX1JFLHI6MH1dfX07aGxqcy5MQU5HVUFHRVMucnVieT1mdW5jdGlvbigpe3ZhciBhPSJbYS16QS1aX11bYS16QS1aMC05X10qKFxcIXxcXD8pPyI7dmFyIGo9IlthLXpBLVpfXVxcdypbIT89XT98Wy0rfl1cXEB8PDx8Pj58PX58PT09P3w8PT58Wzw+XT0/fFxcKlxcKnxbLS8rJV4mKn5gfF18XFxbXFxdPT8iO3ZhciBmPXtrZXl3b3JkOnthbmQ6MSwiZmFsc2UiOjEsdGhlbjoxLGRlZmluZWQ6MSxtb2R1bGU6MSwiaW4iOjEsInJldHVybiI6MSxyZWRvOjEsImlmIjoxLEJFR0lOOjEscmV0cnk6MSxlbmQ6MSwiZm9yIjoxLCJ0cnVlIjoxLHNlbGY6MSx3aGVuOjEsbmV4dDoxLHVudGlsOjEsImRvIjoxLGJlZ2luOjEsdW5sZXNzOjEsRU5EOjEscmVzY3VlOjEsbmlsOjEsImVsc2UiOjEsImJyZWFrIjoxLHVuZGVmOjEsbm90OjEsInN1cGVyIjoxLCJjbGFzcyI6MSwiY2FzZSI6MSxyZXF1aXJlOjEseWllbGQ6MSxhbGlhczoxLCJ3aGlsZSI6MSxlbnN1cmU6MSxlbHNpZjoxLG9yOjEsZGVmOjF9LGtleW1ldGhvZHM6e19faWRfXzoxLF9fc2VuZF9fOjEsYWJvcnQ6MSxhYnM6MSwiYWxsPyI6MSxhbGxvY2F0ZToxLGFuY2VzdG9yczoxLCJhbnk/IjoxLGFyaXR5OjEsYXNzb2M6MSxhdDoxLGF0X2V4aXQ6MSxhdXRvbG9hZDoxLCJhdXRvbG9hZD8iOjEsImJldHdlZW4/IjoxLGJpbmRpbmc6MSxiaW5tb2RlOjEsImJsb2NrX2dpdmVuPyI6MSxjYWxsOjEsY2FsbGNjOjEsY2FsbGVyOjEsY2FwaXRhbGl6ZToxLCJjYXBpdGFsaXplISI6MSxjYXNlY21wOjEsImNhdGNoIjoxLGNlaWw6MSxjZW50ZXI6MSxjaG9tcDoxLCJjaG9tcCEiOjEsY2hvcDoxLCJjaG9wISI6MSxjaHI6MSwiY2xhc3MiOjEsY2xhc3NfZXZhbDoxLCJjbGFzc192YXJpYWJsZV9kZWZpbmVkPyI6MSxjbGFzc192YXJpYWJsZXM6MSxjbGVhcjoxLGNsb25lOjEsY2xvc2U6MSxjbG9zZV9yZWFkOjEsY2xvc2Vfd3JpdGU6MSwiY2xvc2VkPyI6MSxjb2VyY2U6MSxjb2xsZWN0OjEsImNvbGxlY3QhIjoxLGNvbXBhY3Q6MSwiY29tcGFjdCEiOjEsY29uY2F0OjEsImNvbnN0X2RlZmluZWQ/IjoxLGNvbnN0X2dldDoxLGNvbnN0X21pc3Npbmc6MSxjb25zdF9zZXQ6MSxjb25zdGFudHM6MSxjb3VudDoxLGNyeXB0OjEsImRlZmF1bHQiOjEsZGVmYXVsdF9wcm9jOjEsImRlbGV0ZSI6MSwiZGVsZXRlISI6MSxkZWxldGVfYXQ6MSxkZWxldGVfaWY6MSxkZXRlY3Q6MSxkaXNwbGF5OjEsZGl2OjEsZGl2bW9kOjEsZG93bmNhc2U6MSwiZG93bmNhc2UhIjoxLGRvd250bzoxLGR1bXA6MSxkdXA6MSxlYWNoOjEsZWFjaF9ieXRlOjEsZWFjaF9pbmRleDoxLGVhY2hfa2V5OjEsZWFjaF9saW5lOjEsZWFjaF9wYWlyOjEsZWFjaF92YWx1ZToxLGVhY2hfd2l0aF9pbmRleDoxLCJlbXB0eT8iOjEsZW50cmllczoxLGVvZjoxLCJlb2Y/IjoxLCJlcWw/IjoxLCJlcXVhbD8iOjEsImV2YWwiOjEsZXhlYzoxLGV4aXQ6MSwiZXhpdCEiOjEsZXh0ZW5kOjEsZmFpbDoxLGZjbnRsOjEsZmV0Y2g6MSxmaWxlbm86MSxmaWxsOjEsZmluZDoxLGZpbmRfYWxsOjEsZmlyc3Q6MSxmbGF0dGVuOjEsImZsYXR0ZW4hIjoxLGZsb29yOjEsZmx1c2g6MSxmb3JfZmQ6MSxmb3JlYWNoOjEsZm9yazoxLGZvcm1hdDoxLGZyZWV6ZToxLCJmcm96ZW4/IjoxLGZzeW5jOjEsZ2V0YzoxLGdldHM6MSxnbG9iYWxfdmFyaWFibGVzOjEsZ3JlcDoxLGdzdWI6MSwiZ3N1YiEiOjEsImhhc19rZXk/IjoxLCJoYXNfdmFsdWU/IjoxLGhhc2g6MSxoZXg6MSxpZDoxLGluY2x1ZGU6MSwiaW5jbHVkZT8iOjEsaW5jbHVkZWRfbW9kdWxlczoxLGluZGV4OjEsaW5kZXhlczoxLGluZGljZXM6MSxpbmR1Y2VkX2Zyb206MSxpbmplY3Q6MSxpbnNlcnQ6MSxpbnNwZWN0OjEsaW5zdGFuY2VfZXZhbDoxLGluc3RhbmNlX21ldGhvZDoxLGluc3RhbmNlX21ldGhvZHM6MSwiaW5zdGFuY2Vfb2Y/IjoxLCJpbnN0YW5jZV92YXJpYWJsZV9kZWZpbmVkPyI6MSxpbnN0YW5jZV92YXJpYWJsZV9nZXQ6MSxpbnN0YW5jZV92YXJpYWJsZV9zZXQ6MSxpbnN0YW5jZV92YXJpYWJsZXM6MSwiaW50ZWdlcj8iOjEsaW50ZXJuOjEsaW52ZXJ0OjEsaW9jdGw6MSwiaXNfYT8iOjEsaXNhdHR5OjEsIml0ZXJhdG9yPyI6MSxqb2luOjEsImtleT8iOjEsa2V5czoxLCJraW5kX29mPyI6MSxsYW1iZGE6MSxsYXN0OjEsbGVuZ3RoOjEsbGluZW5vOjEsbGp1c3Q6MSxsb2FkOjEsbG9jYWxfdmFyaWFibGVzOjEsbG9vcDoxLGxzdHJpcDoxLCJsc3RyaXAhIjoxLG1hcDoxLCJtYXAhIjoxLG1hdGNoOjEsbWF4OjEsIm1lbWJlcj8iOjEsbWVyZ2U6MSwibWVyZ2UhIjoxLG1ldGhvZDoxLCJtZXRob2RfZGVmaW5lZD8iOjEsbWV0aG9kX21pc3Npbmc6MSxtZXRob2RzOjEsbWluOjEsbW9kdWxlX2V2YWw6MSxtb2R1bG86MSxuYW1lOjEsbmVzdGluZzoxLCJuZXciOjEsbmV4dDoxLCJuZXh0ISI6MSwibmlsPyI6MSxuaXRlbXM6MSwibm9uemVybz8iOjEsb2JqZWN0X2lkOjEsb2N0OjEsb3BlbjoxLHBhY2s6MSxwYXJ0aXRpb246MSxwaWQ6MSxwaXBlOjEscG9wOjEscG9wZW46MSxwb3M6MSxwcmVjOjEscHJlY19mOjEscHJlY19pOjEscHJpbnQ6MSxwcmludGY6MSxwcml2YXRlX2NsYXNzX21ldGhvZDoxLHByaXZhdGVfaW5zdGFuY2VfbWV0aG9kczoxLCJwcml2YXRlX21ldGhvZF9kZWZpbmVkPyI6MSxwcml2YXRlX21ldGhvZHM6MSxwcm9jOjEscHJvdGVjdGVkX2luc3RhbmNlX21ldGhvZHM6MSwicHJvdGVjdGVkX21ldGhvZF9kZWZpbmVkPyI6MSxwcm90ZWN0ZWRfbWV0aG9kczoxLHB1YmxpY19jbGFzc19tZXRob2Q6MSxwdWJsaWNfaW5zdGFuY2VfbWV0aG9kczoxLCJwdWJsaWNfbWV0aG9kX2RlZmluZWQ/IjoxLHB1YmxpY19tZXRob2RzOjEscHVzaDoxLHB1dGM6MSxwdXRzOjEscXVvOjEscmFpc2U6MSxyYW5kOjEscmFzc29jOjEscmVhZDoxLHJlYWRfbm9uYmxvY2s6MSxyZWFkY2hhcjoxLHJlYWRsaW5lOjEscmVhZGxpbmVzOjEscmVhZHBhcnRpYWw6MSxyZWhhc2g6MSxyZWplY3Q6MSwicmVqZWN0ISI6MSxyZW1haW5kZXI6MSxyZW9wZW46MSxyZXBsYWNlOjEscmVxdWlyZToxLCJyZXNwb25kX3RvPyI6MSxyZXZlcnNlOjEsInJldmVyc2UhIjoxLHJldmVyc2VfZWFjaDoxLHJld2luZDoxLHJpbmRleDoxLHJqdXN0OjEscm91bmQ6MSxyc3RyaXA6MSwicnN0cmlwISI6MSxzY2FuOjEsc2VlazoxLHNlbGVjdDoxLHNlbmQ6MSxzZXRfdHJhY2VfZnVuYzoxLHNoaWZ0OjEsc2luZ2xldG9uX21ldGhvZF9hZGRlZDoxLHNpbmdsZXRvbl9tZXRob2RzOjEsc2l6ZToxLHNsZWVwOjEsc2xpY2U6MSwic2xpY2UhIjoxLHNvcnQ6MSwic29ydCEiOjEsc29ydF9ieToxLHNwbGl0OjEsc3ByaW50ZjoxLHNxdWVlemU6MSwic3F1ZWV6ZSEiOjEsc3JhbmQ6MSxzdGF0OjEsc3RlcDoxLHN0b3JlOjEsc3RyaXA6MSwic3RyaXAhIjoxLHN1YjoxLCJzdWIhIjoxLHN1Y2M6MSwic3VjYyEiOjEsc3VtOjEsc3VwZXJjbGFzczoxLHN3YXBjYXNlOjEsInN3YXBjYXNlISI6MSxzeW5jOjEsc3lzY2FsbDoxLHN5c29wZW46MSxzeXNyZWFkOjEsc3lzc2VlazoxLHN5c3RlbToxLHN5c3dyaXRlOjEsdGFpbnQ6MSwidGFpbnRlZD8iOjEsdGVsbDoxLHRlc3Q6MSwidGhyb3ciOjEsdGltZXM6MSx0b19hOjEsdG9fYXJ5OjEsdG9fZjoxLHRvX2hhc2g6MSx0b19pOjEsdG9faW50OjEsdG9faW86MSx0b19wcm9jOjEsdG9fczoxLHRvX3N0cjoxLHRvX3N5bToxLHRyOjEsInRyISI6MSx0cl9zOjEsInRyX3MhIjoxLHRyYWNlX3ZhcjoxLHRyYW5zcG9zZToxLHRyYXA6MSx0cnVuY2F0ZToxLCJ0dHk/IjoxLHR5cGU6MSx1bmdldGM6MSx1bmlxOjEsInVuaXEhIjoxLHVucGFjazoxLHVuc2hpZnQ6MSx1bnRhaW50OjEsdW50cmFjZV92YXI6MSx1cGNhc2U6MSwidXBjYXNlISI6MSx1cGRhdGU6MSx1cHRvOjEsInZhbHVlPyI6MSx2YWx1ZXM6MSx2YWx1ZXNfYXQ6MSx3YXJuOjEsd3JpdGU6MSx3cml0ZV9ub25ibG9jazoxLCJ6ZXJvPyI6MSx6aXA6MX19O3ZhciBjPXtjTjoieWFyZG9jdGFnIixiOiJAW0EtWmEtel0rIn07dmFyIGs9W3tjTjoiY29tbWVudCIsYjoiIyIsZToiJCIsYzpbY119LHtjTjoiY29tbWVudCIsYjoiXlxcPWJlZ2luIixlOiJeXFw9ZW5kIixjOltjXSxyOjEwfSx7Y046ImNvbW1lbnQiLGI6Il5fX0VORF9fIixlOiJcXG4kIn1dO3ZhciBkPXtjTjoic3Vic3QiLGI6IiNcXHsiLGU6In0iLGw6YSxrOmZ9O3ZhciBpPVtobGpzLkJFLGRdO3ZhciBiPVt7Y046InN0cmluZyIsYjoiJyIsZToiJyIsYzppLHI6MH0se2NOOiJzdHJpbmciLGI6JyInLGU6JyInLGM6aSxyOjB9LHtjTjoic3RyaW5nIixiOiIlW3F3XT9cXCgiLGU6IlxcKSIsYzppLHI6MTB9LHtjTjoic3RyaW5nIixiOiIlW3F3XT9cXFsiLGU6IlxcXSIsYzppLHI6MTB9LHtjTjoic3RyaW5nIixiOiIlW3F3XT97IixlOiJ9IixjOmkscjoxMH0se2NOOiJzdHJpbmciLGI6IiVbcXddPzwiLGU6Ij4iLGM6aSxyOjEwfSx7Y046InN0cmluZyIsYjoiJVtxd10/LyIsZToiLyIsYzppLHI6MTB9LHtjTjoic3RyaW5nIixiOiIlW3F3XT8lIixlOiIlIixjOmkscjoxMH0se2NOOiJzdHJpbmciLGI6IiVbcXddPy0iLGU6Ii0iLGM6aSxyOjEwfSx7Y046InN0cmluZyIsYjoiJVtxd10/XFx8IixlOiJcXHwiLGM6aSxyOjEwfV07dmFyIGg9e2NOOiJmdW5jdGlvbiIsYjoiXFxiZGVmXFxzKyIsZToiIHwkfDsiLGw6YSxrOmYsYzpbe2NOOiJ0aXRsZSIsYjpqLGw6YSxrOmZ9LHtjTjoicGFyYW1zIixiOiJcXCgiLGU6IlxcKSIsbDphLGs6Zn1dLmNvbmNhdChrKX07dmFyIGc9e2NOOiJpZGVudGlmaWVyIixiOmEsbDphLGs6ZixyOjB9O3ZhciBlPWsuY29uY2F0KGIuY29uY2F0KFt7Y046ImNsYXNzIixiOiJcXGIoY2xhc3N8bW9kdWxlKVxcYiIsZToiJHw7IixrOnsiY2xhc3MiOjEsbW9kdWxlOjF9LGM6W3tjTjoidGl0bGUiLGI6IltBLVphLXpfXVxcdyooOjpcXHcrKSooXFw/fFxcISk/IixyOjB9LHtjTjoiaW5oZXJpdGFuY2UiLGI6IjxcXHMqIixjOlt7Y046InBhcmVudCIsYjoiKCIraGxqcy5JUisiOjopPyIraGxqcy5JUn1dfV0uY29uY2F0KGspfSxoLHtjTjoiY29uc3RhbnQiLGI6Iig6Oik/KFtBLVpdXFx3Kig6Oik/KSsiLHI6MH0se2NOOiJzeW1ib2wiLGI6IjoiLGM6Yi5jb25jYXQoW2ddKSxyOjB9LHtjTjoibnVtYmVyIixiOiIoXFxiMFswLTdfXSspfChcXGIweFswLTlhLWZBLUZfXSspfChcXGJbMS05XVswLTlfXSooXFwuWzAtOV9dKyk/KXxbMF9dXFxiIixyOjB9LHtjTjoibnVtYmVyIixiOiJcXD9cXHcifSx7Y046InZhcmlhYmxlIixiOiIoXFwkXFxXKXwoKFxcJHxcXEBcXEA/KShcXHcrKSkifSxnLHtiOiIoIitobGpzLlJTUisiKVxccyoiLGM6ay5jb25jYXQoW3tjTjoicmVnZXhwIixiOiIvIixlOiIvW2Etel0qIixpOiJcXG4iLGM6W2hsanMuQkVdfV0pLHI6MH1dKSk7ZC5jPWU7aC5jWzFdLmM9ZTtyZXR1cm57ZE06e2w6YSxrOmYsYzplfX19KCk7aGxqcy5MQU5HVUFHRVMuc2NhbGE9ZnVuY3Rpb24oKXt2YXIgYj17Y046ImFubm90YXRpb24iLGI6IkBbQS1aYS16XSsifTt2YXIgYT17Y046InN0cmluZyIsYjondT9yPyIiIicsZTonIiIiJyxyOjEwfTtyZXR1cm57ZE06e2s6e3R5cGU6MSx5aWVsZDoxLGxhenk6MSxvdmVycmlkZToxLGRlZjoxLCJ3aXRoIjoxLHZhbDoxLCJ2YXIiOjEsImZhbHNlIjoxLCJ0cnVlIjoxLHNlYWxlZDoxLCJhYnN0cmFjdCI6MSwicHJpdmF0ZSI6MSx0cmFpdDoxLG9iamVjdDoxLCJudWxsIjoxLCJpZiI6MSwiZm9yIjoxLCJ3aGlsZSI6MSwidGhyb3ciOjEsImZpbmFsbHkiOjEsInByb3RlY3RlZCI6MSwiZXh0ZW5kcyI6MSwiaW1wb3J0IjoxLCJmaW5hbCI6MSwicmV0dXJuIjoxLCJlbHNlIjoxLCJicmVhayI6MSwibmV3IjoxLCJjYXRjaCI6MSwic3VwZXIiOjEsImNsYXNzIjoxLCJjYXNlIjoxLCJwYWNrYWdlIjoxLCJkZWZhdWx0IjoxLCJ0cnkiOjEsInRoaXMiOjEsbWF0Y2g6MSwiY29udGludWUiOjEsInRocm93cyI6MX0sYzpbe2NOOiJqYXZhZG9jIixiOiIvXFwqXFwqIixlOiJcXCovIixjOlt7Y046ImphdmFkb2N0YWciLGI6IkBbQS1aYS16XSsifV0scjoxMH0saGxqcy5DTENNLGhsanMuQ0JMQ0xNLGhsanMuQVNNLGhsanMuUVNNLGEse2NOOiJjbGFzcyIsYjoiKChjYXNlICk/Y2xhc3MgfG9iamVjdCB8dHJhaXQgKSIsZToiKHt8JCkiLGk6IjoiLGs6eyJjYXNlIjoxLCJjbGFzcyI6MSx0cmFpdDoxLG9iamVjdDoxfSxjOlt7YldLOnRydWUsazp7ImV4dGVuZHMiOjEsIndpdGgiOjF9LHI6MTB9LHtjTjoidGl0bGUiLGI6aGxqcy5VSVJ9LHtjTjoicGFyYW1zIixiOiJcXCgiLGU6IlxcKSIsYzpbaGxqcy5BU00saGxqcy5RU00sYSxiXX1dfSxobGpzLkNOTSxiXX19fSgpO2hsanMuTEFOR1VBR0VTLnNxbD17Y0k6dHJ1ZSxkTTp7aToiW15cXHNdIixjOlt7Y046Im9wZXJhdG9yIixiOiIoYmVnaW58c3RhcnR8Y29tbWl0fHJvbGxiYWNrfHNhdmVwb2ludHxsb2NrfGFsdGVyfGNyZWF0ZXxkcm9wfHJlbmFtZXxjYWxsfGRlbGV0ZXxkb3xoYW5kbGVyfGluc2VydHxsb2FkfHJlcGxhY2V8c2VsZWN0fHRydW5jYXRlfHVwZGF0ZXxzZXR8c2hvd3xwcmFnbWF8Z3JhbnQpXFxiIixlOiI7fCIraGxqcy5FUixrOntrZXl3b3JkOnthbGw6MSxwYXJ0aWFsOjEsZ2xvYmFsOjEsbW9udGg6MSxjdXJyZW50X3RpbWVzdGFtcDoxLHVzaW5nOjEsZ286MSxyZXZva2U6MSxzbWFsbGludDoxLGluZGljYXRvcjoxLCJlbmQtZXhlYyI6MSxkaXNjb25uZWN0OjEsem9uZToxLCJ3aXRoIjoxLGNoYXJhY3RlcjoxLGFzc2VydGlvbjoxLHRvOjEsYWRkOjEsY3VycmVudF91c2VyOjEsdXNhZ2U6MSxpbnB1dDoxLGxvY2FsOjEsYWx0ZXI6MSxtYXRjaDoxLGNvbGxhdGU6MSxyZWFsOjEsdGhlbjoxLHJvbGxiYWNrOjEsZ2V0OjEscmVhZDoxLHRpbWVzdGFtcDoxLHNlc3Npb25fdXNlcjoxLG5vdDoxLGludGVnZXI6MSxiaXQ6MSx1bmlxdWU6MSxkYXk6MSxtaW51dGU6MSxkZXNjOjEsaW5zZXJ0OjEsZXhlY3V0ZToxLGxpa2U6MSxpbGlrZToyLGxldmVsOjEsZGVjaW1hbDoxLGRyb3A6MSwiY29udGludWUiOjEsaXNvbGF0aW9uOjEsZm91bmQ6MSx3aGVyZToxLGNvbnN0cmFpbnRzOjEsZG9tYWluOjEscmlnaHQ6MSxuYXRpb25hbDoxLHNvbWU6MSxtb2R1bGU6MSx0cmFuc2FjdGlvbjoxLHJlbGF0aXZlOjEsc2Vjb25kOjEsY29ubmVjdDoxLGVzY2FwZToxLGNsb3NlOjEsc3lzdGVtX3VzZXI6MSwiZm9yIjoxLGRlZmVycmVkOjEsc2VjdGlvbjoxLGNhc3Q6MSxjdXJyZW50OjEsc3Fsc3RhdGU6MSxhbGxvY2F0ZToxLGludGVyc2VjdDoxLGRlYWxsb2NhdGU6MSxudW1lcmljOjEsInB1YmxpYyI6MSxwcmVzZXJ2ZToxLGZ1bGw6MSwiZ290byI6MSxpbml0aWFsbHk6MSxhc2M6MSxubzoxLGtleToxLG91dHB1dDoxLGNvbGxhdGlvbjoxLGdyb3VwOjEsYnk6MSx1bmlvbjoxLHNlc3Npb246MSxib3RoOjEsbGFzdDoxLGxhbmd1YWdlOjEsY29uc3RyYWludDoxLGNvbHVtbjoxLG9mOjEsc3BhY2U6MSxmb3JlaWduOjEsZGVmZXJyYWJsZToxLHByaW9yOjEsY29ubmVjdGlvbjoxLHVua25vd246MSxhY3Rpb246MSxjb21taXQ6MSx2aWV3OjEsb3I6MSxmaXJzdDoxLGludG86MSwiZmxvYXQiOjEseWVhcjoxLHByaW1hcnk6MSxjYXNjYWRlZDoxLGV4Y2VwdDoxLHJlc3RyaWN0OjEsc2V0OjEscmVmZXJlbmNlczoxLG5hbWVzOjEsdGFibGU6MSxvdXRlcjoxLG9wZW46MSxzZWxlY3Q6MSxzaXplOjEsYXJlOjEscm93czoxLGZyb206MSxwcmVwYXJlOjEsZGlzdGluY3Q6MSxsZWFkaW5nOjEsY3JlYXRlOjEsb25seToxLG5leHQ6MSxpbm5lcjoxLGF1dGhvcml6YXRpb246MSxzY2hlbWE6MSxjb3JyZXNwb25kaW5nOjEsb3B0aW9uOjEsZGVjbGFyZToxLHByZWNpc2lvbjoxLGltbWVkaWF0ZToxLCJlbHNlIjoxLHRpbWV6b25lX21pbnV0ZToxLGV4dGVybmFsOjEsdmFyeWluZzoxLHRyYW5zbGF0aW9uOjEsInRydWUiOjEsImNhc2UiOjEsZXhjZXB0aW9uOjEsam9pbjoxLGhvdXI6MSwiZGVmYXVsdCI6MSwiZG91YmxlIjoxLHNjcm9sbDoxLHZhbHVlOjEsY3Vyc29yOjEsZGVzY3JpcHRvcjoxLHZhbHVlczoxLGRlYzoxLGZldGNoOjEscHJvY2VkdXJlOjEsImRlbGV0ZSI6MSxhbmQ6MSwiZmFsc2UiOjEsImludCI6MSxpczoxLGRlc2NyaWJlOjEsImNoYXIiOjEsYXM6MSxhdDoxLCJpbiI6MSx2YXJjaGFyOjEsIm51bGwiOjEsdHJhaWxpbmc6MSxhbnk6MSxhYnNvbHV0ZToxLGN1cnJlbnRfdGltZToxLGVuZDoxLGdyYW50OjEscHJpdmlsZWdlczoxLHdoZW46MSxjcm9zczoxLGNoZWNrOjEsd3JpdGU6MSxjdXJyZW50X2RhdGU6MSxwYWQ6MSxiZWdpbjoxLHRlbXBvcmFyeToxLGV4ZWM6MSx0aW1lOjEsdXBkYXRlOjEsY2F0YWxvZzoxLHVzZXI6MSxzcWw6MSxkYXRlOjEsb246MSxpZGVudGl0eToxLHRpbWV6b25lX2hvdXI6MSxuYXR1cmFsOjEsd2hlbmV2ZXI6MSxpbnRlcnZhbDoxLHdvcms6MSxvcmRlcjoxLGNhc2NhZGU6MSxkaWFnbm9zdGljczoxLG5jaGFyOjEsaGF2aW5nOjEsbGVmdDoxLGNhbGw6MSwiZG8iOjEsaGFuZGxlcjoxLGxvYWQ6MSxyZXBsYWNlOjEsdHJ1bmNhdGU6MSxzdGFydDoxLGxvY2s6MSxzaG93OjEscHJhZ21hOjF9LGFnZ3JlZ2F0ZTp7Y291bnQ6MSxzdW06MSxtaW46MSxtYXg6MSxhdmc6MX19LGM6W3tjTjoic3RyaW5nIixiOiInIixlOiInIixjOltobGpzLkJFLHtiOiInJyJ9XSxyOjB9LHtjTjoic3RyaW5nIixiOiciJyxlOiciJyxjOltobGpzLkJFLHtiOiciIid9XSxyOjB9LHtjTjoic3RyaW5nIixiOiJgIixlOiJgIixjOltobGpzLkJFXX0saGxqcy5DTk1dfSxobGpzLkNCTENMTSx7Y046ImNvbW1lbnQiLGI6Ii0tIixlOiIkIn1dfX07aGxqcy5MQU5HVUFHRVMuc3Rhbj17ZE06e2M6W2hsanMuSENNLGhsanMuQ0xDTSxobGpzLlFTTSxobGpzLkNOTSx7Y046Im9wZXJhdG9yIixiOiIoPzo8LXx+fFxcfFxcfHwmJnw9PXwhPXw8PT98Pj0/fFxcK3wtfFxcLj8vfFxcXFx8XFxefFxcXnwhfCd8JXw6fCx8O3w9KVxcYiIsZTpobGpzLklNTUVESUFURV9SRSxyOjEwfSx7Y046InBhcmVuIixiOiJbWyh7XFxdKX1dIixlOmhsanMuSU1NRURJQVRFX1JFLHI6MH0se2NOOiJmdW5jdGlvbiIsYjoiKD86UGhpfFBoaV9hcHByb3h8YWJzfGFjb3N8YWNvc2h8YXBwZW5kX2NvbHxhcHBlbmRfcm93fGFzaW58YXNpbmh8YXRhbnxhdGFuMnxhdGFuaHxiZXJub3VsbGlfY2NkZl9sb2d8YmVybm91bGxpX2NkZnxiZXJub3VsbGlfY2RmX2xvZ3xiZXJub3VsbGlfbG9nfGJlcm5vdWxsaV9sb2dpdF9sb2d8YmVybm91bGxpX3JuZ3xiZXNzZWxfZmlyc3Rfa2luZHxiZXNzZWxfc2Vjb25kX2tpbmR8YmV0YV9iaW5vbWlhbF9jY2RmX2xvZ3xiZXRhX2Jpbm9taWFsX2NkZnxiZXRhX2Jpbm9taWFsX2NkZl9sb2d8YmV0YV9iaW5vbWlhbF9sb2d8YmV0YV9iaW5vbWlhbF9ybmd8YmV0YV9jY2RmX2xvZ3xiZXRhX2NkZnxiZXRhX2NkZl9sb2d8YmV0YV9sb2d8YmV0YV9ybmd8YmluYXJ5X2xvZ19sb3NzfGJpbm9taWFsX2NjZGZfbG9nfGJpbm9taWFsX2NkZnxiaW5vbWlhbF9jZGZfbG9nfGJpbm9taWFsX2NvZWZmaWNpZW50X2xvZ3xiaW5vbWlhbF9sb2d8Ymlub21pYWxfbG9naXRfbG9nfGJpbm9taWFsX3JuZ3xibG9ja3xjYXRlZ29yaWNhbF9sb2d8Y2F0ZWdvcmljYWxfbG9naXRfbG9nfGNhdGVnb3JpY2FsX3JuZ3xjYXVjaHlfY2NkZl9sb2d8Y2F1Y2h5X2NkZnxjYXVjaHlfY2RmX2xvZ3xjYXVjaHlfbG9nfGNhdWNoeV9ybmd8Y2JydHxjZWlsfGNoaV9zcXVhcmVfY2NkZl9sb2d8Y2hpX3NxdWFyZV9jZGZ8Y2hpX3NxdWFyZV9jZGZfbG9nfGNoaV9zcXVhcmVfbG9nfGNoaV9zcXVhcmVfcm5nfGNob2xlc2t5X2RlY29tcG9zZXxjb2x8Y29sc3xjb2x1bW5zX2RvdF9wcm9kdWN0fGNvbHVtbnNfZG90X3NlbGZ8Y29zfGNvc2h8Y3Jvc3Nwcm9kfGNzcl9leHRyYWN0X3V8Y3NyX2V4dHJhY3Rfdnxjc3JfZXh0cmFjdF93fGNzcl9tYXRyaXhfdGltZXNfdmVjdG9yfGNzcl90b19kZW5zZV9tYXRyaXh8Y3VtdWxhdGl2ZV9zdW18ZGV0ZXJtaW5hbnR8ZGlhZ19tYXRyaXh8ZGlhZ19wb3N0X211bHRpcGx5fGRpYWdfcHJlX211bHRpcGx5fGRpYWdvbmFsfGRpZ2FtbWF8ZGltc3xkaXJpY2hsZXRfbG9nfGRpcmljaGxldF9ybmd8ZGlzdGFuY2V8ZG90X3Byb2R1Y3R8ZG90X3NlbGZ8ZG91YmxlX2V4cG9uZW50aWFsX2NjZGZfbG9nfGRvdWJsZV9leHBvbmVudGlhbF9jZGZ8ZG91YmxlX2V4cG9uZW50aWFsX2NkZl9sb2d8ZG91YmxlX2V4cG9uZW50aWFsX2xvZ3xkb3VibGVfZXhwb25lbnRpYWxfcm5nfGV8ZWlnZW52YWx1ZXNfc3ltfGVpZ2VudmVjdG9yc19zeW18ZXJmfGVyZmN8ZXhwfGV4cDJ8ZXhwX21vZF9ub3JtYWxfY2NkZl9sb2d8ZXhwX21vZF9ub3JtYWxfY2RmfGV4cF9tb2Rfbm9ybWFsX2NkZl9sb2d8ZXhwX21vZF9ub3JtYWxfbG9nfGV4cF9tb2Rfbm9ybWFsX3JuZ3xleHBtMXxleHBvbmVudGlhbF9jY2RmX2xvZ3xleHBvbmVudGlhbF9jZGZ8ZXhwb25lbnRpYWxfY2RmX2xvZ3xleHBvbmVudGlhbF9sb2d8ZXhwb25lbnRpYWxfcm5nfGZhYnN8ZmFsbGluZ19mYWN0b3JpYWx8ZmRpbXxmbG9vcnxmbWF8Zm1heHxmbWlufGZtb2R8ZnJlY2hldF9jY2RmX2xvZ3xmcmVjaGV0X2NkZnxmcmVjaGV0X2NkZl9sb2d8ZnJlY2hldF9sb2d8ZnJlY2hldF9ybmd8Z2FtbWFfY2NkZl9sb2d8Z2FtbWFfY2RmfGdhbW1hX2NkZl9sb2d8Z2FtbWFfbG9nfGdhbW1hX3B8Z2FtbWFfcXxnYW1tYV9ybmd8Z2F1c3NpYW5fZGxtX29ic19sb2d8Z2V0X2xwfGd1bWJlbF9jY2RmX2xvZ3xndW1iZWxfY2RmfGd1bWJlbF9jZGZfbG9nfGd1bWJlbF9sb2d8Z3VtYmVsX3JuZ3xoZWFkfGh5cGVyZ2VvbWV0cmljX2xvZ3xoeXBlcmdlb21ldHJpY19ybmd8aHlwb3R8aWZfZWxzZXxpbnRfc3RlcHxpbnZ8aW52X2NoaV9zcXVhcmVfY2NkZl9sb2d8aW52X2NoaV9zcXVhcmVfY2RmfGludl9jaGlfc3F1YXJlX2NkZl9sb2d8aW52X2NoaV9zcXVhcmVfbG9nfGludl9jaGlfc3F1YXJlX3JuZ3xpbnZfY2xvZ2xvZ3xpbnZfZ2FtbWFfY2NkZl9sb2d8aW52X2dhbW1hX2NkZnxpbnZfZ2FtbWFfY2RmX2xvZ3xpbnZfZ2FtbWFfbG9nfGludl9nYW1tYV9ybmd8aW52X2xvZ2l0fGludl9waGl8aW52X3NxcnR8aW52X3NxdWFyZXxpbnZfd2lzaGFydF9sb2d8aW52X3dpc2hhcnRfcm5nfGludmVyc2V8aW52ZXJzZV9zcGR8aXNfaW5mfGlzX25hbnxsYmV0YXxsZ2FtbWF8bGtqX2NvcnJfY2hvbGVza3lfbG9nfGxral9jb3JyX2Nob2xlc2t5X3JuZ3xsa2pfY29ycl9sb2d8bGtqX2NvcnJfcm5nfGxtZ2FtbWF8bG9nfGxvZzEwfGxvZzFtfGxvZzFtX2V4cHxsb2cxbV9pbnZfbG9naXR8bG9nMXB8bG9nMXBfZXhwfGxvZzJ8bG9nX2RldGVybWluYW50fGxvZ19kaWZmX2V4cHxsb2dfZmFsbGluZ19mYWN0b3JpYWx8bG9nX2ludl9sb2dpdHxsb2dfbWl4fGxvZ19yaXNpbmdfZmFjdG9yaWFsfGxvZ19zb2Z0bWF4fGxvZ19zdW1fZXhwfGxvZ2lzdGljX2NjZGZfbG9nfGxvZ2lzdGljX2NkZnxsb2dpc3RpY19jZGZfbG9nfGxvZ2lzdGljX2xvZ3xsb2dpc3RpY19ybmd8bG9naXR8bG9nbm9ybWFsX2NjZGZfbG9nfGxvZ25vcm1hbF9jZGZ8bG9nbm9ybWFsX2NkZl9sb2d8bG9nbm9ybWFsX2xvZ3xsb2dub3JtYWxfcm5nfG1hY2hpbmVfcHJlY2lzaW9ufG1heHxtZGl2aWRlX2xlZnRfdHJpX2xvd3xtZGl2aWRlX3JpZ2h0X3RyaV9sb3d8bWVhbnxtaW58bW9kaWZpZWRfYmVzc2VsX2ZpcnN0X2tpbmR8bW9kaWZpZWRfYmVzc2VsX3NlY29uZF9raW5kfG11bHRpX2dwX2Nob2xlc2t5X2xvZ3xtdWx0aV9ncF9sb2d8bXVsdGlfbm9ybWFsX2Nob2xlc2t5X2xvZ3xtdWx0aV9ub3JtYWxfY2hvbGVza3lfcm5nfG11bHRpX25vcm1hbF9sb2d8bXVsdGlfbm9ybWFsX3ByZWNfbG9nfG11bHRpX25vcm1hbF9ybmd8bXVsdGlfc3R1ZGVudF90X2xvZ3xtdWx0aV9zdHVkZW50X3Rfcm5nfG11bHRpbm9taWFsX2xvZ3xtdWx0aW5vbWlhbF9ybmd8bXVsdGlwbHlfbG9nfG11bHRpcGx5X2xvd2VyX3RyaV9zZWxmX3RyYW5zcG9zZXxuZWdfYmlub21pYWxfMl9jY2RmX2xvZ3xuZWdfYmlub21pYWxfMl9jZGZ8bmVnX2Jpbm9taWFsXzJfY2RmX2xvZ3xuZWdfYmlub21pYWxfMl9sb2d8bmVnX2Jpbm9taWFsXzJfbG9nX2xvZ3xuZWdfYmlub21pYWxfMl9sb2dfcm5nfG5lZ19iaW5vbWlhbF8yX3JuZ3xuZWdfYmlub21pYWxfY2NkZl9sb2d8bmVnX2Jpbm9taWFsX2NkZnxuZWdfYmlub21pYWxfY2RmX2xvZ3xuZWdfYmlub21pYWxfbG9nfG5lZ19iaW5vbWlhbF9ybmd8bmVnYXRpdmVfaW5maW5pdHl8bm9ybWFsX2NjZGZfbG9nfG5vcm1hbF9jZGZ8bm9ybWFsX2NkZl9sb2d8bm9ybWFsX2xvZ3xub3JtYWxfcm5nfG5vdF9hX251bWJlcnxudW1fZWxlbWVudHN8b3JkZXJlZF9sb2dpc3RpY19sb2d8b3JkZXJlZF9sb2dpc3RpY19ybmd8b3dlbnNfdHxwYXJldG9fY2NkZl9sb2d8cGFyZXRvX2NkZnxwYXJldG9fY2RmX2xvZ3xwYXJldG9fbG9nfHBhcmV0b19ybmd8cGFyZXRvX3R5cGVfMl9jY2RmX2xvZ3xwYXJldG9fdHlwZV8yX2NkZnxwYXJldG9fdHlwZV8yX2NkZl9sb2d8cGFyZXRvX3R5cGVfMl9sb2d8cGFyZXRvX3R5cGVfMl9ybmd8cGl8cG9pc3Nvbl9jY2RmX2xvZ3xwb2lzc29uX2NkZnxwb2lzc29uX2NkZl9sb2d8cG9pc3Nvbl9sb2d8cG9pc3Nvbl9sb2dfbG9nfHBvaXNzb25fbG9nX3JuZ3xwb2lzc29uX3JuZ3xwb3NpdGl2ZV9pbmZpbml0eXxwb3d8cHJvZHxxcl9RfHFyX1J8cXVhZF9mb3JtfHF1YWRfZm9ybV9kaWFnfHF1YWRfZm9ybV9zeW18cmFua3xyYXlsZWlnaF9jY2RmX2xvZ3xyYXlsZWlnaF9jZGZ8cmF5bGVpZ2hfY2RmX2xvZ3xyYXlsZWlnaF9sb2d8cmF5bGVpZ2hfcm5nfHJlcF9hcnJheXxyZXBfbWF0cml4fHJlcF9yb3dfdmVjdG9yfHJlcF92ZWN0b3J8cmlzaW5nX2ZhY3RvcmlhbHxyb3VuZHxyb3d8cm93c3xyb3dzX2RvdF9wcm9kdWN0fHJvd3NfZG90X3NlbGZ8c2NhbGVkX2ludl9jaGlfc3F1YXJlX2NjZGZfbG9nfHNjYWxlZF9pbnZfY2hpX3NxdWFyZV9jZGZ8c2NhbGVkX2ludl9jaGlfc3F1YXJlX2NkZl9sb2d8c2NhbGVkX2ludl9jaGlfc3F1YXJlX2xvZ3xzY2FsZWRfaW52X2NoaV9zcXVhcmVfcm5nfHNkfHNlZ21lbnR8c2lufHNpbmd1bGFyX3ZhbHVlc3xzaW5ofHNpemV8c2tld19ub3JtYWxfY2NkZl9sb2d8c2tld19ub3JtYWxfY2RmfHNrZXdfbm9ybWFsX2NkZl9sb2d8c2tld19ub3JtYWxfbG9nfHNrZXdfbm9ybWFsX3JuZ3xzb2Z0bWF4fHNvcnRfYXNjfHNvcnRfZGVzY3xzb3J0X2luZGljZXNfYXNjfHNvcnRfaW5kaWNlc19kZXNjfHNxcnR8c3FydDJ8c3F1YXJlfHNxdWFyZWRfZGlzdGFuY2V8c3RlcHxzdHVkZW50X3RfY2NkZl9sb2d8c3R1ZGVudF90X2NkZnxzdHVkZW50X3RfY2RmX2xvZ3xzdHVkZW50X3RfbG9nfHN0dWRlbnRfdF9ybmd8c3ViX2NvbHxzdWJfcm93fHN1bXx0YWlsfHRhbnx0YW5ofHRjcm9zc3Byb2R8dGdhbW1hfHRvX2FycmF5XzFkfHRvX2FycmF5XzJkfHRvX21hdHJpeHx0b19yb3dfdmVjdG9yfHRvX3ZlY3Rvcnx0cmFjZXx0cmFjZV9nZW5fcXVhZF9mb3JtfHRyYWNlX3F1YWRfZm9ybXx0cmlnYW1tYXx0cnVuY3x1bmlmb3JtX2NjZGZfbG9nfHVuaWZvcm1fY2RmfHVuaWZvcm1fY2RmX2xvZ3x1bmlmb3JtX2xvZ3x1bmlmb3JtX3JuZ3x2YXJpYW5jZXx2b25fbWlzZXNfbG9nfHZvbl9taXNlc19ybmd8d2VpYnVsbF9jY2RmX2xvZ3x3ZWlidWxsX2NkZnx3ZWlidWxsX2NkZl9sb2d8d2VpYnVsbF9sb2d8d2VpYnVsbF9ybmd8d2llbmVyX2xvZ3x3aXNoYXJ0X2xvZ3x3aXNoYXJ0X3JuZylcXGIiLGU6aGxqcy5JTU1FRElBVEVfUkUscjoxMH0se2NOOiJmdW5jdGlvbiIsYjoiKD86YmVybm91bGxpfGJlcm5vdWxsaV9sb2dpdHxiZXRhfGJldGFfYmlub21pYWx8Ymlub21pYWx8Ymlub21pYWxfbG9naXR8Y2F0ZWdvcmljYWx8Y2F0ZWdvcmljYWxfbG9naXR8Y2F1Y2h5fGNoaV9zcXVhcmV8ZGlyaWNobGV0fGRvdWJsZV9leHBvbmVudGlhbHxleHBfbW9kX25vcm1hbHxleHBvbmVudGlhbHxmcmVjaGV0fGdhbW1hfGdhdXNzaWFuX2RsbV9vYnN8Z3VtYmVsfGh5cGVyZ2VvbWV0cmljfGludl9jaGlfc3F1YXJlfGludl9nYW1tYXxpbnZfd2lzaGFydHxsa2pfY29ycnxsa2pfY29ycl9jaG9sZXNreXxsb2dpc3RpY3xsb2dub3JtYWx8bXVsdGlfZ3B8bXVsdGlfZ3BfY2hvbGVza3l8bXVsdGlfbm9ybWFsfG11bHRpX25vcm1hbF9jaG9sZXNreXxtdWx0aV9ub3JtYWxfcHJlY3xtdWx0aV9zdHVkZW50X3R8bXVsdGlub21pYWx8bmVnX2Jpbm9taWFsfG5lZ19iaW5vbWlhbF8yfG5lZ19iaW5vbWlhbF8yX2xvZ3xub3JtYWx8b3JkZXJlZF9sb2dpc3RpY3xwYXJldG98cGFyZXRvX3R5cGVfMnxwb2lzc29ufHBvaXNzb25fbG9nfHJheWxlaWdofHNjYWxlZF9pbnZfY2hpX3NxdWFyZXxza2V3X25vcm1hbHxzdHVkZW50X3R8dW5pZm9ybXx2b25fbWlzZXN8d2VpYnVsbHx3aWVuZXJ8d2lzaGFydClcXGIiLGU6aGxqcy5JTU1FRElBVEVfUkUscjoxMH0se2NOOiJrZXl3b3JkIixiOiIoPzpmb3J8aW58d2hpbGV8aWZ8dGhlbnxlbHNlfHJldHVybnxsb3dlcnx1cHBlcnxwcmludHxpbmNyZW1lbnRfbG9nX3Byb2J8aW50ZWdyYXRlX29kZXxyZWplY3QpXFxiIixlOmhsanMuSU1NRURJQVRFX1JFLHI6MTB9LHtjTjoia2V5d29yZCIsYjoiKD86aW50fHJlYWx8dmVjdG9yfHNpbXBsZXh8dW5pdF92ZWN0b3J8b3JkZXJlZHxwb3NpdGl2ZV9vcmRlcmVkfHJvd192ZWN0b3J8bWF0cml4fGNob2xlc2t5X2ZhY3Rvcl9jb3Z8Y2hvbGVza3lfZmFjdG9yX2NvcnJ8Y29ycl9tYXRyaXh8Y292X21hdHJpeHx2b2lkKVxcYiIsZTpobGpzLklNTUVESUFURV9SRSxyOjV9LHtjTjoia2V5d29yZCIsYjoiKD86ZnVuY3Rpb25zfGRhdGF8dHJhbnNmb3JtZWRcXHMrZGF0YXxwYXJhbWV0ZXJzfHRyYW5zZm9ybWVkXFxzK3BhcmFtZXRlcnN8bW9kZWx8Z2VuZXJhdGVkXFxzK3F1YW50aXRpZXMpXFxiIixlOmhsanMuSU1NRURJQVRFX1JFLHI6NX1dfX07aGxqcy5MQU5HVUFHRVMueG1sPWZ1bmN0aW9uKCl7dmFyIGI9IltBLVphLXowLTlcXC5fOi1dKyI7dmFyIGE9e2VXOnRydWUsYzpbe2NOOiJhdHRyaWJ1dGUiLGI6YixyOjB9LHtiOic9IicsckI6dHJ1ZSxlOiciJyxjOlt7Y046InZhbHVlIixiOiciJyxlVzp0cnVlfV19LHtiOiI9JyIsckI6dHJ1ZSxlOiInIixjOlt7Y046InZhbHVlIixiOiInIixlVzp0cnVlfV19LHtiOiI9IixjOlt7Y046InZhbHVlIixiOiJbXlxccy8+XSsifV19XX07cmV0dXJue2NJOnRydWUsZE06e2M6W3tjTjoicGkiLGI6IjxcXD8iLGU6IlxcPz4iLHI6MTB9LHtjTjoiZG9jdHlwZSIsYjoiPCFET0NUWVBFIixlOiI+IixyOjEwLGM6W3tiOiJcXFsiLGU6IlxcXSJ9XX0se2NOOiJjb21tZW50IixiOiI8IS0tIixlOiItLT4iLHI6MTB9LHtjTjoiY2RhdGEiLGI6IjxcXCFcXFtDREFUQVxcWyIsZToiXFxdXFxdPiIscjoxMH0se2NOOiJ0YWciLGI6IjxzdHlsZSg/PVxcc3w+fCQpIixlOiI+IixrOnt0aXRsZTp7c3R5bGU6MX19LGM6W2FdLHN0YXJ0czp7Y046ImNzcyIsZToiPC9zdHlsZT4iLHJFOnRydWUsc0w6ImNzcyJ9fSx7Y046InRhZyIsYjoiPHNjcmlwdCg/PVxcc3w+fCQpIixlOiI+IixrOnt0aXRsZTp7c2NyaXB0OjF9fSxjOlthXSxzdGFydHM6e2NOOiJqYXZhc2NyaXB0IixlOiI8XC9zY3JpcHQ+IixyRTp0cnVlLHNMOiJqYXZhc2NyaXB0In19LHtjTjoidmJzY3JpcHQiLGI6IjwlIixlOiIlPiIsc0w6InZic2NyaXB0In0se2NOOiJ0YWciLGI6IjwvPyIsZToiLz8+IixjOlt7Y046InRpdGxlIixiOiJbXiAvPl0rIn0sYV19XX19fSgpOwpobGpzLmluaXRIaWdobGlnaHRpbmdPbkxvYWQoKTsKCg=="></script>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
pre:not([class]) {
background-color: white;
}
</style>
<script type="text/javascript">
if (window.hljs && document.readyState && document.readyState === "complete") {
window.setTimeout(function() {
hljs.initHighlighting();
}, 0);
}
</script>
<style type="text/css">
h1 {
font-size: 34px;
}
h1.title {
font-size: 38px;
}
h2 {
font-size: 30px;
}
h3 {
font-size: 24px;
}
h4 {
font-size: 18px;
}
h5 {
font-size: 16px;
}
h6 {
font-size: 12px;
}
.table th:not([align]) {
text-align: left;
}
</style>
</head>
<body>
<style type="text/css">
.main-container {
max-width: 940px;
margin-left: auto;
margin-right: auto;
}
code {
color: inherit;
background-color: rgba(0, 0, 0, 0.04);
}
img {
max-width:100%;
height: auto;
}
.tabbed-pane {
padding-top: 12px;
}
button.code-folding-btn:focus {
outline: none;
}
</style>
<div class="container-fluid main-container">
<!-- tabsets -->
<script>
$(document).ready(function () {
window.buildTabsets("TOC");
});
</script>
<!-- code folding -->
<div class="fluid-row" id="header">
<h1 class="title toc-ignore">Fundamentos da Inferência Bayesiana</h1>
<h4 class="author"><em>Igor Nascimento</em></h4>
<h4 class="date"><em>2017-07-31 10:00:00</em></h4>
</div>
<p><link href="data:text/css; charset=utf-8,%40font%2Dface%20%7B%0A%20%20font%2Dfamily%3A%20%27Rock%20Salt%27%3B%0A%20%20font%2Dstyle%3A%20normal%3B%0A%20%20font%2Dweight%3A%20400%3B%0A%20%20src%3A%20local%28%27Rock%20Salt%27%29%2C%20local%28%27RockSalt%27%29%2C%20url%28https%3A%2F%2Ffonts%2Egstatic%2Ecom%2Fs%2Frocksalt%2Fv6%2FQ94aHXFHGip10K5uxi1jOKCWcynf%5FcDxXwCLxiixG1c%2Ettf%29%20format%28%27truetype%27%29%3B%0A%7D%0A" rel="stylesheet"> <link href="data:text/css; charset=utf-8,%40font%2Dface%20%7B%0A%20%20font%2Dfamily%3A%20%27Sofia%27%3B%0A%20%20font%2Dstyle%3A%20normal%3B%0A%20%20font%2Dweight%3A%20400%3B%0A%20%20src%3A%20local%28%27Sofia%27%29%2C%20local%28%27Sofia%2DRegular%27%29%2C%20url%28https%3A%2F%2Ffonts%2Egstatic%2Ecom%2Fs%2Fsofia%2Fv5%2FKjFw0GXBsysA148bxeiikg%2Ettf%29%20format%28%27truetype%27%29%3B%0A%7D%0A" rel="stylesheet"></p>
<div id="eventos-probabilidade-e-condicionalidade" class="section level1">
<h1>Eventos, Probabilidade e Condicionalidade</h1>
<p>No livro <em>The History of Probability</em> o autor Todhunter relata de forma cronológica considerações de aspectos elementares da Teoria da Probabilidade de alguns notáveis personagens da história. No entanto, os primórdios da probabilidade está relatado nas correspondências entre Pierre De Fermat e Blaise Pascal sobre um problema de jogos em lançamento de dados no século XVII, citados em <em>Games, Gods & Gambling</em>.</p>
<p>Probabilidade é a área da matemática responsável por mensurar aquilo que não é determinístico. Os resultados dos lançamentos de dados ou moedas são considerados <strong>experimentos de probabilidade</strong>, pois estão sujeitos ao acaso.</p>
<p>Para o cálculo de probabilidades, considere as seguintes abordagens:</p>
<ul>
<li><p><strong>Clássica</strong>: “Suponha que dentre <span class="math inline">\(n\)</span> resultados possíveis e equiprováveis <span class="math inline">\(m\)</span> sejam favoráveis. A probabilidade de um evento favorável é <span class="math inline">\(p = \frac{m}{n}\)</span>.” Essa abordagem é o resultado das correspondências entre Fermat e Pascal.</p></li>
<li><p><strong>Frequentista</strong>: “Foram realizados <span class="math inline">\(n\)</span> experimentos dos quais <span class="math inline">\(m\)</span> eram favoráveis. A frequência relativa da ocorrência de um evento favorável é <span class="math inline">\(\frac{m}{n}\)</span>.” Jakob Bernoulli, em seu livro <em>Ars Conjectandi</em>, provou a convergência entre a frequência relativa de ocorrência e a probabilidade <span class="math inline">\(p\)</span> clássica a medida que aumenta-se o número de experimentos <span class="math inline">\(n\)</span>.</p></li>
</ul>
<p>Dito isso, vamos defir como <span class="math inline">\(P(A)\)</span> a probabilidade de ocorrer o evento <span class="math inline">\(A\)</span> em um determinado conjunto de valores possíveis <span class="math inline">\(\Omega\)</span>. Antes de tudo vamos aquecer o cérebro compreendendo os importantes conceitos de <strong>independência</strong> e <strong>permutabilidade</strong> para o estudo de probabilidade.</p>
<div id="independencia" class="section level2">
<h2>Independência</h2>
<p>Seja uma caixa contendo <strong>2 bolas brancas</strong> e <strong>3 pretas</strong>. Considere o experimento da retirada aleatória e observância da cor da bolas, com representação <strong>Bernoulli</strong> (<span class="math inline">\(X_1\)</span>) de ocorrência:</p>
<ul>
<li><p><span class="math inline">\(X_1 = 0\)</span> caso a bola retirada seja branca</p></li>
<li><p><span class="math inline">\(X_1 = 1\)</span> caso a bola retirada seja preta</p></li>
</ul>
<p>Pela abordagem clássica, a probabilidade da bola ser branca é <span class="math inline">\(P(X_1 = 0) = \frac{2}{5}\)</span> e de ser preta <span class="math inline">\(P(X_1 = 1) = \frac{3}{5}\)</span>.</p>
<p>Após a primeira retirada, e sem reposição, você retira mais uma bola. Qual a probabilidade da segunda bola ser branca?</p>
<p>A resposta mais intuitiva é <strong>DEPENDE</strong>. De fato, a probabilidade da segunda retirada (<span class="math inline">\(X_2\)</span>) está <strong>condicionada</strong> ao resultado da primeira. Perceba, caso a primeira seja branca, restam mais <span class="math inline">\(1\)</span> branca e as demais <span class="math inline">\(3\)</span> pretas, e, nesse caso, a probabilidade de uma segunda retirada branca é <span class="math inline">\(\frac{1}{4}\)</span>. Caso a primeira tenha sido preta, seria <span class="math inline">\(\frac{2}{4}\)</span>.</p>
<p>De maneira geral, a probabilidade do evento <span class="math inline">\(B\)</span> condicionada ao evento <span class="math inline">\(A\)</span> é representada por <span class="math inline">\(P(B|A)\)</span>. Nesse caso, temos que:</p>
<ul>
<li><p><span class="math inline">\(P(X_2 = 0|X_1 = 0) = \frac{1}{4}\)</span></p></li>
<li><p><span class="math inline">\(P(X_2 = 0|X_1 = 1) = \frac{2}{4}\)</span></p></li>
</ul>
<p>Dessa forma, dizemos que o evento <span class="math inline">\(X_2\)</span> é <strong>dependente</strong> do evento <span class="math inline">\(X_1\)</span>.</p>
<p>A probabilidade conjunta dos eventos <span class="math inline">\(A\)</span> e <span class="math inline">\(B\)</span> é expressa pela regra do produto: <span class="math display">\[P( B \cap A) = P(B|A) P(A)\]</span> que também pode ser expressa por <span class="math inline">\(P( B \cap A) = P( B , A)\)</span>.</p>
<p>Considere agora um outro experimento, o lançamento de uma <strong>moeda honesta</strong> e a observância da face virada para cima. Considere a representação <strong>Bernoulli</strong> (<span class="math inline">\(X_1\)</span>) de ocorrência:</p>
<ul>
<li><p><span class="math inline">\(0\)</span> caso o resultado do lançamento seja coroa</p></li>
<li><p><span class="math inline">\(1\)</span> caso o resultado do lançamento seja cara</p></li>
</ul>
<p>Por ser justa, a probabilidade do resultado cara é <span class="math inline">\(P(X_1 = 1) = \frac{1}{2}\)</span> e o de coroa é <span class="math inline">\(P(X_1 = 0) = \frac{1}{2}\)</span>.</p>
<p>Em seguida, a moeda é lançada novamente e o resultado representado por <span class="math inline">\(X_2\)</span>. Perceba que nesse caso, a probabilidade da ocorrência de cara no segundo lançamento também é igual a <span class="math inline">\(P(X_2 = 1) = \frac{1}{2}\)</span> por não ser afetado pelo resultado do primeiro lançamento.</p>
<p>Dizemos que <span class="math inline">\(X_2\)</span> é <strong>independente</strong> de <span class="math inline">\(X_1\)</span>, e nesse caso, temos que a regra do produto é:</p>
<span class="math display">\[\begin{eqnarray}
P(X_2 , X_1 ) & = P(X_2|X_1) P(X_1) \nonumber \\
P(X_2 , X_1 ) & = P(X_2)P(X_1 ) \nonumber
\end{eqnarray}\]</span>
</div>
<div id="permutabilidade" class="section level2">
<h2>Permutabilidade</h2>
<p>Permutabilidade é a propriedade da alteração no ordenamento de realizações em uma sequência de eventos sem que a probabilidade conjunta seja alterada.</p>
<p>Considere o lançamento de <span class="math inline">\(5\)</span> moedas não viciadas, com representação semelhante a apresentada anteriormente, sendo observado o seguinte resultado <span class="math inline">\((1,0,1,1,0)\)</span>, isto é, (cara,coroa,cara,cara,cora). Sabemos que os lançamentos são <strong>independentes</strong> e que a probabilidade conjunta desse evento é <span class="math inline">\(P(1,0,1,1,0) = P(X_5 = 1) \times P(X_4 = 0)\times P(X_3 = 1)\times P(X_2 = 1)\times P(X_1 = 0) = \frac{1}{2^5}\)</span>.</p>
<p>Nessa situação, caso fosse observado o evento <span class="math inline">\((1,1,1,0,0)\)</span>, a probabilidade não seria alterada, pois <span class="math inline">\(P(1,0,1,1,0) = P(1,1,1,0,0) =\frac{1}{2^5}\)</span>. Dessa forma, a ordem da ocorrências dos resultados cara não altera a probabilidade conjunta, desde que seja a mesma quantidade de resultados de “sucesso”. Esse é uma versão não rigora do Teorema de De Finetti.</p>
<p>De maneira geral, a independência de uma sequência de eventos garante a permutabilidade da mesma.</p>
<p>No entanto, a permutabililidade não é condição necessária para a permutabilidade, apenas suficiente. Isto é, ainda que uma sequência não seja formada por eventos independente, é possível que sejam permutáveis.</p>
<p>Considere a mesma representação do exemplo da caixa com bolas apresentado anteriormente para o caso da retirada de <span class="math inline">\(5\)</span> bolas sem reposição. Como visto, esses eventos não são <strong>independentes</strong>, pois a probabilidade de um determinado evento na sequência, depende do resultado observado nos eventos anteriores.</p>
<p>Dessa forma, vamos verificar se o evento <span class="math inline">\((1,0,1,1,0)\)</span> é permutável. Inicialmente, vamos calcular a probabilidade <span class="math inline">\(P(1,0,1,1,0)\)</span>:</p>
<span class="math display">\[\begin{eqnarray}
P(1,0,1,1,0) = & P(X_1 = 1)\times P(X_2 = 0 | X_1 = 1) & \times P(X_3 = 1 |X_2 = 0 , X_1 = 1) \times \nonumber \\
& P(X_4 = 1|X_3 = 1 ,X_2 = 0 , X_1 = 1) & \times P(X_5 = 0|X_4 = 1 , X_3 = 1 ,X_2 = 0 , X_1 = 1) \nonumber \\
P(1,0,1,1,0) = & \frac{3}{5} \times \frac{2}{4} \times \frac{2}{3} \times \frac{1}{2} \times \frac{1}{1} & = \frac{1}{10}\nonumber
\end{eqnarray}\]</span>
<p>Agora, vamos calcular a probabilidade <span class="math inline">\(P(1,1,1,0,0)\)</span>, alterando o resultado do segundo e o quarto evento:</p>
<span class="math display">\[\begin{eqnarray}
P(1,1,1,0,0) = & P(X_1 = 1)\times P(X_2 = 1 | X_1 = 1) & \times P(X_3 = 1 |X_2 = 1 , X_1 = 1) \times \nonumber \\
& P(X_4 = 0|X_3 = 1 ,X_2 = 1 , X_1 = 1) & \times P(X_5 = 0|X_4 = 0 , X_3 = 1 ,X_2 = 1 , X_1 = 1) \nonumber \\
P(1,1,1,0,0) = & \frac{3}{5} \times \frac{2}{4} \times \frac{1}{3} \times \frac{2}{2} \times \frac{1}{1} & = \frac{1}{10}\nonumber
\end{eqnarray}\]</span>
<p>Dessa forma, embora essa sequência seja formada por eventos dependentes, a ordem desses eventos não altera a probabilidade conjunta, tornando-a permutável.</p>
</div>
</div>
<div id="teorema-de-bayes" class="section level1">
<h1>Teorema de Bayes</h1>
<p>O teorema de bayes estabelece a seguinte relação entre dois eventos A e B, com probabilidades, respectivamente, P(A) e P(B):</p>
<p><span class="math display">\[P(A|B) = \frac{P( B | A) }{P(B)}P(A)\]</span></p>
<p>Considerando os eventos <span class="math inline">\(A\)</span> e <span class="math inline">\(B\)</span> permutáveis, o termo <span class="math inline">\(P(A \cap B)\)</span> é igual a <span class="math inline">\(P( B \cap A )\)</span> e, dessa forma, pode ser escrita como:</p>
<p><span class="math display">\[P( B \cap A ) = P( B | A)P(A)\]</span></p>
<p>Por fim, tem-se a seguinte relação: <span class="math display">\[P(A|B) = \frac{P( B | A) }{P(B)}P(A)\]</span></p>
<p>Nesse caso, o probabilidade <span class="math inline">\(P(A)\)</span> é denominada probabilidade a <em>priori</em>, isto é, a informação sobre o evento <span class="math inline">\(A\)</span> antes que se soubesse algo sobre o evento <span class="math inline">\(B\)</span>. Mais adiante, quando se tenha conhecimento sobre <span class="math inline">\(B\)</span>, a probabilidade relacionada ao evento <span class="math inline">\(A\)</span> deve ser atualizada pela probabilidade do evento <span class="math inline">\(B\)</span>. A probabilidade <span class="math inline">\(P(A|B)\)</span> é agora denominada probabilidade a <em>posteriori</em>. Sendo a razão <span class="math inline">\(\frac{P(B|A) }{P(B)}\)</span> o fator de atualização das informações sobre o evento <span class="math inline">\(A\)</span>.</p>
<p>Para compreender com mais detalhes o Teorema de Bayes é necessário entender a <strong>regra da probabilidade total (RPT)</strong>, que expressa a probabilidade total de um resultado por meio de vários eventos disjuntos.</p>
<p>Inicialmente, considere o problema em encontrar o valor para a probabilidade do evento <span class="math inline">\(A\)</span>, vide (a). Considere agora que seja possível particionar o espaço <span class="math inline">\(\Omega\)</span> em partes <span class="math inline">\(B_i\)</span> sem intersecções entre si, vide (b). A probabilidade <span class="math inline">\(A\)</span> pode ser determinada pela intersecção entre o evento <span class="math inline">\(A\)</span> e cada partição <span class="math inline">\(B_i\)</span>, vide (c) e (d).</p>
<p>Nos espaços amostrais <span class="math inline">\(\Omega\)</span> formados pela união de partes <span class="math inline">\(B_i\)</span> disjuntas (mutuamente exclusivas) a probabilidade de qualquer evento de <span class="math inline">\(\Omega\)</span> é:</p>
<span class="math display">\[\begin{eqnarray}
P(A) = & P(A \cap B_1) + P(A \cap B_2) + ... + P(A \cap B_N) \nonumber \\
P(A) = & P(A | B_1)P(B_1)+P(A | B_2)P(B_2) + ... + P(A | B_N)P(B_N)
\end{eqnarray}\]</span>
<p>Dessa forma, a probabilidade do evento <span class="math inline">\(A\)</span> pode ser representado por:</p>
<span class="math display">\[\begin{equation}
P(A) = \sum_{i=1}^N P(A | B_i)P(B_i)
\end{equation}\]</span>
<p></p>
</div>
<div id="aplicacao-simples" class="section level1">
<h1>Aplicação simples</h1>
<p>Um amigo muito próximo lhe pediu <span class="math inline">\(R\$ 1.000,00\)</span> emprestado (<span class="math inline">\(V_{emprestado}\)</span>) para solução financeira de uma emergência. Você é um investidor nato e não suporta a ideia de perder o patrimônio conquistado. Embora você decida ajudar seu amigo, você está preocupado com o <strong>risco</strong> do não pagamento do empréstimo e, por isso, cobrará juros <span class="math inline">\(T_{juros}\)</span> sobre o montante inicial emprestado:</p>
<span class="math display">\[\begin{eqnarray}
V_{devolvido} = V_{emprestado} \times (1 + T_{juros}) \nonumber
\end{eqnarray}\]</span>
<p>Você percebeu que o <strong>valor devolvido</strong> (<span class="math inline">\(V_{devolvido}\)</span>) do seu “investimento” ao final do período de empréstimo está sujeito às “variações do mercado”, que, nesse caso, estão relacionadas a um evento do não pagamento da dívida. Com isso, você define o <strong>valor esperado</strong> (<span class="math inline">\(V_{esperado}\)</span>) como o valor recebido ao final do período considerando tal incerteza.</p>
<p>Seja <span class="math inline">\(A\)</span> o evento indicativo do pagamento do seu amigo, então o valor esperado (<span class="math inline">\(V_{esperado}\)</span>) ao final do período de empréstimo é a média ponderada entre as possibilidades de valores devolvidos, <span class="math inline">\(V_{devolvido}\)</span> e <span class="math inline">\(0\)</span>, e suas respectivas probabilidades, <span class="math inline">\(P(A)\)</span> e <span class="math inline">\(1 - P(A)\)</span>:</p>
<span class="math display">\[\begin{eqnarray}
V_{esperado} = & V_{devolvido} \times P(A) & + 0 \times [1 - P(A)] \nonumber \\
V_{esperado} = & [V_{emprestado} \times (1 + T_{juros})] \times P(A) & + 0 \times [1 - P(A)] \nonumber \\
V_{esperado} = & [V_{emprestado} \times (1 + T_{juros})] \times P(A)
\end{eqnarray}\]</span>
<p>Da relação anterior, é possível obter a a taxa de juros adotada:</p>
<span class="math display">\[\begin{eqnarray}
T_{juros} = & \frac{V_{esperado}}{V_{emprestado} \times P(A)} - 1\nonumber \\
\end{eqnarray}\]</span>
<p>Você decide que o valor dos juros será determinado de maneira que o valor esperado seja igual ao investimento inicial, isto é, <span class="math inline">\(V_{esperado}=V_{emprestado}\)</span>. Dessa forma, a taxa de juros utilizada será:</p>
<span class="math display">\[\begin{eqnarray}
T_{juros} = & \frac{1000}{1000 \times P(A)} - 1 = \frac{1}{P(A)} - 1
\label{eq:juros}
\end{eqnarray}\]</span>
<p>Você utilizará uma <em>proxy</em> o evento <span class="math inline">\(A\)</span> baseado no cadastro nacional de bons ou maus pagador. Infelizmente, você não tem acesso à esse cadastro. No entanto, você sabe que, assim como você, seu amigo possui conta no banco ABC, que regularmente publica informações agregadas sobre as operações com os clientes.</p>
<p>Tal banco realizou um levantamento informando que <span class="math inline">\(1\)</span> em cada <span class="math inline">\(10\)</span> clientes possuem registo ativo no cadastro nacional de maus pagadores. Dessa forma, a probabilidade do pagamento do seu amigo se concretizar é de <span class="math inline">\(P(A)=\frac{9}{10} = 90\%\)</span>.</p>
Dito isso, utilizando a taxa de juros que você deve adotar é:
<span class="math display">\[\begin{eqnarray}
T_{juros} = & \frac{1}{0.9} - 1 = 11.111\% \nonumber
\end{eqnarray}\]</span>
<p>Dessa forma, a <em>priori</em>, seu amigo deveria lhe pagar R$ <span class="math inline">\(1.111,11\)</span> ao final do período para garantir que, em média e desconsiderando inflação, seu investimento inicial seja recuperado.</p>
<p>Nos informativos do banco também consta que <span class="math inline">\(2\)</span> em cada <span class="math inline">\(4\)</span> maus pagadores atrasam o pagamento do boleto, enquanto dentre os bons pagadores, apenas <span class="math inline">\(1\)</span> a cada <span class="math inline">\(20\)</span> atrasam suas obrigações.</p>
<p>Durante a conversa, seu amigo te informou que possui boletos atrasados nesse banco. Baseado nessa <strong>nova informação</strong>, qual a probabilidade do seu amigo ser mau pagador dado que atrasou o pagamento? Qual a nova taxa de juros que você deve adotar para proteger seu “investimento”?</p>
<p>O Teorema de Bayes responde diretamente essa pergunta. Antes disso, vamos modelar os eventos e identificar suas probabilidades. Considere o evento <span class="math inline">\(A\)</span> o cliente ser um bom pagador e o evento <span class="math inline">\(B\)</span> o atraso do pagamento de um boleto da obrigação financeira nesse banco.</p>
<ul>
<li>Ser bom pagador: evento <span class="math inline">\(A\)</span>. Sendo <span class="math inline">\(P(A)=\frac{9}{10}\)</span>.</li>
<li>Ser mal pagador: evento <span class="math inline">\(A^{c}\)</span>. Sendo <span class="math inline">\(P(A^{c})=1-P(A)=\frac{1}{10}\)</span>.</li>
<li>Atraso no pagamento: evento <span class="math inline">\(B\)</span>. Sendo <span class="math inline">\(P(B)=\)</span> não informado.</li>
<li>Atraso no pagamento dos bons pagadores: evento <span class="math inline">\(B|A\)</span>. Sendo <span class="math inline">\(P(B|A)=\frac{1}{20}\)</span>.</li>
<li>Atraso no pagamento dos mal pagadores: evento <span class="math inline">\(B|A^{c}\)</span>. Sendo <span class="math inline">\(P(B|A^{c})=\frac{2}{4}\)</span>.</li>
<li>Probabilidade do seu amigo ser bom pagadores caso tenha atrasado o pagamento. <span class="math inline">\(P(A|B)=\)</span>?.</li>
</ul>
Utilizando o Teorema de Bayes e a RPT em <span class="math inline">\(P(B)\)</span>, tem-se que:
<span class="math display">\[\begin{eqnarray}
P(A|B) = & \frac{P( B | A) }{P(B)}P(A) \nonumber \\
P(A|B) = & \left[ \frac{P( B | A) }{P(B | A)P(A)+P(B | A^{c})P(A^{c})}\right]P(A) \nonumber \\
P(A|B) = & \left[ \frac{\frac{1}{20} }{\frac{1}{20}\frac{9}{10}+\frac{2}{4}\frac{1}{10}}\right]\frac{9}{10} \nonumber \\
P(A|B) = & \left[ \frac{38}{20}\right]\frac{9}{10} \nonumber \\
P(A|B) = & 47.36\% \nonumber
\end{eqnarray}\]</span>
<p>Dessa forma, após saber que ele não pagou o boleto do banco, a probabilidade de ser bom pagador a <em>posteriori</em> reduz em quase a metade da <em>priori</em>. Dessa forma, a nova taxa de juros é <span class="math inline">\(\frac{1}{0.4736} - 1 = 111.111\%\)</span>, fazendo com que o valor cobrado seja de R$ <span class="math inline">\(2.111,11\)</span>.</p>
<p>Esse é uma versão introdutória do Teorema de Bayes e serve para motivação para posts futuros que exigirão mais pré requisitos em teoria de probabilidades. Enquanto isso, vamos ver uma aplicação me modelos de séries temporais das propriedades do Teorema de Bayes.</p>
</div>
<div id="modelos-de-espacos-de-estados" class="section level1">
<h1>Modelos de Espaços de Estados</h1>
<p>Os modelos de Espaços de Estados são uma classe de modelos utilizados para estudar e conhecer séries temporais, conjunto de valores observados ao longo de instantes no tempo, podendo ser representado por <span class="math inline">\((Y_t)_{(t>0)}\)</span>, sendo <span class="math inline">\(t=1,2,\cdots,T\)</span> o indexador que representa o instante de mensuração da quantidade.</p>
<p>Considere a seguinte estrutura de dependência para a série temporal <span class="math inline">\(Y_t\)</span>:</p>
<p><span class="math display">\[Y_t = \theta + \epsilon_t\]</span></p>
<p>É importante notar que a <span class="math inline">\(Y_1,Y_2,....,Y_T\)</span> é <strong>condicionamente independente</strong> por meio do do parâmetro <span class="math inline">\(\theta\)</span>. Em outras palavras, as informações em <span class="math inline">\(t\)</span> são independentes das em <span class="math inline">\(t-1\)</span>, condicionadas a informação de <span class="math inline">\(\theta\)</span>. Como exemplo, para <span class="math inline">\(t=2\)</span>, essa relação é determinada pelo resultado <span class="math inline">\(P(Y_2|Y_1,\theta) = P(Y_2|\theta)\)</span>. Para um <span class="math inline">\(t\)</span> qualquer, tem-se que <span class="math inline">\(P(Y_t|Y_1,Y_2,...,Y_{t-1},\theta) = P(Y_t|\theta)\)</span>.</p>
<p>Essa propriedade permite que a distribuição conjunta dessa série possa ser reescrita por:</p>
<span class="math display">\[\begin{eqnarray}
P(Y_T,....,Y_1|\theta) = & \frac{P(Y_T,....,Y_1,\theta)}{P(\theta)} \\
P(Y_T,....,Y_1|\theta) = & \frac{P(Y_T|Y_{T-1},....,Y_2,Y_1,\theta)P(Y_{T-1},....,Y_2,Y_1,\theta)}{P(\theta)} \\
P(Y_T,....,Y_1|\theta) = & P(Y_T|\theta)\frac{P(Y_{T-1},....,Y_2,Y_1,\theta)}{P(\theta)} \\
\end{eqnarray}\]</span>
<p>Replicando esse procedimento para a série inteira, não é difícil chegar a seguinte resultado:</p>
<p><span class="math display">\[P(Y_T,....,Y_1|\theta) = \prod^T_{t=1} P(Y_t|\theta)P(\theta)\]</span></p>
<p>Dessa forma, a distribuição conjunta dessa série é incrementada sequêncialmente a cada nova informação <span class="math inline">\(Y_t\)</span> por meio da distribuição condicional <span class="math inline">\(P(Y_t|\theta)\)</span>. Dessa relação, é possível obter <strong>atualizações</strong> sobre <span class="math inline">\(\theta\)</span>. Vamos entender esse conceito com o estudo de um caso.</p>
</div>
<div id="modelos-gaussianos" class="section level1">
<h1>Modelos Gaussianos</h1>
<p>Um investidor está interessado em conhecer melhor o comportamento dos retornos mensais do Índice Ibovespa utilizando a estrutura de dependência apresentada anteriormente:</p>
<p><span class="math display">\[Y_t = \theta + \epsilon_t\]</span></p>
<p>Com <span class="math inline">\(\epsilon_t \sim N(0,\sigma^2)\)</span>, sendo <span class="math inline">\(\sigma^2\)</span> conhecido e igual a <span class="math inline">\(5\)</span>. Nesse caso, temos a dependência condicional:</p>
<p><span class="math display">\[ Y_1,Y_2,...,Y_T|\theta \sim N(\theta,\sigma^2) \]</span></p>
<p>Conversando com colegas ele obteve a <strong>informação inicial</strong> de que o comportamento da média dos retornos mensais (<span class="math inline">\(\theta\)</span>) tem distribuição Normal como média <span class="math inline">\(\eta_0=2\)</span> e variância <span class="math inline">\(\phi_0^2 = 2\)</span>. Essa é a informação a <em>priori</em> do parâmetro da série temporal de interesse. Com base nessa informação, o investidor pretende observar os índices ao final de cada mês e <strong>atualizar</strong> o conhecimento sobre <span class="math inline">\(\theta\)</span>, a distribuição a <em>posteriori</em>, a medida que novas observações da série do índice mensal do Ibovespa <span class="math inline">\(Y_t\)</span> estejam disponíveis.</p>
<p>Sabendo que o valor do índice Ibovespa para janeiro de 2017 foi <a href="http://www.bmfbovespa.com.br/pt_br/servicos/market-data/historico/mercado-a-vista/series-historicas/"><span class="math inline">\(Y_1=7.38\)</span></a>, qual é a distribuição e os parâmetros da <em>posteiriori</em> <span class="math inline">\(P(\theta|Y_1)\)</span>?.</p>
<p>Ao final do primeiro mês o investidor pretende obter a distribuição <span class="math inline">\(P(\theta|Y_1)\)</span> e para isso utiliza o Teorema de Bayes, chegando a seguinte relação:</p>
<p><span class="math display">\[P(\theta|Y_1) = \frac{P(Y_1,\theta)}{p(Y_1)} = \frac{P(Y_1|\theta) P(\theta)}{\int P(Y_1|\theta) P(\theta)}\]</span></p>
<p>O desafio, nesse ponto, é obter a distribuição conjunta <span class="math inline">\(P(Y_1,\theta)\)</span> por meio do produto entre a probabilidade da série, <span class="math inline">\(P(Y_1|\theta)\)</span>, e a <em>priori</em> do parâmetro <span class="math inline">\(\theta\)</span>, <span class="math inline">\(P(\theta)\)</span>. Utilizando informaçõe das distribuições normais informadas, temos que:</p>
<span class="math display">\[\begin{eqnarray}
P(Y_1,\theta) & = & P(Y_1|\theta) P(\theta) \\
P(Y_1,\theta) & =& (2 \sigma^2)^{-\frac{1}{2}}e^{[-(2\sigma^2)^{-1}(y_1 - \theta)^2]} \times (2\phi_0^2)^{-\frac{1}{2}}e^{[-(2\phi_0^2)^{-1}(\theta - \eta_0)^2]} \\
P(Y_1,\theta) & =& (2 \sigma^2)^{-\frac{1}{2}} e^{[-(2\sigma^2)^{-1}(y_1^2 - 2y\theta + \theta^2)]} \times (2\phi_0^2)^{-\frac{1}{2}}e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0 + \eta_0^2)]} \\
P(Y_1,\theta) & = & \left[(2 \sigma^2)^{-\frac{1}{2}}(2\phi_0^2)^{-\frac{1}{2}}\right]\times\left[ e^{[-(2\sigma^2)^{-1}( \theta^2 - 2y_1\theta )]} \times e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0)]} \right]\times\left[ e^{[-(2\sigma^2)^{-1}(y^2)]} e^{[-(2\phi_0^2)^{-1}(\eta_0^2)]}\right]\\
P(Y_1,\theta) & = & c3\times\left[ e^{[-(2\sigma^2)^{-1}( \theta^2 - 2y_1\theta )]} \times e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0)]} \right]\\
P(Y_1,\theta) & = & c3\times\left[ e^{[-(2\sigma^2)^{-1}( \theta^2 - 2y\theta )]} \times e^{[-(2\phi_0^2)^{-1}(\theta^2 - 2\theta\eta_0)]} \right]\\
P(Y_1,\theta) & = & c3\times\left[ e^{[-(2)^{-1}( \theta^2 (\sigma^{-2} + \phi_0^{-2}) - 2\theta(y_1\sigma^{-2} + \eta_0 \phi_0^{-2}) )]} \right]\\
P(Y_1,\theta) & = & c3\times\left[ e^{[-(2)^{-1}(\sigma^{-2} + \phi_0^{-2})( \theta^2 - 2\theta\frac{(y_1\sigma^{-2} + \eta_0 \phi_0^{-2})}{(\sigma^{-2} + \phi_0^{-2})} )]} \right]\\
\end{eqnarray}\]</span>
<p>Perceba que, a menos de constantes, essa distribuição conjunta tem o núcleo de uma distribuição normal com média:</p>
<p><span class="math display">\[\frac{(y\sigma^{-2} + \eta \phi^{-2})}{(\sigma^{-2} + \phi^{-2})} = \frac{y_1\phi^2 + \eta \sigma^2}{\sigma^2 + \eta^2} = \frac{7.38 \times 2 + 2 \times 5}{2 + 5} = 3.53 \]</span></p>
<p>e variância</p>
<p><span class="math display">\[\frac{1}{\sigma^{-2} + \phi^{-2}} = \frac{1}{5^{-1} + 2^{-1}} = 1.42\]</span></p>
<p>Perceba que o denominador é a integração dessa distribuição conjunta (numerador) com relação a <span class="math inline">\(\theta\)</span> e, com um pouco de esforço algébrico, é a <strong>constante normalizadora</strong>. Mais detalhes dos processo podem ser consultados em Petris et al (2009).</p>
<p>Dessa forma, temos que <span class="math inline">\(\theta|Y_1 \sim N(3.53,1.42)\)</span>.</p>
<p>Essa é a distribuição a <em>posteriori</em> de <span class="math inline">\(\theta\)</span> com relação a informação <span class="math inline">\(Y_1\)</span>. O gráfico a seguir apresenta a comparação entre as distribuições <em>priori</em> e <em>posteriori</em>.</p>
<p>A distribuição a <em>posteriori</em> tem seus parâmetros <span class="math inline">\(\eta_t\)</span> e <span class="math inline">\(\phi_t\)</span> atualizados no instante <span class="math inline">\(t\)</span> a medida que se tenha acesso a novas informações da série temporal. Em todos esses instantes, a <em>posteriori</em> obtida no passo <span class="math inline">\(t\)</span> é a nova <em>priori</em> para a estimação em <span class="math inline">\(t+1\)</span>.</p>
<p>A repetição do processo de estimação em um instante <span class="math inline">\(t\)</span> qualquer fornece o seguinte resultado:</p>
<p><span class="math display">\[\theta|Y_1,Y_2,...Y_t \sim N(\eta_t,\phi_t)\]</span></p>
<p>Sendo <span class="math inline">\(\eta_t\)</span> a média entre a o valor inical <span class="math inline">\(\eta_0\)</span> e a média da série <span class="math inline">\(Y_1,...,Y_t\)</span> ponderados pelas variâncias do processo:</p>
<p><span class="math display">\[\eta_t = \frac{\frac{\sum_{i=1}^t y_i}{t} \phi_0^2 + \eta_0 \frac{\sigma^2}{t}}{\frac{\sigma^2}{t} + \eta_0^2}\]</span></p>
<p>e a variância</p>
<p><span class="math display">\[\phi_t = t\sigma^{-2} + \phi_0^{-2}\]</span></p>
</div>
<div id="consideracoes-finais" class="section level1">
<h1>Considerações finais</h1>
<p>O conteúdo do post, embora simples, apresenta de que maneira a Teoria Bayesiana é usada para modelos de séries temporais, permitindo que haja a atualização do conhecimento a medida que se tenha acesso a novas informações.</p>
<p>Por fim, é possível destacar três pontos de destaque em estudos nessa área:</p>
<ul>
<li><p>estrutura de dependência temporal que incorpore tendência, sazonalidade</p></li>
<li><p>relações não gaussianas e não-lineares.</p></li>
<li><p>aumentar número de parâmetros desconhecidos ( ex.: <span class="math inline">\(\sigma^2\)</span>)</p></li>
</ul>
<p>O aumento da complexidade requer a utilização de técnicas estatísticas e computacionais mais sofisticadas para lidar com o processo de estimação. É comum encontrar distribuições que não tenham formas fechadas ou situações com alta dimensão devido a quantidade de parâmetros e tamanho da série temporal. Nesses casos, técnicas como <a href="https://lamfo-unb.github.io/2017/06/28/Bootstrap/">Bootstrap</a>, MCMC, Gibbs Sampler e Filtro de Partículas podem ser adotadas.</p>
<div id="referencias" class="section level2">
<h2>Referências</h2>
<p>Todhunter, Isaac (1873). History of the Mathematical Theories of Attraction and Figure of the Earth from Newton to Laplace.</p>
<p>David, F. N. (1962). Games, gods and gambling.</p>
<p>Petris, Giovanni, Sonia Petrone, and Patrizia Campagnoli. (2009). Dynamic Linear Models With R.</p>
</div>
</div>
</div>
<script>
// add bootstrap table styles to pandoc tables
function bootstrapStylePandocTables() {
$('tr.header').parent('thead').parent('table').addClass('table table-condensed');
}
$(document).ready(function () {
bootstrapStylePandocTables();
});
</script>
<!-- dynamically load mathjax for compatibility with self-contained -->
<script>
(function () {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
document.getElementsByTagName("head")[0].appendChild(script);
})();
</script>
</body>
</html>
Os Três Tipos de Aprendizado de Máquina2017-07-27T16:55:44+00:00http://lamfo-unb.github.io/2017/07/27/tres-tipos-am<h2 id="aprendizado-de-máquina">Aprendizado de Máquina</h2>
<h3 id="formalmente">Formalmente:</h3>
<p>Aprendizado de máquina é definido por um sistema computacional que busca realizar uma <strong>tarefa</strong> \(T\), aprendendo a partir de uma <strong>experiência</strong> \(E\) procurando melhorar uma <strong>performance</strong> \(P\).</p>
<h3 id="mas-afinal-o-que-isto-quer-dizer">Mas afinal, o que isto quer dizer?</h3>
<p align="center">
<img src="/img/tres-tipos-am/f002.jpg" width="400" />
</p>
<p>Basicamente, um algoritmo pode aprender a atingir um objetivo a partir de um grande volume de dados - suas <strong>experiências</strong>. Eis um exemplo para ficar mais claro. Suponha que nossa <strong>tarefa</strong> seja prever o resultado de um jogo de futebol. Como podemos fazer isso?</p>
<p>Poderíamos fornecer ao computador dados sobre o técnico, composição do time, formação tática, etc., seguidos dos resultados das partidas. Com um grande volume de dados em formato de pares <strong>(variáveis, resultados)</strong>, esperamos que o computador possa aprender quais padrões levam à vitória. Também esperamos que o computador acerte mais conforme lhe apresentamos mais dados, pois ele terá mais exemplos de padrões que pode <strong>generalizar</strong> para situações ainda não vistas. Assim, quanto mais dados, isto é, quanto mais experiência, melhores serão os resultados, isto é, melhor será a nossa <strong>performance</strong></p>
<h2 id="aprendizado-supervisionado">Aprendizado Supervisionado</h2>
<p>Isto é o que chamamos de <strong>Aprendizado de Máquina Supervisionado</strong>: Quando tentamos prever uma <strong>variável dependente</strong> a partir de uma lista de <strong>variáveis independentes</strong>. Por exemplo:</p>
<table>
<thead>
<tr>
<th>Var. Independentes</th>
<th>Var. Dependentes</th>
</tr>
</thead>
<tbody>
<tr>
<td>Anos de Carreira, Formação, Idade</td>
<td>Salário</td>
</tr>
<tr>
<td>Idade do Carro, Idade do Motorista</td>
<td>Risco de Acidente Automotivo</td>
</tr>
<tr>
<td>Texto de um livro</td>
<td>Escola Literária</td>
</tr>
<tr>
<td>Temperatura</td>
<td>Receita de venda de sorvete</td>
</tr>
<tr>
<td>Imagem da Rodovia</td>
<td>Ângulo da direção de um carro autônomo</td>
</tr>
<tr>
<td>Histórico escolar</td>
<td>nota no ENEM</td>
</tr>
</tbody>
</table>
<p>Note que a característica básica de sistemas de aprendizado supervisionado é que os dados que utilizamos para treiná-los <strong>contém a resposta desejada</strong>, isto é, contém a variável dependente resultante das variáveis independentes observadas. Nesse caso, dizemos que os <strong>dados são anotados</strong> com as respostas ou classes a serem previstas.</p>
<p>Dentre as técnicas mais conhecidas para resolver problemas de aprendizado supervisionado estão regressão linear, regressão logística, redes neurais artificiais, máquina se suporte vetorial (ou máquinas kernel), árvores de decisão, k-vizinhos mais próximos e Bayes ingênuo. Aprendizado de máquina supervisionado é a área que concentra a maioria das aplicações bem sucedidas e onde a maioria dos problemas já estão bem definidos.</p>
<p align="center">
<img src="/img/tres-tipos-am/f017.png" width="400" />
</p>
<h2 id="aprendizado-não-supervisionado">Aprendizado Não Supervisionado</h2>
<p>Mas nem todos os problemas podem ser resolvidos desta forma. Em alguns casos, conseguir dados anotados é extremamente custoso ou até mesmo impossível. Por exemplo, imagine que você é dono de um comércio e quer conhecer o perfil dos seus consumidores. Pode haver um perfil de consumidor que sempre compra vinho e queijo ou que compra carne e carvão ou ainda leite em pó e fralda. Se esse for o caso, colocar esses produtos em prateleiras distantes pode aumentar vendas, já que aumentará o tempo e o percurso do cliente no mercado. No entanto, nesse caso não estamos anotado para cada compra à qual perfil o consumidor pertence. Mais ainda, sequer sabemos quantos perfis de consumidores há.</p>
<p>Nesse caso, o computador terá que descobrir os perfis sem dados anotados e precisaremos de métodos de aprendizado não supervisionados. Uma opção seria observar nos registros de compras se existem padrões repetidos e que permitiriam a inferência de um grupo ou perfil de consumidor. Outra opção seria ver diretamente quais produtos são frequentemente comprados juntos e, então, aprender uma regra associativa entre eles.</p>
<p>De uma forma geral, com aprendizado não supervisionado queremos achar uma representação mais informativa dos dados que temos. Geralmente, essa representação mais informativa é também mais simples, condensando a informação em pontos mais relevantes. Alguns exemplos são:</p>
<table>
<thead>
<tr>
<th>Dados</th>
<th>Forma Representativa</th>
</tr>
</thead>
<tbody>
<tr>
<td>Transações bancárias</td>
<td>Normalidade da transação</td>
</tr>
<tr>
<td>Registros de Compras</td>
<td>Associação entre produtos</td>
</tr>
<tr>
<td>Dados Multidimensionais</td>
<td>Dados com dimensão reduzida</td>
</tr>
<tr>
<td>Registros de Compras</td>
<td>Perfil dos consumidores</td>
</tr>
<tr>
<td>Palavras em um texto</td>
<td>Representação matemática das palavras</td>
</tr>
</tbody>
</table>
<p align="center">
<img src="/img/tres-tipos-am/f008.png" width="600" />
</p>
<p>Outros exemplos de aplicações de aprendizado não supervisionados são sistemas de recomendação de filmes ou músicas, detecção de anomalias e visualização de dados. Dentre as técnicas mais conhecidas para resolver problemas de aprendizado não supervisionado estão redes neurais artificiais, Expectativa-Maximização, clusterização k-médias, máquina se suporte vetorial (ou máquinas kernel), Clusterização Hierárquica, <em>word2vec</em>, análise de componentes principais, florestas isoladoras, mapas auto-organizados, máquinas de Boltzmann restritas, <em>eclat</em>, <em>apriori</em>, <em>t-SNE</em>. Problemas de aprendizado não supervisionado são consideravelmente mais complicados do que problemas de aprendizado supervisionado, principalmente porque não temos a reposta anotada nos dados. Como consequência, é extremamente complicado e controverso avaliar um modelo de aprendizado não supervisionado e esse tipo de modelo está na fronteira do conhecimento em aprendizado de máquina.</p>
<h2 id="aprendizagem-por-reforço">Aprendizagem por reforço</h2>
<p>A terceira abordagem de aprendizagem de máquinas é a chamada “aprendizagem por reforço”, em que a máquina tenta aprender qual é a melhor ação a ser tomada, dependendo das circunstâncias na qual essa ação será executada.</p>
<p>O futuro é uma variável aleatória: como não se sabe a priori o que irá acontecer, é desejável uma abordagem que leve em consideração essa incerteza, e consiga incorporar as eventuais mudanças no ambiente do processo de tomada da melhor decisão. Essa ideia de fato deriva do conceito de “aprendizagem por reforço” da psicologia, no qual uma <strong>recompensa</strong> ou <strong>punição</strong> é dada a um agente, dependendo da decisão tomada; com o tempo e a repetição dos experimentos, espera-se que o agente consiga associar as ações que geram maior recompensa para cada situação que o ambiente apresenta, e passe a evitar as ações que geram punição ou recompensa menor. Na psicologia, essa abordagem é chama de <em>behaviorismo</em> e tem B. F. Skinner como um dos principais expoentes, um famoso psicólogo que, dentre outros experimentos, usou a ideia de recompensas e punições para treinar pombos para conduzir mísseis na Segunda Guerra Mundial.</p>
<p>Essa mesma ideia é vista no aprendizado de máquinas: a máquina observa um “estado da natureza” dentre o conjunto de cenários futuros possíveis e, com base nisso, escolhe uma ação a se tomar e recebe a recompensa associada a essa ação específica e nesse estado específico obtendo, assim, a informação dessa combinação. O processo se repete até que a máquina seja capaz de escolher a melhor ação a se tomar para cada um dos cenários possíveis a serem observados no futuro.</p>
<p>Ilustrando com um exemplo bem simples: suponha que você queira adestrar seu cão a se sentar ao seu comando por essa abordagem. De primeira, dificilmente o animal executará o comando requerido, e você responde a isso dando um “reforço negativo” (punição), repreendendo-o verbalmente, com suas expressões faciais ou mesmo com uma pancada de jornal (ou algo mais hostil, a depender do seu temperamento…). Quando o cão se aproxima do que deveria fazer, você pode dar “reforços positivos” como sinais de aprovação ou incentivo. Se o cão de fato sentar após o comando, você lhe dá uma recompensa - um biscoitinho, por exemplo. Com várias repetições desse mesmo experimento, espera-se que, com o tempo, o cão passe a associar a relação de “causa-efeito” entre o comando e a recompensa a ser recebida, e com isso “aprenda” a obedecer a esse comando. O famoso experimento do “cão de Pavlov” ilustra bem esse paradigma de aprendizagem. Ivan Pavlov foi um cientista russo notório por apresentar a ideia do “reflexo condicionado”, baseado no seguinte experimento: apresentando um pedaço de carne a um cão, o animal passa a salivar, desejando o alimento. Em vez de apresentar apenas a carne, Pavlov soava uma campainha sempre que isso acontecia; com a repetição, o cão passava a associar os dois “estímulos” (carne e campainha) e salivar assim que ouve a campainha.</p>
<p align="center">
<img src="/img/tres-tipos-am/f011.jpg" width="450" />
</p>
<p>Essa ideia é bastante versátil quando a transportamos para o âmbito da ciência de dados: em vez de adestrar cachorros, podemos por exemplo construir uma máquina que monta portfolios no mercado financeiro e que ajusta a combinação de ativos comprados/vendidos a depender da “recompensa” (retorno financeiro) da carteira anterior e da evolução (“estados”) do mercado. Ou ainda um automóvel que dirige “sozinho”, que toma decisões dependendo do cenário que observa ao redor, recebendo recompensas negativas quando colide com o ambiente ou com outros veículos, e com repetidas etapas, aos poucos “aprenda” a contornar os obstáculos.</p>
<p align="center">
<img src="/img/tres-tipos-am/f021.jpg" width="500" />
</p>
<p>Vamos mais além: voltando ao exemplo do adestramento de cães, suponha que, depois de tê-lo ensinado a sentar com sucesso, você queira fazer um teste de obediência - fazer o cão ficar sentado enquanto você anda para trás, até chegar a uma distância de cinco metros dele. Caso o cão se sente, você dá a ele o biscoitinho (assim como antes); mas caso ele não se levante até você ficar a cinco metros dele, você dá a ele uma recompensa maior (um pedaço de bife, por exemplo). Como o cão poderia ganhar a recompensa maior? Note que agora o cão tem uma “escolha difícil”: ele pode simplesmente sentar (já que ele já aprendeu essa tarefa) e ganhar sempre o biscoito, assim como pode “explorar” novas possibilidades - no caso, ficar parado mesmo com o dono longe - para ver se eventualmente não há uma recompensa maior ainda. O dono continuará fornecendo reforços positivos e negativos enquanto anda para trás, elogiando-o se ficar parado e repreendendo-o caso saia da posição; mas será que o animal está disposto a abrir mão da recompensa que ele já tem “garantida”?</p>
<p>Essa situação ilustra um <em>trade-off</em>: o animal pode escolher por “testar” novas combinações de ações ótimas em uma sequência de “estados” não realizadas anteriormente em busca de uma recompensa maior, mas não imediata (o chamado <strong>“exploration”</strong>); ou simplesmente se ater à recompensa que se obtém através de uma ação já conhecida (o chamado <strong>“exploitation”</strong>). Veja como essa ideia pode se estender facilmente para outros contextos; em finanças, por exemplo, reflete bem o <em>grau de aversão ao risco</em> de um agente econômico - o quanto ele está disposto a correr mais riscos em busca de retornos maiores, ou está disposto a correr menos risco e obter um retorno menor, porém mais seguro.</p>
<p align="center">
<img src="/img/tres-tipos-am/f010.jpg" width="350" />
</p>
<p>Fazer a máquina ser capaz de encontrar o meio termo ótimo entre “exploration” e “exploitation” é um dos principais desafios da aprendizagem por reforço, e é bastante pertinente para aplicações mais complicadas, como ensinar uma máquina a jogar xadrez, por exemplo: como é bem sabido, uma estratégia vencedora frequentemente envolve abrir mão de vantagem imediata, ou até mesmo sacrifício de peças, visando ao sucesso a longo prazo - um bom jogador deve ser capaz de levar em consideração as consequências de sua jogada várias rodadas adiante, e sabendo que a resposta do oponente também estará visando a um benefício futuro, e assim por diante.</p>
<h2 id="qual-das-três-abordagens-é-a-melhor">Qual das três abordagens é a melhor?</h2>
<p align="center">
<img src="/img/tres-tipos-am/f001.jpg" width="500" />
</p>
<p>A resposta a essa pergunta depende do que você está analisando. Cada problema possui suas peculiaridades, e uma maneira de resolução que funcionou bem para o problema <strong>A</strong> pode ser desastrosa para um outro problema <strong>B</strong>. Por isso, ao trabalhar com informática, <em>data science</em>, computação, <em>machine learning</em>, ou máquinas em geral, tenha em mente a seguinte “lei”:</p>
<p><strong>A MÁQUINA NÃO FAZ O QUE VOCÊ QUER: ELA FAZ O QUE VOCÊ MANDA!</strong></p>
<p>A máquina é, acima de tudo, um instrumento de conveniência; o desempenho da inteligência artificial está inteiramente condicionado à inteligência humana de quem a treinou. Fatores como o <a href="https://lamfo-unb.github.io/2017/04/29/Um-Olhar-Descontraido-Sobre-o-Dilema-Vies-Variancia" title="Dilema Viés-Variância">dilema viés-variância</a> exigem um cuidado do pesquisador para que a máquina forneça de fato os resultados requeridos. Técnicas de regularização e validação cruzada também são mecanismos importantes para “guiar” a máquina e garantir um meio termo entre acurácia na amostra e poder de generalização. “Saber mandar” é algo que nenhuma máquina pode fazer por você. Por isso, conhecer bem o problema a ser solucionado é sempre o primeiro passo, pois esse é o passo essencial para que o pesquisador tenha controle sobre a máquina, ao invés do contrário…</p>
<p align="center">
<img src="/img/tres-tipos-am/f004.jpg" width="700" />
</p>
The three types of machine learning2017-07-27T12:42:09+00:00http://lamfo-unb.github.io/2017/07/27/tres-tipos-am-english<h2 id="machine-learning">Machine learning</h2>
<h3 id="formally">Formally:</h3>
<p>Machine learning can be defined as a computacional system Machine learning and defined by a computational system that seeks to perform a <strong>task</strong> \(T\), learning from an <strong>experience</strong> \(E\) seeking to optimize a <strong>performance</strong> \(P\)</p>
<h3 id="well-but-what-does-that-exactly-mean">Well, but what does that exactly mean?</h3>
<p align="center">
<img src="/img/tres-tipos-am/f002.jpg" width="400" />
</p>
<p>Basically, an algorithm can learn a goal, based on a large volume of data - its <strong>experiences</strong>. Here’s an example to make it clearer: Suppose our <strong>task</strong> is to predict the outcome of a football game. How can we do that?</p>
<p>We could provide the computer with data about the manager, the squad composition, tactical line-ups, etc., followed by the match results. With a large volume of data in pairs like <strong>(variables, results)</strong>, we expect the computer to learn tha patterns that lead to victory. We also expect the computer get more accurate predictions as we feed it more datato, as it will have more examples of patterns that can <strong>generalize</strong> for situations not yet seen. Thus, the more data that is, the more experience the computer gets, and the better are the results, that is, the better our <strong>performance</strong></p>
<h2 id="supervised-learning">Supervised learning</h2>
<p>This is what we call <strong>Supervised Machine Learning</strong>: When we try to predict a <strong>dependent variable</strong> from a list of <strong>independent variables</strong>. For example:</p>
<table>
<thead>
<tr>
<th>Independent variables</th>
<th>Dependent variables</th>
</tr>
</thead>
<tbody>
<tr>
<td>Years of experience, Training background, Age</td>
<td>Salary</td>
</tr>
<tr>
<td>Age of Car, Driver Age</td>
<td>Risk of Automotive Accident</td>
</tr>
<tr>
<td>Text of a book</td>
<td>Literary Style</td>
</tr>
<tr>
<td>Temperature</td>
<td>Ice Cream Sales Revenue</td>
</tr>
<tr>
<td>Image of a Highway</td>
<td>Steering angle of a self-driving car</td>
</tr>
<tr>
<td>School Records</td>
<td>SAT Score</td>
</tr>
</tbody>
</table>
<p>It should be noted that a basic structure of supervised learning systems is that the data we use to train them <strong>contains a desired response</strong>, that is, it contains a dependent variable resulting from the observed independent variables. In this case, we say that <strong>data are labelled</strong> as answers or lessons to be predicted.</p>
<p>Among the best-known techniques for solving supervised learning problems are linear regression, logistic regression, artificial neural networks, kernel machines and devices, decision trees, k-neighbors, and naive Bayes. Supervised machine learning is an area that concentrates most successful applications and where a majority of problems are already well defined.</p>
<p align="center">
<img src="/img/tres-tipos-am/f017.png" width="400" />
</p>
<h2 id="unsupervised-learning">Unsupervised Learning</h2>
<p>But not all problems can be solved in this way. In some cases, getting labelled data is extremely costly or even impossible. For example, imagine that you own a business and want to know the profile of your consumers. There may be a consumer profile that always buys wine and cheese, or meat and charcoal, or milk powder and diaper. If this is the case, putting these products on distant shelves can increase sales, since it will increase the time and the customer’s path in the market. However, in this case we are not “labelled” for each purchase to which profile the consumer belongs. Furthermore, we don’t even know how many consumer profiles there are.</p>
<p>In this case, the computer will have to find out the profiles without any labelled data and we will need unsupervised learning methods. One option would be to look whether there are repeated patterns in the purchase records that would allow the inference of a consumer group or profile. Another option would be to directly see which products are often bought together and then learn an associative rule between them.</p>
<p>In general, with unsupervised learning we want to find a more informative representation of the data we have. Generally, this more informative representation is also simpler, condensing the information into more relevant points. Some examples are:</p>
<table>
<thead>
<tr>
<th>Data</th>
<th>Representative form</th>
</tr>
</thead>
<tbody>
<tr>
<td>Banking transactions</td>
<td>Normality of the transaction</td>
</tr>
<tr>
<td>Purchase Records</td>
<td>Association between products</td>
</tr>
<tr>
<td>Multidimensional Data</td>
<td>Data with reduced size</td>
</tr>
<tr>
<td>Purchase Records</td>
<td>Consumer profile</td>
</tr>
<tr>
<td>Words in a text</td>
<td>Mathematical representation of words</td>
</tr>
</tbody>
</table>
<p align="center">
<img src="/img/tres-tipos-am/f008.png" width="600" />
</p>
<p>Other examples of unsupervised learning applications are movie or music recommendation systems, anomaly detection, and data visualization. Among the best known techniques to solve unsupervised learning problems are artificial neural networks, Expectation-Maximization, k-medium clusters, support vector machines (kernel machines), Hierarchical Clustering, <em>word2vec</em>, principal components analysis, insulation forests , Self-organized maps, restricted Boltzmann machines, <em>eclat</em>, <em>apriori</em>, <em>t-SNE</em>. Unsupervised learning problems are considerably more complicated than supervised learning problems, mainly because we do not have the labelled answer in the data. As a consequence, it is extremely complicated and controversial to evaluate an unsupervised learning model and this type of model is at the frontier of knowledge in machine learning.</p>
<h2 id="reinforcement-learning">Reinforcement learning</h2>
<p>The third approach to machine learning is called “reinforcement learning”, in which the machine tries to learn the best action to take, depending on the circumstances in which this action will be performed.</p>
<p>The future is a random variable: since we do not know a priori what will happen, an approach that takes this uncertainty into account is desirable and can incorporate any changes in the environment of the decision making process. This idea indeed derives from the concept of “learning by reinforcement” from psychology, in which a <strong>reward</strong> or <strong>punishment</strong> is given to an agent, depending on the decision made; through the repetition of the experiments, the agent is expected to be able to associate the actions that generate the greatest reward for each situation that the environment presents, and to avoid actions that generate less punishment or reward. In psychology, this approach is called “behaviorism” and has B. F. Skinner as a leading exponent, a famous psychologist who, among other experiments, used the idea of rewards and punishments to train pigeons to conduct missiles in World War II.</p>
<p>This same idea is seen in machine learning: the machine observes a “state of nature” from the set of possible future scenarios and, based on this, chooses an action to take and receives the reward associated with that specific action and in that state, thus obtaining the information of this specific combination. The process is repeated until the machine is able to choose the best action to take for each of the possible scenarios to be observed in the future.</p>
<p>Illustrating with a very simple example: suppose you want to train your dog to sit at your command using this approach. At first, your pet will hardly perform the required command, and you respond by giving a “negative reinforcement” (punishment), scolding it verbally, with your facial expressions or even hitting it with a newspaper (or something more hostile, depending upon your temperament …). When the dog gets close to what it should do, you can give “positive reinforcements” as signs of approval or encouragement. If the dog does sit down after the command, you give him a reward - a cookie, for instance. With several repetitions of this same experiment, it is expected that, over time, the dog will associate the cause-effect relationship between the command and the reward to be received, and thereby “learn” to obey this command. The famous “Pavlov’s Dog” experiment illustrates this learning paradigm well. Ivan Pavlov was a Russian scientist notorious for presenting the idea of “conditioned reflex”, based on the following experiment: presenting a piece of meat to a dog, the animal starts to salivate, wishing for food. Instead of presenting only the meat, Pavlov always rang a bell at same time; through repetition, the dog would associate the two “stimuli” (meat and bell) and salivate as soon as the bell rings.</p>
<p align="center">
<img src="/img/tres-tipos-am/f011.jpg" width="450" />
</p>
<p>This idea is quite versatile when we move it into the realm of data science: instead of training puppies, we could build a machine that makes portfolios in the financial market and adjusts the combination of long/short assets depending on the “reward” (Financial return) of the previous portfolio and the evolution (“states”) of the market. Or a car that drives “by itself”, making decisions depending on the scenery it sees around, receiving negative rewards when it collides with the environment or with other vehicles, and with repeated steps, gradually “learns” to get round the obstacles.</p>
<p align="center">
<img src="/img/tres-tipos-am/f021.jpg" width="500" />
</p>
<p>Let’s go further: by going back to the example of dog training, suppose that you’ve successfully taught him to sit down, and now you want to do an obedience test - make the dog sit as you walk backwards, until you reach a five feet distance from it. If the dog sits down, you give it the cookie (as before); But if it does not get up until you’re five feet away from it, you give it a bigger reward (a piece of steak, for example). How could the dog earn the bigger reward? Note that now the dog has a “tough choice”: it can simply sit (since it has already learned this task) and always win the cookie, just as it can “explore” new possibilities - in the case, standing still with the owner away - to see if there is possibly a even greater reward. The owner will continue to provide positive and negative reinforcements as he walks backwards, praising the pet if it sits still and reproaching it if it leaves the position; But is the animal willing to give up the reward he already has “guaranteed”?</p>
<p>This situation illustrates a trade-off: the animal may choose to “test” new combinations of optimal actions in a sequence of previously unrealized “states” in pursuit of a larger but not immediate reward (the so-called <strong>“exploration”</strong>); Or simply to stick to the reward that is obtained through an already known action (the so-called <strong>exploitation</strong>). Note how this idea can easily extend to other contexts: In finance, for example, this reflects well the <em>risk aversion degree</em> of an economic agent - how willing he is to take more risks in search of larger returns, or is willing to take less risk and get a smaller, but safer return.</p>
<p align="center">
<img src="/img/tres-tipos-am/f010.jpg" width="350" />
</p>
<p>Making the machine being able to find the optimal middle ground between “exploration” and “exploitation” is one of the main challenges of reinforcement learning, and is quite relevant for more complicated applications, such as teaching a machine to play chess, for example: As is well known, a winning strategy often involves giving up immediate advantage, or even sacrifice pieces, aiming for long-term success - a good player should be able to take into account his moves’ consequences several rounds ahead, knowing that the opponent’s response will also be aimed at a future benefit, and so on.</p>
<h2 id="which-one-of-those-three-approaches-is-the-best">Which one of those three approaches is the best?</h2>
<p align="center">
<img src="/img/tres-tipos-am/f001.jpg" width="500" />
</p>
<p>The answer to this question depends on what you are analyzing. Each problem has its peculiarities, and a solving method that worked well for the problem <strong>A</strong> can be disastrous for another problem <strong>B</strong>. Therefore, when working with computing, data science, machine learning, or machines in general, keep in mind the following “law”:</p>
<p><strong>THE MACHINE DOESN’T DO WHAT YOU WANT: IT DOES WHAT YOU COMMAND!</strong></p>
<p>The machine is, above all, an instrument of convenience; The performance of artificial intelligence is entirely conditioned to the human intelligence of who trained it. Issues such as the <a href="https://lamfo-unb.github.io/2017/04/29/A-Casual-Look-at-the-Bias-Variance-Dilemma" title="Bias-Variance Dilemma">bias-variance dilemma</a> require careful attention from the researcher in order for the machine to actually provide the required results. Regularization and cross-validation techniques are also important mechanisms to “guide” the machine and guarantee a compromise between accuracy in the sample and generalization power. “Knowing how to command” is something that no machine can do for you. So knowing well the problem to be solved is always the first step, because this is the essential step for the researcher to have control over the machine, instead of the opposite…</p>
<p align="center">
<img src="/img/tres-tipos-am/f004.jpg" width="700" />
</p>
Introduction to Stock Analysis with R2017-07-22T00:00:00+00:00http://lamfo-unb.github.io/2017/07/22/intro-stock-analysis-1<p>Stock and investments analysis is a theme that can be deeply explored in programming. This includes R language, which already has a big literature, packages and functions developed in this matter. In this post, we’ll do a brief introduction to the subject using the packages <code class="language-plaintext highlighter-rouge">quantmod</code> and <code class="language-plaintext highlighter-rouge">ggplot2</code>.</p>
<p>For those who are beginning, <a href="https://www.r-project.org/">R</a> is a programming language and integrated enviroment focused in statistics, but with a lot of applications in different areas. The software download can be done <a href="https://cran.r-project.org/mirrors.html">here</a> using your preferred mirror. I also recommend installing <a href="https://www.rstudio.com/products/rstudio/download3/">RStudio</a>, which is an interface with a lot of additional resources for R.</p>
<p>The analyzed stock here will be PBR, from the brazilian company Petrobras, with data extracted from <a href="https://finance.yahoo.com/">Yahoo Finance</a> using the package <a href="https://cran.r-project.org/web/packages/quantmod/index.html">quantmod</a>. <code class="language-plaintext highlighter-rouge">quantmod</code> is a well known package used to quantitave financial modelling. Also, we’ll use the package <a href="https://cran.r-project.org/web/packages/ggplot2/index.html">ggplot2</a> for data visualization.</p>
<h3 id="preparing-the-environment">Preparing the environment</h3>
<p>The environment preparation is quite simple, even for those who are beginning or those who aren’t used to code. Firstly, we install and load the necessary packages.</p>
<pre><code class="language-{r}">rm(list=ls())
install.packages("quantmod")
install.packages("ggplot2")
library(quantmod)
library(ggplot2)
</code></pre>
<p>I think it’s important to highlight that we only install the packages once. In the next times we run the code, it’ll be necessary only to load them using the <code class="language-plaintext highlighter-rouge">library</code> command.</p>
<p>After installing and loading the packages, now we’ll download the stock prices series and treat the data in order to get them in the best possible format for the analysis. We download the data using the function <code class="language-plaintext highlighter-rouge">getSymbols</code>.</p>
<pre><code class="language-{r}">pbr <- getSymbols("PBR", src = "yahoo", from = "2013-01-01", to = "2017-06-01", auto.assign = FALSE)
</code></pre>
<p>Let’s do it step by step!</p>
<p>The first argument <code class="language-plaintext highlighter-rouge">PBR</code> is the symbol in Yahoo Finance of the stock that we’re going to analyze. If you want to look for other stock or asset, you can search its symbol <a href="https://finance.yahoo.com/lookup/">here</a>.</p>
<p>The argument <code class="language-plaintext highlighter-rouge">src= "yahoo"</code> indicates the source of the data. We can also use other sources like <a href="https://www.google.com/finance">Google Finance</a>, <a href="http://research.stlouisfed.org/fred2/">FRED</a>, <a href="http://www.oanda.com/">Oanda</a>, local databases, CSVs and many others.</p>
<p>The third and fourth arguments indicate the time period in which the data is going to be extracted, with data in the format “yyyy-mm-dd”.</p>
<p>Lastly, the argument <code class="language-plaintext highlighter-rouge">auto.assign = FALSE</code> allows us to name the dataset with the name we want. In case it’s <code class="language-plaintext highlighter-rouge">TRUE</code>, the name automatically will be the symbol we’re looking for, that is, the first argument.</p>
<h4 id="addendum">Addendum</h4>
<p>If Yahoo Finance API is not working, it’s possible to download the prices straight from the website. You just have to <a href="https://finance.yahoo.com/lookup/">search</a> for the stock tick or company name. In the asset page, click on “Historical Data”, just like the image below:</p>
<p><img src="/img/acoes1/screen01.png" align="middle" /></p>
<p>Then, select the desired period and click on “Download Data”. The download file will be in the format <code class="language-plaintext highlighter-rouge">csv</code>. Now, just move it for your <em>working directory</em>, that can be discovered using the command <code class="language-plaintext highlighter-rouge">getwd()</code>.</p>
<p>With the file in the folder, use the following commands to read the base:</p>
<pre><code class="language-{r}">pbr <- read.csv("PBR.csv")
pbr[,1] <- as.Date(pbr[,1])
pbr <- xts(pbr)
pbr <- pbr[,-1]
</code></pre>
<p>The command <code class="language-plaintext highlighter-rouge">read.csv()</code> reads the file and assigns it to an object. Then, we transform the first column of the base to date format. Next, we use the command <code class="language-plaintext highlighter-rouge">xts()</code> to transform the base from <code class="language-plaintext highlighter-rouge">dataframe</code> type to <code class="language-plaintext highlighter-rouge">xts</code>. Lastly, we remove the first column (date), since now the price lines are already indexed by day.</p>
<h3 id="prices-visualization">Prices Visualization</h3>
<p>Now let’s take a brief look at the data, just to know them better. Run the following lines and analyze each output.</p>
<pre><code class="language-{r}">head(pbr)
tail(pbr)
summary(pbr)
str(pbr)
</code></pre>
<pre><code class="language-{r}">## PBR.Open PBR.High PBR.Low PBR.Close PBR.Volume PBR.Adjusted
## 2012-01-03 26.993 28.025 26.939 26.11 12754300 24.54040
## 2012-01-04 27.567 28.280 27.567 26.46 12351500 24.86936
## 2012-01-05 27.993 28.057 27.525 26.11 8568600 24.54040
## 2012-01-06 27.929 27.929 27.280 25.69 8532100 24.14565
## 2012-01-09 27.748 28.695 27.588 26.88 26046600 25.26411
## 2012-01-10 29.078 29.461 28.993 27.45 16966500 25.79985
</code></pre>
<pre><code class="language-{r}">## PBR.Open PBR.High PBR.Low PBR.Close PBR.Volume PBR.Adjusted
## 2017-05-23 8.76 8.91 8.74 8.83 22071200 8.83
## 2017-05-24 8.95 9.20 8.88 9.08 25863100 9.08
## 2017-05-25 9.07 9.25 8.81 8.89 30557400 8.89
## 2017-05-26 8.74 9.03 8.72 8.95 22845300 8.95
## 2017-05-30 8.85 8.90 8.69 8.70 21082600 8.70
## 2017-05-31 8.67 8.76 8.44 8.48 23066100 8.48
</code></pre>
<pre><code class="language-{r}">## Index PBR.Open PBR.High PBR.Low
## Min. :2013-01-02 Min. : 2.88 Min. : 2.97 Min. : 2.71
## 1st Qu.:2014-02-08 1st Qu.: 7.05 1st Qu.: 7.20 1st Qu.: 6.82
## Median :2015-03-18 Median :10.25 Median :10.40 Median :10.08
## Mean :2015-03-17 Mean :10.67 Mean :10.86 Mean :10.46
## 3rd Qu.:2016-04-23 3rd Qu.:14.42 3rd Qu.:14.60 3rd Qu.:14.15
## Max. :2017-05-31 Max. :20.83 Max. :20.94 Max. :19.96
## PBR.Close PBR.Volume PBR.Adjusted
## Min. : 2.900 Min. : 6046400 Min. : 2.900
## 1st Qu.: 7.005 1st Qu.: 17193900 1st Qu.: 7.005
## Median :10.210 Median : 24066300 Median :10.230
## Mean :10.657 Mean : 27527831 Mean :10.814
## 3rd Qu.:14.330 3rd Qu.: 33655150 3rd Qu.:14.615
## Max. :20.650 Max. :164885500 Max. :20.650
</code></pre>
<pre><code class="language-{r}">## An 'xts' object on 2013-01-02/2017-05-31 containing:
## Data: num [1:1111, 1:6] 18.9 18.7 19.2 19.2 18.9 ...
## - attr(*, "dimnames")=List of 2
## ..$ : NULL
## ..$ : chr [1:6] "PBR.Open" "PBR.High" "PBR.Low" "PBR.Close" ...
## Indexed by objects of class: [Date] TZ: UTC
## xts Attributes:
## List of 2
## $ src : chr "yahoo"
## $ updated: POSIXct[1:1], format: "2017-07-16 20:52:31"
</code></pre>
<p>With the commands <code class="language-plaintext highlighter-rouge">head()</code> and <code class="language-plaintext highlighter-rouge">tail()</code> we can see the first and last 6 lines of the base. There are 6 columns with: opening price, maximum and minimum prices, closing price, volume of transactions and adjusted price. Using the command <code class="language-plaintext highlighter-rouge">summary()</code> we verify the descriptive statistics of each price series and volume. The command <code class="language-plaintext highlighter-rouge">str()</code> returns the object structure. In this case, it’s a <a href="https://cran.r-project.org/web/packages/xts/vignettes/xts.pdf">xts</a> object, a time series.</p>
<p>Now let’s plot daily prices, using the Adjusted Price column, since it incorporates events like <a href="https://en.wikipedia.org/wiki/Stock_split">splits</a> and dividends distribution, which can affect the series.</p>
<pre><code class="language-{r}">ggplot(pbr, aes(x = index(pbr), y = pbr[,6])) + geom_line(color = "darkblue") + ggtitle("Petrobras prices series") + xlab("Date") + ylab("Price") + theme(plot.title = element_text(hjust = 0.5)) + scale_x_date(date_labels = "%b %y", date_breaks = "6 months")
</code></pre>
<p><img src="/img/acoes1/image1en.png" height="350" width="550" align="middle" /></p>
<p>We created this graphic using the command <code class="language-plaintext highlighter-rouge">ggplot</code>. First, we use the object <code class="language-plaintext highlighter-rouge">pbr</code> as the series to be ploted. Then we indicate which elements will be in the axes: <code class="language-plaintext highlighter-rouge">index(pbr)</code>, the date in x-axis, and the adjusted price column, <code class="language-plaintext highlighter-rouge">pbr[,6]</code>, in y-axis. Next, we add the element to be ploted, in this case, a blue line: <code class="language-plaintext highlighter-rouge">geom_line(color = "darkblue")</code>.</p>
<p>Afterwards, we include the title and names of the axes, with the commands <code class="language-plaintext highlighter-rouge">ggtitle("Petrobras prices series")</code>, <code class="language-plaintext highlighter-rouge">xlab("Date")</code>, <code class="language-plaintext highlighter-rouge">ylab("Price")</code>. By standard, the graph title is aligned to the left. To centralize it, the command <code class="language-plaintext highlighter-rouge">theme(plot.title = element_text(hjust = 0.5))</code> is used.</p>
<p>Lastly, to make the temporal axis more informative, we put the date tick at every 6 months in the format <code class="language-plaintext highlighter-rouge">mmm aa</code> using <code class="language-plaintext highlighter-rouge">scale_x_date(date_labels = "%b %y", date_breaks = "6 months")</code>.</p>
<p>In stocks <a href="https://en.wikipedia.org/wiki/Technical_analysis">Technical Analysis</a>, a very used technique is the plot of Moving Averages in the prices graphs. A simple moving average is an arithmetic average from the last \(q\) days from a \(x_{t}\) series in the \(t\) time period. So, the moving average \(MA^{q}_{t}\) is given by:</p>
\[MA^{q}_{t}= \frac{1}{q} \sum_{i=0}^{q-1}x_{t-1}\]
<p>This indicator is interesting because it helps to identify trends and smooths noises from prices. That is, the bigger the days window for the MA calculation, smaller is the MA responsiveness to price variation. The smaller the window, the faster MA adapts itself to changes. Now let’s calculate two moving averages for the stock prices series, one with 10 days window and the other with 30 days:</p>
<pre><code class="language-{r}">pbr_mm <- subset(pbr, index(pbr) >= "2016-01-01")
pbr_mm10 <- rollmean(pbr_mm[,6], 10, fill = list(NA, NULL, NA), align = "right")
pbr_mm30 <- rollmean(pbr_mm[,6], 30, fill = list(NA, NULL, NA), align = "right")
pbr_mm$mm10 <- coredata(pbr_mm10)
pbr_mm$mm30 <- coredata(pbr_mm30)
</code></pre>
<p>First we subset the base for data since 2016 using the function <code class="language-plaintext highlighter-rouge">subset()</code>. Then, we use the function <code class="language-plaintext highlighter-rouge">rollmean()</code>, which takes as argument: the series \((x_t)\), in this case the adjusted price; the window of periods \((q)\); an optional fill argument, that is used to complete the days where it’s not possible to calculate the moving average, since the enough quantity of days hasn’t passed; the argument <code class="language-plaintext highlighter-rouge">align</code> indicates if the moving average should be calculated using the periods in the left, in the center or in the right of the \(t\) day of the series. Lastly, we add the MA to two new columns in the initial database.</p>
<p>We calculated the two MA using 10 and 30 days of windows, filling the values with NA and using the periods in the left. Afterwards, we can plot both series in the same graphic of prices to identify trends. An existing theory in Technical Analysis is the one that when two MA of short and long term cross each other, there is an indication of buying or selling the stock. When the short term MA cross the long term upwards, there’s a <strong>buy</strong> a signal. When the opposite happens, there’s a <strong>sell</strong> signal.</p>
<p>Ploting the prices series and the moving averages for all days since 2016:</p>
<pre><code class="language-{r}">ggplot(pbr_mm, aes(x = index(pbr_mm))) +
geom_line(aes(y = pbr_mm[,6], color = "PBR")) + ggtitle("Petrobras prices series") +
geom_line(aes(y = pbr_mm$mm10, color = "MM10")) +
geom_line(aes(y = pbr_mm$mm30, color = "MM30")) + xlab("Date") + ylab("Price") +
theme(plot.title = element_text(hjust = 0.5), panel.border = element_blank()) +
scale_x_date(date_labels = "%b %y", date_breaks = "3 months") +
scale_colour_manual("Series", values=c("PBR"="gray40", "MM10"="firebrick4", "MM30"="darkcyan"))
</code></pre>
<p><img src="/img/acoes1/image2en.png" height="350" width="550" align="middle" /></p>
<p>To create the graph, we plot the line of prices and the lines of moving averages. In this case, we plot each line differently, creating a kind of nickname for the color of each one. Then, we add the line <code class="language-plaintext highlighter-rouge">scale_colour_manual</code>, indicating the color of each nickname in order to make the color visible in the legend of the graph.</p>
<p>Verifying the plot, it’s possible to notice that there were 14 points in which the series crossed themselves and 1 point where they overlapped. Following the buy signal, we’d have been successful in 4 of 7 times. Following the sell indication, we’d have done right 5 in 7 times. In total, we’d be 9/14, that is 64% of success with a quite simple indicator. Of course this metric shouldn’d be used alone, many other informations should be considerated.</p>
<h3 id="returns">Returns!</h3>
<p>We have seen how the stock price has changed over time. Now we’ll verify how the stock return has behaved in the same period. To do this, we first need to create a new object with the calculated returns, using the adjusted prices column:</p>
<pre><code class="language-{r}">pbr_ret <- diff(log(pbr[,6]))
pbr_ret <- pbr_ret[-1,]
</code></pre>
<p>What we’ve done here was using logarithm properties to calculate the log-return of the stock. We did:</p>
\[r_{t} = ln(1+R_t) = ln\bigg(\frac{P_t}{P_{t-1}}\bigg) = ln(P_{t})-ln(P_{t-1}) \approx R_{t}\]
<p>The <code class="language-plaintext highlighter-rouge">diff</code> command calculates the difference of all values in any vector or element. With this, we only apply the difference to natural logarithms of stock prices.</p>
<p>In addition to this way, it’s possible to calculate returns differently. The package <code class="language-plaintext highlighter-rouge">quantmod</code> has some interesting functions to do this. Firstly, it’s really simple to select only one column of prices of each stock. For example:</p>
<pre><code class="language-{r}">Op(pbr)
Cl(pbr)
Ad(pbr)
</code></pre>
<p>Each line will have as output the opening, closing and adjusted prices, respectively. The same accounts for other columns: <code class="language-plaintext highlighter-rouge">Hi()</code>, <code class="language-plaintext highlighter-rouge">Lo()</code> and <code class="language-plaintext highlighter-rouge">Vo()</code>, for maximum and minimum prices and volume of transactions.</p>
<p>For the returns, we simply adapt and define which columns will be used, for example: <code class="language-plaintext highlighter-rouge">ClCl()</code> will give us the returns using the closing prices from two periods; <code class="language-plaintext highlighter-rouge">OpCl()</code> will result in the return from the closing price over the opening price from the same day.</p>
<p>Another interesting possibility given by <code class="language-plaintext highlighter-rouge">quantmod</code> is the calculation of returns for different periods. For example, it’s possible to calculate the returns by day, week, month, quarter and year, just by using the following commands:</p>
<pre><code class="language-{r}">dailyReturn(pbr)
weeklyReturn(pbr)
monthlyReturn(pbr)
quarterlyReturn(pbr)
yearlyReturn(pbr)
</code></pre>
<p>All these commands make the analysis and the calculation much faster and simpler to do.</p>
<p>Now let’s verify some basic statistics from Petrobras returns.</p>
<pre><code class="language-{r}">summary(pbr_ret)
## Index PBR.Adjusted
## Min. :2013-01-03 Min. :-0.1852413
## 1st Qu.:2014-02-10 1st Qu.:-0.0209915
## Median :2015-03-18 Median :-0.0005999
## Mean :2015-03-18 Mean :-0.0007548
## 3rd Qu.:2016-04-24 3rd Qu.: 0.0177905
## Max. :2017-05-31 Max. : 0.1555103
</code></pre>
<pre><code class="language-{r}">sd(pbr_ret)
## [1] 0.03713089
</code></pre>
<p>This indicates that in average the stock hasn’t performed well. Now we can plot the returns and see how they’ve done over time:</p>
<pre><code class="language-{r}">ggplot(pbr_ret, aes(x = index(pbr_ret), y = pbr_ret)) +
geom_line(color = "deepskyblue4") +
ggtitle("Petrobras returns series") +
xlab("Date") + ylab("Return") +
theme(plot.title = element_text(hjust = 0.5)) + scale_x_date(date_labels = "%b %y", date_breaks = "6 months")
</code></pre>
<p><img src="/img/acoes1/image3en.png" height="350" width="550" align="middle" /></p>
<p>To plot this last graph, we used the same parameters of the prices graph, changing only the line color.</p>
<p>Making a brief analysis of the graphic, it’s possible to see that the smallest return of the series happened around may. More specifically, in may 18, one day after the news release with recordings of brazilian president Michel Temer. In the audios, he agreed to give payments in exchange of silence from arrested politicians. This fact strongly impacted the stocks market, specially brazilian and public companies, like Petrobras.</p>
<p>Now let’s take a small look at the stock returns in 2017:</p>
<pre><code class="language-{r}">pbr_ret17 <- subset(pbr_ret, index(pbr_ret) > "2017-01-01")
ggplot(pbr_ret17, aes(x = index(pbr_ret17), y = pbr_ret17)) +
geom_line(color = "deepskyblue4") +
ggtitle("Petrobras returns series in 2017") + xlab("Date") + ylab("Return") +
theme(plot.title = element_text(hjust = 0.5)) + scale_x_date(date_labels = "%b %y", date_breaks = "1 months")
</code></pre>
<p><img src="/img/acoes1/image4en.png" height="350" width="550" align="middle" /></p>
<pre><code class="language-{r}">summary(pbr_ret17)
sd(pbr_ret17)
</code></pre>
<pre><code class="language-{r}">## Index PBR.Adjusted
## Min. :2017-01-03 Min. :-0.185241
## 1st Qu.:2017-02-08 1st Qu.:-0.014350
## Median :2017-03-17 Median :-0.002689
## Mean :2017-03-17 Mean :-0.001707
## 3rd Qu.:2017-04-24 3rd Qu.: 0.014977
## Max. :2017-05-31 Max. : 0.068795
## [1] 0.03089105
</code></pre>
<p>We separated in an object all of the returns from 2017, using the function <code class="language-plaintext highlighter-rouge">subset()</code>. With this, the descriptive statistics still suggest a negative average return. In other hand, the standard deviation is smaller, which indicates smaller risk. Furthermore, this negative return is given by, in majority, by the big fall in the day 18.</p>
<h3 id="conclusion">Conclusion</h3>
<p>That’s all for this tutorial, folks. In future posts I pretend to do deeper analysis and also approach portfolio and risk theory. I hope you’ve liked!</p>
Introdução à Análise de Ações com R2017-07-22T00:00:00+00:00http://lamfo-unb.github.io/2017/07/22/intro-analise-acoes-1<p>A análise de ações e investimentos é um tema que pode ser muito bem explorado na programação. Isso inclui a linguagem R, que já possui vasta literatura, pacotes e funções desenvolvidas no tema. Neste post faremos uma breve introdução ao assunto utilizando os pacotes <code class="language-plaintext highlighter-rouge">quantmod</code> e <code class="language-plaintext highlighter-rouge">ggplot2</code>.</p>
<p>Para quem está iniciando, o <a href="https://www.r-project.org/">R</a> é uma linguagem e ambiente de desenvolvimento integrado focado em estatística, mas que possui aplicações em diferentes áreas. O download do programa pode ser feito <a href="https://cran.r-project.org/mirrors.html">aqui</a> utilizando qualquer um dos <em>mirrors</em>. Recomendo também a instalação do <a href="https://www.rstudio.com/products/rstudio/download3/">RStudio</a> que é uma interface com recursos adicionais para o R.</p>
<p>A ação analisada será a da Petrobras, com dados extraídos do site <a href="https://finance.yahoo.com/">Yahoo Finance</a> por meio do pacote <a href="https://cran.r-project.org/web/packages/quantmod/index.html">quantmod</a> que é bastante utilizado para a modelagem quantitativa de dados financeiros. Além disso, o pacote <a href="https://cran.r-project.org/web/packages/ggplot2/index.html">ggplot2</a> será utilizado para a visualização dos dados.</p>
<h3 id="preparando-o-ambiente">Preparando o ambiente</h3>
<p>A preparação do ambiente é bem simples, mesmo para quem não está acostumado ou que esteja iniciando. Primeiramente, instalamos e carregamos os pacotes necessários.</p>
<pre><code class="language-{r}">rm(list=ls())
install.packages("quantmod")
install.packages("ggplot2")
library(quantmod)
library(ggplot2)
</code></pre>
<p>Acho importante ressaltar que instalamos os pacotes apenas uma vez. Nas próximas vezes que executarmos o código, é necessário apenas carregar os pacotes por meio do comando <code class="language-plaintext highlighter-rouge">library</code>.</p>
<p>Depois de termos os pacotes instalados e carregados, vamos baixar a série de preços da ação e tratar os dados para que fiquem da melhor forma possível para a realização das análises. Isso é feito por meio do comando <code class="language-plaintext highlighter-rouge">getSymbols</code>.</p>
<pre><code class="language-{r}">pbr <- getSymbols("PBR", src = "yahoo", from = "2013-01-01", to = "2017-06-01", auto.assign = FALSE)
</code></pre>
<p>Vamos por partes!</p>
<p>O primeiro argumento <code class="language-plaintext highlighter-rouge">PBR</code> é o símbolo do ativo que queremos analisar no Yahoo Finance. Você pode procurar pelo símbolo de outra ação ou índice que desejar analisar clicando <a href="https://finance.yahoo.com/lookup/">aqui</a>.</p>
<p>O argumento <code class="language-plaintext highlighter-rouge">src = "yahoo"</code> indica a fonte dos dados. Também podemos utilizar outras fontes como o <a href="https://www.google.com/finance">Google Finance</a>, <a href="http://research.stlouisfed.org/fred2/">FRED</a>, <a href="http://www.oanda.com/">Oanda</a>, bancos de dados locais, CSVs e vários outros.</p>
<p>O terceiro e quarto argumentos indicam o período no qual os dados serão extraídos, com a data no formato “aaaa-mm-dd”.</p>
<p>Por último, o argumento <code class="language-plaintext highlighter-rouge">auto.assign = FALSE</code> nos permite nomear o dataset com o nome que quisermos. Caso seja <code class="language-plaintext highlighter-rouge">TRUE</code>, o nome será automaticamente o símbolo que estamos buscando, ou seja, o primeiro argumento.</p>
<h4 id="adendo">Adendo</h4>
<p>Caso a API do Yahoo Finance não esteja funcionando, é possível baixar a base de preços diretamente do site. Basta buscar pelo tick da ação ou pelo nome da empresa. Na página do ativo, basta clicar em “Historical Data”, conforme imagem abaixo:</p>
<p><img src="/img/acoes1/screen01.png" alt="" class="center-image" /></p>
<p>Depois, basta selecionar o período desejado e clicar em “Download Data”. O arquivo baixado estará no formato <code class="language-plaintext highlighter-rouge">csv</code>. Agora é só colocá-lo no seu <em>working directory</em>, que pode ser descoberto utilizando o comando <code class="language-plaintext highlighter-rouge">getwd()</code>.</p>
<p>Com o arquivo na pasta, basta usar os seguintes comandos para ler a base:</p>
<pre><code class="language-{r}">pbr <- read.csv("PBR.csv")
pbr[,1] <- as.Date(pbr[,1])
pbr <- xts(pbr)
pbr <- pbr[,-1]
</code></pre>
<p>O comando <code class="language-plaintext highlighter-rouge">read.csv()</code> lê o arquivo e o atribui a um objeto. Em seguida, transformamos a primeira coluna da base no formato tipo data. Depois usamos o comando <code class="language-plaintext highlighter-rouge">xts()</code> para transformar a base do tipo <code class="language-plaintext highlighter-rouge">data frame</code> em <code class="language-plaintext highlighter-rouge">xts</code>. Por último, removemos a primeira coluna, de data, da base, visto que agora as linhas de preço já estão indexadas pelo dia.</p>
<h3 id="visualização-de-preços">Visualização de Preços</h3>
<p>Agora vamos dar uma breve olhada nos dados, apenas para conhecê-los melhor. Rode as linhas a seguir e analise cada output.</p>
<pre><code class="language-{r}">head(pbr)
tail(pbr)
summary(pbr)
str(pbr)
</code></pre>
<pre><code class="language-{r}">## PBR.Open PBR.High PBR.Low PBR.Close PBR.Volume PBR.Adjusted
## 2012-01-03 26.993 28.025 26.939 26.11 12754300 24.54040
## 2012-01-04 27.567 28.280 27.567 26.46 12351500 24.86936
## 2012-01-05 27.993 28.057 27.525 26.11 8568600 24.54040
## 2012-01-06 27.929 27.929 27.280 25.69 8532100 24.14565
## 2012-01-09 27.748 28.695 27.588 26.88 26046600 25.26411
## 2012-01-10 29.078 29.461 28.993 27.45 16966500 25.79985
</code></pre>
<pre><code class="language-{r}">## PBR.Open PBR.High PBR.Low PBR.Close PBR.Volume PBR.Adjusted
## 2017-05-23 8.76 8.91 8.74 8.83 22071200 8.83
## 2017-05-24 8.95 9.20 8.88 9.08 25863100 9.08
## 2017-05-25 9.07 9.25 8.81 8.89 30557400 8.89
## 2017-05-26 8.74 9.03 8.72 8.95 22845300 8.95
## 2017-05-30 8.85 8.90 8.69 8.70 21082600 8.70
## 2017-05-31 8.67 8.76 8.44 8.48 23066100 8.48
</code></pre>
<pre><code class="language-{r}">## Index PBR.Open PBR.High PBR.Low
## Min. :2013-01-02 Min. : 2.88 Min. : 2.97 Min. : 2.71
## 1st Qu.:2014-02-08 1st Qu.: 7.05 1st Qu.: 7.20 1st Qu.: 6.82
## Median :2015-03-18 Median :10.25 Median :10.40 Median :10.08
## Mean :2015-03-17 Mean :10.67 Mean :10.86 Mean :10.46
## 3rd Qu.:2016-04-23 3rd Qu.:14.42 3rd Qu.:14.60 3rd Qu.:14.15
## Max. :2017-05-31 Max. :20.83 Max. :20.94 Max. :19.96
## PBR.Close PBR.Volume PBR.Adjusted
## Min. : 2.900 Min. : 6046400 Min. : 2.900
## 1st Qu.: 7.005 1st Qu.: 17193900 1st Qu.: 7.005
## Median :10.210 Median : 24066300 Median :10.230
## Mean :10.657 Mean : 27527831 Mean :10.814
## 3rd Qu.:14.330 3rd Qu.: 33655150 3rd Qu.:14.615
## Max. :20.650 Max. :164885500 Max. :20.650
</code></pre>
<pre><code class="language-{r}">## An 'xts' object on 2013-01-02/2017-05-31 containing:
## Data: num [1:1111, 1:6] 18.9 18.7 19.2 19.2 18.9 ...
## - attr(*, "dimnames")=List of 2
## ..$ : NULL
## ..$ : chr [1:6] "PBR.Open" "PBR.High" "PBR.Low" "PBR.Close" ...
## Indexed by objects of class: [Date] TZ: UTC
## xts Attributes:
## List of 2
## $ src : chr "yahoo"
## $ updated: POSIXct[1:1], format: "2017-07-16 20:52:31"
</code></pre>
<p>Pelos comandos <code class="language-plaintext highlighter-rouge">head()</code> e <code class="language-plaintext highlighter-rouge">tail()</code> podemos ver as primeiras e últimas 6 linhas da base. São 6 colunas com: preço de abertura, preços máximo e mínimo do dia, preço de fechamento, volume de transações e preço ajustado. Pelo comando <code class="language-plaintext highlighter-rouge">summary</code> verificamos as estatísticas descritivas de cada série de preços e volume. Já o comando <code class="language-plaintext highlighter-rouge">str</code> fornece a estrutura do objeto. Neste caso, é um objeto <a href="https://cran.r-project.org/web/packages/xts/vignettes/xts.pdf">xts</a>, uma série temporal.</p>
<p>Vamos agora plotar os preços diários, utilizando a coluna de Preço Ajustado, visto que ela incorpora eventos como <a href="https://pt.wikipedia.org/wiki/Desdobramento_de_a%C3%A7%C3%B5es">splits</a> e distribuição de dividendos, que podem afetar a série.</p>
<pre><code class="language-{r}">ggplot(pbr, aes(x = index(pbr), y = pbr[,6])) + geom_line(color = "darkblue") +
ggtitle("Série de preços da Petrobras") +
xlab("Data") + ylab("Preço ($)") + theme(plot.title = element_text(hjust = 0.5)) +
scale_x_date(date_labels = "%b %y", date_breaks = "6 months")
</code></pre>
<p><img src="/img/acoes1/image1.png" height="350" width="550" /></p>
<p>Criamos esse gráfico usando o comando <code class="language-plaintext highlighter-rouge">ggplot</code>. Primeiro utilizamos o objeto <code class="language-plaintext highlighter-rouge">pbr</code> como a série a ser plotada. Depois indicamos quais elementos serão os eixos: <code class="language-plaintext highlighter-rouge">index(pbr)</code>, a data no eixo x, e a coluna de preço ajustado, <code class="language-plaintext highlighter-rouge">pbr[,6]</code>, no eixo y. Em seguida, adicionamos o elemento a ser plotado, no caso, uma linha azul: <code class="language-plaintext highlighter-rouge">geom_line(color = "darkblue")</code>.</p>
<p>Depois, acrescentamos o título e nomes dos eixos, com os comandos <code class="language-plaintext highlighter-rouge">ggtitle("Série de preços da Petrobras")</code>, <code class="language-plaintext highlighter-rouge">xlab("Data")</code>, <code class="language-plaintext highlighter-rouge">ylab("Preço ($)")</code>. Por padrão, o título do gráfico fica alinhado à esquerda. Para centralizá-lo, utilizamos <code class="language-plaintext highlighter-rouge">theme(plot.title = element_text(hjust = 0.5))</code>.</p>
<p>Por último, para deixar o eixo temporal com mais informações, colocamos o <em>tick</em> de data a cada seis meses e na forma de <code class="language-plaintext highlighter-rouge">mmm aa</code> utilizando <code class="language-plaintext highlighter-rouge">scale_x_date(date_labels = "%b %y", date_breaks = "6 months")</code>.</p>
<p>Em <a href="https://pt.wikipedia.org/wiki/An%C3%A1lise_t%C3%A9cnica">Análise Técnica</a> de ações, uma técnica muito utilizada é a plotagem de médias móveis nos gráficos de preços. Uma média móvel simples é a média aritmética dos últimos \(q\) dias de uma série \(x_{t}\) no período de tempo \(t\). Assim, a média móvel \(MM^{q}_{t}\) é dada por:</p>
\[MM^{q}_{t}= \frac{1}{q} \sum_{i=0}^{q-1}x_{t-1}\]
<p>Esse indicador é interessante pois ajuda a identificar tendências e suaviza ruídos dos preços. Isto é, quanto maior a janela de dias para o cálculo da média, menor é a responsividade da MM à variação no preço. Quanto menor a janela, mais rápido à média móvel se ajusta às mudanças. Vamos então calcular agora duas médias móveis para a série de preços da Petrobras, uma com janela de 10 dias e outra com janela de 30 dias:</p>
<pre><code class="language-{r}">pbr_mm <- subset(pbr, index(pbr) >= "2016-01-01")
pbr_mm10 <- rollmean(pbr_mm[,6], 10, fill = list(NA, NULL, NA), align = "right")
pbr_mm30 <- rollmean(pbr_mm[,6], 30, fill = list(NA, NULL, NA), align = "right")
pbr_mm$mm10 <- coredata(pbr_mm10)
pbr_mm$mm30 <- coredata(pbr_mm30)
</code></pre>
<p>Primeiro dividimos a base para dados a partir de 2016 utilizando a função <code class="language-plaintext highlighter-rouge">subset()</code>. Em seguida, usamos a função <code class="language-plaintext highlighter-rouge">rollmean()</code>, que toma como argumento a série (\(x_t)\), no caso o preço ajustado; a janela de períodos (\(q)\); um argumento opcional de preenchimento, que é utilizado para completar os dias em que ainda não é possível calcular a média móvel, ou seja, quando não se passaram dias suficiente para completar a janela desejada; e, por último, o argumento <code class="language-plaintext highlighter-rouge">align</code>, que indica se a média móvel deve ser calculada usando os períodos à esquerda, ao centro ou à direita do dia \(t\) da série. Por último, acrescentamos as médias móveis a duas novas colunas na base inicial.</p>
<p>Em nosso caso, calculamos utilizando 10 e 30 dias de janela, preenchendo os valores com NA e utilizando os períodos à esquerda do dia em questão. Em seguida, podemos plotar ambas as séries no mesmo gráfico de preços para identificar tendências. Uma teoria existente na Análise Técnica é a de que quando duas médias móveis de janelas de curto e longo prazo se cruzam, há uma indicação de compra ou de venda. Caso a MM de menor período cruze de baixo para cima a MM de maior período, há uma indicação de <strong>compra</strong>. Se o cruzamento for o contrário, é um sinal de <strong>venda</strong>.</p>
<p>Plotando a série de preços e as médias móveis para todos os dias a partir de 2016, temos:</p>
<pre><code class="language-{r}">ggplot(pbr_mm, aes(x = index(pbr_mm))) + geom_line(aes(y = pbr_mm[,6], color = "PBR")) +
ggtitle("Série de preços da Petrobras") +
geom_line(aes(y = pbr_mm$mm10, color = "MM10")) +
geom_line(aes(y = pbr_mm$mm30, color = "MM30")) +
xlab("Data") + ylab("Preço ($)") +
theme(plot.title = element_text(hjust = 0.5), panel.border = element_blank()) +
scale_x_date(date_labels = "%b %y", date_breaks = "3 months") +
scale_colour_manual("Séries", values=c("PBR"="gray40", "MM10"="firebrick4", "MM30"="darkcyan"))
</code></pre>
<p><img src="/img/acoes1/image2.png" height="350" width="550" align="middle" /></p>
<p>Para criar o gráfico, plotamos a linha de preços e as linhas das médias móveis. Nesta ocasião, utilizamos de forma diferente a plotagem de cada linha, criando uma espécie de apelido para as cores de cada uma. Em seguida, adicionamos a linha <code class="language-plaintext highlighter-rouge">scale_colour_manual</code>, indicando a cor de cada apelido para que as cores constassem na legenda de cada série.</p>
<p>Verificando o gráfico, é possível notar que foram 14 pontos em que as séries se cruzaram e 1 ponto em que estiveram sobrepostas. Seguindo a indicação de compra, teríamos acertado 4 de 7 vezes. Pelas indicações de venda, seriam 5 acertos em 7 possibilidades. No total, 9/14, ou seja, 64% de acerto com um indicador bastante simples. Claro que essa métrica não deve ser utilizada sozinha, diversas outras informações devem ser consideradas.</p>
<h3 id="retornos">Retornos!</h3>
<p>Vimos como o preço da ação tem variado ao longo do tempo. Vamos agora verificar como se comportou o retorno da ação no mesmo período. Para isso, precisamos primeiro criar um novo objeto com os retornos calculados, utilizando também a coluna de preço ajustado:</p>
<pre><code class="language-{r}">pbr_ret <- diff(log(pbr[,6]))
pbr_ret <- pbr_ret[-1,]
</code></pre>
<p>O que fizemos aqui foi utilizar as propriedades do logaritmo para calcular o retorno logarítmico da ação. Ou seja, fizemos:</p>
\[r_{t} = ln(1+R_t) = ln\bigg(\frac{P_t}{P_{t-1}}\bigg) = ln(P_{t})-ln(P_{t-1}) \approx R_{t}\]
<p>O comando <code class="language-plaintext highlighter-rouge">diff</code> calcula a diferença de todos os valores de algum vetor ou elemento. Com isso, apenas aplicamos a diferença aos logaritmos naturais dos preços da ação.</p>
<p>Além desse modo, é possível calcular os retornos de forma diferente. O pacote <code class="language-plaintext highlighter-rouge">quantmod</code> possui algumas funções interessantes para isso. Primeiramente, é bastante fácil selecionar apenas uma coluna de preços de cada ação, por exemplo:</p>
<pre><code class="language-{r}">Op(pbr)
Cl(pbr)
Ad(pbr)
</code></pre>
<p>Cada linha terá como output os preços de abertura, fechamento e ajustados, respectivamente. O mesmo vale para as outras colunas: <code class="language-plaintext highlighter-rouge">Hi()</code>, <code class="language-plaintext highlighter-rouge">Lo()</code>, <code class="language-plaintext highlighter-rouge">Vo()</code>, para preço máximo, preço mínimo e volume de transações.</p>
<p>Para os retornos, basta adaptar e definir quais colunas serão utilizadas, por exemplo: <code class="language-plaintext highlighter-rouge">ClCl()</code> fornecerá os retornos utilizando os preços de fechamento de dois períodos; já <code class="language-plaintext highlighter-rouge">OpCl()</code> resultará no retorno do preço de fechamento sobre o preço de abertura do mesmo dia.</p>
<p>Outra possibilidade interessante fornecida pelo <code class="language-plaintext highlighter-rouge">quantmod</code> é o cálculo de retornos por períodos diferentes. Por exemplo, é possível calcular os retornos por dia, semana, mês, trimestre e ano, basta utilizar os comandos a seguir:</p>
<pre><code class="language-{r}">dailyReturn(pbr)
weeklyReturn(pbr)
monthlyReturn(pbr)
quarterlyReturn(pbr)
yearlyReturn(pbr)
</code></pre>
<p>Todos esses comandos tornam a análise e os cálculos muito mais rápidos e fáceis de serem feitos.</p>
<p>Vamos agora verificar algumas estatísticas básicas dos retornos da Petrobras:</p>
<pre><code class="language-{r}">summary(pbr_ret)
## Index PBR.Adjusted
## Min. :2013-01-03 Min. :-0.1852413
## 1st Qu.:2014-02-10 1st Qu.:-0.0209915
## Median :2015-03-18 Median :-0.0005999
## Mean :2015-03-18 Mean :-0.0007548
## 3rd Qu.:2016-04-24 3rd Qu.: 0.0177905
## Max. :2017-05-31 Max. : 0.1555103
</code></pre>
<pre><code class="language-{r}">sd(pbr_ret)
## [1] 0.03713089
</code></pre>
<p>Ou seja, em média a ação não tem tido um bom desempenho. Podemos agora plotar um gráfico dos retornos e ver como eles desempenharam ao longo do tempo:</p>
<pre><code class="language-{r}">ggplot(pbr_ret, aes(x = index(pbr_ret), y = pbr_ret)) + geom_line(color = "deepskyblue4") +
ggtitle("Série de retornos da Petrobras") + xlab("Data") + ylab("Retorno") +
theme(plot.title = element_text(hjust = 0.5)) +
scale_x_date(date_labels = "%b %y", date_breaks = "6 months")
</code></pre>
<p><img src="/img/acoes1/image3.png" height="350" width="550" align="middle" /></p>
<p>Para plotar este último gráfico, utilizamos os mesmos parâmetros do gráfico de preços, alterando apenas a cor da linha.</p>
<p>Dando uma breve analisada no gráfico, é possível ver que o menor retorno da série ocorreu por volta de maio. Mais precisamente, no dia 18 de maio, um dia após a divulgação de matéria com trechos da gravação do presidente Michel Temer dando aval para a compra de silêncio de políticos. Esse fato impactou fortemente o mercado de ações, especialmente de empresas brasileiras e públicas, como a Petrobras.</p>
<p>Vamos fazer agora uma breve checagem dos retornos da ação em 2017:</p>
<pre><code class="language-{r}">pbr_ret17 <- subset(pbr_ret, index(pbr_ret) > "2017-01-01")
ggplot(pbr_ret17, aes(x = index(pbr_ret17), y = pbr_ret17)) + geom_line(color = "deepskyblue4") +
ggtitle("Série de retornos da Petrobras em 2017") + xlab("Data") + ylab("Retorno") +
theme(plot.title = element_text(hjust = 0.5)) +
scale_x_date(date_labels = "%b %y", date_breaks = "1 months")
</code></pre>
<p><img src="/img/acoes1/image4.png" height="350" width="550" align="middle" /></p>
<pre><code class="language-{r}">summary(pbr_ret17)
sd(pbr_ret17)
</code></pre>
<pre><code class="language-{r}">## Index PBR.Adjusted
## Min. :2017-01-03 Min. :-0.185241
## 1st Qu.:2017-02-08 1st Qu.:-0.014350
## Median :2017-03-17 Median :-0.002689
## Mean :2017-03-17 Mean :-0.001707
## 3rd Qu.:2017-04-24 3rd Qu.: 0.014977
## Max. :2017-05-31 Max. : 0.068795
## [1] 0.03089105
</code></pre>
<p>Separamos em um objeto todos os retornos de 2017, utilizando a função <code class="language-plaintext highlighter-rouge">subset()</code>. Com isso, as estatísticas descritivas continuam indicando um retorno médio negativo em 2017. Porém, em 2017 o desvio padrão tem sido menor, o que indica menor risco. Além disso, esse retorno negativo na média se dá em maioria pela grande queda do dia 18.</p>
<h3 id="conclusão">Conclusão</h3>
<p>Bom, isso é tudo para esse tutorial, pessoal. Em posts futuros pretendo abordar análises mais elaboradas e também análise de portfólio e risco. Espero que tenham gostado. Até a próxima!</p>
Tutorial de SVM2017-07-13T16:55:44+00:00http://lamfo-unb.github.io/2017/07/13/svm<h1 id="tutorial-de-svm">Tutorial de SVM</h1>
<p>Neste tutorial será trabalhado uma introdução geral a <em>Support Vector Machines</em> (SVM) e uma aplicação básica utilizando o pacote <code class="language-plaintext highlighter-rouge">e1071</code>.</p>
<h2 id="o-que-é-o-support-vector-machine"><em>O que é o Support Vector Machine?</em></h2>
<p>O Support Vector Machine, também conhecido como Máquina de Suporte Vetorial, foi elaborado com o estudo proposto por Boser, Guyon e Vapnik em 1992. Ele é um algoritmo de aprendizado supervisionado, cujo objetivo é classificar determinado conjunto de pontos de dados que são mapeados para um espaço de características multidimensional usando uma função kernel, abordagem utilizada para classificar problemas. Nela, o limite de decisão no espaço de entrada é representado por um hiperplano em dimensão superior no espaço (VAPNIK et al., 1997 e SARADHI et al., 2005).</p>
<h3 id="de-forma-mais-simples"><em>De forma mais simples…</em></h3>
<p>O SVM realiza a separação de um conjunto de objetos com diferentes classes, ou seja, utiliza o conceito de planos de decisão.
Podemos analisar o uso do SVM com o seguinte exemplo. Na Figura 1 é possível observar duas classes de objetos: azul ou laranja. Essa linha que os separa define o limite em que se encontram os pontos azuis e os pontos laranjas. Ao entrarem novos objetos na análise, estes serão classificados como laranjas se estiverem à direita e como azuis caso situem-se à esquerda. Neste caso, conseguimos separar, por meio de uma linha, o conjunto de objetos em seu respectivo grupo, o que caracteriza um classificador linear.</p>
<p><img src="/img/svm/svm1.jpeg" alt="" align="middle" /></p>
<p>No entanto, problemas de classificação costumam ser mais elaborados, sendo necessário realizar a separação ótima por meio de estruturas mais complexas. O SVM propõe a classificação de novos objetos (teste) com base em dados disponíveis (treinamento). Como pode-se observar na Figura 2. A separação ótima nesse caso ocorreria com a utilização de uma curva.</p>
<p><img src="/img/svm/svm2.jpeg" alt="" align="middle" /></p>
<p>Na esquerda da Figura 3 observamos a complexidade em separar os objetos originais. Para mapeá-los, utilizamos um conjunto de funções matemáticas, conhecido como <em>Kernels</em>. Esse mapeamento é conhecido como o processo de reorganização dos objetos.</p>
<p><img src="/img/svm/svm3.jpeg" alt="" align="middle" /></p>
<p>Observa-se que à direita da Figura 3 há uma separação linear dos objetos. Assim, ao invés de construir uma curva complexa, como no esquema à esquerda; o SVM propõe, nesse caso, essa linha ótima capaz de separar os pontos azuis dos laranjas.</p>
<p><a href="">#sensacional</a> <a href="">#inesquecível</a></p>
<h2 id="e-agora-como-posso-aplicar-esse-modelo"><em>E agora, como posso aplicar esse modelo?</em></h2>
<p>Primeiramente, é necessário carregar os dados que serão estudados. Felizmente esse dataset já está disponível nativamente no R. Para carregá-lo, basta executar o seguinte comando:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">data</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Após carregar a base algumas explorações serão feitas:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">summary</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">tail</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">str</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>O comando <code class="language-plaintext highlighter-rouge">summary</code> apresenta algumas estatísticas das variáveis do <em>dataframe</em>, como média, mediana, máximo, mínimo e quantis.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>summary(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
Min. :4.300 Min. :2.000 Min. :1.000 Min. :0.100 setosa :50
1st Qu.:5.100 1st Qu.:2.800 1st Qu.:1.600 1st Qu.:0.300 versicolor:50
Median :5.800 Median :3.000 Median :4.350 Median :1.300 virginica :50
Mean :5.843 Mean :3.057 Mean :3.758 Mean :1.199
3rd Qu.:6.400 3rd Qu.:3.300 3rd Qu.:5.100 3rd Qu.:1.800
Max. :7.900 Max. :4.400 Max. :6.900 Max. :2.500
</code></pre></div></div>
<p>Os comandos <code class="language-plaintext highlighter-rouge">head</code> e <code class="language-plaintext highlighter-rouge">tail</code> mostram as primeiras seis linhas e as últimas seis linhas nesta ordem. Já o comando <code class="language-plaintext highlighter-rouge">str</code> apresenta a estrutura das variáveis. Por exemplo, se são quantitativas ou categóricas.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> head()
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
</code></pre></div></div>
<p>A partir disso, é possível ter uma noção de como são os dados e quais os tipos de variáveis trabalhadas. É muito importante conhecer bem os dados que serão usados.</p>
<p>Como vamos utilizar as variáveis quantitativas ‘Sepal Length’, ‘Sepal Width’, ‘Petal Length’ e ‘Petal Width’ como preditoras para a variável categórica ‘Species’, é interessante observar a correlação entre as covariáveis do modelo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> names(iris)
[1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
> cor(iris[,1:4])
Sepal.Length Sepal.Width Petal.Length Petal.Width
Sepal.Length 1.0000000 -0.1175698 0.8717538 0.8179411
Sepal.Width -0.1175698 1.0000000 -0.4284401 -0.3661259
Petal.Length 0.8717538 -0.4284401 1.0000000 0.9628654
Petal.Width 0.8179411 -0.3661259 0.9628654 1.0000000
</code></pre></div></div>
<h2 id="gráficos-contam-histórias">Gráficos contam histórias!</h2>
<p>Gráficos são uma excelente ferramenta de abstração e apresentação de suas explorações, estudos que atingem maior público são aqueles que usam de todos os recursos póssiveis para tornar a informação o mais inteligivel possivel, vamos visualizar como cada variável se relaciona por um mapa de gradiente, definindo o vermelho (cor quente) para maior correlação entre as variáveis e o azul (cor fria) para menor correlação:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">lattice</span><span class="p">)</span><span class="w">
</span><span class="n">cor</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">cor</span><span class="p">(</span><span class="n">iris</span><span class="p">[,</span><span class="m">1</span><span class="o">:</span><span class="m">4</span><span class="p">])</span><span class="w">
</span><span class="n">rgb.palette</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colorRampPalette</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="s2">"blue"</span><span class="p">,</span><span class="w"> </span><span class="s2">"red"</span><span class="p">),</span><span class="w"> </span><span class="n">space</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"rgb"</span><span class="p">)</span><span class="w">
</span><span class="n">levelplot</span><span class="p">(</span><span class="n">cor</span><span class="p">,</span><span class="w"> </span><span class="n">main</span><span class="o">=</span><span class="s2">"Correlation Iris Dataset"</span><span class="p">,</span><span class="w"> </span><span class="n">xlab</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span><span class="w"> </span><span class="n">ylab</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span><span class="w"> </span><span class="n">col.regions</span><span class="o">=</span><span class="n">rgb.palette</span><span class="p">(</span><span class="m">120</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>
<p><a href="">#voilà</a></p>
<p><img src="/img/svm/svm4.jpeg" alt="" width="600px" /></p>
<p>Um belo gráfico de correlação. :sunglasses: Primeiro importamos a biblioteca <code class="language-plaintext highlighter-rouge">lattice</code> responsável pela geração de nosso gráfico, armazenamos a matriz de correlação em uma variável e então criamos uma paleta de cores (um array com a definição computacional dessas cores) com a função <code class="language-plaintext highlighter-rouge">colorRampPaletter</code>, indo do azul ao vermelho, por fim passamos essas definições a função <code class="language-plaintext highlighter-rouge">levelplot</code> que cuidará do resto.</p>
<p>Agora o gráfico definitivo para entendermos os nossos dados, o gráfico de dispersão tridimensional. Temos quatro variáveis mas apenas 3 nos possibilitarão enxergar além!</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">install.packages</span><span class="p">(</span><span class="s2">"scatterplot3d"</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">scatterplot3d</span><span class="p">)</span><span class="w">
</span><span class="n">colors</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s2">"#e41a1c"</span><span class="p">,</span><span class="w"> </span><span class="s2">"#377eb8"</span><span class="p">,</span><span class="w"> </span><span class="s2">"#4daf4a"</span><span class="p">)</span><span class="w">
</span><span class="n">colors</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colors</span><span class="p">[</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">iris</span><span class="o">$</span><span class="n">Species</span><span class="p">)]</span><span class="w">
</span><span class="n">scatterplot3d</span><span class="p">(</span><span class="n">iris</span><span class="p">[,</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">],</span><span class="w"> </span><span class="n">pch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">15</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="o">=</span><span class="n">colors</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/svm/svm5.jpeg" alt="" width="600px" /></p>
<p>Com o pacote <code class="language-plaintext highlighter-rouge">scatterplot3d</code> instalado e carregado, definimos 3 cores hexadecimais e salvamos no array colors, então sobrescrevemos esse array com um array referente a espécie substituindo pela cor, especie 1, cor 1, especie 2, cor 2… Por fim passamos todos esses parametros para nossa função que gera nosso gráfico. Como pode ver é clara uma ‘separação’ para os nossos dados, assim não será um trabalho difícil para nossa máquina.</p>
<h2 id="agora-a-parte-mais-esperada-vamoslá">Agora a parte mais esperada… <a href="">#vamoslá</a></h2>
<p>Para utilizar o SVM, é necessário instalar o pacote <em>e1071</em> por meio do comando <code class="language-plaintext highlighter-rouge">install.packages("e1071")</code>.
Aguarde o processo de instalação finalizar e vamos à separação dos dados.</p>
<p>Primeiramente, iremos separar 70% das observações do dataset para ‘calibrarmos’ o modelo e utilizaremos as demais observações para verificar o poder de predição do modelo ajustado.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> dim(iris)
[1] 150 5
> treino <- sample(1:150, 0.7*150)
> teste <- setdiff(1:150,treino)
> iris_treino <- iris[treino,]
> iris_teste <- iris[teste,]
</code></pre></div></div>
<p>No pacote <code class="language-plaintext highlighter-rouge">e1071</code>, usamos a função <code class="language-plaintext highlighter-rouge">svm()</code> para ajustar o modelo de máquina de suporte vetorial. Nota-se que a sintaxe é bastante parecida com as funções <code class="language-plaintext highlighter-rouge">lm()</code> e <code class="language-plaintext highlighter-rouge">glm()</code> para modelos, lineares e lineares generalizados. Uma vez que declaramos a variável dependente (a variável em que queremos fazer predições), a função automaticamente detecta o seu tipo (categórica ou quantitativa) e utiliza o procedimento adequado para o ajuste do modelo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> require(e1071)
> modelo1 <- svm(Species ~ . , data = iris_treino)
> summary(modelo1)
Call:
svm(formula = Species ~ ., data = iris_treino)
Parameters:
SVM-Type: C-classification
SVM-Kernel: radial
cost: 1
gamma: 0.25
Number of Support Vectors: 49
</code></pre></div></div>
<p>Vimos que foi utilizado o kernel “radial” no modelo proposto, pois é o default (o que a função admite se nada é informado no argumento). A função svm() aceita os seguintes kernels: radial, linear, polynomial e sigmoide.</p>
<p>Diferentes kernels ajustam diferentes modelos e, consequentemente, diferentes valores preditos. Ajustaremos então, um modelo para cada kernel, visando obter uma menor taxa de erro de classificação.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">modelo2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">svm</span><span class="p">(</span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">kernel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"linear"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span><span class="n">modelo3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">svm</span><span class="p">(</span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">kernel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"polynomial"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span><span class="n">modelo4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">svm</span><span class="p">(</span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">kernel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"sigmoid"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Agora aplicamos os modelos ajustados nas observações da base ‘teste’ e, por meio de uma tabela de contingência, comparamos a classificação proposta pelos modelos com a classificação real das observações.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>preditos1 <- predict(modelo1,iris_teste)
> table(preditos1,iris_teste$Species)
preditos setosa versicolor virginica
setosa 11 0 0
versicolor 0 20 0
virginica 0 1 13
</code></pre></div></div>
<p>Ao realizar o mesmo procedimento para os demais modelos, podemos utilizar a soma dos elementos não pertencentes à diagonal principal como uma medida de erro, já que estes correspodem aos elementos classificados erroneamente.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">preditos2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo2</span><span class="p">,</span><span class="n">iris_teste</span><span class="p">)</span><span class="w">
</span><span class="n">preditos3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo3</span><span class="p">,</span><span class="n">iris_teste</span><span class="p">)</span><span class="w">
</span><span class="n">preditos4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo4</span><span class="p">,</span><span class="n">iris_teste</span><span class="p">)</span><span class="w">
</span><span class="n">t1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos1</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span><span class="n">t2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos2</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span><span class="n">t3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos3</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span><span class="n">t4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos4</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>> sum(c(t1[lower.tri(t1)],t1[upper.tri(t1)]))
[1] 1
> sum(c(t2[lower.tri(t2)],t2[upper.tri(t2)]))
[1] 1
> sum(c(t3[lower.tri(t3)],t3[upper.tri(t3)]))
[1] 3
> sum(c(t4[lower.tri(t4)],t4[upper.tri(t4)]))
[1] 7
</code></pre></div></div>
<p>Assim, vimos que o modelo1 (kernel = radial) e o modelo2 (kernel = linear) apresentaram resultados mais satisfatórios, pois erraram apenas uma classificação na base de teste.</p>
<h2 id="conclusão">Conclusão</h2>
<p>O SVM possui grande abrangência de aplicações em diversas áreas, como finanças, biologia, medicina, logística, entre outras.
Isso ocorre devido às suas vantagens de aplicação como: bom desempenho de generalização; tratabilidade matemática; interpretação geométrica e a utilização para a exploração de dados não rotulados (YANG et al., 2002).
Este tutorial é apenas uma pequena demonstração de como esta poderosa ferramenta pode ser utilizada. Esperamos que tenha sido útil para os nossos leitores!</p>
<h2 id="referências">Referências</h2>
<p>BOSER, B. E.; GUYON, I. M.; VAPNIK, V. N. A Training Algorithm for Optimal Margin Classifiers. In: ANNUAL WORKSHOP ON COMPUTACIONAL LEARNING, 5, 1992, Pittsburgh. ACM Press. Pittsburgh: Haussler D, jul 1992. p.144-152 .</p>
<p>DRUCKER, H.; BURGES, C. J.; KAUFMAN, L.; SMOLA, A.; VAPNIK, V. Support vector regression machines. Advances in neural information processing systems, Morgan Kaufmann Publishers, p. 155–161, 1997.</p>
<p>SARADHI, V., KAMIK, H., MITRA, P. A Decomposition Method for Support Vector Clustering. In Proc. of the 2nd International Conference on Intelligent Sensing and Information Processing (ICISIP), p. 268-271, 2005.</p>
SVM Tutorial2017-07-13T16:55:44+00:00http://lamfo-unb.github.io/2017/07/13/svm-en<h1 id="svm-tutorial">SVM Tutorial</h1>
<p>In this tutorial we will present a general introduction of <em>Support Vector Machines</em> (SVM) and a basic application using the package <code class="language-plaintext highlighter-rouge">e1071</code>.</p>
<h2 id="what-is-support-vector-machine"><em>What is Support Vector Machine?</em></h2>
<p>Support Vector Machine was developed in the study of Boser, Guyon e Vapnik in 1992. It is a supervised learning algorithm that aims to classify a certain set of data points that are mapped to a multidimensional feature space using a kernel function, the approach used to classify problems. In this case, the decision boundary in the input space is represented by a hyperplane in a larger dimension in space (VAPNIK et al., 1997 and SARADHI et al., 2005).</p>
<h3 id="simplifying"><em>Simplifying…</em></h3>
<p>SVM performs the separation of a set of objects with different classes, in other words, it uses the concept of decision plans.</p>
<p>We can analyze the use of SVM with the following example. It is possible to observe in Figure 1 two classes of objects: blue or orange. This line that divide them defines the boundary between the blue dots and the orange dots. When entering new objects in the analysis, these will be classified as oranges if they are to the right and as blue if they are on the left. In this case, we were able to separate, through a line, the set of objects in their respective group, which characterizes a linear classifier.</p>
<p><img src="/img/svm/svm1.jpeg" /></p>
<p>However, classification problems are usually more elaborate, and it is necessary to perform optimal separation through more complex structures. The SVM proposes to classify new objects (test) based on available data (training). This can be seen in Figure 2. The optimal separation in this case would occur with the use of a curve.</p>
<p><img src="/img/svm/svm2.jpeg" /></p>
<p>On the left of Figure 3 we observe the complexity in separating the original objects. To map them, we use a set of mathematical functions, acknowledged as <em>Kernels</em>. This mapping is known as the process of object reorganization.</p>
<p><img src="/img/svm/svm3.jpeg" /></p>
<p>We can observe in the right of Figure 3 that there is a linear separation between objects. Thus, instead of constructing a complex curve, as in the left scheme; the SVM proposes, in this case, an optimum line capable of separating the blue points from the oranges.</p>
<p><a href="">#incredible</a> <a href="">#unforgettable</a></p>
<h2 id="and-now-how-can-i-apply-this-model"><em>And now, how can I apply this model?</em></h2>
<p>First, it is necessary to load the data that will be studied. Luckily, this dataset is already natively available in R. To load it, simply run the following command:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">data</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>After loading the database we will do some explorations:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">summary</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">tail</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">str</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">summary()</code> command presents some statistics of the <em>dataframe</em> variables, such as mean, median, maximum, minimum and quantiles.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span><span class="n">summary</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">Sepal.Length</span><span class="w"> </span><span class="n">Sepal.Width</span><span class="w"> </span><span class="n">Petal.Length</span><span class="w"> </span><span class="n">Petal.Width</span><span class="w"> </span><span class="n">Species</span><span class="w">
</span><span class="n">Min.</span><span class="w"> </span><span class="o">:</span><span class="m">4.300</span><span class="w"> </span><span class="n">Min.</span><span class="w"> </span><span class="o">:</span><span class="m">2.000</span><span class="w"> </span><span class="n">Min.</span><span class="w"> </span><span class="o">:</span><span class="m">1.000</span><span class="w"> </span><span class="n">Min.</span><span class="w"> </span><span class="o">:</span><span class="m">0.100</span><span class="w"> </span><span class="n">setosa</span><span class="w"> </span><span class="o">:</span><span class="m">50</span><span class="w">
</span><span class="m">1</span><span class="n">st</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">5.100</span><span class="w"> </span><span class="m">1</span><span class="n">st</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">2.800</span><span class="w"> </span><span class="m">1</span><span class="n">st</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">1.600</span><span class="w"> </span><span class="m">1</span><span class="n">st</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">0.300</span><span class="w"> </span><span class="n">versicolor</span><span class="o">:</span><span class="m">50</span><span class="w">
</span><span class="n">Median</span><span class="w"> </span><span class="o">:</span><span class="m">5.800</span><span class="w"> </span><span class="n">Median</span><span class="w"> </span><span class="o">:</span><span class="m">3.000</span><span class="w"> </span><span class="n">Median</span><span class="w"> </span><span class="o">:</span><span class="m">4.350</span><span class="w"> </span><span class="n">Median</span><span class="w"> </span><span class="o">:</span><span class="m">1.300</span><span class="w"> </span><span class="n">virginica</span><span class="w"> </span><span class="o">:</span><span class="m">50</span><span class="w">
</span><span class="n">Mean</span><span class="w"> </span><span class="o">:</span><span class="m">5.843</span><span class="w"> </span><span class="n">Mean</span><span class="w"> </span><span class="o">:</span><span class="m">3.057</span><span class="w"> </span><span class="n">Mean</span><span class="w"> </span><span class="o">:</span><span class="m">3.758</span><span class="w"> </span><span class="n">Mean</span><span class="w"> </span><span class="o">:</span><span class="m">1.199</span><span class="w">
</span><span class="m">3</span><span class="n">rd</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">6.400</span><span class="w"> </span><span class="m">3</span><span class="n">rd</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">3.300</span><span class="w"> </span><span class="m">3</span><span class="n">rd</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">5.100</span><span class="w"> </span><span class="m">3</span><span class="n">rd</span><span class="w"> </span><span class="n">Qu.</span><span class="o">:</span><span class="m">1.800</span><span class="w">
</span><span class="n">Max.</span><span class="w"> </span><span class="o">:</span><span class="m">7.900</span><span class="w"> </span><span class="n">Max.</span><span class="w"> </span><span class="o">:</span><span class="m">4.400</span><span class="w"> </span><span class="n">Max.</span><span class="w"> </span><span class="o">:</span><span class="m">6.900</span><span class="w"> </span><span class="n">Max.</span><span class="w"> </span><span class="o">:</span><span class="m">2.500</span><span class="w">
</span></code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">head()</code> and<code class="language-plaintext highlighter-rouge"> tail()</code> commands show the first and the last six lines in this order. The <code class="language-plaintext highlighter-rouge">str()</code> command displays the structure of the variables. For example, if they are quantitative or categorical.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span><span class="w"> </span><span class="n">head</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="n">Sepal.Length</span><span class="w"> </span><span class="n">Sepal.Width</span><span class="w"> </span><span class="n">Petal.Length</span><span class="w"> </span><span class="n">Petal.Width</span><span class="w"> </span><span class="n">Species</span><span class="w">
</span><span class="m">1</span><span class="w"> </span><span class="m">5.1</span><span class="w"> </span><span class="m">3.5</span><span class="w"> </span><span class="m">1.4</span><span class="w"> </span><span class="m">0.2</span><span class="w"> </span><span class="n">setosa</span><span class="w">
</span><span class="m">2</span><span class="w"> </span><span class="m">4.9</span><span class="w"> </span><span class="m">3.0</span><span class="w"> </span><span class="m">1.4</span><span class="w"> </span><span class="m">0.2</span><span class="w"> </span><span class="n">setosa</span><span class="w">
</span><span class="m">3</span><span class="w"> </span><span class="m">4.7</span><span class="w"> </span><span class="m">3.2</span><span class="w"> </span><span class="m">1.3</span><span class="w"> </span><span class="m">0.2</span><span class="w"> </span><span class="n">setosa</span><span class="w">
</span><span class="m">4</span><span class="w"> </span><span class="m">4.6</span><span class="w"> </span><span class="m">3.1</span><span class="w"> </span><span class="m">1.5</span><span class="w"> </span><span class="m">0.2</span><span class="w"> </span><span class="n">setosa</span><span class="w">
</span><span class="m">5</span><span class="w"> </span><span class="m">5.0</span><span class="w"> </span><span class="m">3.6</span><span class="w"> </span><span class="m">1.4</span><span class="w"> </span><span class="m">0.2</span><span class="w"> </span><span class="n">setosa</span><span class="w">
</span><span class="m">6</span><span class="w"> </span><span class="m">5.4</span><span class="w"> </span><span class="m">3.9</span><span class="w"> </span><span class="m">1.7</span><span class="w"> </span><span class="m">0.4</span><span class="w"> </span><span class="n">setosa</span><span class="w">
</span></code></pre></div></div>
<p>From this, it is possible to have a sense about the data structure and which types of variables we will work with. It is very important to know the data that will be used.</p>
<p>Since we will use the quantitative variables ‘Sepal Length’, ‘Sepal Width’, ‘Petal Length’ and ‘Petal Width’ as predictors for the categorical variable ‘Species’, it is interesting to observe the correlation between the model covariables.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span><span class="w"> </span><span class="nf">names</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="s2">"Sepal.Length"</span><span class="w"> </span><span class="s2">"Sepal.Width"</span><span class="w"> </span><span class="s2">"Petal.Length"</span><span class="w"> </span><span class="s2">"Petal.Width"</span><span class="w"> </span><span class="s2">"Species"</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">cor</span><span class="p">(</span><span class="n">iris</span><span class="p">[,</span><span class="m">1</span><span class="o">:</span><span class="m">4</span><span class="p">])</span><span class="w">
</span><span class="n">Sepal.Length</span><span class="w"> </span><span class="n">Sepal.Width</span><span class="w"> </span><span class="n">Petal.Length</span><span class="w"> </span><span class="n">Petal.Width</span><span class="w">
</span><span class="n">Sepal.Length</span><span class="w"> </span><span class="m">1.0000000</span><span class="w"> </span><span class="m">-0.1175698</span><span class="w"> </span><span class="m">0.8717538</span><span class="w"> </span><span class="m">0.8179411</span><span class="w">
</span><span class="n">Sepal.Width</span><span class="w"> </span><span class="m">-0.1175698</span><span class="w"> </span><span class="m">1.0000000</span><span class="w"> </span><span class="m">-0.4284401</span><span class="w"> </span><span class="m">-0.3661259</span><span class="w">
</span><span class="n">Petal.Length</span><span class="w"> </span><span class="m">0.8717538</span><span class="w"> </span><span class="m">-0.4284401</span><span class="w"> </span><span class="m">1.0000000</span><span class="w"> </span><span class="m">0.9628654</span><span class="w">
</span><span class="n">Petal.Width</span><span class="w"> </span><span class="m">0.8179411</span><span class="w"> </span><span class="m">-0.3661259</span><span class="w"> </span><span class="m">0.9628654</span><span class="w"> </span><span class="m">1.0000000</span><span class="w">
</span></code></pre></div></div>
<h2 id="the-charts-tell-stories">The charts tell stories!</h2>
<p>Charts are an excellent tool to abstract and present your explorations. Studies that reach most spectators are those which use all possible resources to make the information as intelligible as possible. Let’s visualize how each variable is related by a gradient map, defining red (warm color) for greater correlation between the variables and blue (cold color) for lower correlation:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">lattice</span><span class="p">)</span><span class="w">
</span><span class="n">cor</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">cor</span><span class="p">(</span><span class="n">iris</span><span class="p">[,</span><span class="m">1</span><span class="o">:</span><span class="m">4</span><span class="p">])</span><span class="w">
</span><span class="n">rgb.palette</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colorRampPalette</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="s2">"blue"</span><span class="p">,</span><span class="w"> </span><span class="s2">"red"</span><span class="p">),</span><span class="w"> </span><span class="n">space</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"rgb"</span><span class="p">)</span><span class="w">
</span><span class="n">levelplot</span><span class="p">(</span><span class="n">cor</span><span class="p">,</span><span class="w"> </span><span class="n">main</span><span class="o">=</span><span class="s2">"Correlation Iris Dataset"</span><span class="p">,</span><span class="w"> </span><span class="n">xlab</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span><span class="w"> </span><span class="n">ylab</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span><span class="w"> </span><span class="n">col.regions</span><span class="o">=</span><span class="n">rgb.palette</span><span class="p">(</span><span class="m">120</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>
<p><a href="">#voilà</a></p>
<p><img src="/img/svm/svm4.jpeg" width="600" /></p>
<p>A nice correlation chart :sunglasses:. First we import the <code class="language-plaintext highlighter-rouge">lattice</code> library which is responsible for generating our graph, store a correlation matrix in a variable and then create a color scheme (an array with a computational definition of these colors) with a <code class="language-plaintext highlighter-rouge">ColorRampPaletter()</code> function, going From blue to red. Finally we give these definitions to the function <code class="language-plaintext highlighter-rouge">levelplot()</code> that will take care of the rest.</p>
<p>Now we will present the definitive chart to understand our data, the three-dimensional scatter chart. We have four variables but only 3 will allow us to see beyond!</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">install.packages</span><span class="p">(</span><span class="s2">"scatterplot3d"</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">scatterplot3d</span><span class="p">)</span><span class="w">
</span><span class="n">colors</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">c</span><span class="p">(</span><span class="s2">"#e41a1c"</span><span class="p">,</span><span class="w"> </span><span class="s2">"#377eb8"</span><span class="p">,</span><span class="w"> </span><span class="s2">"#4daf4a"</span><span class="p">)</span><span class="w">
</span><span class="n">colors</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">colors</span><span class="p">[</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">iris</span><span class="o">$</span><span class="n">Species</span><span class="p">)]</span><span class="w">
</span><span class="n">scatterplot3d</span><span class="p">(</span><span class="n">iris</span><span class="p">[,</span><span class="m">1</span><span class="o">:</span><span class="m">3</span><span class="p">],</span><span class="w"> </span><span class="n">pch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">15</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="o">=</span><span class="n">colors</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/svm/svm5.jpeg" width="600" /></p>
<p>After installing and loading the <code class="language-plaintext highlighter-rouge">scatterplot3d</code>, we define 3 hexadecimal colors and save in the colors array, so we overwritten this array with an array referring to the species and replacing it by the color. Species 1, color 1, species 2, color 2… Finally, we pass all these parameters to our function that generates our graph. As you can see, a ‘separation’ is clear for our data, so it will not be a difficult job for our machine.</p>
<h2 id="now-the-most-expected-part-letsgo">Now the most expected part… <a href="">#letsgo</a></h2>
<p>To use SVM, you need to install the <em>e1071</em> package using the <code class="language-plaintext highlighter-rouge">install.packages("e1071")</code> command.
Wait to finish the installation process and let’s separate the data.</p>
<p>First, we will separate 70% of the observations from our dataset to ‘calibrate’ the model and use the other observations to verify the predictive power of the adjusted model.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span><span class="w"> </span><span class="nf">dim</span><span class="p">(</span><span class="n">iris</span><span class="p">)</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="m">150</span><span class="w"> </span><span class="m">5</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">treino</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">150</span><span class="p">,</span><span class="w"> </span><span class="m">0.7</span><span class="o">*</span><span class="m">150</span><span class="p">)</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">teste</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">setdiff</span><span class="p">(</span><span class="m">1</span><span class="o">:</span><span class="m">150</span><span class="p">,</span><span class="n">treino</span><span class="p">)</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">iris_treino</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">iris</span><span class="p">[</span><span class="n">treino</span><span class="p">,]</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">iris_teste</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">iris</span><span class="p">[</span><span class="n">teste</span><span class="p">,]</span><span class="w">
</span></code></pre></div></div>
<p>In the <code class="language-plaintext highlighter-rouge">e1071</code> package, we use the<code class="language-plaintext highlighter-rouge">svm()</code> function to adjust the support vector machine model. Note that the syntax is quite similar to the <code class="language-plaintext highlighter-rouge">lm()</code> and <code class="language-plaintext highlighter-rouge">glm()</code> functions for linear and generalized linear models. Once we declare the dependent variable (the variable in which we want to make predictions), the function will automatically detect its type (categorical or quantitative) and use the appropriate procedure to fit the model.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span><span class="w"> </span><span class="n">require</span><span class="p">(</span><span class="n">e1071</span><span class="p">)</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">modelo1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">svm</span><span class="p">(</span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">summary</span><span class="p">(</span><span class="n">modelo1</span><span class="p">)</span><span class="w">
</span><span class="n">Call</span><span class="o">:</span><span class="w">
</span><span class="n">svm</span><span class="p">(</span><span class="n">formula</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span><span class="n">Parameters</span><span class="o">:</span><span class="w">
</span><span class="n">SVM</span><span class="o">-</span><span class="n">Type</span><span class="o">:</span><span class="w"> </span><span class="n">C</span><span class="o">-</span><span class="n">classification</span><span class="w">
</span><span class="n">SVM</span><span class="o">-</span><span class="n">Kernel</span><span class="o">:</span><span class="w"> </span><span class="n">radial</span><span class="w">
</span><span class="n">cost</span><span class="o">:</span><span class="w"> </span><span class="m">1</span><span class="w">
</span><span class="n">gamma</span><span class="o">:</span><span class="w"> </span><span class="m">0.25</span><span class="w">
</span><span class="n">Number</span><span class="w"> </span><span class="n">of</span><span class="w"> </span><span class="n">Support</span><span class="w"> </span><span class="n">Vectors</span><span class="o">:</span><span class="w"> </span><span class="m">49</span><span class="w">
</span></code></pre></div></div>
<p>We used the “radial” kernel in the proposed model, since it is the default (which the function admits if nothing in the argument is informed). The <code class="language-plaintext highlighter-rouge">svm()</code> function accepts the following kernels: radial, linear, polynomial, and sigmoid.</p>
<p>Different kernels fit different models and, consequently, different predicted values. We will then adjust one model for each kernel, aiming to obtain a lower rate of classification error.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">modelo2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">svm</span><span class="p">(</span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">kernel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"linear"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span><span class="n">modelo3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">svm</span><span class="p">(</span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">kernel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"polynomial"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span><span class="n">modelo4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">svm</span><span class="p">(</span><span class="n">Species</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">.</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">kernel</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"sigmoid"</span><span class="w"> </span><span class="p">,</span><span class="w"> </span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">iris_treino</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>We now apply the adjusted models in the observations of the ‘test’ base and, through a contingency table, compare the classification proposed by the models with the actual observations classification.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">preditos1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo1</span><span class="p">,</span><span class="n">iris_teste</span><span class="p">)</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos1</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span><span class="n">preditos</span><span class="w"> </span><span class="n">setosa</span><span class="w"> </span><span class="n">versicolor</span><span class="w"> </span><span class="n">virginica</span><span class="w">
</span><span class="n">setosa</span><span class="w"> </span><span class="m">11</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">0</span><span class="w">
</span><span class="n">versicolor</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">20</span><span class="w"> </span><span class="m">0</span><span class="w">
</span><span class="n">virginica</span><span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="m">13</span><span class="w">
</span></code></pre></div></div>
<p>When performing the same procedure for other models, we can use the sum of the elements that don’t belong to the main diagonal as a measure of error, since they correspond to elements that were misclassified.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">preditos2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo2</span><span class="p">,</span><span class="n">iris_teste</span><span class="p">)</span><span class="w">
</span><span class="n">preditos3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo3</span><span class="p">,</span><span class="n">iris_teste</span><span class="p">)</span><span class="w">
</span><span class="n">preditos4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">predict</span><span class="p">(</span><span class="n">modelo4</span><span class="p">,</span><span class="n">iris_teste</span><span class="p">)</span><span class="w">
</span><span class="n">t1</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos1</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span><span class="n">t2</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos2</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span><span class="n">t3</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos3</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span><span class="n">t4</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">table</span><span class="p">(</span><span class="n">preditos4</span><span class="p">,</span><span class="n">iris_teste</span><span class="o">$</span><span class="n">Species</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">></span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">t1</span><span class="p">[</span><span class="n">lower.tri</span><span class="p">(</span><span class="n">t1</span><span class="p">)],</span><span class="n">t1</span><span class="p">[</span><span class="n">upper.tri</span><span class="p">(</span><span class="n">t1</span><span class="p">)]))</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="m">1</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">t2</span><span class="p">[</span><span class="n">lower.tri</span><span class="p">(</span><span class="n">t2</span><span class="p">)],</span><span class="n">t2</span><span class="p">[</span><span class="n">upper.tri</span><span class="p">(</span><span class="n">t2</span><span class="p">)]))</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="m">1</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">t3</span><span class="p">[</span><span class="n">lower.tri</span><span class="p">(</span><span class="n">t3</span><span class="p">)],</span><span class="n">t3</span><span class="p">[</span><span class="n">upper.tri</span><span class="p">(</span><span class="n">t3</span><span class="p">)]))</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="m">3</span><span class="w">
</span><span class="o">></span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="nf">c</span><span class="p">(</span><span class="n">t4</span><span class="p">[</span><span class="n">lower.tri</span><span class="p">(</span><span class="n">t4</span><span class="p">)],</span><span class="n">t4</span><span class="p">[</span><span class="n">upper.tri</span><span class="p">(</span><span class="n">t4</span><span class="p">)]))</span><span class="w">
</span><span class="p">[</span><span class="m">1</span><span class="p">]</span><span class="w"> </span><span class="m">7</span><span class="w">
</span></code></pre></div></div>
<p>Thus, we saw that model 1 (kernel = radial) and model 2 (kernel = linear) presented more satisfactory results, since they missed only one classification in the test base.</p>
<h2 id="conclusion">Conclusion</h2>
<p>The SVM has a wide range of applications in several areas, such as finance, biology, medicine, logistics, among others.</p>
<p>This is due to its application advantages such as: good generalization performance; mathematical treatability; geometric interpretation and the use for the exploitation of unlabeled data (YANG et al., 2002).</p>
<p>This tutorial is only a small demonstration of how this powerful tool can be used. We hope it has been useful to our readers!</p>
<h2 id="references">References</h2>
<p>BOSER, B. E.; GUYON, I. M.; VAPNIK, V. N. A Training Algorithm for Optimal Margin Classifiers. In: ANNUAL WORKSHOP ON COMPUTACIONAL LEARNING, 5, 1992, Pittsburgh. ACM Press. Pittsburgh: Haussler D, jul 1992. p.144-152 .</p>
<p>DRUCKER, H.; BURGES, C. J.; KAUFMAN, L.; SMOLA, A.; VAPNIK, V. Support vector regression machines. Advances in neural information processing systems, Morgan Kaufmann Publishers, p. 155–161, 1997.</p>
<p>SARADHI, V., KAMIK, H., MITRA, P. A Decomposition Method for Support Vector Clustering. In Proc. of the 2nd International Conference on Intelligent Sensing and Information Processing (ICISIP), p. 268-271, 2005.</p>
Modelo Tweedie Poisson Compound para dados de sinistros de veículos2017-07-05T16:24:52+00:00http://lamfo-unb.github.io/2017/07/05/Modelo-Tweedie-Poisson<h1 id="modelo-tweedie-poisson-compound-para-dados-de-sinistros-de-veículos">Modelo Tweedie Poisson Compound para Dados de Sinistros de Veículos</h1>
<p>Situações onde se deseja verificar/quantificar a influência de certos fatores em uma variável de interesse são comuns em problemas estatísticos.</p>
<p>Para as seguradoras, a análise do nível de risco é extremamente importante para se estabelecer preço, tarifas e até o planejamento da empresa, como projeção de receitas e despesas. Desta forma, é essencial que as seguradoras possuam um modelo que apresente quais fatores influenciam o nível de diferentes riscos, como por exemplo, se uma certo tipo de automóvel tende a gerar mais custos de pagamento do que outros, etc.</p>
<p>Ainda utilizando o exemplo dos tipos de carro. Cada tipo de carro apresenta um preço de seguro diferente, isso se deve porque cada tipo de carro é classificado em uma determinada categoria de acordo com seu nível de risco. O nível de risco é definido por um conjunto de fatores, que podem apresentar ou não apresentar diferenças entre si. Logo, carros que apresentem fatores de risco similares, terão um preço igual ou muito próximo, enquanto que carros que possuem fatores de risco mais destoantes entre si terão um preços divergentes.</p>
<p>Dividiremos o post nas seguintes etapas: (1) explicaremos os modelos usados para cálculo do risco; (2) aplicabilidade, utilizando uma base real.</p>
<h2 id="modelagem">Modelagem</h2>
<p>Para problemas com este tipo interesse (influência de fatores), uma das técnicas mais clássicas é a regressão linear, onde se pode ajustar um modelo para verificar a influência de certas covariáveis (variáveis explicativas) em uma variável de interesse. Entretanto, a regressão linear possui vários pressupostos que frequentemente não são satisfeitos, restringindo sua aplicabilidade. Alguns desses pressupostos são erros independentes e identicamente distribuídos, centrados em zero com distribuição normal, homogeneidade de variância, variáveis explicativas não correlacionadas, entre outros.</p>
<p>Nelder e Wedderburn (1972) propuseram uma classe de modelos de regressão mais flexível, os modelos lineares generalizados. Esta nova classe abrange as distribuições pertencentes à família exponencial (Normal, Gamma, Poisson, Binomial, Normal-Inversa), aumentando a quantidade de problema a serem abordados. Uma distribuição que pertença à família exponencial pode ser representada da seguinte forma:</p>
\[f(y_i;\theta_i,\phi) = \mbox{exp}\left\{\phi^{-1} [y_i \theta_i - b(\theta_i)] + c(y_i,\phi)\right\},\]
<p>em que \(\theta_i\) é o parâmetro canônico; \(b(\cdot)\) e \(c(\cdot)\) são funções conhecidas.
Assim, denota-se \(Y_i \sim \mbox{FE}(\mu_i , \phi)\). A média e variância de \(Y_i\) são dadas, respectivamente, por:</p>
\[E(Y_i) = b'(\theta_i) = {\mu_i}\]
\[Var(Y_i) = \phi b''(\theta_i) = \phi V(\mu_i),\]
<p>em que \(V(\mu_i)\) é a função de variância, que depende unicamente de \(\mu_i\).</p>
<p>Outra classe de modelos importante é a classe dos modelos de dispersão, que inclui distribuições para dados positivos, positivos com massa de probabilidade em zero, contagem e dados na reta real e podem ser classificados como:</p>
<ul>
<li>Modelos de dispersão próprio;</li>
<li>Modelos de dispersão exponencial;</li>
</ul>
<p>Aqui, focaremos no segundo caso.</p>
<p>Modelos de Dispersão Exponencial (ED) têm função densidade de probabilidade dada por:</p>
\[f(y_i;\theta_i,\lambda) = a(y_i,\lambda) \mbox{exp}\left\{\lambda [y_i \theta_i - k(\theta_i)]\right\}, \qquad y_i \in R\]
<p>com parâmetro canônico \(\theta_i\), função adequada \(a(\cdot)\) e \(k(\theta_i)\) função definida como</p>
\[k(\theta) = log \int e^{\theta y} \nu dy\]
<p>em que \(\nu\) é uma medida finita em \(R\).</p>
<p>Por definição, temos que:</p>
<ul>
<li>\(\mu_i\) = \(E(Y_i)\) = \(k'(\theta_i)\)</li>
<li>\(Var(Y_i)\) = \(\frac{1}{\lambda} Var(\mu_i)\) = \(\frac{1}{\lambda}k''(\theta_i)\)</li>
</ul>
<p>Considerando a reparametrização \(\sigma²\) = \(\frac{1}{\lambda}\), temos que \(\sigma²\) representa o parâmetro de dispersão.</p>
<p>O modelo ED, denotado por \(ED(\mu , \sigma²)\), pode ser escrito da seguinte maneira:</p>
\[f(\textbf{y};\mu,\sigma²) = a(\textbf{y},\sigma²) \mbox{exp}\left\{-\frac{1}{2\sigma²} d(\textbf{y};\mu)\right\},\]
<p>em que \(a(\textbf{y};\sigma²) \geq 0\), \(d(\textbf{y};\mu)\) representa a função deviance, \(\mu\) é o parâmetro de locação e \(\sigma²\) é o parâmetro de escala (dispersão).</p>
<p>Percebe-se então, a similaridade entre os modelos lineares generalizados e modelos de dispersão exponencial.</p>
<p>Um caso especial dos modelos de dispersão exponencial, são as distribuições Tweedi (Tweedie, 1984). Nessas distribuições, a função de variância definida anteriormente, tem a forma:</p>
\[V(\mu) = \mu^p , \qquad p \notin (0,1)\]
<p>A distribuição Poisson Compound, caracteriza-se no caso \(1 < p < 2\). Dentre outros casos particulares, observa-se a distribuição Poisson (\(p = 1\)) e a distribuição Gamma (\(p = 2\)).</p>
<h3 id="número-de-sinistros-e-pagamento-total">Número de Sinistros e Pagamento Total</h3>
<p>Os dados referem-se ao número de sinistros e total de pagamento (valores monetários) gerados, por grupo. Desta maneira, um grupo corresponde a uma observação no banco de dados.</p>
<p>Dados referentes a pagamentos pelo total de sinistros por grupo, são contínuos (pois a variável valor de pagamento, geralmente está em unidades de moeda nacional) mas possuem uma massa de probabilidade em zero, vinda dos grupos em que não obtiveram nenhum sinistro no período observado.</p>
<p>Esta característica em particular torna inviável o ajuste de distribuições que já pensaríamos em primeira hipótese em se tratando de dados contínuos à direita, como a distribuição gamma e gaussiana-inversa.</p>
<p>Então como modelar?</p>
<p>Segundo Withers e Nadarajah (2011), a soma de v.a.’s com distribuição gamma (valor monetário de cada sinistro) com seu tamanho dado por v.a.’s independentes de distribuição Poisson (número de sinistros observados), resulta na distribuição Poisson-Gamma Composta (Poisson Compound). Então temos que:</p>
<p>Seja \(T\) o número de sinistros em determinado grupo e \(X_i\) o valor de pagamento do i-ésimo sinistro. Definimos \(Y\) como</p>
\[Y = \sum_{i=1}^{T} X_i\]
<p>Dado que \(T \sim Poisson(\lambda)\) e \(X_i \stackrel{i.i.d.}{\sim} Gamma(\alpha, \gamma)\), temos que \(Y\) possui distribuição Poisson Compound..</p>
<h3 id="aplicação">Aplicação</h3>
<p>Para realizar uma aplicação real dos modelos apresentados, faremos um exercício utilizando o banco de dados de sinistros de automóveis na Suécia, no ano de 1977, utilizando o ambiente R de computação estatística.</p>
<p>A base de dados pode ser obtida no link a seguir: <a href="http://www.statsci.org/data/general/motorins.html">StatiSci</a>.
A descrição das variáveis está disponível no link, mas aqui utilizaremos apenas: Payment (Pagamento total do grupo), Zone (Zona Geográfica; 1 corresponde às maiores cidades) e Make (tipos de carros, agrupados em classes).</p>
<p>Inicialmente, vamos ler os dados e transformar a variável ‘Make’ em fator.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">tweedie</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">faraway</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">statmod</span><span class="p">)</span><span class="w">
</span><span class="n">dados</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">read.table</span><span class="p">(</span><span class="s2">"http://www.statsci.org/data/general/motorins.txt"</span><span class="p">,</span><span class="w">
</span><span class="n">sep</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"\t"</span><span class="p">,</span><span class="w"> </span><span class="n">head</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">Make</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">as.factor</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">Make</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Filtrando os dados, selecionando apenas valores com ‘Zone’ igual a 1 (maiores cidades) e ‘Make’ diferente de 9 (carros mais ‘raros’).</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dados</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dados</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">filter</span><span class="p">(</span><span class="w"> </span><span class="n">Zone</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="m">1</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">Make</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="m">9</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">dados</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Kilometres Zone Bonus Make Insured Claims Payment
1 1 1 1 1 455.13 108 392491
2 1 1 1 2 69.17 19 46221
3 1 1 1 3 72.88 13 15694
4 1 1 1 4 1292.39 124 422201
5 1 1 1 5 191.01 40 119373
6 1 1 1 6 477.66 57 170913
>
</code></pre></div></div>
<p>A estimação do parâmetro \(p\) é dado atraves de uma log-verossimilhança perfilada. Sendo assim, para cada valor fixo de \(p\), são calculados os parâmetros \(\mu\) e \(\phi\) e a log-verossimilhança é observada. Escolhe-se então, o valor de \(p\) que levou à maior log-verosimilhança. Desta maneira, o \(p\) estimado foi de \(1,73\).</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">perfil</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">tweedie.profile</span><span class="p">(</span><span class="w"> </span><span class="n">Payment</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">Make</span><span class="p">,</span><span class="w">
</span><span class="n">p.vec</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">seq</span><span class="p">(</span><span class="m">1.1</span><span class="p">,</span><span class="m">2</span><span class="p">,</span><span class="n">length</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">10</span><span class="p">),</span><span class="w">
</span><span class="n">method</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"interpolation"</span><span class="p">,</span><span class="w">
</span><span class="n">do.plot</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">,</span><span class="w">
</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dados</span><span class="p">)</span><span class="w">
</span><span class="n">perfil</span><span class="o">$</span><span class="n">p.max</span><span class="w">
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[1] 1.736735
</code></pre></div></div>
<p>Ajustamos um modelo simples, onde deseja-se verificar se os diferentes grupos de tipos de carro diferem em valor de pagamento, em relação à classe de referência. No nosso modelo a classe de referência é Make igual a 1.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">modelo</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">glm</span><span class="p">(</span><span class="n">Payment</span><span class="w"> </span><span class="o">~</span><span class="w"> </span><span class="n">Make</span><span class="p">,</span><span class="w">
</span><span class="n">family</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">tweedie</span><span class="p">(</span><span class="n">var.power</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">perfil</span><span class="o">$</span><span class="n">p.max</span><span class="p">),</span><span class="w">
</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">dados</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Verificando os residuos. O modelo não parece estar mal ajustado.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">res</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">qres.tweedie</span><span class="p">(</span><span class="n">modelo</span><span class="p">)</span><span class="w">
</span><span class="n">qqnorm</span><span class="p">(</span><span class="n">res</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/tweeres.png" alt="" /></p>
<p>Através dos resultados, podemos observar que todas os demais tipos de carro diferem do tipo utilizado como referência no modelo. Tal conclusão auxilia num embasamento para que diferentes tarifas sejam cobradas, por exemplo.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>summary(modelo)
Call:
glm(formula = Payment ~ Make, family = tweedie(var.power = perfil$p.max),
data = seguros2)
Deviance Residuals:
Min 1Q Median 3Q Max
-12.771 -6.329 -2.474 1.764 17.402
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.146e-04 1.511e-05 7.583 5.35e-13 ***
Make2 1.579e-04 4.512e-05 3.500 0.000544 ***
Make3 2.024e-04 5.312e-05 3.810 0.000172 ***
Make4 2.467e-04 6.143e-05 4.016 7.65e-05 ***
Make5 2.288e-04 5.803e-05 3.942 0.000103 ***
Make6 1.573e-04 4.501e-05 3.494 0.000555 ***
Make7 3.678e-04 8.543e-05 4.305 2.33e-05 ***
Make8 5.276e-04 1.193e-04 4.423 1.41e-05 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for Tweedie family taken to be 39.68757)
Null deviance: 14409 on 279 degrees of freedom
Residual deviance: 10958 on 272 degrees of freedom
AIC: NA
Number of Fisher Scoring iterations: 7
</code></pre></div></div>
<p>Observando as médias por grupo, nota-se que o grupo 1 demonstra possuir uma média de pagamentos maior que os demais, de modo que também seria valido observar o número de sinistros para futuras conclusões.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>>tapply(dados$Payment , dados$Make , mean)
1 2 3 4 5 6 7 8
295303.29 88720.63 71936.57 59976.89 64369.14 89016.20 40156.29 26995.97
</code></pre></div></div>
<p>Analogamente, modelos podem ser ajustados incluindo as demais covariáveis, dando suporte na tomada de decisões e precificações de seguros, no caso.</p>
<h3 id="referências">Referências.</h3>
<p>Nelder, J. A., and R. W. Wedderburn. “M (1972) Generalized linear models J Rev.” Stat. Soc 135: 370-383.</p>
<p>Tweedie, M. C. K. “An index which distinguishes between some important exponential families.” Statistics: Applications and new directions: Proc. Indian statistical institute golden Jubilee International conference. Vol. 579. 1984.</p>
<p>Withers, Christopher, and Saralees Nadarajah. “On the compound Poisson-gamma distribution.” Kybernetika 47.1 (2011): 15-37.</p>
Bootstrap2017-06-28T10:00:00+00:00http://lamfo-unb.github.io/2017/06/28/Bootstrap<link href="https://fonts.googleapis.com/css?family=Rock Salt" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Sofia" rel="stylesheet" />
<h1 id="bootstrap">Bootstrap</h1>
<p>Nesse post apresentaremos a técnica estatística Bootstrap. Nada melhor do que um exemplo de brigadeiro para termos um gostinho inicial sobre o tema.</p>
<p><img src="/img/bootstrap/Avelã.jpg" width="700" /></p>
<p>Imagine que você seja dono de uma loja de doces. Um cliente espera que, ao comprar um brigadeiro, este tenha, em média, o mesmo peso que o de outro cliente. No entanto, é impossível pesar todos os brigadeiros que serão produzidos pela sua loja!!</p>
<p>O que fazer então??</p>
<p>Você, dono do estabelecimento, pode utilizar técnicas de amostragem capazes de selecionar aleatoriamente 150 brigadeiros e calcular o peso médio desses brigadeiros. Feito isso, poderá concluir que a média da população está dentro de uma margem de erro relativa à média da amostra.</p>
<p>Suponha que você queira saber, após alguns meses, qual o peso médio do brigadeiro no dia em que foi feita uma amostra da linha de produção levando em conta uma maior precisão.</p>
<p>Como diversas variáveis surgiram, não podemos mais usar como base o brigadeiro produzido hoje. Dentre essas variáveis consideramos os diferentes tipos de açúcar, cacau e manteiga, novos sabores, o tipo de confeito, o recheio, entre outros.</p>
<p>Assuma que a única informação que temos é o peso daqueles 150 brigadeiros na data de teste inicial. E, podemos considerar a margem de erro inicial como nossa informação mais relevante.</p>
<p>Felizmente, para solucionar esse problema existe o</p>
<h1>
<div style="font-family: 'Rock Salt';font-size: 60px;">
Bootstrap!! :tada:
</div>
</h1>
<p>Dessa forma, criamos nossa amostra Bootstrap, que surge a partir da amostragem aleatória dos 150 pesos conhecidos. Caso seja permitida a reposição dos pesos, essa amostra bootstrap não será necessariamente idêntica à inicial. Alguns dados podem estar omitidos e outros repetidos. Assim, inúmeras amostras bootstrap são rapidamente criadas com ajuda computacional.</p>
<h2 id="visão-técnica">Visão técnica</h2>
<p>Vamos agora apresentar o Bootstrap com mais detalhes.</p>
<p>Essa técnica estatística foi inicialmente proposta por Bradley Efron, em 1979. Ela vem ganhando força, em especial, devido ao avanço computacional.</p>
<div style="font-family: 'Sofia';font-size: 30px;">
Qual a origem da palavra Bootstrap?
</div>
<p>O termo Bootstrap tem origem inglesa e faz referência ao laço da parte de trás de uma bota que o auxilia a calçá-la.</p>
<p>Seu uso surge da frase “To lift himself up by his bootstraps.”, ou seja, “Erguer-se utilizando seu bootstrap”. Ocorre aqui uma alusão a algo impossível, de difícil realização.</p>
<p>Imagine levantar-se no ar puxando apenas pedaços de couro de sua bota. Isso é impossível! E a ideia que esse modelo quis trazer é a de poder fazer o impossível.</p>
<p>A história do Barão Munchausen, também mencionada na origem do Bootstrap, conta que o Barão conseguiu erguer a si e o seu cavalo de um pântano por meio de seu cabelo (especificamente, seu rabo de cavalo). No entanto, na história não há o uso da palavra bootstrap como a conhecemos e nenhuma outra referência explícita aos bootstraps foi encontrada em outras partes das várias versões dos contos Munchausen.</p>
<div class="row">
<div class="col-md-6">
<img class="img-responsive thumbnail" src="/img/bootstrap/boot2.jpg" alt="mat_elis_1" style="width:0.000001" />
<div class="caption">
</div>
</div>
<div class="col-md-6">
<img class="img-responsive thumbnail" src="/img/bootstrap/pic2.png" alt="mat_elis_2" style="width:0.000001" />
<div class="caption">
</div>
</div>
</div>
<h3 id="teoria">Teoria</h3>
<p>Pense no caso de uma amostra aleatória de tamanho <em>n</em> , a partir de uma função de distribuição de probabilidade <em>F</em> indefinida:
\(X_i=x_i, X_i\) \(\sim\) \(F_{ind}\), \(i=1,2,...,n\).</p>
<p>Sejam \(X= (X_1,X_2,...X_n)\) e \(x=(x_1,x_2,...,x_n)\) as variáveis aleatórias e as observações das variáveis aleatórias independentes, com função de distribuição comum <em>F</em>. Vamos investigar a variabilidade e a distribuição amostral do cálculo da estimativa local a partir da amostra de tamanho <em>n</em>. Denotamos essa estimativa local como \(\widehatθ\). Note que \(\widehatθ\) é uma função das variáveis aleatórias \((X_1,X_2,...X_n)\) e, por isso, possui uma distribuição de probabilidade, sua distribuição amostral, que é determinada por <em>n</em> e <em>F</em>.</p>
<p>Com base em Efron and Tibshirani (1993), os passos básicos para criação do Bootstrap são:</p>
<h4 id="passo-1">Passo 1:</h4>
<p>Construa, a partir da amostra, uma distribuição de probabilidade empírica \(F_n\), inserindo, em cada ponto \(x_1,x_2,...x_n\) da amostra, uma probabilidade \(1/n\).</p>
<p>Caracterizada como uma função de distribuição empírica da amostra, esta é uma estimativa não paramétrica de máxima probabilidade da distribuição populacional, <em>F</em>.</p>
<h4 id="passo-2">Passo 2:</h4>
<p>Realize a reamostragem: desenhe uma amostra aleatória de tamanho <em>n</em> com reposição a partir da função de distribuição \(F_n\).</p>
<h4 id="passo-3">Passo 3:</h4>
<p>Calcule para essa reamostragem a estatística de interesse \(T_n\), gerando \(T_n^*\).</p>
<h4 id="passo-4">Passo 4:</h4>
<p>Repita os passos 2 e 3 <em>B</em> vezes. Para criar <em>B</em> reamostras, <em>B</em> deve ser um valor grande. O tamanho de <em>B</em> depende de testes a serem realizados com os dados. Quando uma estimativa com intervalo de confiança de \(T_n\) é necessária, sugere-se que <em>B</em> seja ao menos igual à 1000.</p>
<h4 id="passo-5">Passo 5:</h4>
<p>Construa a partir do valor <em>B</em> de \(T_n\) a frequência relativa do histograma, atribuindo probabilidade de \(1/B\) à cada ponto \(T_n^1\), \(T_n^2\),…, \(T_n^B\).</p>
<p>A distribuição obtida é a estimativa Bootstrap da distribuição amostral de \(T_n\). Pode-se realizar inferências sobre o parâmetro θ, utilizando essa distribuição, estimando \(T_n\).</p>
<h2 id="bootstrap-e-ações-do-mercado-financeiro-utilizando-o-r">Bootstrap e ações do mercado financeiro utilizando o R</h2>
<p>No exemplo a seguir, criaremos a amostra Bootstrap para os retornos diários das ações da Apple e do índice S&P500 de 02/06/2016 a 31/05/2017. Para tanto, primeiro baixe a base <em>bootstrap.txt</em> que está disponível no <a href="https://raw.githubusercontent.com/lamfo-unb/lamfo-data/master/dadosBootstrap.txt">link</a>. Faça a leitura dessa base no R conforme demonstrado no código abaixo:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dados</span><span class="o"><-</span><span class="n">read.table</span><span class="p">(</span><span class="n">file.choose</span><span class="p">())</span><span class="w">
</span></code></pre></div></div>
<p>Para trabalhar com a base digite o seguinte comando:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">spxret</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dados</span><span class="p">[,</span><span class="w"> </span><span class="s1">'SP500index'</span><span class="p">]</span><span class="w">
</span><span class="n">applret</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dados</span><span class="p">[,</span><span class="s1">'APPLE'</span><span class="p">]</span><span class="w">
</span><span class="nf">names</span><span class="p">(</span><span class="n">dados</span><span class="p">)[</span><span class="nf">names</span><span class="p">(</span><span class="n">dados</span><span class="p">)</span><span class="o">==</span><span class="s2">"SP500index"</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"sp500"</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">as.numeric</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="p">))</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="p">)))</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">APPLE</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">APPLE</span><span class="p">)))</span><span class="w">
</span><span class="n">spxret</span><span class="o"><-</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">spxret</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Os comandos <code class="language-plaintext highlighter-rouge">spxret</code> e <code class="language-plaintext highlighter-rouge">applret</code> extraem uma coluna para criar um vetor. Nas linhas seguintes trabalhamos a base para transformar todos os dados em numéricos, retiramos NA’s e transformamos os retornos em log retornos.</p>
<p>Na nossa análise obtivemos, em um ano, 251 retornos diários. Aleatoriamente uma amostra bootstrap foi obtida dos retornos diários. No nosso caso, você observará que alguns dias estarão diversas vezes na amostra bootstrap enquanto outros nem aparecerão. Isso ocorre devido ao fato de realizarmos amostragem com reposição. A partir da nossa amostra bootstrap, optamos por realizar a soma dos valores. Tipicamente várias amostras bootstrap são criadas.</p>
<p>O código abaixo mostra como utilizar o Bootstrap para gerar 1000 amostras Bootstrap. Podemos observar abaixo que amostramos com inteiros de 1 a 251. Criamos uma amostra de tamanho 251 e a amostramos com reposição. Com o comando <code class="language-plaintext highlighter-rouge">this.samp</code> temos um ano com retornos diários que poderiam ter acontecido. Coletamos os retornos anuais para cada ano hipotético na linha de código seguinte.</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">spx.boot.sum</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">numeric</span><span class="p">(</span><span class="m">1000</span><span class="p">)</span><span class="w"> </span><span class="c1"># numeric vector 1000 long</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="m">1000</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">this.samp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">spxret</span><span class="p">[</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="m">251</span><span class="p">,</span><span class="w"> </span><span class="m">251</span><span class="p">,</span><span class="w"> </span><span class="n">replace</span><span class="o">=</span><span class="kc">TRUE</span><span class="p">)</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="n">spx.boot.sum</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="n">this.samp</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Você pode também plotar a distribuição dos retornos anuais obtidos com o Bootstrap com o código a seguir:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">plot</span><span class="p">(</span><span class="n">density</span><span class="p">(</span><span class="n">spx.boot.sum</span><span class="p">),</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="o">=</span><span class="s2">"orange"</span><span class="p">)</span><span class="w">
</span><span class="n">abline</span><span class="p">(</span><span class="n">v</span><span class="o">=</span><span class="nf">sum</span><span class="p">(</span><span class="n">spxret</span><span class="p">),</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="o">=</span><span class="s1">'blue'</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Segundo a imagem abaixo, o retorno anual é bastante variável. Caso você utilize uma base de dados inicial diferente, o seu gráfico sofrerá alterações. Nessa situação encontramos bem próximo ao meio da distribuição o nosso retorno anual. Vale ressaltar que esse resultado pode ser diferente devido a vieses estatísticos ou na base de dados.</p>
<p><img src="/img/bootstrap/Rplot02.png" width="500" /></p>
<h3 id="vamos-praticar">Vamos praticar?</h3>
<h2 id="referências">Referências</h2>
<p>Efron, B. (1979). Bootstrap methods: another look at the jackknife. The annals of Statistics, 1-26.</p>
<p>Efron, B, and Tibshirani, R.J. (1993). An introduction to the bootstrap. Chapman and Hall, London.</p>
Bootstrap2017-06-28T10:00:00+00:00http://lamfo-unb.github.io/2017/06/28/Bootstrap-en<link href="https://fonts.googleapis.com/css?family=Rock Salt" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Sofia" rel="stylesheet" />
<h1 id="bootstrap">Bootstrap</h1>
<p>In this post, we present a statistic technique called Bootstrap. Nothing better than an example of brigadeiro (a typical and popular desert in Brazil) for a preliminary taste on the subject.</p>
<p><img src="/img/bootstrap/Avelã.jpg" width="700" /></p>
<p>Imagine you own a candy store. A customer expects that, when buying a brigadeiro, it will have, on average, the same weight as the one of another customer. However, it is impossible to weigh all the brigadeiros that will be produced in your store!!</p>
<p>What should we do then??</p>
<p>You, the owner of the establishment, can use sampling techniques to randomly select 150 brigadeiros and calculate the average weight of these brigadeiros. Done this, you can conclude that the population mean is within an margin error relative to the sample mean.</p>
<p>Suppose you want to know, after a few months, what the average weight of the brigadeiro would be on a given production line date, taking into account greater accuracy.</p>
<p>As several variables have emerged, we can no longer use the sample of brigadeiros produced today as a baseline. Among these variables involved, we consider different types of sugar, cocoa and butter, new flavors, type of confectionery, the filling, among others.</p>
<p>Let us assume that the only information we have is the weight of a sample of 150 brigadeiros on the initial testing date. We can consider the initial error margin as our most relevant information.</p>
<p>Fortunately, to solve this problem there is</p>
<h1>
<div style="font-family: 'Rock Salt';font-size: 60px;">
Bootstrap!! :tada:
</div>
</h1>
<p>In this scenario, we create our Bootstrap sample, which arises from the random sampling of the 150 known weights. If weight replacement is allowed, this bootstrap sample will not necessarily be identical to the initial sample. Some data may be omitted and others may be repeated. In this scenarion, numerous bootstrap samples are quickly created.</p>
<h2 id="technical-view">Technical View</h2>
<p>Let’s now introduce Bootstrap with more detail.</p>
<p>This statistical technique was initially proposed by Bradley Efron in 1979. It has been gaining strength, especially due to the advances in computer power.</p>
<div style="font-family: 'Sofia';font-size: 30px;">What is the origin of the word Bootstrap??</div>
<p>Bootstrap term has English origin and refers to the lace on the back of a boot which helps to put it on.</p>
<p>Its use comes from the phrase “To lift himself up by his bootstraps”, that is, “Get up using your bootstrap”. Here, there is an allusion to something impossible, difficult to achieve.</p>
<p>Imagine getting up in the air pulling only pieces of leather from your boot. This is impossible! And the idea that this model wants to bring is to be able to do the impossible.</p>
<p>The story of Baron Munchausen, also mentioned in the origin of the Bootstrap concept, tells that he was able to raise himself and his horse from a swamp by pulling his own hair (specifically, his ponytail). However, in this history there is no use of the word bootstrap as we know it and no other explicit reference to bootstraps has been found elsewhere in the various versions of Munchausen tales.</p>
<div class="row">
<div class="col-md-6">
<img class="img-responsive thumbnail" src="/img/bootstrap/boot2.jpg" alt="mat_elis_1" style="width:0.000001" />
<div class="caption">
</div>
</div>
<div class="col-md-6">
<img class="img-responsive thumbnail" src="/img/bootstrap/pic2.png" alt="mat_elis_2" style="width:0.000001" />
<div class="caption">
</div>
</div>
</div>
<h3 id="theory">Theory</h3>
<p>Think about the case of a random sample of size <em>n</em> , from a probability distribution function <em>F</em> undefined:
\(X_i=x_i, X_i\) \(\sim\) \(F_{i}\), \(i=1,2,...,n\).</p>
<p>Let \(X= (X_1,X_2,...X_n)\) and \(x=(x_1,x_2,...,x_n)\) be the random variables and the observations of the independent random variables, with the same distribution function <em>F</em> . We will investigate the variability and the sampling distribution of the local estimation calculation from the sample of size <em>n</em>. We denote this local estimate as \(\widehatθ\). Note that \(\widehatθ\) is a function of the random variables \((X_1, X_2, ... X_n)\) and, therefore, has a probability distribution, its sample distribution, which is determined by <em>n</em> and <em>F</em>.</p>
<p>Based on Efron and Tibshirani (1993), the basic steps for creating Bootstrap are:</p>
<h4 id="step-1">Step 1:</h4>
<p>Construct, from the sample, an empirical probability distribution \(F_n\), inserting, in each point \(x_1, x_2, ... x_n\) of the sample, a probability \(1/n\).</p>
<p>Characterized as an empirical distribution function of the sample, this is a non-parametric estimate of the maximum probability from the population distribution, <em>F</em>.</p>
<h4 id="step-2">Step 2:</h4>
<p>Perform the resample: draw a random sample of size <em>n</em> with replacement from the \(F_n\) distribution function.</p>
<h4 id="step-3">Step 3:</h4>
<p>Calculate for this resampling the statistic of interest \(T_n\), generating \(T_n^*\).</p>
<h4 id="step-4">Step 4:</h4>
<p>Repeat steps 2 and 3 <em>B</em> times. To create <em>B</em> resamples, <em>B</em> must be a large value. The size of <em>B</em> depends on tests that will be performed with the data. When an estimate with confidence interval of \(T_n\) is required, it is suggested that <em>B</em> should be at least equal to 1000.</p>
<h4 id="step-5">Step 5:</h4>
<p>Build, from the value <em>B</em> of \(T_n\), the relative frequency of the histogram, assigning probability of \(1/B\) to each point \(T_n^1\), \(T_n^2\),…, \(T_n^B\).</p>
<p>The obtained distribution is the Bootstrap estimate of the sampling distribution of \(T_n\). One can make inferences from parameter θ, using this distribution, estimating \(T_n\).</p>
<h2 id="bootstrap-and-stocks-in-financial-market-using-r">Bootstrap and stocks in financial market using R</h2>
<p>In the following example, we will create the Bootstrap sample for the daily returns of Apple shares and the S&P500 index from 06/02/2016 to 05/31/2017. To do so, first download the base <em>bootstrap.txt</em> from the following <a href="https://raw.githubusercontent.com/lamfo-unb/lamfo-data/master/dadosBootstrap.txt">file</a>. Now, read the database in R using the code below:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">dados</span><span class="o"><-</span><span class="n">read.table</span><span class="p">(</span><span class="n">file.choose</span><span class="p">())</span><span class="w">
</span></code></pre></div></div>
<p>To work with this file type the following command:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">spxret</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dados</span><span class="p">[,</span><span class="w"> </span><span class="s1">'SP500index'</span><span class="p">]</span><span class="w">
</span><span class="n">applret</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">dados</span><span class="p">[,</span><span class="s1">'APPLE'</span><span class="p">]</span><span class="w">
</span><span class="nf">names</span><span class="p">(</span><span class="n">dados</span><span class="p">)[</span><span class="nf">names</span><span class="p">(</span><span class="n">dados</span><span class="p">)</span><span class="o">==</span><span class="s2">"SP500index"</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"sp500"</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">as.numeric</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="p">))</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">sp500</span><span class="p">)))</span><span class="w">
</span><span class="n">dados</span><span class="o">$</span><span class="n">APPLE</span><span class="o"><-</span><span class="nf">c</span><span class="p">(</span><span class="kc">NA</span><span class="p">,</span><span class="n">diff</span><span class="p">(</span><span class="nf">log</span><span class="p">(</span><span class="n">dados</span><span class="o">$</span><span class="n">APPLE</span><span class="p">)))</span><span class="w">
</span><span class="n">spxret</span><span class="o"><-</span><span class="nf">as.numeric</span><span class="p">(</span><span class="n">spxret</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>The <code class="language-plaintext highlighter-rouge">spxret</code> and<code class="language-plaintext highlighter-rouge"> applret</code> commands extract a column to create a vector. In the following lines of the code above, we work on the database to turn all data into numerics, removing NA’s (No Data values) and transforming returns into log returns.
In our analysis we obtained, in one year, 251 daily returns. Randomly a bootstrap sample was obtained from daily returns. In our case, you will notice that some days will appear several times in the bootstrap sample while others will not appear at all. This is due to the fact that we perform sampling with replacement. From our bootstrap sample, we chose to perform the sum of the values. Typically several bootstrap samples are created.</p>
<p>The code below shows how to use Bootstrap to generate 1000 Bootstrap samples. We can see below that we sample with integers from 1 to 251. We created a sample of size 251 and sample it with replacement. With the command <code class="language-plaintext highlighter-rouge">this.samp</code> we get a year with daily returns that could have happened. We collect annual returns for each hypothetical year in the following code line.</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">spx.boot.sum</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">numeric</span><span class="p">(</span><span class="m">1000</span><span class="p">)</span><span class="w"> </span><span class="c1"># numeric vector 1000 long</span><span class="w">
</span><span class="k">for</span><span class="p">(</span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="m">1</span><span class="o">:</span><span class="m">1000</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="n">this.samp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">spxret</span><span class="p">[</span><span class="w"> </span><span class="n">sample</span><span class="p">(</span><span class="m">251</span><span class="p">,</span><span class="w"> </span><span class="m">251</span><span class="p">,</span><span class="w"> </span><span class="n">replace</span><span class="o">=</span><span class="kc">TRUE</span><span class="p">)</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="n">spx.boot.sum</span><span class="p">[</span><span class="n">i</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">sum</span><span class="p">(</span><span class="n">this.samp</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>You can also plot the annual returns distribution obtained using Bootstrap with the following code:</p>
<div class="language-R highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">plot</span><span class="p">(</span><span class="n">density</span><span class="p">(</span><span class="n">spx.boot.sum</span><span class="p">),</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="o">=</span><span class="s2">"orange"</span><span class="p">)</span><span class="w">
</span><span class="n">abline</span><span class="p">(</span><span class="n">v</span><span class="o">=</span><span class="nf">sum</span><span class="p">(</span><span class="n">spxret</span><span class="p">),</span><span class="w"> </span><span class="n">lwd</span><span class="o">=</span><span class="m">3</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="o">=</span><span class="s1">'blue'</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>According to the image below, the annual return is quite variable. If you use a different initial database, your chart will change. In this case we find that our annual return is very close to the middle of the distribution. It is noteworthy that this result may be different due to statistical biases or the database.</p>
<p><img src="https://i.imgur.com/HrxEhHM.png" alt="" /></p>
<h3 id="lets-practice">Let’s practice?</h3>
<h2 id="references">References</h2>
<p>Efron, B. (1979). Bootstrap methods: another look at the jackknife. The annals of Statistics, 1-26.</p>
<p>Efron, B, and Tibshirani, R.J. (1993). An introduction to the bootstrap. Chapman and Hall, London.</p>
Uma Abordagem Intuitiva às Redes Neurais2017-06-18T10:19:07+00:00http://lamfo-unb.github.io/2017/06/18/itro-ao-deep-learning<h2 id="conteúdo">Conteúdo</h2>
<ol>
<li><a href="#intro">Introdução</a></li>
<li><a href="#am-contemp">Aprendizado de Máquina Contemporâneo</a></li>
<li><a href="#neuronios">Neurônios</a></li>
<li><a href="#RNA">Redes Neurais Artificiais</a></li>
<li><a href="#treino">Treinamento</a></li>
<li><a href="#implementacao">Implementando uma Rede Neural Artificial</a></li>
<li><a href="#ref">Referências</a></li>
</ol>
<h2 id="introdução-">Introdução <a name="intro"></a></h2>
<p>Antes de começarmos, é necessário ter uniformidade em nossa liguagem. Por isso, peço que leia a <a href="https://matheusfacure.github.io/AM-Essencial/">introdução ao aprendizado de máquina</a> que fiz especialmente para quem quer iniciar o entendimento sobre o assunto. Lá, falo sobre o que é e para que serve aprendizado de máquina e apresento alguns do principais conceitos dessa ciência, como os três tipos de aprendizado, o dilema de viés e variância, treinamento, avaliação e validação cruzada. Reconheço que é um post um pouco longo, mas, por favor, invista um pouco do seu tempo nele e entenda bem os conceitos lá apresentados.</p>
<p>Bom, espero que você tenha lido o que recomendei. A partir desse ponto, utilizarei alguns dos termos apresentados (e que, talvez, você tenha acabado de aprender). Isso me permitirá tornar este post mais curto, já que não precisarei explicar todos os conceitos de aprendizado de máquina do zero.</p>
<p><strong>Aviso:</strong> Ao final deste post, você entenderá intuitivamente o que é uma rede neural e será capaz de treinar uma para reconhecimento de imagem. Mesmo assim, esse post é apenas uma breve introdução ao aprendizado de máquina contemporâneo. Pensei nele como uma forma de instigar a sua curiosidade e lhe convencer de que aprendizado de máquina é um assunto no qual vale a pena se aprofundar. Assim, do <strong>fundo do meu coração</strong>, não terminem essa leitura achando que já sabem o suficiente e, por favor, continuem aprendendo mais, bem mais, do que o conteúdo apresentado aqui.</p>
<h2 id="aprendizado-de-máquina-contemporâneo-">Aprendizado de Máquina Contemporâneo <a name="am-contemp"></a></h2>
<p>A maioria dos algoritmos de aprendizado de máquina são do século passado. Alguns, como redes neurais, são especialmente velhos, tendo sido inventados na década de 50. Por que, então, só agora observamos aprendizado de máquina em todos os cantos e seu anúncio em revistas e jornais aos quatro ventos? Podemos argumentar que, embora os algoritmos em si sejam velhos, algumas pequenas melhorias mais recentes os tornaram, finalmente, extremamente úteis. Isso é parcialmente verdade, mas foram outros dois fatores que mais contribuíram para o atual renascimento da inteligência artificial: </p>
<ul>
<li>Aumento do poder computacional (leia-se GPUs enormes)</li>
<li>Aumento da disponibilidade de dados (leia-se <b>Big Data</b> ou simplesmente bases de dados maiores)</li>
</ul>
<p>Infelizmente, ainda hoje, para que um modelo de aprendizado de máquina consiga extrapolar um padrão aprendido, ele precisa de uma abundância de exemplos desses padrões. Por exemplo, para que um sistema inteligente consiga interpretar uma palavra, ele necessita antes visualizar milhões de frases para entender como as plavras se relacionam. Isso só foi possível recentemente, com a expansão da quantidade de dados e da capacidade computacional para processá-los.</p>
<p>Devemos ter em mente que os <strong>sistemas de inteligência artificias contemporâneos não são nada mais do que modelos matemáticos complexos que conseguem aprender uma representação simplificada da realidade, a partir da extração de padrões estatísticos presentes nos dados, que são, por sua vez, extraídos dessa mesma realidade que motiva o aprendizado</strong>. E, <a href="https://arxiv.org/abs/1605.06065">por enquanto</a>, um ponto fraco desses sistemas ou modelos estatísticos é que eles precisam de muitos dados para conseguir entender os padrões que se apresentam na nossa complexa realidade.</p>
<p>Mas como exatamente esses sistemas conseguem entender a nossa realidade? Infelizmente, ainda não podemos dizer com certeza como isso é feito. Agora explicarei da forma mais aceita e cujas evidenciais são mais fortes. Em poucas palavras, os sistemas de inteligência artificial modernos primeiro aprendem uma <strong>representação interna abstrata</strong> dos dados brutos e, a partir dessa representação abstrata, realizam alguma tarefa, geralmente uma previsão. Por exemplo, considere a tarefa de prever que objeto está em uma imagem. Nesse caso, os dados são simples pixeis com quantidades de vermelho, verde e azul (se a imagem for preta e branca, os pixeis são ainda mais simples, indicando apenas a quantidade de preto). Como é muito difícil sair desses dados brutos para conceitos abstratos - como a transparência de uma garrafa pet, um olho em uma face, o telhado de uma casa -, o sistema antes converte os pixeis de uma imagem em algo mais abstrato, como o conceito visual de um olho.</p>
<p>Isso é provavelmente o que eu e você fazemos quando enxergamos. O nosso corpo percebe raios multicoloridos refletidos nos objetos, mas o que vemos são conceitos com uma carga semântica muito maior, tais como a textura da madeira em uma cadeira ou a silhueta opaca de um gato branco passeando sob a meia luz. Para representar esse nível de abstração, os sistemas contemporâneos de IA são geralmente construídos em camadas. Podemos pensar nelas como <strong>níveis hierárquicos de abstração</strong> que serão aprendidos por um modelo estatístico. Por exemplo, a primeira camada de um sistema pode aprender a abstrair pixeis em cantos e quinas de objetos ou diferenças de contraste e luminosidade; a segunda camada, partido das abstrações da primeira, converte os cantos e quinas em formas mais elaboradas, como círculos, triângulos e quadrados; a terceira camada então pode partir dessas formas para criar abstrações sobre parte de objetos, como a roda de um carro ou o bico de um papagaio; por fim, o sistema usa essas abstrações finais para identificar o que está em uma foto colorida. (Isso é mais do que um mero exemplo. Na verdade, existem <a href="https://matheusfacure.github.io/2017/05/09/deepdream/">formas um tanto divertidas de ver as abstrações aprendidas por IAs</a>).</p>
<p>Esse modo de estruturar os sistemas de IA é o que leva o nome de <strong>Deep Learning</strong> (aprendizado profundo) ou aprendizado de representações. A palavra “profundo” vem do simples fato de construímos nossos sistemas empilhando camadas.</p>
<h2 id="neurônios-">Neurônios <a name="neuronios"></a></h2>
<p>Nesta introdução, para exemplificar a construção e o treinamento de um sistema moderno de IA, realizaremos uma simples tarefa de visão computacional, na qual usaremos uma rede neural bem simples para reconhecer dígitos escritos. Em termos técnicos, será uma tarefa de <a href="https://pt.wikipedia.org/wiki/Reconhecimento_%C3%B3tico_de_caracteres">OCR (Optical Character Recognition)</a>. Mas, antes de entendermos o que são e como treinar redes neurais, precisamos falar sobre seu componente mais básico: os neurônios.</p>
<figure class="figure center-block thumbnail">
<img src="/img/simple_DNN/perceptron.png" class="img-responsive center-block" alt="perceptron" />
<figcaption class="figure-caption text-center"><a href="https://blog.dbrgn.ch/2013/3/26/perceptrons-in-python/">Fonte</a></figcaption>
</figure>
<p>Como grande parte dos algoritmos de aprendizado de máquina, os neurônios são modelos matemáticos (ou funções) que representam a realidade de forma simplificada. Eles são compostos por uma soma ponderada, seguida ou não de uma função ativação. Por exemplo, considere a tarefa de prever se o preço de uma casa será maior ou menor do que a média, dadas as variáveis \(x_1\), o tamanho da casa em metros quadrados, \(x_2\), o índice de pobreza da vizinhança e \(x_3\) o tamanho do meu cabelo. Podemos facilmente utilizar um neurônio para resolver essa tarefa. Note que, provavelmente, quanto maior \(x_1\), maior a probabilidade da casa ter um preço acima da média (e vice versa). Assim, devemos esperar que o peso de \(x_1\), \(w_1\), na soma ponderada do nosso neurônio seja positivo, indicando que essa variável tem um impacto igualmente positivo na probabilidade do preço da casa ser acima da média. Com o mesmo raciocínio, podemos argumentar que \(w_2\) será negativo. Note que esses dois pesos não precisam ter a mesma intensidade. Pode ser que o impacto positivo de \(x_1\) seja muito maior que o impacto negativo de \(x_2\), de forma que \(w_1\) seja maior que \(w_2\). Em outras palavras, pode ser que o tamanho da casa seja um determinante mais importante do preço do que o índice de pobreza da vizinhança. Por fim, é provável que o tamanho do meu cabelo, \(x_3\), não tenha muito impacto no preço de uma casa. Por isso, esperamos que \(w_3\) seja muito próximo de zero na soma ponderada do nosso neurônio. Isso indica que essa variável influencia pouco o preço da casa. Repare também que temos uma variável que é sempre \(1\). A ponderação desse \(1\) com o \(w_0\) é o que chamamos de viés. Esse viés captura a tendência da casa ter valor alto, uma vez que já consideramos as outras variáveis. Por fim, é importante ressaltar que os \(w\)s são o que chamamos de parâmetros do modelo. Eles são variáveis que o neurônio (e, mais para frente, a rede neural) vai aprender (ou estimar) durante o treinamento.</p>
<p>Além da soma ponderada, nosso neurônio precisa de uma função de ativação. Isso porque a soma ponderada pode nos dar um resultado qualquer, mas, como nossa previsão é uma probabilidade, precisamos de uma função ativação que converta um número qualquer, positivo ou negativo, em um valor entre 0 e 1. Essa função é denominada função <a href="https://en.wikipedia.org/wiki/Softmax_function">softmax</a>, que será utilizada após a soma ponderada do nosso neurônio. Existem várias funções de ativação e, dependendo da tarefa em questão, uma é mais recomendada do que outra. Infelizmente, para falar delas é preciso mais conhecimento matemático. Intuitivamente, quando as mencionamos em redes neurais, imagine a função ativação como algo que dá um comportamento mais complexo aos neurônios. Elas também são fundamentais nas redes neurais, para que essas consigam representar padrões complexos.</p>
<h2 id="redes-neurais-artificiais-">Redes Neurais Artificiais <a name="RNA"></a></h2>
<p>Infelizmente, os neurônios são bastante limitados. Em aprendizado de máquina, queremos que um algoritmo possa aprender qualquer tipo de padrão presente nos dados, mas isso não é possível com um simples neurônio. Por isso, construímos as redes neurais, que são simplesmente vários neurônios conectados. Pense nos neurônios como blocos de Lego e nas redes neurais como estruturas que montamos empilhando esses blocos de Lego. Dependendo da tarefa, uma estrutura pode se mais útil do que outra. No entanto, aqui, vamos considerar apenas a estrutura mais simples e mais comum de rede neural, o modelo de <strong>redes neurais <em>feedforward</em> densas</strong>.</p>
<figure class="figure center-block thumbnail">
<img src="/img/simple_DNN/RNA1.png" class="img-responsive center-block" alt="RNA1" />
<figcaption class="figure-caption text-center"><a href="http://www.texample.net/tikz/examples/neural-network/">Fonte</a></figcaption>
</figure>
<p>Na rede neural acima, como exemplo, dizemos que ainda lidamos com o problema de prever se o preço de uma casa será acima ou abaixo da média. Na entrada da rede, temos as mesmas 3 variáveis mais o viés, que são representados pelas bolinhas verdes. Isso é o que chamamos de camada de entrada da rede neural. Posteriormente, utilizando 5 neurônios, realizamos 5 somas ponderadas seguidas de uma função de ativação. Essas operações são representadas pelas bolinhas azuis, que recebem o nome de camada oculta da rede neural. Por fim, usamos um único neurônio que realiza uma soma ponderada do resultado dos neurônios anteriores e então converte essa soma ponderada em uma probabilidade com a função softmax. Isso é o que chamamos de camada de saída da rede neural e está representado pela bolinha vermelha.</p>
<p>Ignore a camada de entrada (verde) por um momento. Você notou como a camada de saída mais a camada oculta são exatamente o modelo de neurônio que vimos anteriormente? A camada de saída é simplesmente um modelo de neurônio, que está tratando a camada oculta como se fosse as variáveis independentes que determinam a variável de resposta (no nosso exemplo, a probabilidade do preço da casa ser alto). Assim, podemos observar que a rede neural está <strong>aprendendo novas variáveis</strong> e usando um modelo de neurônio nessas novas variáveis. Esse é o princípio básico de <em>deep learning</em>: aprender variáveis representativas, geralmente mais abstratas, que auxiliem na tarefa em questão, no caso, uma tarefa de previsão.</p>
<p>Podemos ir um passo além e adicionar uma segunda camada oculta.</p>
<figure class="figure center-block thumbnail">
<img src="/img/simple_DNN/RNA2.jpeg" class="img-responsive center-block" alt="RNA2" />
<figcaption class="figure-caption text-center"><a href="http://cs231n.github.io/neural-networks-1/">Fonte</a></figcaption>
</figure>
<p>Isso aumenta ainda mais o poder representativo da rede neural. Lembre-se de que <strong>podemos pensar nas camadas da rede neural como níveis hierárquicos de abstração</strong>.</p>
<h2 id="treinamento-">Treinamento <a name="treino"></a></h2>
<p>Agora que entendemos o que são redes neurais em um nível intuitivo, iremos treiná-las. Isso é feito por um processo de otimização no qual minimizamos uma função custo (ou objetivo). Para manter o nível de simplicidade, pense na função custo como algo que mede a diferença entre o que a rede neural prevê e o que de fato foi observado. Por exemplo, se a rede neural prever um valor pequeno para a probabilidade de uma casa ter preço acima da média, mas a casa, na verdade, for bastante cara, então a função custo terá um valor alto.</p>
<p>Para iniciar o treinamento, vamos chutar alguns valores para os \(w\)s de cada neurônio. Em seguida, observaremos a previsão da rede neural em alguns dados, que, muito provavelmente, será péssima. Dessa forma, os \(w\)s iniciais serão associados a um alto custo ou a uma <strong>região elevada na superfície de custo</strong>. No treinamento então, vamos atualizar os \(w\)s de maneira iterativa, de forma a diminuir o custo. Isso é feito com a técnica de gradiente descendente estocástico, que pode ser entendida como uma descida na superfície de custo de uma tarefa de otimização.</p>
<figure class="figure center-block thumbnail">
<img src="/img/simple_DNN/gd.png" class="img-responsive center-block" alt="GD" />
<figcaption class="figure-caption text-center"><a href="https://sebastianraschka.com/faq/docs/closed-form-vs-gd.html">Fonte</a></figcaption>
</figure>
<p>Para entender a fundo essa técnica, é preciso saber cálculo multivariado, mas, intuitivamente, ela é bem simples. Em primeiro lugar, escolhemos aleatoriamente (daí a palavra estocástico) um pequeno punhado de dados para conseguir uma estimativa da nossa posição na superfície de custo. Então, movemos os parâmetros \(w\) na direção oposta da inclinação dessa superfície. Isso é como dar um passo para baixo na superfície de custo. Com passos suficientes, nossa esperança é que os \(w\) nos coloque em uma região de custo (ou erro) baixa o suficiente.</p>
<h2 id="implementando-uma-rede-neural-artificial-">Implementando uma Rede Neural Artificial <a name="implementacao"></a></h2>
<p>Muito bem, tudo isso já parece bastante promissor. Vamos então construir e treinar uma rede neural de duas camadas ocultas para uma tarefa simples de reconhecimento de caracteres em imagens. Para isso, utilizarei a linguagem de programação Python, mas não se preocupe, não será preciso saber programar para entender o que vem a seguir. Na verdade, quase não vou usar programação. Peço então que, por hora, você pense no Python apenas como um programa de computador como outro qualquer. Com ele, podemos digitar uma série de comandos para que o computador os execute. Aqui, vou simplesmente mostrar quais são os comando necessários para construir e treinar uma simples rede neural.</p>
<p>Junto com o Python, utilizarei alguns pacotes para ajudar na construção e treinamento de redes neurais. Você pode pensar nesses pacotes como extensões de um programa de computador. Mais concretamente, pense em um pacote do Python como uma fonte nova que você baixa para seu editor de texto. Particularmente importante será o pacote <a href="https://en.wikipedia.org/wiki/TensorFlow">TensorFlow</a>, que foi desenvolvido pelo Google e feito <em>open source</em> (aberto) em 2015.</p>
<p>Se você ainda não tem esses programas, não se preocupe. Também fiz um <a href="https://lamfo-unb.github.io/2017/06/10/Instalando-Python/">tutorial sobre como instalá-los</a>. Sugiro que você instale os programas necessários e acompanhe o tutorial a seguir executando cada passo no seu computador.</p>
<p>Sem mais delongas, no Python, importaremos alguns pacotes:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">tensorflow</span> <span class="k">as</span> <span class="n">tf</span> <span class="c1"># importa o TensorFlow
</span><span class="kn">from</span> <span class="nn">tensorflow.contrib.learn</span> <span class="kn">import</span> <span class="n">DNNClassifier</span> <span class="c1"># importa o modelo de rede neural do TensorFlow
</span>
<span class="c1"># pacotes adicionais
</span><span class="kn">import</span> <span class="nn">numpy</span> <span class="k">as</span> <span class="n">np</span> <span class="c1"># para computação numérica menos intensiva
</span><span class="kn">import</span> <span class="nn">os</span> <span class="c1"># para criar pastas
</span></code></pre></div></div>
<p><strong>OBS</strong>: em uma sequência de comandos (código) de Python, o computador ignora tudo que for escrito após #, por isso, # indica o início de um comentário meu explicando o código.</p>
<h3 id="os-dados">Os dados</h3>
<p>Em primeiro lugar, vamos ver como são nossos dados. Já disse que trabalharemos com OCR. Em particular, utilizamos a base de dados <a href="https://en.wikipedia.org/wiki/MNIST_database">MNIST</a>, que contém 55 mil dados de treino e 10 mil dados de teste. Os dados são imagens de 28x28 pixeis, o que nos dá 784 variáveis para colocar na camada de entrada da nossa rede neural. Mas, antes disso, vamos criar uma nova pasta no nosso computador e baixar esses dados nela.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># criamos uma pasta para colocar os dados
</span><span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">exists</span><span class="p">(</span><span class="s">'tmp'</span><span class="p">):</span> <span class="c1"># se a pasta não existir
</span> <span class="n">os</span><span class="p">.</span><span class="n">makedirs</span><span class="p">(</span><span class="s">'tmp'</span><span class="p">)</span> <span class="c1"># cria a pasta
</span>
<span class="c1"># baixa os dados na pasta criada
</span><span class="kn">from</span> <span class="nn">tensorflow.examples.tutorials.mnist</span> <span class="kn">import</span> <span class="n">input_data</span> <span class="c1"># baixa os dados
</span><span class="n">data</span> <span class="o">=</span> <span class="n">input_data</span><span class="p">.</span><span class="n">read_data_sets</span><span class="p">(</span><span class="s">"tmp/"</span><span class="p">,</span> <span class="n">one_hot</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span> <span class="c1"># baixa e carrega os dados já formatados
</span></code></pre></div></div>
<p>Após executar os comandos acima, todos os dados, tanto de treino como de teste, estão armazenados em <code class="language-plaintext highlighter-rouge">data</code>. Você pode pensar em <code class="language-plaintext highlighter-rouge">data</code> como uma planilha do Excel aberta. As únicas diferenças são que você não pode interagir com a linhas e colunas da planilha clicando com o mouse e que você não pode ver a planilha a todo tempo. No entanto, podemos facilmente ver como são nossos dados usando o comando <code class="language-plaintext highlighter-rouge">print()</code> do Python. Para interagir com os dados em <code class="language-plaintext highlighter-rouge">data</code>, usamos a notação de ponto <code class="language-plaintext highlighter-rouge">.</code>. Por exemplo, <code class="language-plaintext highlighter-rouge">data.train.images</code> nos dá acesso aos dados de treino e, a partir daí, às imagens de treino. Podemos ir além e usar <code class="language-plaintext highlighter-rouge">data.train.images.shape</code> para ver o atributo de tamanho dos dados de treino.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">images</span><span class="p">.</span><span class="n">shape</span><span class="p">)</span> <span class="c1"># mostra o formato dos dados de treino
</span><span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">test</span><span class="p">.</span><span class="n">images</span><span class="p">.</span><span class="n">shape</span><span class="p">)</span> <span class="c1"># mostra o formato dos dados de teste
</span><span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">images</span><span class="p">)</span> <span class="c1"># mostra algumas linhas e colunas dos dados de treino
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(55000, 784)
(10000, 784)
[[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
...,
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 0. 0. 0.]]
</code></pre></div></div>
<p>Acima, observamos que os dados de treino são uma tabela com 55 mil linhas, cada uma com uma observação de 784 colunas, (que representam os pixeis de uma imagem). Como nossa tarefa se encaixa no regime de aprendizado supervisionado, cada imagem vem anotada com um alvo, o dígito que está nela (e que queremos prever). Podemos acessar os alvos de treino com o comando <code class="language-plaintext highlighter-rouge">print()</code> mais <code class="language-plaintext highlighter-rouge">data.train.labels</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">labels</span><span class="p">.</span><span class="n">shape</span><span class="p">)</span> <span class="c1"># mostra o formato dos alvos de treino
</span><span class="k">print</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">labels</span><span class="p">)</span> <span class="c1"># mostra os alvos de treino
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(55000,)
[7 3 4 ..., 5 6 8]
</code></pre></div></div>
<p>As anotações da base de treino podem ser entendidas como uma tabela de 55 mil linhas e com uma única coluna. Pelo que vemos acima, nossa primeira imagem é um 7, nossa segunda imagem é um 3 e assim por diante. Com o intuito de minimizar o nível de abstração, analisaremos como são essas imagens. Para tanto, necessitamos de um pacote do Python para visualizar as imagens. Abaixo, importamos esse pacote, desenhamos a segunda imagem de treino com o comando <code class="language-plaintext highlighter-rouge">plt.imshow(...)</code> (usamos índice 1 para selecionar a segunda imagem, pois em ciência da computação a contagem é iniciada a partir do zero), usamos o alvo correspondente como título da imagem com <code class="language-plaintext highlighter-rouge">plt.title(...)</code> e, por fim, usamos <code class="language-plaintext highlighter-rouge">plt.show()</code> para mostrar a imagem. Além disso, na imagem, usamos <code class="language-plaintext highlighter-rouge">.reshape(28,28)</code> para reformatá-la de uma linha com 784 pixeis para uma grade com 28px de altura e largura.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">matplotlib</span> <span class="kn">import</span> <span class="n">pyplot</span> <span class="k">as</span> <span class="n">plt</span> <span class="c1"># importa pacote para mostrar imagens
</span>
<span class="c1"># mostra a primeira imagem no set de treino
</span><span class="n">plt</span><span class="p">.</span><span class="n">imshow</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">images</span><span class="p">[</span><span class="mi">1</span><span class="p">].</span><span class="n">reshape</span><span class="p">(</span><span class="mi">28</span><span class="p">,</span><span class="mi">28</span><span class="p">),</span> <span class="n">cmap</span><span class="o">=</span><span class="s">'Greys'</span><span class="p">,</span> <span class="n">interpolation</span><span class="o">=</span><span class="s">'nearest'</span><span class="p">)</span>
<span class="n">plt</span><span class="p">.</span><span class="n">title</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">labels</span><span class="p">[</span><span class="mi">1</span><span class="p">]))</span> <span class="c1"># anotação do dígito
</span><span class="n">plt</span><span class="p">.</span><span class="n">show</span><span class="p">()</span>
</code></pre></div></div>
<p><img src="/img/simple_DNN/mnist3.png" class="img-responsive" alt="mnist_digit" /></p>
<h3 id="definindo-os-hiper-parâmetros">Definindo os hiper-parâmetros</h3>
<p>Tudo parece OK com os nossos dados. Podemos então começar a construção da rede neural. O primeiro passo é definir os hiper-parâmetros do modelo. Diferentemente dos parâmetros da rede, os \(w\), os hiper-parâmetros não são naturalmente aprendidos durante o treinamento e devem ser ajustados à mão. Alguns dos hiper-parâmetros mais importantes da rede neural são o número de camadas e o número de neurônios em cada camada. Esses hiper-parâmetros definem a capacidade da rede neural e, por meio deles, podemos ajustar o <a href="https://matheusfacure.github.io/AM-Essencial/#Viés-e-variância"><em>trade-off</em> entre erro por viés e por variância</a>. Quanto maior o número de neurônios, mais potente será a rede neural, mas a probabilidade dela sofrer com sobre-ajustamento será superior.</p>
<p>Outros hiper-parâmetros da rede neural são o tamanho do punhado de dados usado durante a otimização e o tamanho do passo dado a cada iteração de treino. Em outras palavras, o tamanho do punhado de dados define quão precisa será nossa estimativa local da superfície de custo, enquanto que a taxa de aprendizado definirá o tamanho do passo em cada descida nessa superfície de custo.</p>
<p>Outro detalhe importante é que a rede neural que vamos construir não tem apenas um neurônio na camada de saída, mas 10 neurônios. Cada neurônio representará a probabilidade da imagem conter um dos dígitos de 0 a 9.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># definindo constantes
</span><span class="n">lr</span> <span class="o">=</span> <span class="mf">0.01</span> <span class="c1"># taxa de aprendizado
</span><span class="n">n_iter</span> <span class="o">=</span> <span class="mi">1000</span> <span class="c1"># número de iterações de treino
</span><span class="n">batch_size</span> <span class="o">=</span> <span class="mi">128</span> <span class="c1"># qtd. de imagens no punhado de dados
</span><span class="n">n_inputs</span> <span class="o">=</span> <span class="mi">28</span> <span class="o">*</span> <span class="mi">28</span> <span class="c1"># número de variáveis (pixeis)
</span><span class="n">n_l1</span> <span class="o">=</span> <span class="mi">512</span> <span class="c1"># número de neurônios da primeira camada
</span><span class="n">n_l2</span> <span class="o">=</span> <span class="mi">512</span> <span class="c1"># número de neurônios da segunda camada
</span><span class="n">n_outputs</span> <span class="o">=</span> <span class="mi">10</span> <span class="c1"># número de neurônios da camada de saída
</span></code></pre></div></div>
<p>Nossa rede neural terá duas camadas, cada uma com 512 neurônios.</p>
<h3 id="construindo-a-rede-neural">Construindo a rede neural</h3>
<p>Felizmente, não precisamos construir uma rede neural do zero. Como elas são extremamente populares, outras pessoas já as deixaram pré-montada para facilitar nossa vida. A única coisa que precisamos fazer é dizer quais serão os hiper-parâmetros da rede neural, que o pacote TensorFlow construirá para nós.</p>
<p>O primeiro passo é converter os dados para um formato com que TensorFlow consiga trabalhar facilmente. Isso é feito com o comando <code class="language-plaintext highlighter-rouge">tf.contrib.learn.infer_real_valued_columns_from_input(...)</code> e passamos como argumento desse comando as imagens de treino. Por fim, transmitimos os hiper-parâmetros definidos acima para o comando <code class="language-plaintext highlighter-rouge">DNNClassifier(...)</code>, o que cria a nossa rede neural e a armazena em <code class="language-plaintext highlighter-rouge">deep_ann</code>.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># converte os dados
</span><span class="n">x_input</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">contrib</span><span class="p">.</span><span class="n">learn</span><span class="p">.</span><span class="n">infer_real_valued_columns_from_input</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">images</span><span class="p">)</span>
<span class="c1"># cria a rede neural
</span><span class="n">deep_ann</span> <span class="o">=</span> <span class="n">DNNClassifier</span><span class="p">(</span><span class="n">hidden_units</span> <span class="o">=</span> <span class="p">[</span><span class="n">n_l1</span><span class="p">,</span> <span class="n">n_l2</span><span class="p">],</span> <span class="c1"># qtd. de neurônios por camada
</span> <span class="n">feature_columns</span> <span class="o">=</span> <span class="n">x_input</span><span class="p">,</span> <span class="c1"># camada de entrada (dados)
</span> <span class="n">n_classes</span> <span class="o">=</span> <span class="n">n_outputs</span><span class="p">,</span> <span class="c1"># número de classes (10 dígitos)
</span> <span class="n">activation_fn</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">nn</span><span class="p">.</span><span class="n">relu</span><span class="p">,</span> <span class="c1"># função de ativação das camadas
</span> <span class="n">optimizer</span> <span class="o">=</span> <span class="n">tf</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">AdamOptimizer</span><span class="p">(</span><span class="n">learning_rate</span><span class="o">=</span><span class="n">lr</span><span class="p">))</span> <span class="c1"># otimizador
</span></code></pre></div></div>
<p>OBS: Ao rodar esse código, talvez você veja alguns textos de aviso. Apenas os ignore. Nesses casos, o TensorFlow está nos fornecendo mais informação do que precisamos.</p>
<h3 id="treinando-e-avaliando-a-rna">Treinando e Avaliando a RNA</h3>
<p>Para treinar a rede neural criada acima basta um único comando do TensorFlow. Esse comando vem com o nosso modelo de rede neural e podemos acessá-lo com a notação de ponto a partir da rede neural criada acima: <code class="language-plaintext highlighter-rouge">deep_ann.fit(...)</code>. Passamos ao comando as imagens de treino com os respectivos dígitos anotados. Lembre-se que esse é um problema de aprendizado de máquina supervisionado e que a tarefa da rede neural é aprender como mapear dos valores numéricos dos pixeis no dígito que está escrito na imagem. Por isso, precisamos passar também as anotações das imagens de treino: <code class="language-plaintext highlighter-rouge">data.train.labels</code>. Antes de encaminhar esses dados à rede neural, precisamos convertê-los para os tipos aceitos pelo modelo. As imagens devem ser do tipo <code class="language-plaintext highlighter-rouge">float32</code> (dígitos com casas decimais), enquanto que as anotações devem ser do tipo <code class="language-plaintext highlighter-rouge">int64</code> (dígitos inteiros, sem casas decimais). Por fim, passamos para o comando de treinamento o número de iterações de treino (passos na caminhada para baixo na superfície de custo).</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">deep_ann</span><span class="p">.</span><span class="n">fit</span><span class="p">(</span><span class="n">x</span><span class="o">=</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">images</span><span class="p">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">float32</span><span class="p">),</span> <span class="c1"># conversão de tipo
</span> <span class="n">y</span><span class="o">=</span><span class="n">data</span><span class="p">.</span><span class="n">train</span><span class="p">.</span><span class="n">labels</span><span class="p">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">int64</span><span class="p">),</span> <span class="c1"># conversão de tipo
</span> <span class="n">batch_size</span><span class="o">=</span><span class="n">batch_size</span><span class="p">,</span> <span class="c1"># tamanho do punhado de dados
</span> <span class="n">steps</span><span class="o">=</span><span class="n">n_iter</span><span class="p">)</span> <span class="c1"># iterações de treino
</span></code></pre></div></div>
<p>Após treinada, precisamos avaliar nossa rede neural nos dados de teste. Para isso, usamos o comando <code class="language-plaintext highlighter-rouge">.evaluate</code>, que pode ser acessado uma vez que a rede neural for treinada. Enviamos os dados e anotações de teste para esse comando e observamos a acurácia da rede neural, isto é, a taxa de acerto.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">deep_ann</span><span class="p">.</span><span class="n">evaluate</span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">test</span><span class="p">.</span><span class="n">images</span><span class="p">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">float32</span><span class="p">),</span> <span class="c1"># variáveis independentes
</span> <span class="n">data</span><span class="p">.</span><span class="n">test</span><span class="p">.</span><span class="n">labels</span><span class="p">.</span><span class="n">astype</span><span class="p">(</span><span class="n">np</span><span class="p">.</span><span class="n">int64</span><span class="p">))</span> <span class="c1"># variáveis dependentes
</span></code></pre></div></div>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{'accuracy': 0.96030003, 'global_step': 1000, 'loss': 0.14502561}
</code></pre></div></div>
<p>Com apenas 1000 iterações de treino, nossa simples rede neural já consegue uma taxa de acerto de 96%. Isso não é um resultado muito bom, mas já é satisfatório, principalmente se considerarmos quão simples foi treinar esse modelo.</p>
<h2 id="próximos-passos">Próximos Passos</h2>
<p>Como já disse, este post é bastante introdutório e tem o propósito de simplesmente instigar a curiosidade sobre aprendizado de máquina. Dentre tópicos que não podemos abarcar em um post introdutório estão outras arquiteturas de redes neurais (convolucionais, recorrentes, <em>autoencoders</em>, <em>deep-q</em>, adversárias…), formas de acelerar o treinamento, técnicas de regularização para controlar o sobre-ajustamento, isso sem falar nas outras classes de modelos de aprendizado de máquina, como máquinas de suporte vetoriais, árvores de decisão, Bayes ingênuo, k-vizinhos mais próximos…</p>
<p>Além disso, mesmo em se tratando de redes neurais bem simples como a que treinamos, o nível de abstração desse post é demasiadamente elevado, isto é, não mostrei como construir cada camada de neurônios, como conectá-las nem como construir o algoritmo de treinamento. Embora você possa utilizar aprendizado de máquina sem se preocupar muito com esses detalhes mais mecânicos, conhecê-los é extremamente importante. Entender de fato o funcionamento dos modelos é condição fundamental para solucionar possíveis falhas no treinamento, para descobrir quais modelos utilizar em cada situação e até mesmo para criar novos modelos ou melhorias que possam contribuir para a ciência de aprendizado de máquina.</p>
<p>Termino com um apelo: não seja um cientista de dados que simplesmente tenta aplicar um modelo caixa preta atrás do outro, na esperança de que algum resolva seu problema. <strong>Isso não é aprendizado de máquina; é tentativa e erro</strong>. Se for estudar aprendizado de máquina, entenda <strong>BEM</strong> as ferramentas que você usa. Entenda a matemática e a mecânica de um algoritmo em seus mínimos detalhes. Se possível, implemente os modelos de aprendizado de máquina sem o auxílio de pacotes. E, por fim, detalhes são muito, muito, muito importantes! A eles que devemos parte do renascimento atual de IA, então não os deixe passar batido.</p>
<p>Não é difícil encontrar material gratuito e de qualidade na internet, mas também é fácil cair em armadilhas, aprendendo apenas IA em um nível intuitivo, sem se adentrar nos detalhes. Segue uma pequena lista de onde encontrar conteúdo de qualidade sobre aprendizado de máquina:</p>
<ul>
<li>Blogs
<ul>
<li><a href="https://matheusfacure.github.io/tutorials/">{Quinhentos:Nove}</a>: Sou suspeito para falar, mas acredito que meu blog tenha os melhores tutoriais em português sobre aprendizado de máquina. Em parte, eu o criei com o objetivo de corrigir algumas falhas que percebi nos outros blogs sobre AM. Percebi que o conteúdo deles ou eram simplesmente intuitivos, sem aprofundamento na matemática e na implementação dos modelos, ou eram muito técnicos. Por isso, comecei a criar tutoriais estruturados para conter uma explicação intuitiva da técnica explicada, seguida de uma explicação matemática mais aprofundada e terminando com uma implementação bem documentada. Além disso, eu frequentemente <a href="https://matheusfacure.github.io/blog/">posto sobre meus trabalhos </a> para que sirvam como exemplos de aplicações de aprendizado de máquina.</li>
<li><a href="https://lamfo-unb.github.io/">Blog do LAMFO</a>: O nosso blog é uma excelente fonte de tutoriais e exemplos de aplicações de aprendizado de máquina. O LAMFO é a primeira entidade acadêmica no Brasil a tratar de aprendizado de máquina dentro da grande área de ciências humanas (e até onde sei, ainda é a única que atua na área), então acho que posso dizer que somos autoridade nesse assunto.</li>
<li><a href="http://colah.github.io/">colah's blog</a>: Esse é um dos melhores blogs que conheço sobre aprendizado de máquina. Infelizmente, o conteúdo é mais avançado e com pouco enfoque em questões práticas (aquele problema do qual falei sobre ser muito técnico).</li>
<li><a href="https://r2rt.com/">R2RT</a>: É um blog excelente, tanto em termos de tutoriais quanto em termos de explicação técnica e matemática por detrás dos algoritmos ensinados. Infelizmente, já começa no nível avançado, sem uma progressão clara entre os tutoriais.</li>
<li><a href="http://karpathy.github.io/">Andrej Karpathy blog</a>: Andrej Karpathy é um pesquisador extremamente inteligente e que escreve com uma simplicidade incrível para alguém do seu nível de conhecimento. Esse não é um blog sobre tutoriais, mas fala sobre assuntos muito interessantes em aprendizado de máquina, além de fornecer implementações detalhadas e bem documentadas sobre o assunto tratado.</li>
</ul>
</li>
</ul>
<h2 id="referências-">Referências <a name="ref"></a></h2>
<p>Esse post abrange o conteúdo que ministrei em um <em>workshop</em> do LAMFO sobre redes neurais. A proposta dessa iniciativa era mostrar que é possível falar sobre inteligência artificial e aprendizado de máquina de maneira simples e intuitiva, sem pressupor nenhum conhecimento técnico de quem está começando a aprender. Você pode acessar os slides do <em>workshop</em> <a href="/img/simple_DNN/workshop_dl.pdf">aqui</a>. Todas as imagens foram retiradas da internet e assumi que estavam em domínio público. Caso encontre uma imagem sua e queira as devidas citações, favor <a href="mailto:matheusfacure01@gmail.com">entrar em contato</a>.</p>
<p>Como de costume, fiz o <em>upload</em> de um notebook Jupyter com o código desenvolvido nesse post. Nesse notebook, código e explicação são intercalados, de forma que você pode acompanhar esse mesmo post ao mesmo tempo que executa os comandos em Python. Recomendo que você baixe o notebook e reveja esse tutorial de redes neurais por lá. Isso te dará mais confiança para generalizar o que ensinei aqui para outras situações. Também coloquei um exercício adicional lá, para quem quiser fixar o que vimos acima. O notebook está no <a href="https://github.com/matheusfacure/Tutoriais-de-AM/blob/master/Redes%20Neurais%20Artificiais/RNA_simples.ipynb">meu GitHub</a></p>
Instalando Python para Aprendizado de Máquina2017-06-10T10:19:07+00:00http://lamfo-unb.github.io/2017/06/10/Instalando-Python<p>UPDATE: 18/06/2017</p>
<h2 id="conteúdo">Conteúdo</h2>
<ol>
<li><a href="#req">Requisitos</a></li>
<li><a href="#python">Instalando Python</a></li>
<li><a href="#tf">Instalando TensorFlow</a></li>
<li><a href="#git">Instalando Git</a></li>
<li><a href="#test">Testando</a></li>
<li><a href="#fim">Considerações Finais</a></li>
</ol>
<h2 id="requisitos-computacionais-">Requisitos computacionais <a name="req"></a></h2>
<p>Para seguir com esse tutorial de instalação, você precisa de um computador com Windows 64 bits e pelo menos 4 GB de RAM. Mas mais do que isso, se você planeja seguir adiante com estudos ou aplicações de aprendizado de máquina, é recomendável ter pelo menos 8 GB de RAM e um processador minimamente decente, como um Intel i5 ou outro processador com pelo menos quatro núcleos (<em>quad core</em>).</p>
<h2 id="instalando-python-">Instalando Python <a name="python"></a></h2>
<p><img src="/img/python.png" alt="python" class="img-responsive thumbnail pull-right" style="margin-left:3%; width:45%;" /></p>
<p>No momento, Python a linguagem de programação preferida pelos cientistas de dados, especialmente para aprendizado de máquina. Mas mais do que isso, Python tem uma sintaxe extremamente simples e legível, o que te permite focar mais no conteúdo do seu programa do que em como escrevê-lo. Aqui, vamos ensinar como instalar a distribuição <a href="https://www.continuum.io/downloads">Anaconda</a>, um pacote de programas que inclui o Python mais uma série de extensões utilizadas em ciência de dados e aprendizado de máquina (como Numpy, Pandas, Jupyter Notebooks e Scikit Learn).</p>
<p>Antes de mais nada, <a href="https://support.microsoft.com/pt-br/help/827218/how-to-determine-whether-a-computer-is-running-a-32-bit-version-or-64-bit-version-of-the-windows-operating-system">certifique-se de que seu sistema operacional é 64 bits</a>. Infelizmente, o tutorial a seguir só funciona na versão 64 bits do Windows, então uma vez que você tenha confirmado essa versão, podemos prosseguir com a instalação. Agora, vá em <a href="https://www.continuum.io/downloads">https://www.continuum.io/downloads</a> e baixe o Anaconda para Windows, versão 64-bit. Ao clicar no botão do download, um arquivo executável será baixado.</p>
<p>Clique no arquivo executável para inicializar a instalação. Prossiga com as opções padrões, mas certifique-se de que a caixa com a opção <code class="language-plaintext highlighter-rouge">Add Anaconda to PATH</code> esteja selecionada. Esse processo de instalação pode demorar um pouco. Quando a instalação concluir, podemos testar se tudo deu certo.</p>
<p>Abra a prompt de comando. Antes de prosseguir, vamos nos familiarizar com ela um pouco. A propt de comando é uma forma alternativa de interagir com o seu computador. Da mesma forma que você navega pelas pastas e arquivos clicando com o mouse, você pode fazer isso na linha de comando. Por padrão, a linha de comando abre no seu <code class="language-plaintext highlighter-rouge">Home</code>, o local onde ficam suas pastas de imagens, documentos, downloads, etc. Após abrir o prompt de comando, digite <code class="language-plaintext highlighter-rouge">ls</code> para ver o que está na sua pasta, naquele local. Você verá escrito as pastas de arquivos do seu <code class="language-plaintext highlighter-rouge">Home</code>. O comando <code class="language-plaintext highlighter-rouge">ls</code> lista o que está na sua pasta (ou diretório) corrente.</p>
<p>Agora, digite <code class="language-plaintext highlighter-rouge">cd Desktop</code> para navegar ao Desktop do seu computador. Se quiser, digite <code class="language-plaintext highlighter-rouge">ls</code> para mostrar quais arquivos estão no seu Desktop. O comando <code class="language-plaintext highlighter-rouge">cd</code> (change directory) troca o diretório (ou pasta) corrente. O comando <code class="language-plaintext highlighter-rouge">cd ..</code> sobe um nível nas pastas do seu computador. Se você digitar isso na prompt de comando enquanto estiver no Desktop, ele te levará de volta ao <code class="language-plaintext highlighter-rouge">Home</code>, que é a o diretório um nível acima do <code class="language-plaintext highlighter-rouge">Desktop</code>. Volte para o <code class="language-plaintext highlighter-rouge">HOME</code>.</p>
<p>No <code class="language-plaintext highlighter-rouge">HOME</code>, digite <code class="language-plaintext highlighter-rouge">python</code> na prompt de comando. Isso iniciará o modo interativa do Python. Execute algumas operações matemáticas como <code class="language-plaintext highlighter-rouge">2+2</code> e veja o resultado sendo calculado pelo Python. Quando terminar, digite <code class="language-plaintext highlighter-rouge">quit()</code> para sair da versão interativa do Python.</p>
<p>Para finalizar, digite <code class="language-plaintext highlighter-rouge">jupyter notebook</code> na linha de comando. Isso inicializará o Jupyter, um programa que executa códigos em Python. Uma nova aba será aberta no seu browser (OBS: funciona apenas com Chrome ou Firefox) e nela você verá a interface do Jupyter. Caso essa aba não abra, na prompt de comando, procure um link que deve começar com <code class="language-plaintext highlighter-rouge">http://localhost:8889/</code>. Copie e cole esse link em uma nova aba do seu browser para abrir a interface do Jupyter. Nessa interface, você poderá escrever <em>notebooks</em> que intercalam código em Python intercalado com comentários, se assim desejar (veja um <a href="https://github.com/matheusfacure/Tutoriais-de-AM/blob/master/Redes%20Neurais%20Artificiais/DeepANN.ipynb">exemplo</a>). Para sair do notebook, feche a aba no seu browser, volte a prompt de comando e aperte CTRL+C, seguido de y e enter. CTRL+C é um comando para fechar programas que estão rodando na sua prompt de comando; você terá que confirmar o fechamento com y (<em>yes</em>), seguido de enter.</p>
<p>Para aprender mais sobre a linha de comando, sugiro este <a href="https://learnpythonthehardway.org/book/appendixa.html">link</a>. Para aprender mais sobre o Jupyter, sugiro este <a href="http://jupyter.readthedocs.io/en/latest/content-quickstart.html">link</a>.</p>
<h2 id="instalando-tensorflow-">Instalando TensorFlow <a name="tf"></a></h2>
<p><img src="/img/tf.jpg" alt="python" class="img-responsive thumbnail pull-right" style="margin-left:3%; width:45%;" /></p>
<p>O <a href="https://www.tensorflow.org/">TensorFlow</a> é um programa de computação numérica, que tem sua versão principal em Python. Nós usamos o TensorFlow para programas de <em>deep learning</em>, devido a sua eficiência computacional e abundância de comandos facilitadores para construção e treinamento de redes neurais. Antes de instalar o TensorFlow, vamos criar um ambiente Python. Nesse ambiente, todas as extensões (ou pacotes) que vem no Anaconda estarão presentes, mas o que instalarmos nele não será acessível de fora dele. Isso evita que a instalação de um pacote novo possa prejudicar o funcionamento dos pacotes já instalados.</p>
<p>Para criar um ambiente novo, digite <code class="language-plaintext highlighter-rouge">conda create -n tensorflow</code> na linha de comando. Confirme a criação do ambiente digitando y (<em>yes</em>), seguido de enter. Agora, digite <code class="language-plaintext highlighter-rouge">activate tensorflow</code> para entrar nesse ambiente. Note que a sua linha de comando mudará para incluir <code class="language-plaintext highlighter-rouge">(tensorflow)</code> antes do nome do seu diretório corrente. Para sair do ambiente, basta digitar <code class="language-plaintext highlighter-rouge">deactivate</code>.</p>
<p>Finalmente, para instalar o TensorFlow, entre no ambiente recém criado e digite:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install</span> <span class="nt">--ignore-installed</span> <span class="nt">--upgrade</span> https://storage.googleapis.com/tensorflow/windows/cpu/tensorflow-1.2.0-cp36-cp36m-win_amd64.whl
</code></pre></div></div>
<p>Dica: CTRL+C e CTRL+V não funciona na linha de comando, mas você pode copiar e colar comandos clicando com o botão direito do mouse. Em alguns computadores, na linha de comando, podemos usar CTRL+SHIFT+C para copiar e CTRL+SHITF+V para colar.</p>
<p>Na instalação do TensorFlow, usaremos <code class="language-plaintext highlighter-rouge">pip</code>, que é o gerenciador de pacotes do Python, para instalar o TensorFlow 1.2 para Windows, com suporte para CPU apenas. A instalação com suporte para GPU é mais complicada e varia muito. Caso queira instalá-la, siga as <a href="https://www.tensorflow.org/install/install_windows">instruções no site do TensorFlow</a>. Teste agora sua instalação. Na linha de comando, digite <code class="language-plaintext highlighter-rouge">python</code> para iniciar o modo iterativo do Python. Digite <code class="language-plaintext highlighter-rouge">import tensorflow as tf</code>. Se tudo ocorreu bem até aqui, você não verá nenhum erro.</p>
<h2 id="instalando-git-">Instalando Git <a name="git"></a></h2>
<p>Git é um programa de controle de versões. Ele permite que você volte a uma versão anterior do seu código caso escreva algum bug ou alguma coisa que pare o funcionamento do seu programa. Em outras palavras, o Git te permite experimentar novas coisas sem medo de ferrar com o que já foi feito, afinal você sempre poderá restaurar versões passadas do seu código. Além disso, o Git tem uma plataforma online, o <a href="https://github.com/">GitHub</a>, que permite colaboração entre programadores, principalmente para códigos abertos. O GitHub também funciona como um currículo do cientista de dados. Por meio dele, é possível compartilhar seus trabalhos de forma que eles sejam completamente reprodutíveis, permitindo que qualquer um possa certificar-se das suas habilidades.</p>
<p>Para baixar o Git, va em <a href="https://git-scm.com/downloads">https://git-scm.com/downloads</a> e clique na versão para Windows. Isso iniciará o download de um executável. Quando o download terminar, clique no executável para iniciar a instalação. Aceite todas as configurações padrão, <strong>exceto</strong> a Configuração de Final de Linha. Nesse caso, mude para <code class="language-plaintext highlighter-rouge">Checkout as-is, commit Unix-style line endings</code>. Isso facilitará muito no momento que você estiver contribuindo com outros projetos via GitHub.</p>
<p>Recomendo fortemente que você faça <a href="https://br.udacity.com/course/how-to-use-git-and-github--ud775/">este pequeno curso online</a> (e gratuito) sobre como usar controle de versões, Git e GitHub. Não deve te tomar muito tempo.</p>
<h2 id="testando-">Testando <a name="test"></a></h2>
<p>Vamos fazer um último teste para ver se tudo está funcionando. Abra a linha de comando do Git e digite</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/matheusfacure/DeepArt.git
</code></pre></div></div>
<p>Isso baixará um repositório meu com uma implementação do <a href="https://en.wikipedia.org/wiki/DeepDream">algoritmo de DeepDream</a>. Por padrão, o a linha de comando do Git também abre no <code class="language-plaintext highlighter-rouge">HOME</code>. Se não for o caso, navega até o Home com <code class="language-plaintext highlighter-rouge">cd</code> e então clone o repositório com o comando acima. Voltando à linha de comando do Windows, você deve estar no Home também. Digite <code class="language-plaintext highlighter-rouge">ls</code> para ver a pasta <code class="language-plaintext highlighter-rouge">DeepArt</code> que baixamos com o Git.</p>
<p>Na linha de comando do Windows, digite agora <code class="language-plaintext highlighter-rouge">cd DeepArt/</code> para entrar no diretório baixado. Por fim, digite <code class="language-plaintext highlighter-rouge">python deep_dream.py</code> para executar o programa que fiz. Isso baixará uma rede neural (pode levar alguns minutos) e a utilizará para realizar o algoritmo de DeepDream. Usando o navegador padrão do seu sistema operacional (clicando com o mouse). Vá até o diretório (ou pasta) de DeepArt que acabamos de baixar e veja a imagem criada pelo algoritmo de DeepDream. Caso não saiba onde está essa pasta, na linha de comando do Git, digite <code class="language-plaintext highlighter-rouge">pwd</code> (print working directory) para mostrar o endereço da pasta.</p>
<h2 id="considerações-finais-">Considerações Finais <a name="fim"></a></h2>
<p>Eu testei a execução dos passos desse tutorial algumas vezes e tudo ocorreu sem problemas. No entanto, é possível que alguém encontre alguma dificuldade ou erro no meio do caminho. Se for o caso, por favor comente a sua dificuldade ou erro neste post. Além disso, qualquer sugestão é bem vinda e estarei sempre atualizando este tutorial, tanto para abarcar a resolução dos erros frequentemente encontrados quanto para torná-lo mais compreensível.</p>
Visualization and exploration of Spatial data in R2017-06-03T16:25:15+00:00http://lamfo-unb.github.io/2017/06/03/Vizualization-and-exploration-of-Spatial-data-in-R<h1 id="visualization-and-exploration-of-spatial-data-in-r"><strong><em>Visualization and exploration of Spatial data in R</em></strong></h1>
<p>In this post we will base ourselves on the tutorial by Robin Lovelace et. Al. (2017) and the material that will be used is available <a href="https://github.com/Robinlovelace/Creating-maps-in-R">here</a> in the <em>Creating-maps-in-R.Rproj</em> project.</p>
<p>Initially, you need to install the following packages in the R:
<code class="language-plaintext highlighter-rouge">"ggplot2", "ggmap","rgdal","rgeos","maptools","dplyr","tidyr","tmap"</code></p>
<p>The next step is to open the shape file. The shapefile is a file format that stores geospatial data, such as position, shape, and attributes, in a vector form. In RStudio you can open this type of file as follows:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">rgdal</span><span class="p">)</span><span class="w">
</span><span class="n">lnd</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">readOGR</span><span class="p">(</span><span class="n">dsn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"data"</span><span class="p">,</span><span class="w"> </span><span class="n">layer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"london_sport"</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>The last line of the code shows that the variable class <em>Pop_2001</em> is classified as a factor, whereas it should be numeric. We must change it for this analysis:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">lnd</span><span class="o">$</span><span class="n">Pop_2001</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">as.numeric</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">lnd</span><span class="o">$</span><span class="n">Pop_2001</span><span class="p">))</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>A first analysis can be made selecting the regions that have a certain index of participation in the sport:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sel</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lnd</span><span class="o">$</span><span class="n">Partic_Per</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="m">20</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">lnd</span><span class="o">$</span><span class="n">Partic_Per</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="m">25</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"lightgrey"</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">sel</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"turquoise"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/chunk-3-1.png" width="500" /></p>
<p>Another interesting analysis is the identification of quadrants. This division can be made based on the coordinates of the centroid, which in this case represents the central point of London.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">rgeos</span><span class="p">)</span><span class="w">
</span><span class="c1">## encontrando o centro da região de londres</span><span class="w">
</span><span class="n">lat</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">coordinates</span><span class="p">(</span><span class="n">gCentroid</span><span class="p">(</span><span class="n">lnd</span><span class="p">))[[</span><span class="m">1</span><span class="p">]]</span><span class="w">
</span><span class="n">lng</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">coordinates</span><span class="p">(</span><span class="n">gCentroid</span><span class="p">(</span><span class="n">lnd</span><span class="p">))[[</span><span class="m">2</span><span class="p">]]</span><span class="w">
</span><span class="c1">## argumento para testar se a região está ao norte ou ao leste do centro</span><span class="w">
</span><span class="n">norte</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">2</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">lng</span><span class="p">)</span><span class="w">
</span><span class="n">leste</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">1</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">lat</span><span class="p">)</span><span class="w">
</span><span class="n">oeste</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">1</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">lat</span><span class="p">)</span><span class="w">
</span><span class="n">sul</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">2</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">lng</span><span class="p">)</span><span class="w">
</span><span class="c1">## testando se a coordenada está a norte ou leste do centro</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"nordeste"</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"noroeste"</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"sudeste"</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"sudoeste"</span><span class="w">
</span><span class="c1">## colorindo os quadrantes no gráfico</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">as.factor</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">))</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"lightgrey"</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">,],</span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"red"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"blue"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"green"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"yellow"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/chunk-4-1.png" width="500" /></p>
<h2 id="creating-maps-whith-tmap-ggplot-and-leaflet">Creating maps whith tmap, ggplot and leaflet</h2>
<p><strong>Tmap</strong></p>
<p>The analysis can be done by generating a color gradient based on the percentage participation of the population in the sport:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">tmap</span><span class="p">)</span><span class="w">
</span><span class="n">qtm</span><span class="p">(</span><span class="n">shp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Partic_Per"</span><span class="p">,</span><span class="w"> </span><span class="n">fill.palette</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"-Blues"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/chunk-5-1.png" width="500" /></p>
<p><strong>ggplot2</strong></p>
<p>Unlike tmap, ggplot requires you to provide the database in data.frame format. This can be done through the <code class="language-plaintext highlighter-rouge">fortify()</code> function:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">ggplot2</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span><span class="w">
</span><span class="n">lnd_f</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">fortify</span><span class="p">(</span><span class="n">lnd</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="n">lnd</span><span class="o">$</span><span class="n">id</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">row.names</span><span class="p">(</span><span class="n">lnd</span><span class="p">)</span><span class="w"> </span><span class="c1"># Atribui um ID para a base sp </span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w"> </span><span class="c1"># ultima checagem antes da junção (os nomes das variáveis precisam ser iguais)</span><span class="w">
</span><span class="n">lnd_f</span><span class="w"> </span><span class="o"><-</span><span class="n">left_join</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">)</span><span class="w"> </span><span class="c1"># juntou pela única variável com nome em comum</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Now the lnd_f object can be used to create a map with ggplot:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">map</span><span class="o"><-</span><span class="n">ggplot</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">long</span><span class="p">,</span><span class="w"> </span><span class="n">lat</span><span class="p">,</span><span class="w"> </span><span class="n">group</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">group</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Partic_Per</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_polygon</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">coord_equal</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">labs</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Easting (m)"</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Northing (m)"</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"% Sports\nParticipation"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">ggtitle</span><span class="p">(</span><span class="s2">"London Sports Participation"</span><span class="p">)</span><span class="w">
</span><span class="n">map</span><span class="w">
</span><span class="c1">## trocando as cores</span><span class="w">
</span><span class="n">map</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">scale_fill_gradient</span><span class="p">(</span><span class="n">low</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"red"</span><span class="p">,</span><span class="w"> </span><span class="n">high</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"green"</span><span class="p">)</span><span class="w">
</span><span class="c1">## salvando o grafico com ggsave</span><span class="w">
</span><span class="n">ggsave</span><span class="p">(</span><span class="s2">"Sport Participation - London.jpg"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/img_ggplot2.jpg" width="500" /></p>
<h2 id="interactive-maps-with-leaflet"><strong>Interactive maps with leaflet</strong></h2>
<p>The leaflet package allows the creation of interactive maps and acts together with the shiny package, making the online visualization possible. The lnd object is with a Coordinate Reference System (CRS) that is not compatible with the leaflet. The display will be possible after the CRS of the lnd object is changed to the EPSG: 4326, which has been the most used one:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">leaflet</span><span class="p">)</span><span class="w">
</span><span class="n">lnd84</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">spTransform</span><span class="p">(</span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">CRS</span><span class="p">(</span><span class="s2">"+init=epsg:4326"</span><span class="p">))</span><span class="w"> </span><span class="c1">#reprojeta</span><span class="w">
</span><span class="n">leaflet</span><span class="p">()</span><span class="w"> </span><span class="o">%>%</span><span class="w">
</span><span class="n">addTiles</span><span class="p">()</span><span class="w"> </span><span class="o">%>%</span><span class="w">
</span><span class="n">addPolygons</span><span class="p">(</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lnd84</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<iframe title="London Map" width="700" height="400" src="https://cdn.rawgit.com/jadermcs/fdb08a2c254288844c6ae4673e4e6e0b/raw/a92f7fdf0ec510d30504c934b3dcecbe8ab67fd3/london_map.html" frameborder="0" allowfullscreen=""></iframe>
<p>This map differs from the others because it allows a similar expirience to the use of googlemaps in the browser.</p>
<p>Next we have another example of visualization in the leaflet, but now we will use the shapefile of the Federal District, available on the IBGE website. After you download the file and sabe it to your current Working Directory, the first step is to assign the file to a new object, here called <em>df_shp</em>:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">raster</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">sp</span><span class="p">)</span><span class="w">
</span><span class="n">df_shp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">readOGR</span><span class="p">(</span><span class="n">dsn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"df_setores_censitarios"</span><span class="p">,</span><span class="w"> </span><span class="n">layer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"53SEE250GC_SIR"</span><span class="p">)</span><span class="w">
</span><span class="c1"># Criação do mapa com leaflet</span><span class="w">
</span><span class="n">df_shp</span><span class="o">@</span><span class="n">proj4string</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">CRS</span><span class="p">(</span><span class="s2">"+init=epsg:4326"</span><span class="p">)</span><span class="w"> </span><span class="c1"># reprojeta</span><span class="w">
</span><span class="n">df_leaf</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">leaflet</span><span class="p">(</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">df_shp</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">addTiles</span><span class="p">()</span><span class="o">%>%</span><span class="w">
</span><span class="n">addPolygons</span><span class="p">(</span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">weight</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">stroke</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"#03F"</span><span class="p">)</span><span class="o">%>%</span><span class="w">
</span><span class="n">addLegend</span><span class="p">(</span><span class="s2">"bottomright"</span><span class="p">,</span><span class="w"> </span><span class="n">colors</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"#03F"</span><span class="p">,</span><span class="w"> </span><span class="n">labels</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Distrito Federal"</span><span class="p">)</span><span class="w">
</span><span class="n">df_leaf</span><span class="w">
</span></code></pre></div></div>
<p>The code above follows the same reasoning of the created for the map of London, but with some more configurations. The .shp file was inserted directly into the leaflet function and the addPolygons function included the fill, weight, stroke and color arguments, which respectively represent whether the interior of the polygons should receive some color, the thickness of the contour line, if the lines of the Polygons should be colored and which color should be chosen. The addLegend function creates a legend for the map. For more details on functions, simply run the following command:?Function-name.</p>
<iframe title="London Map" width="700" height="400" src="https://cdn.rawgit.com/jadermcs/9f68419b0b05e32b8741861e80c7df02/raw/b1d9d0394fdd4f724dbc591a14dfa0537baca45e/df.html" frameborder="0" allowfullscreen=""></iframe>
Visualização e exploração de dados espaciais em R2017-06-03T13:55:44+00:00http://lamfo-unb.github.io/2017/06/03/Visualizacao-e-exploracao-de-dados-espaciais-em-R<h1 id="visualização-e-exploração-de-dados-espaciais-no-r"><strong><em>Visualização e exploração de dados espaciais no R</em></strong></h1>
<p>Neste post iremos nos basear no tutorial de Robin Lovelace et. al. (2017) e o material que será utilizado está disponível em seu <a href="https://www.github.com/Robinlovelace/Creating-maps-in-R">repositorio</a> no Github, no projeto <em>Creating-maps-in-R.Rproj</em>.
Inicialmente, é preciso instalar os seguintes pacotes no R:
<code class="language-plaintext highlighter-rouge">"ggplot2", "ggmap","rgdal","rgeos","maptools","dplyr","tidyr","tmap"</code></p>
<p>Feita a instalação dos pacotes necessários, o primeiro passo é abrir a shape file. Aqui iremos nos basear no tutorial de Robin Lovelace et. al. (2017) e o material que será utilizado está disponível no <a href="https://www.github.com/Robinlovelace/Creating-maps-in-R">link</a> no projeto <em>Creating-maps-in-R.Rproj</em>.</p>
<p>O shapefile é um formato de arquivo que armazena dados geoespaciais, como posição, forma e atributos, em forma de vetor. No RStudio a abertura desse tipo de arquivo pode ser feita da seguinte forma:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">rgdal</span><span class="p">)</span><span class="w">
</span><span class="n">lnd</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">readOGR</span><span class="p">(</span><span class="n">dsn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"data"</span><span class="p">,</span><span class="w"> </span><span class="n">layer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"london_sport"</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>A última linha do código mostra que a classe da variável <em>Pop_2001</em> está classificada como fator, enquanto deveria ser do tipo numérico. Portanto, devemos alterá-la:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">lnd</span><span class="o">$</span><span class="n">Pop_2001</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="nf">as.numeric</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">lnd</span><span class="o">$</span><span class="n">Pop_2001</span><span class="p">))</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Uma primeira análise pode ser feita com apenas selecionando as regiões que possuam determinado índice de participação no esporte:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sel</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">lnd</span><span class="o">$</span><span class="n">Partic_Per</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="m">20</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">lnd</span><span class="o">$</span><span class="n">Partic_Per</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="m">25</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"lightgrey"</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">sel</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"turquoise"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/chunk-3-1.png" width="500" /></p>
<p>Outra análise interessante é a identificação de quadrantes. Essa divisão pode ser feita tendo como base as coordenadas do centroide, que no caso representa o ponto central de Londres.</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">rgeos</span><span class="p">)</span><span class="w">
</span><span class="c1">## encontrando o centro da região de londres</span><span class="w">
</span><span class="n">lat</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">coordinates</span><span class="p">(</span><span class="n">gCentroid</span><span class="p">(</span><span class="n">lnd</span><span class="p">))[[</span><span class="m">1</span><span class="p">]]</span><span class="w">
</span><span class="n">lng</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">coordinates</span><span class="p">(</span><span class="n">gCentroid</span><span class="p">(</span><span class="n">lnd</span><span class="p">))[[</span><span class="m">2</span><span class="p">]]</span><span class="w">
</span><span class="c1">## argumento para testar se a região está ao norte ou ao leste do centro</span><span class="w">
</span><span class="n">norte</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">2</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">lng</span><span class="p">)</span><span class="w">
</span><span class="n">leste</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">1</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">lat</span><span class="p">)</span><span class="w">
</span><span class="n">oeste</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">1</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">lat</span><span class="p">)</span><span class="w">
</span><span class="n">sul</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">sapply</span><span class="p">(</span><span class="n">coordinates</span><span class="p">(</span><span class="n">lnd</span><span class="p">)[,</span><span class="m">2</span><span class="p">],</span><span class="w"> </span><span class="k">function</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">lng</span><span class="p">)</span><span class="w">
</span><span class="c1">## testando se a coordenada está a norte ou leste do centro</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"nordeste"</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"noroeste"</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"sudeste"</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">]</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="s2">"sudoeste"</span><span class="w">
</span><span class="c1">## colorindo os quadrantes no gráfico</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">as.factor</span><span class="p">(</span><span class="nf">as.character</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="o">$</span><span class="n">quadrant</span><span class="p">))</span><span class="w">
</span><span class="n">sapply</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">class</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"lightgrey"</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">,],</span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"red"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">norte</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"blue"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">leste</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"green"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span><span class="n">plot</span><span class="p">(</span><span class="n">lnd</span><span class="p">[</span><span class="n">sul</span><span class="w"> </span><span class="o">&</span><span class="w"> </span><span class="n">oeste</span><span class="p">,],</span><span class="w"> </span><span class="n">col</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"yellow"</span><span class="p">,</span><span class="w"> </span><span class="n">add</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/chunk-4-1.png" width="500" /></p>
<h2 id="criando-mapas-com-tmap-ggplot-e-leaflet">Criando mapas com tmap, ggplot e leaflet</h2>
<p><strong>Tmap</strong></p>
<p>A análise pode ser feita gerando um gradiente de cores com base na participação percentual da população no esporte:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">tmap</span><span class="p">)</span><span class="w">
</span><span class="n">qtm</span><span class="p">(</span><span class="n">shp</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Partic_Per"</span><span class="p">,</span><span class="w"> </span><span class="n">fill.palette</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"-Blues"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/chunk-5-1.png" width="500" /></p>
<p><strong>ggplot2</strong></p>
<p>Diferentemente do tmap, o ggplot exige que você forneça a base de dados em formado de data.frame. Isto pode ser feito por meio da função fortify():</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">ggplot2</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">dplyr</span><span class="p">)</span><span class="w">
</span><span class="n">lnd_f</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">fortify</span><span class="p">(</span><span class="n">lnd</span><span class="p">)</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span><span class="n">lnd</span><span class="o">$</span><span class="n">id</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">row.names</span><span class="p">(</span><span class="n">lnd</span><span class="p">)</span><span class="w"> </span><span class="c1"># Atribui um ID para a base sp </span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w"> </span><span class="c1"># ultima checagem antes da junção (os nomes das variáveis precisam ser iguais)</span><span class="w">
</span><span class="n">lnd_f</span><span class="w"> </span><span class="o"><-</span><span class="n">left_join</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">lnd</span><span class="o">@</span><span class="n">data</span><span class="p">)</span><span class="w"> </span><span class="c1"># juntou pela única variável com nome em comum</span><span class="w">
</span><span class="n">head</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">2</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p>Agora o objeto lnd_f pode ser utilizado para a criação de um mapa com ggplot:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">map</span><span class="o"><-</span><span class="n">ggplot</span><span class="p">(</span><span class="n">lnd_f</span><span class="p">,</span><span class="w"> </span><span class="n">aes</span><span class="p">(</span><span class="n">long</span><span class="p">,</span><span class="w"> </span><span class="n">lat</span><span class="p">,</span><span class="w"> </span><span class="n">group</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">group</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">Partic_Per</span><span class="p">))</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">geom_polygon</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">coord_equal</span><span class="p">()</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">labs</span><span class="p">(</span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Easting (m)"</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Northing (m)"</span><span class="p">,</span><span class="w"> </span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"% Sports\nParticipation"</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w">
</span><span class="n">ggtitle</span><span class="p">(</span><span class="s2">"London Sports Participation"</span><span class="p">)</span><span class="w">
</span><span class="n">map</span><span class="w">
</span><span class="c1">## trocando as cores</span><span class="w">
</span><span class="n">map</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">scale_fill_gradient</span><span class="p">(</span><span class="n">low</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"red"</span><span class="p">,</span><span class="w"> </span><span class="n">high</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"green"</span><span class="p">)</span><span class="w">
</span><span class="c1">## salvando o grafico com ggsave</span><span class="w">
</span><span class="n">ggsave</span><span class="p">(</span><span class="s2">"Sport Participation - London.jpg"</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<p><img src="/img/geospace/img_ggplot2.jpg" width="500" /></p>
<p><strong>Mapas interativos com leaflet</strong></p>
<p>O pacote leaflet permite a criação de mapas interativos e age de forma conjunta com o pacote shiny, tornando possível a visualização online dos mapas. O objeto lnd está com um CRS (Coordinate Reference System) que não é compatível com o leaflet. A visualização será possível depois que o CRS do objeto lnd for alterado para o EPSG:4326, que tem sido o mais utilizado:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">leaflet</span><span class="p">)</span><span class="w">
</span><span class="n">lnd84</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">spTransform</span><span class="p">(</span><span class="n">lnd</span><span class="p">,</span><span class="w"> </span><span class="n">CRS</span><span class="p">(</span><span class="s2">"+init=epsg:4326"</span><span class="p">))</span><span class="w"> </span><span class="c1">#reprojeta</span><span class="w">
</span><span class="n">leaflet</span><span class="p">()</span><span class="w"> </span><span class="o">%>%</span><span class="w">
</span><span class="n">addTiles</span><span class="p">()</span><span class="w"> </span><span class="o">%>%</span><span class="w">
</span><span class="n">addPolygons</span><span class="p">(</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">lnd84</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>
<iframe title="London Map" width="700" height="400" src="https://cdn.rawgit.com/jadermcs/fdb08a2c254288844c6ae4673e4e6e0b/raw/a92f7fdf0ec510d30504c934b3dcecbe8ab67fd3/london_map.html" frameborder="0" allowfullscreen=""></iframe>
<p>Esse mapa se diferencia dos outros por permitir uma interatividade semelhante à que se tem com a utilização do googlemaps no navegador.</p>
<p>A seguir temos mais um exemplo de visualização de uma determinada região no leaflet, porém agora será utilizado o arquivo shapefile do Distrito Federal, disponível no site do IBGE. Depois de baixar o arquivo e salvá-lo no seu Working Directory atual, o primeiro passo é atribuir o arquivo à um novo objeto, aqui denominado <em>df_shp</em>:</p>
<div class="language-r highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">library</span><span class="p">(</span><span class="n">raster</span><span class="p">)</span><span class="w">
</span><span class="n">library</span><span class="p">(</span><span class="n">sp</span><span class="p">)</span><span class="w">
</span><span class="n">df_shp</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">readOGR</span><span class="p">(</span><span class="n">dsn</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"df_setores_censitarios"</span><span class="p">,</span><span class="w"> </span><span class="n">layer</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"53SEE250GC_SIR"</span><span class="p">)</span><span class="w">
</span><span class="c1"># Criação do mapa com leaflet</span><span class="w">
</span><span class="n">df_shp</span><span class="o">@</span><span class="n">proj4string</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">CRS</span><span class="p">(</span><span class="s2">"+init=epsg:4326"</span><span class="p">)</span><span class="w"> </span><span class="c1"># reprojeta</span><span class="w">
</span><span class="n">df_leaf</span><span class="w"> </span><span class="o"><-</span><span class="w"> </span><span class="n">leaflet</span><span class="p">(</span><span class="n">data</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">df_shp</span><span class="p">)</span><span class="w"> </span><span class="o">%>%</span><span class="w"> </span><span class="n">addTiles</span><span class="p">()</span><span class="o">%>%</span><span class="w">
</span><span class="n">addPolygons</span><span class="p">(</span><span class="n">fill</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">FALSE</span><span class="p">,</span><span class="w"> </span><span class="n">weight</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="m">1</span><span class="p">,</span><span class="w"> </span><span class="n">stroke</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="kc">TRUE</span><span class="p">,</span><span class="w"> </span><span class="n">color</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"#03F"</span><span class="p">)</span><span class="o">%>%</span><span class="w">
</span><span class="n">addLegend</span><span class="p">(</span><span class="s2">"bottomright"</span><span class="p">,</span><span class="w"> </span><span class="n">colors</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"#03F"</span><span class="p">,</span><span class="w"> </span><span class="n">labels</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">"Distrito Federal"</span><span class="p">)</span><span class="w">
</span><span class="n">df_leaf</span><span class="w">
</span></code></pre></div></div>
<p>O código acima segue o mesmo raciocínio do criado para o mapa de Londres, porém com algumas configurações a mais. O arquivo .shp foi inserido diretamente na função leaflet e na função addPolygons foram incluídos os argumentos fill, weight, stroke e color, que representam respectivamente se o interior dos polígonos devem receber alguma cor, a espessura da linha de contorno, se as linhas dos polígonos devem ser coloridas e qual a cor escolhida. A função addLegend cria uma legenda para o mapa. Para mais detalhes sobre funções, basta rodar o seguinte comando: ?nomedafunção.</p>
<iframe title="London Map" width="700" height="400" src="https://cdn.rawgit.com/jadermcs/9f68419b0b05e32b8741861e80c7df02/raw/b1d9d0394fdd4f724dbc591a14dfa0537baca45e/df.html" frameborder="0" allowfullscreen=""></iframe>
Aprendizado Semi-Supervisionado para Detecção de Fraudes Parte 32017-05-12T20:57:20+00:00http://lamfo-unb.github.io/2017/05/12/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-3<h1 id="aprendizado-semi-supervisionado-para-detecção-de-fraudes-parte-3">Aprendizado Semi-Supervisionado para Detecção de Fraudes [Parte 3]</h1>
<p>Esta é a continuação (final) da série de postagens sobre detecção de fraudes, <a href="/2017/05/09/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-1/">post1</a>, <a href="/2017/05/11/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-2/">post2</a>. Nesta última etapa apresentaremos mais algumas técnicas semi-supervisionadas para detecção de anomalia e uma breve conclusão. Vamos lá!</p>
<h3 id="modelo-de-máquina-de-suporte-vetorial">Modelo de Máquina de Suporte Vetorial</h3>
<p>Máquinas de Suporte Vetoriais (MSV) são uma classe de modelos originalmente desenhadas para problemas supervisionados de categorização (ou classificação), em que o objetivo é separar dois tipos de observação. Intuitivamente, o que os MSVs fazem é achar o melhor plano de separação entre os dois tipos de dados. Isso pode parecer um pouco restritivo, já quem muitas vezes a superfície que separa duas classes de dados é composta por várias curvaturas, algo que um plano não conseguiria representar. Para superar essa limitação, as MSV fazer uso do truque do kernel, que representa os dados originais em um espaço dimensional maior, de forma que seja possível separar os dois tipos nesse novo espaço.</p>
<p><img src="/img/anomalia/kerneltrick.png" width="500" /></p>
<p>Na imagem acima, vemos como o truque do kernel representa dados em altas dimensões de forma que eles possam ser separados por um plano. As MSVs não são os únicos modelos que podem se beneficiar do truque do kernel, mas elas são especialmente otimizadas por ele. Na verdade, o truque do kernel é tão computacionalmente ineficiente que se torna praticamente proibitivo de ser utilizado com qualquer técnica que não as máquinas de suporte vetorial.</p>
<p>Na versão não supervisionada da MSV, não estamos interessados em separar dois tipos de dados, pois os dados sequer são nomeados com os tipos. Em vez disso, queremos achar a melhor esfera que encapsule todos os dados. É fácil ver como isso é útil no problema de detecção de anomalias: a esfera que contiver os dados normais será definida como nossa fronteira de normalidade, de forma que dados fora dela serão classificados como anomalias. Mas e se os dados normais não se agruparem em uma esfera, mas em uma forma mais complicada? Como talvez, duas esferas ou um ovo? Isso também não é um problema para a versão não supervisionada das MSV, pois podemos usar o truque do kernel e representar os dados em uma dimensão maior até que eles estejam contidos em uma esfera</p>
<p><img src="/img/anomalia/oneclasssvm.png" width="500" /></p>
<p>Na imagem abaixo, por exemplo, a região de normalidade é compreendida por duas esferas disjuntas, mas podemos ver como uma MSV consegue representar bem essas fronteiras. Na verdade, nós podemos dizer que o modelo não supervisionado de MSV é um <strong>aproximador universal de funções densidade de probabilidade</strong>, isto é, ele é capaz de aproximar qualquer distribuição possível. Uma severa desvantagem desse método é o fato dele ser extremamente ineficiente para treinar. Apenas para se ter uma ideia, dos modelos aqui avaliados, o segundo mais demorado de treinar é o de mistura de gaussianas, que leva aproximadamente 5min. O modelo MSV, por sua vez leva em torno de uma hora.</p>
<p>Após treinado, o modelo produz uma superfície de separação e nós podemos usar a distância entre uma observação e essa superfície como uma pontuação de anomalia para a observação. Distâncias negativas significam que a observação está fora da esfera definida pela superfície. Assim, quanto mais negativa a pontuação, maior a probabilidade da amostra ser uma anomalia. Usando a subamostra de validação, nomeada com tipos normais e anômalos, nós ajustamos um limiar para essa pontuação.</p>
<p><img src="/img/anomalia/ocsvmtune.png" width="500" /></p>
<p>O limiar escolhido foi de -22466.53 e com essa regra de decisão conseguimos a seguinte pontuação:</p>
\[R=0,630 \quad P=0,323 \quad F_2=0,529\]
<p>Podemos notar que esse modelo não bate o nosso benchmark, mesmo sendo capaz de representar qualquer distribuição possível. Isso acontece porque todo esse poder vem a um custo de muitas vezes encontrar superfícies de separação mais complicadas do que elas de fato deveriam ser. Algumas vezes - e provavelmente essa é uma delas - a complexidade adicional tem um custo mais elevado do que o benefício que se ganha com capacidade. Isso é o que chamamos de dilema viés-variância em aprendizado de máquina. Para mais informações sobre isso, temos também <a href="https://lamfo-unb.github.io/2017/04/29/Um-Olhar-Descontraido-Sobre-o-Dilema-Vies-Variancia/">esta excelente postagem</a> que cobre de maneira intuitiva o assunto.</p>
<p>Por fim, também é interessante notar como esse modelo peca mais em precisão, tendo uma revocação aceitável.</p>
<p><img src="/img/anomalia/conf-matSVM.png" width="500" /></p>
<h3 id="modelo-de-floresta-de-isolação">Modelo de Floresta de Isolação</h3>
<p>O modelo de floresta de isolação é outro modelo que podemos considerar como um aproximador universal de distribuições. Assim, não precisamos colocar nenhuma hipótese restritiva na forma como os dados são distribuídos. Esse modelo é baseado em estruturas de árvores, uma classe de métodos de aprendizado de máquina que se popularizou muito nos últimos anos devido a sua simplicidade intuitiva e rapidez de treinamento. O modelo de floresta de isolação ajusta várias árvores de isolação aos dados. Para construir cada árvore de isolação, primeiro selecionamos aleatoriamente uma das variáveis nos dados. Em seguida, selecionamos um valor aleatório entre o máximo e o mínimo dessa variável, que será utilizado para separar os dados. Nós continuamos fazendo essas segmentações aleatórias até que todas as observações estejam isoladas, isto é, separadas das demais. Á primeira vista, pode parecer estranho como essas decisões aleatórias vão nos ajudar a detectar anomalias, mas eis a ideia. Na imagem abaixo, \(X_1\) é uma observação normal e \(X_0\) é uma observação anômala.</p>
<p><img src="/img/anomalia/isoforest.png" width="500" /></p>
<p>Nossa esperança é que as anomalias sejam distintas dos dados normais, sendo que esses se aglomeram em algum local do espaço, enquanto que aquelas ficam mais isoladas. Assim, será preciso muito menos segmentações aleatórias para isolar uma anomalia do que para isolar uma observação normal. Nós podemos usar o número de segmentações até uma observação ser isolada como uma pontuação de anomalia: quanto maior esse número, menor a probabilidade da amostra ser uma anomalia. Quando construímos várias dessas árvores e combinamos a pontuação de anomalia delas para conseguir uma pontuação final temos uma floresta de isolação. Após treinada, nós utilizamos a subamostra de validação para ajustar o limiar segundo essa pontuação.</p>
<p><img src="/img/anomalia/tuneforest.png" width="500" /></p>
<p>Nosso limiar ótimo foi de 0,049. Com essa regra de decisão, tornamos à subamostra de teste para produzir uma avaliação final. Os resultados foram os seguintes:</p>
\[R=0,760 \quad P=0,482 \quad F_2=0,681\]
<p>Esses resultados batem o nosso benchmark, mas por pouco. Mais uma vez, notamos que o modelo tem sua performance puxada para baixo pela precisão, sendo que a revocação é bastante boa. Cabe ainda ressaltar que vantagens dessa metodologia frente às máquinas de suporte vetorial são a velocidade de treinamento e a capacidade de fácil paralelização. Como o treinamento de cada árvore é independente das demais, podemos realizá-lo em processos ou máquinas separadas, o que aumenta significativamente a rapidez com que treinamos uma floresta. Para finalizar, colocamos abaixo a matriz de confusão com respeito a avaliação final, na subamostra de teste.</p>
<p><img src="/img/anomalia/confmatforest.png" width="500" /></p>
<h3 id="modelo-neural">Modelo Neural</h3>
<p>Nos últimos anos, redes neurais se tornaram o canivete suíço de aprendizado de máquina, tanto pela sua flexibilidade e efetividade na maioria dos cenários que envolvem problemas estatísticos de alta complexidade e não linearidade. Aqui, nós vamos utilizar um modelo neural chamado autocodificador, no qual pedimos que uma rede neural reconstrua o sinal que lhe é passado. No nosso caso, vamos pedir que ela reconstrua os dados da transação. Para impedir que a rede neural simplesmente copie o que lhe foi passado como reconstrução perfeita, nós colocamos uma camada de neurônios estreita no meio da rede neural. Essa cama terá apenas dois neurônios e como os nossos dados têm 30 variáveis, isso significa que a rede neural terá que aprender uma representação interna que condense 30 dimensões em apenas duas.</p>
<p><img src="/img/anomalia/autoencoder.png" width="500" /></p>
<p>Nós vamos treinar um autocodificador utilizando apenas a subamostra de dados normais. Nossa esperança é que, ao não ser treinada para reconstruir as anomalias, a rede neural fará um péssimo trabalho reconstruindo-as, mas fará um ótimo trabalho reconstruindo observações normais. Assim, podemos usar o erro de reconstrução como uma pontuação para anormalidade: quanto maior o erro, maior a probabilidade da observação ser uma anomalia. Uma vez treinada a nossa rede neural, nós utilizamos a subamostra nomeada de validação para ajustar o limiar quanto à pontuação de anomalia.</p>
<p><img src="/img/anomalia/tuneautoenc.png" width="500" /></p>
<p>O limiar ótimo foi um erro de 1.69, o que nos deu os seguintes resultados:</p>
\[R=0,813 \quad P=0,294 \quad F_2=0,601\]
<p>Notamos que esse modelo não é melhor que o nosso benchmark e, mais uma vez, a precisão prejudicou a performance do modelo. É necessário observar que o autocodificador não é otimizado para detectar anomalias, mas para reconstruir sinais. Nós suspeitamos que ele seja tão bom nisso que esteja reconstruindo bem tanto o sinal normal quanto o anormal, tornando-o não muito bom para detecção de anomalia. Outro aspecto do autocodificador que merece atenção é que ele funciona como um método de redução de dimensões. Como utilizamos apenas dois neurônios na camada estreita, nós guardamos a atividade neural nessa camada como uma representação reduzida dos dados originais. Mais ainda, como temos apenas duas dimensões nessa versão reduzida, podemos colocá-la em um gráfico:</p>
<p><img src="/img/anomalia/autoencbiplot.png" width="600" /></p>
<p>Acima, representamos em branco os pontos normais e em preto, os anormais. É interessante perceber como a maioria das anomalias se agrupam em regiões distintas das regiões de normalidade. Talvez, o autocodificador não devesse ser utilizado como um método de detecção de anomalias em si, mas como um estágio de pré-processamento, onde primeiro conseguiríamos a representação acima e então usaríamos ela em conjunto com algum outro método de detecção de anomalia. Entretanto, isso ficará para um trabalho futuro.</p>
<p>Abaixo, colocamos a matriz de confusão do método neural para detalhar os tipos de erros que ele comete.</p>
<p><img src="/img/anomalia/confmatautoecn.png" width="500" /></p>
<h2 id="conclusão">Conclusão</h2>
<p>Métodos semi-supervisionados de aprendizado de máquina são excelentes em cenários de detecção de anomalias, em que há pouquíssimos exemplos do caso anômalo. Até agora, não encontramos nenhum projeto (no Kaggle) que apresentasse resultados melhores dos aqui apurados. O melhor modelo que desenvolvemos foi o de mistura de gaussianas com um F2-score de 79%. Entretanto, vale ressaltar que esse método não é universalmente superior. Em problemas de detecção de anomalias, bastante específicas de acordo com o domínio de interesse, é improvável que um algoritmo seja sempre melhor do que outro.</p>
<p>Esse post tratou de detecção de fraudes, mas as técnicas foram desenvolvidas de forma bastante geral para se estenderem a outras aplicações. Algumas delas são: detecção de cartéis, irregularidades em leilões, inadimplência, sonegação e corrupção.</p>
Aprendizado Semi-Supervisionado para Detecção de Fraudes Parte 22017-05-11T12:04:52+00:00http://lamfo-unb.github.io/2017/05/11/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-2<h1 id="aprendizado-semi-supervisionado-para-detecção-de-fraudes-parte-2">Aprendizado Semi-Supervisionado para Detecção de Fraudes [Parte 2]</h1>
<p>No <a href="/2017/05/09/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-1/">post anterior</a>, vimos o que é uma anomalia. Agora observaremos a forma de funcionamento de várias técnicas semi-supervisionadas para detecção de anomalia.</p>
<h2 id="os-dados">Os dados</h2>
<p>Nós vamos utilizar a base de dados <a href="https://www.kaggle.com/dalpozz/creditcardfraud"><code class="language-plaintext highlighter-rouge">Credit Card Fraud Detection</code></a> para demonstrar o funcionamento de várias técnicas semi-supervisionadas de detecção de anomalia. Segundo a descrição providenciada pelo fornecedor, “a base de dados contém transações feitas por cartão de crédito em setembro de 2013 por consumidores europeus. Os dados são de transações que ocorreram no período de dois dias, contando com 284’807 transações, dentre as quais 492 são fraudes. A base é altamente desbalanceada; o alvo positivo (fraude) corresponde a apenas 0,172% de todas as transações. Todos os dados são de variáveis numéricas, que são o resultado de transformação PCA, além de variáveis sobre o tempo em que a transação foi efetivada e sobre a quantidade transacionada”. Para efeito de esclarecimento, a técnica de PCA permite manter a informação integral dos dados ao mesmo tempo que retira sua interpretabilidade. Nesse caso, a técnica foi utilizada para manter o sigilo das informações bancárias.</p>
<p>Nós repartimos os dados em 3 subamostras. Em primeiro lugar, reservamos 80% das amostras de transações normais para treino, o que totalizou 227’452 observações. Essa sub amostra será nossa base de treinamento. Em seguida, nós separamos o restante das observações normais e anormais igualmente, formando duas sub amostras com 28’677 observações cada, sendo 246 dessas observações anômalas. A primeira dessas sub amostrar será nosso set de validação e será utilizada para ajustar o limiar da pontuação de anomalia, que será produzida pelo modelo treinado na primeira etapa. Por fim, a última subamostra será para testar a performance da técnica considerada.</p>
<h2 id="métricas-de-avaliação">Métricas de Avaliação</h2>
<p>Em problemas de previsão, a métrica de avaliação mais comum é a acurácia, que mede a proporção de acertos. No entanto, nesse cenário, como mais de 99% dos dados pertencem a uma única categoria, um preditor ingênuo prevendo todas as observações como sendo normais já conseguiria mais de 99% de acerto. Isso nos motiva a utilizar outras métricas: precisão e revocação. Intuitivamente, um sistema com alta revocação e precisão baixa apontaria muitas observações como sendo anômalas, conseguindo achar a maior parte das anomalias, mas a um custo muito alto em falsos positivos. Por outro lado, um sistema com alta precisão e baixa revocação apontaria poucos resultados como sendo transações fraudulentas, acertando-as, porém a um custo de várias fraudes passarem despercebidas. Assim, um sistema ideal teria que ponderar precisão e revocação em algum ponto ótimo. Formalmente, tempos precisão e revocação definidos como:</p>
\[P=\frac{T_p}{T+p + F_p} \quad \quad \quad R=\frac{T_p}{T+p + F_n}\]
<p>Em que \(T_p\) são os verdadeiros positivos, \(T_n\), os verdadeiros negativos, \(F_p\) são os falsos positivos e \(F_n\) são os falsos negativos.</p>
<p>Para que possamos comparar os modelos, é bom que tenhamos uma única métrica que resuma a performance. Para isso, vamos utilizar o \(F_2\)-score, que combina revocação e precisão, dando mais importância a primeira. Nós optamos por essa métrica porque acreditamos ser mais custoso não detectar uma fraude bancária que apontar uma transação como sendo fraudulenta e obter um alarme falso. Assim, desejamos que nosso sistema coloque mais importância em conseguir boa revocação. Formalmente, temos:</p>
\[F_2-score = (1+2)^2 \ast \frac{P \ast R}{2^2 \ast P + R}\]
<h3 id="benchmark">Benchmark</h3>
<p>A maioria dos bons trabalhos que utilizaram essa base de dados fizeram uso de aprendizado puramente supervisionado com alguma técnica para lidar com o desbalanceamento severo entre as categorias. Particularmente, <a href="https://www.kaggle.com/joparga3/d/dalpozz/creditcardfraud/in-depth-skewed-data-classif-93-recall-acc-now">este trabalho</a> disponível no Kaggle conseguiu uma precisão de 0,883, uma revocação de 0,619 e um \(F_2\)-score de 0,658. Como esse é o melhor resultado que achamos dentre os trabalhos disponíveis no Kaggle, vamos tomá-lo como benchmark.</p>
<h2 id="técnicas-de-detecção-de-anomalias">Técnicas de Detecção de Anomalias</h2>
<h3 id="modelo-gaussiano">Modelo Gaussiano</h3>
<p><img src="/img/anomalia/unigaussian.png" width="400" /></p>
<p>A distribuição gaussiana é dada pela curva em formato de sino (acima) e é, com certeza, o modelo estatístico mais famoso, principalmente porque muitos fenômenos do dia a dia se encaixam muito bem nela. Intuitivamente, se um fenômeno tem comportamento gaussiano, podemos dizer que 95% das realizações desse fenômeno aconteceram a no máximo 2 desvios padrões de distância da média. Por exemplo, se a quantidade média transacionada por cartão de crédito for de R$ 50,00, com um desvio padrão de R$ 10,00, podemos dizer que 95% das transações serão de um valor entre 30 e 70 reais. Mais ainda, nós podemos dizer que transações fora desse intervalo são bastante improváveis, indicando que podem ser anomalias.
Aqui, nós estendemos a distribuição gaussiana para o seu caso multivariado, para assim capturar interações entre variáveis. Por exemplo, pode ser que uma grande quantia transacionada por si só não seja estranha, mas essa mesma quantia em uma especifica hora do dia, digamos de madrugada, seja. Nós podemos então modelar as margens da normalidade pela interação entre hora do dia e quantidade transacionada.</p>
<p><img src="/img/anomalia/multigaussian.png" width="450" /></p>
<p>Nossos dados contêm 30 variáveis, logo não podemos visualizá-los em um gráfico como o acima. No entanto, achar uma gaussiana de 30 dimensões é tão simples quanto achar uma de duas e é isso que fizemos com os nossos dados de treino, isto é, a subamostra não nomeada. Quando encontramos a gaussiana multidimensional que melhor se encaixa nos dados, nós podemos extrair a probabilidade de cada observação, que seria a altura da gaussiana multidimensional. Em seguida, nós usamos a subamostra (nomeada) de validação para ajustar um limiar a partir do qual consideraríamos uma transação como anômala. Apenas para efeito de clarificação, ao invés de usar a probabilidade para decidir o limiar, nós usamos o logaritmo da probabilidade (fizemos isso pois a probabilidade é um número muito pequeno que poderia dar problemas de precisão numérica, devido a capacidade limitada do computador em representar números com muitas casas decimais). Abaixo, vemos como as nossas três métricas de avaliação evoluem conforme mudamos o limiar.</p>
<p><img src="/img/anomalia/gaussiantuning.png" width="500" /></p>
<p>O limiar ótimo escolhido foi de -269, isto é, amostras com uma log probabilidade menor do que essa serão consideradas anomalias pelo nosso modelo. Com essa regra aprendida, nós criamos a subamostra de teste para uma avaliação final. As pontuações nessa subamostra foram:</p>
\[R=0,793 \quad P=0,701 \quad F_2=0,773\]
<p>Apenas para que fique claro, uma revocação de 0,793 indica que, de todas as transações fraudulentas, nós conseguimos identificar 79,3% delas; uma precisão de 0,701 indica que, de todas as transações que previmos como sendo fraudulentas, 70,1% delas de fato o eram. O \(F_2\)-score não tem nenhuma interpretação intuitiva. Ele é apenas uma métrica que combina as outras duas de forma que possamos comparar os modelos mais facilmente. Por exemplo, podemos dizer que esse modelo é mais de 10 pontos melhor do que o nosso benchmark, que obteve um \(F_2\)-score de apenas 0,658. Abaixo está a matriz de confusão para mais detalhes sobre como o modelo classificou cada transação.</p>
<p><img src="/img/anomalia/confmatgaussian.png" width="500" /></p>
<h3 id="modelo-histograma">Modelo Histograma</h3>
<p>Nem todas as variáveis dos nossos dados seguem uma distribuição gaussiana. Se plotarmos o histograma de algumas características, podemos ver isso claramente. A começar pela distribuição da variável que mede a quantidade transacionada, que tem uma distribuição bastante complicada, tanto para os dados normais quanto para os anormais. (Novamente, para efeito de esclarecimento, transformamos a variável de quantidade transacionada em sua forma logarítmica. Isso costuma deixar as distribuições mais balanceadas).</p>
<p><img src="/img/anomalia/hist1.png" width="500" />
<img src="/img/anomalia/hist2.png" width="500" />
<img src="/img/anomalia/hist3.png" width="500" />
<img src="/img/anomalia/hist4.png" width="500" /></p>
<p>Quando vemos esses histogramas, notamos facilmente como algumas variáveis são ótimos indicadores de anomalias, uma vez que a distribuição (aproximada pelo histograma) dos dados anômalos e dos dados normais são bastante distinguíveis. Veja por exemplo a variável <code class="language-plaintext highlighter-rouge">V10</code>. A distribuição dos dados normais parece uma gaussiana bastante concentrada no zero, ao passo que os dados anormais parecem seguir uma distribuição bimodal, com um pico em aproximadamente -5 e outro em -15.</p>
<p>Nós vamos explorar essa diferença nos histogramas para construir uma pontuação de normalidade que será proporcional à probabilidade dos dados corresponderem a uma transação normal. Em primeiro lugar, vamos usar os dados de treinamento (não nomeados e com exemplos apenas dos casos normais) para estimar um histograma para cada variável nos dados. Assim, na hora de avaliar uma nova observação, nós analisamos em qual dos compartimentos dos histogramas cada uma de suas variáveis cai. A pontuação de normalidade será então a média da altura desses compartimentos. É fácil perceber que se a observação for normal, ela cairá em uma região do histograma com compartimentos bastante altos.</p>
<p>Uma vez treinado esse modelo, vamos ajustar o limiar para essa nossa pontuação usando a subamostra de validação, que inclui dados nomeados, tanto do caso normal quanto do caso anormal.</p>
<p><img src="/img/anomalia/histtuning.png" width="500" /></p>
<p>O melhor limiar, de acordo com o \(F_2\)-score, foi 36161. Com o modelo assim ajustado, conseguimos os seguintes resultados:</p>
\[R=0,646 \quad P=0,170 \quad F_2=0,415\]
<p>Observamos que esse modelo não é melhor que nosso benchmark, conseguindo um \(F_2\)-score de apenas 0,41. A performance do modelo é particularmente prejudicada pela baixa precisão, de 0,17. Isso indica que, de todas as observações que esse modelo classifica como sendo fraudulentas, apenas 17% delas de fato o são. Assim, o modelo incorre a um elevado custo em termos de falsos positivos. Devemos notar que esse modelo é capaz de aproximar qualquer distribuição por variável, mas não consegue capturar relações entre variáveis. Aparentemente, conseguir capturar interações é algo bastante importante nos dados aqui presente. Abaixo, na matriz de confusão, temos uma ideia melhor do tipo de erro que estamos cometendo.</p>
<p><img src="/img/anomalia/confmathist.png" width="500" /></p>
<h3 id="modelo-de-mistura-de-gaussianas">Modelo de Mistura de Gaussianas</h3>
<p><img src="/img/anomalia/gmm.png" width="400" /></p>
<p>Anteriormente, no modelo gaussiano nós assumimos que os dados vinham de uma distribuição gaussiana multidimensional. Isso talvez seja um pouco restritivo. Como vimos nos histogramas acima, nem todas as variáveis seguem um modelo gaussiano. Nós podemos utilizar um modelo que relaxa essa hipótese, assumindo que os dados vêm de uma distribuição que é uma <strong>mistura de gaussianas</strong>. Pela imagem acima, observamos que essa hipótese não é nem um pouco restritiva e que distribuições bastante complexas podem ser representadas por misturas de gaussianas. De fato, contanto que tenhamos gaussianas suficiente, qualquer distribuição poderá ser aproximada por uma mistura de gaussiana.</p>
<p>Se quisermos capturar interações entre variáveis, é fácil o suficiente estender o modelo para uma mistura de gaussianas multivariadas, como na imagem abaixo (dimensão da probabilidade/altura está suprimida e representada como curva de nível):</p>
<p><img src="/img/anomalia/gmmmultivariate.png" width="500" /></p>
<p>No nosso modelo de detecção de anomalias, nós ajustamos 3 gaussianas aos dados com um algoritmo de Expectativa-Maximização. Fizemos isso utilizando apenas os dados de treino, que não estavam nomeados e que continham apenas casos de transações normais. Com esse modelo treinado, conseguimos mais uma vez ter acesso direto à probabilidade de cada amostra e mais uma vez optamos por utilizar o logaritmo da probabilidade para não ter que lidar com muitas casas decimais. Na subamostra de validação com dados nomeados, ajustamos um limiar para o logaritmo da probabilidade, para decidir abaixo de que pontuação consideraríamos uma anomalia. A evolução das três métricas conforme a evolução do limiar pode ser conferida abaixo.</p>
<p><img src="/img/anomalia/gmmtune.png" width="500" /></p>
<p>O limiar ótimo escolhido foi de -101, de forma que observações com uma pontuação menor do que isso seriam consideradas anômalas. Por fim, tornamos à subamostra de teste para uma avaliação final. Os resultados foram os seguintes:</p>
\[R=0,809 \quad P=0,726 \quad F_2=0,791\]
<p>Esse foi o nosso melhor modelo, com elevada revocação e precisão. Para mais informações sobre o tipo de erro que esse modelo comete, abaixo colocamos a matriz de confusão da avaliação final, na subamostra de teste.</p>
<p><img src="/img/anomalia/confmatgmm.png" width="500" /></p>
<p>No post 3 analisaremos mais algumas técnicas de detecção de anomalia.
<a href="/2017/05/12/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-3/">Parte 3 - Final</a></p>
Semi-Supervised Learning for Fraud Detection Part 12017-05-09T12:04:52+00:00http://lamfo-unb.github.io/2017/05/09/Semi-Supervised-learning-for-fraud-detection-Part-1<p>Weather to detect fraud in an airplane or nuclear plant, or to notice illicit expenditures by congressman, or even to catch tax evasion. the art of realizing suspect patterns and behaviors can be quite useful in a wide range of scenarios. With that in mind, we made a small list of procedures to carry out this kind of task. Some of them will be incredibly simple and surprisingly effective. Other, not so simple. Anyway, we will focus on <strong>semi-supervised machine learning techniques for anomaly detection</strong>. Don’t worry if this sound confusing at first. Before anything, we will explain what are anomalies and what is semi-supervised machine learning. Next, we will give some intuitive explanations about the techniques here explored, as well as cast light in their advantages and disadvantages. This work is freely inspired in a survey by Chandola et al (2009).</p>
<p>This work does not intent to be extensive nor rigorous; out goal is to be the least complicated we can and the more intuitive as possible. For a more details and technical discussion, please check out our <a href="https://www.kaggle.com/matheusfacure/d/dalpozz/creditcardfraud/semi-supervised-anomaly-detection-survey">implementation of this work on Kaggle</a></p>
<h2 id="what-is-an-anomaly">What is an anomaly?</h2>
<p>“Anomalies are patterns in data that do not conform to a well-defined notion of normal behavior” (Chandola et al, 2009). In other words, they are data are somewhat strange and distinct from normal observations. For example, points in \(O_1\), \(O_2\) in the image bellow are isolated and outside the normal region (\(N_1\) and \(N_2\)), thereby being considered anomalies. The dots in region \(O_3\), although being in a neighborhood, are also anomalies, for that whole region is outside the normal boundaries.</p>
<p><img class="center-block thumbnail img-responsive" src="/img/anomalia/anomaly.png" /></p>
<p>A fairly straightforward approach for anomaly detection would be to simple define the regions in the data where in the normal data lies and then classify everything outside that regions as anomalous. However, this is most easy said than done and there are some quite difficult challenges that arise in anomaly detection problems:</p>
<ul>
<li>
<p>Modeling a regions that captures all notions of normality is extremely difficult and the frontiers between normal and abnormal are usually blurred;</p>
</li>
<li>
<p>Anomalies can be the result of malicious activities (e.g. frauds). In this case, there is an adversary that is always adapting to make anomalous observations seem normal;</p>
</li>
<li>
<p>What is normal can change, that is, a notion of normality defined today may not be valid in the future;</p>
</li>
<li>
<p>The notion of normality varies a lot from application to application and there is no general enough algorithm to capture them all in an optimized way;</p>
</li>
<li>
<p>Gathering samples from the abnormal behavior is a major challenge in anomaly detection. These samples tend to be very scarce or non existent.</p>
</li>
</ul>
<p>To deal with this problems, we propose a semi-supervised approach, that requires only a small portion of abnormal samples.</p>
<h2 id="what-is-semi-supervised-machine-learning">What is semi-supervised machine learning?</h2>
<p>In rough terms, machine learning is the science that uses computer science and statistical methods to analyze data. Machine learning techniques started in the field of artificial intelligence, as a way to allow for computers acquire their own knowledge from data. Today, machine learning has expanded in its own field and has had success in problems that demand statistical reasoning being our human limitations. In the regimes that machine learning operates on, the most prominent is the supervised one, that focus on predictions tasks: having data on pairs of labels and observations \((x, y)\), the goal is to learn how the labels are associated with the features. This is done by presenting the machine with enough samples of features and its observed labels, to the point where it can learn an association rule between them. Some examples are: identifying the presence of a disease (label), given the patient symptoms (features); identify which person (label) is in a given image (features) or classify a book (features) in a given literary school (label).</p>
<p>One limitation of supervised machine learning is that gathering labels can be costly. For example, consider the problem of prediction the class of an article given its written content. To teach a computer to do such tasks, we first need to collect the articles and label them with the right category. Usually, we need thousands of examples, so labeling such an amount of articles can be very time-consuming. In anomaly detection task, we often have an abundant observations of the normal case, but it is very hard to gather abnormal observations. In some extreme cases, such as nuclear plant failure detection, it is not only hard to have anomaly examples, but it is undesirable. Therefore, with little or no examples of anomalies, the computer doesn’t have enough information to learn their statistical proprieties, making the problem in detecting them extremely difficult.</p>
<p>One possibility is to use semi-supervised machine learning, where we consider only as small fraction of the data as being labeled and that the majority of the unlabeled data has only normal samples. Thus, we can use unsupervised machine learning techniques (that learn the structure in data) to learn some notion of normality. By the end of this unsupervised stage, the machine will be able so associate each observation with a score that is proportional to the probabilities of that observation being normal. Then, we can use some labeled data to tune a threshold for this score, below which we will consider a sample as being an anomalies.</p>
<p>OK… Maybe this last paragraph has a little too much information, which makes understanding slower. Think this way: first, we teach the machine only to understand how the normal case is, for we do not have (much) anomaly samples; next, we use a little of the few anomaly examples we have to fine tune our machine’s perceptions of normality; lastly, we use the rest of our data - with a few anomalies and lots of normal observations, to produce a final evaluation of our anomaly detection technique. If you still didn’t get it, don’t worry. Soon we will an empirical research with lots of examples showing how to use semi-supervised machine learning for fraud detection.</p>
Aprendizado Semi-Supervisionado para Detecção de Fraudes Parte 12017-05-09T12:04:52+00:00http://lamfo-unb.github.io/2017/05/09/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-1<h1 id="aprendizado-semi-supervisionado-para-detecção-de-fraudes-parte-1">Aprendizado Semi-Supervisionado para Detecção de Fraudes [Parte 1]</h1>
<p>Seja para detectar falhas em um avião ou usina nuclear, seja para perceber gastos ilícitos de um deputado ou seja para apontar sonegação no imposto de renda, a arte de notar comportamentos e padrões suspeitos pode ser bastante útil em diversos cenários. Pensando nisso, preparamos uma pequena lista de procedimentos para esse tipo de tarefa. Algumas delas serão incrivelmente simples e surpreendentemente efetivas. Outras, nem tão simples assim. De qualquer forma vamos nos concentrar em <strong>técnicas de aprendizado de máquina semi-supervisionado para detecção de anomalias</strong>. Não se preocupe se isso soou confuso. Antes de mais nada, vamos explicar tanto o que são anomalias quanto o que é aprendizado de máquina semi-supervisionado. Em seguida, vamos fornecer uma explicação intuitiva do funcionamento de cada uma das técnicas aqui explicadas, assim como esclarecer suas vantagens e desvantagens. Esse trabalho é livremente inspirado em uma pesquisa em que Chandola et al (2009) compilam várias técnicas de detecção de anomalia.</p>
<p>Essa pesquisa não pretende ser extensiva e nem rigorosa; nossa esperança é sermos o menos complicado possível na linguagem e o mais direto possível nas explicações intuitivas. Para uma versão mais detalhada e técnica, você pode conferir <a href="https://www.kaggle.com/matheusfacure/d/dalpozz/creditcardfraud/semi-supervised-anomaly-detection-survey">implementação que fizemos diretamente no Kaggle</a> (em inglês).</p>
<h2 id="o-que-é-uma-anomalia">O que é uma anomalia?</h2>
<p>“Anomalias são padrões nos dados que não obedecem bem as noções definidas como normalidade” (Chandola et al, 2009). Em outras palavras, são dados que apresentam algum comportamento estranho, distinto do padrão normal. Por exemplo, os pontos \(O_1\), \(O_2\) na imagem abaixo estão isolados e fora das regiões de normalidade (\(N_1\) e \(N_2\)), sendo assim considerados anomalias. Os pontos na região \(O_3\), embora tenham uma vizinhança, também são anomalias, pois a região inteira está fora da de normalidade.</p>
<p><img src="/img/anomalia/anomaly.png" width="400" /></p>
<p>Assim sendo, uma abordagem bastante direta para detecção de anomalias seria simplesmente definir a região onde os dados normais estão presentes e classificar tudo o que aparecer fora dessa região como anomalia. No entanto, isso é mais fácil de falar do que de fazer e há alguns desafios bastante complicados que surgem em problemas de detecção de anomalias:</p>
<ul>
<li>
<p>Modelar uma região que capture todas as noções de normalidade é extremamente difícil e as fronteiras entre normal e anormal geralmente não são bem definidas;</p>
</li>
<li>
<p>Anomalias podem ser o resultado de atividade maliciosa (e.g. fraudes bancárias). Nesse caso, há um adversário que está sempre tentando se adaptar para fazer com que as observações anômalas pareçam normais;</p>
</li>
<li>
<p>O que é normal pode mudar, isto é, uma noção de normalidade definida hoje pode não ser válida no futuro;</p>
</li>
<li>
<p>A noção de normalidade varia muito de aplicação para aplicação e não há um algoritmo geral o suficiente para capturá-la de forma ótima;</p>
</li>
<li>
<p>Conseguir amostrar o comportamento <strong>anormal</strong> é geralmente um dos maiores problemas em detecção de anomalias, sendo essas amostras extremamente escassas ou até mesmo inexistentes.</p>
</li>
</ul>
<p>Para lidar com esses problemas, nós sugerimos uma abordagem semi-supervisionada, que não requer nada além de uma pequena parcela de amostras anormais.</p>
<h2 id="o-que-é-aprendizado-de-máquina-semi-supervisionado">O que é aprendizado de máquina semi-supervisionado</h2>
<p>Aprendizado de máquina é uma ciência que utiliza métodos da ciência da computação e estatística para analisar dados. As técnicas de aprendizado de máquina surgiram dentro do campo de inteligência artificial, como um meio de permitir que os computadores aprendessem uma forma de conhecimento própria. Hoje, aprendizado de máquina se expandiu em um campo autônomo e tem obtido sucessos também em problemas que demandam raciocínio estatístico além da capacidade humana. Dentro dos regimes de aprendizado de máquina, destaca-se o de aprendizado de máquina supervisionado, que foca em problemas de previsão: tendo uma base de dados com “alvos” para cada observação (pares \((x,y)\)), a meta é aprender quais “alvos” (\(y\)) estão associados a quais dados (\(x\)). Isso é feito apresentando ao computador pares suficientes de dados e alvos, até que ele aprenda a associar um ao outro. Alguns exemplos desse tipo de problema são: identificar a presença de uma doença (alvo), dado os sintomas do paciente (dados); prever se o preço da ação de uma empresa vai subir ou cair (alvo), dado o histórico do mercado financeiro (dados); identificar de que pessoa é a face (alvo) em uma imagem (dados) ou classificar um livro (dados) em uma escola literária (alvo).</p>
<p>Uma limitação de aprendizado de máquina supervisionado é que pode ser extremamente custoso conseguir os alvos para cada observação (nós chamamos isso de nomear a base de dados). Por exemplo, considere o problema de prever o tema de um artigo de jornal (alvo) dado o seu conteúdo escrito (dados). Para que um computador faça isso, é preciso que antes alguém tenha lido uma grande quantidade (muitas vezes, milhares) de artigos e nomeado cada um com um tema. Assim, o computador terá acesso tanto ao conteúdo, quanto ao alvo que ele precisa prever, nesse caso o tema do artigo. Em cenários de detecção de anomalias, muitas vezes nós só temos dados que representam o caso normal, sendo extremamente difícil conseguir dados que representam anomalias. Em alguns extremos, como, por exemplo, o problema de detectar falhas em uma usina nuclear, conseguir exemplos de falhas críticas é tanto impossível quanto indesejável. Assim, com poucos ou nenhum exemplo do que é um caso anormal, o computador não tem informação suficiente para aprender os padrões estatísticos da anormalidade, tornando o problema de detectá-la extremamente difícil.</p>
<p>Uma possibilidade é utilizar <strong>aprendizado de máquina semi-supervisionado, em que consideramos apenas uma pequena parcela dos dados como estando nomeada</strong> e que os dados não nomeados só contêm exemplos do caso normal, que geralmente é abundante. Assim, nós utilizamos técnicas de aprendizado <strong>não</strong> supervisionado (para aprender a estrutura dos dados) nos dados não nomeados para extrair alguma noção de normalidade. Ao final dessa etapa não supervisionada, a máquina conseguirá associar cada observação com uma pontuação proporcional à probabilidade do dado ter vindo da região normal. Em seguida, usamos a parte nomeada dos dados (com exemplos tanto de anomalias, quanto do caso normal) para definir um limiar na pontuação, a partir do qual consideraremos a amostra como anômala.</p>
<p>OK… Talvez esse último parágrafo contenha muitas e complexas informações, o que torna a compreensão mais lenta. Pense no seguinte: primeiro, nós ensinamos a máquina apenas como é o caso normal, pois não temos (muitos) exemplos de anomalias; em seguida, nós usamos um pouco dos exemplos de casos anormais para refinar a percepção de normalidade da máquina; por fim, utilizamos o resto dos dados - com um pouco de casos anormais e muitos casos normais – para produzir uma avaliação final do nosso método de detecção de anomalias. Se você ainda não entendeu, não se preocupe. Logo mais colocaremos um estudo empírico com vários exemplos utilizando métodos de aprendizado semi-supervisionado para detectar fraudes.</p>
<p>Continua… <a href="/2017/05/11/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-2/">Parte 2</a> <a href="/2017/05/12/Aprendizado-Semi-Supervisionado-para-Deteccao-de-Fraudes-Parte-3/">Parte 3</a></p>
Um Olhar Descontraído Sobre o Dilema Viés-Variância2017-04-29T23:59:07+00:00http://lamfo-unb.github.io/2017/04/29/Um-Olhar-Descontraido-Sobre-o-Dilema-Vies-Variancia<h1 id="um-olhar-descontraído-sobre-o-dilema-viés-variância">Um Olhar Descontraído Sobre o Dilema Viés-Variância</h1>
<p>Fazer previsões é uma das principais ambições do ser humano. Uma pessoa pode ter a motivação de saber prever quase qualquer coisa, desde o placar de um evento esportivo até o preço de uma ação ou o humor da sua namorada… Mas o futuro é uma variável aleatória – ninguém sabe de fato como vai ser, qualquer previsão é em essência um “chute”. Bem, como chutar então? Você pode simplesmente jogar uma moeda, isso é bem conveniente, mas certamente não dá o melhor chute possível. É aí que entra a estatística, uma área do conhecimento que defino sucintamente como “a ciência do chute”.</p>
<p>Enquanto o futuro é um inerente mistério, o passado é um ambiente onde não há mais incerteza, então nada mais natural e sensato que tentar prever o futuro com base no que já aconteceu. A grosso modo, com base em potenciais elementos (uma lista de \(x_1,x_2,...,x_k\) variáveis independentes) que influenciem essa variável que se deseja prever (uma variável dependente \(y\)), tentar chutar valores futuros de \(y\) ao se coletar novos valores dos \(x\)’s (em aprendizado de máquina, o jargão para isso é “aprendizagem supervisionada”). Ou seja, a estatística busca fornecer o melhor chute, condicionado às informações disponíveis.</p>
<p>Pense intuitivamente: por mais que o futuro possa trazer uma coisa completamente diferente de tudo que já foi visto, é razoável assumir que o futuro e o passado compartilham de certos <strong>padrões</strong>, conexões que fazem as duas instâncias temporais serem manifestações de um mesmo fenômeno. Para obter bons chutes, um conceito bem importante é o chamado <strong>dilema viés-variância</strong>.</p>
<h4 id="o-que-isso-quer-dizer">O que isso quer dizer?</h4>
<p>Vamos discutir primeiro o “viés”. É fácil imaginar que, para ser capaz de prever com exatidão o futuro, primeiro é preciso entender bem o passado. Um preditor que não consegue mapear bem as características daquilo que já se observou claramente tende a não se sair bem para o futuro. O que aqui chamamos de “viés” são os desvios entre aquilo que se observou no passado e aquilo que se prevê pelo modelo proposto – em suma, é o quão bem o modelo está <strong>descrevendo</strong> os dados observados.</p>
<p><img src="/img/chunk-8.png" alt="alt text" title="Distribuições" /></p>
<p>É natural pensar que quanto melhor o modelo descreve os dados da amostra, melhor ele é. Porém, isso não é verdade, pois o objetivo primordial <strong>não</strong> é descrever os dados, mas usá-los para fazer previsões (ou <strong>inferências</strong>) sobre o futuro. Isso nos leva para o lado da “variância”:</p>
<p>O objetivo aqui é conseguir prever a variável de interesse com base em <strong>alguns</strong> elementos. De cara temos um problema, pois aquilo que efetivamente vemos é apenas uma parte do fenômeno todo; então, se nos atermos demais a simplesmente descrever os dados disponíveis, estamos no fundo torcendo para que o <strong>mesmo padrão observado se repita para o futuro</strong>, o que claramente não é verdade. Para poder <strong>generalizar</strong> o que se observou para amostras futuras – ou seja, antecipar alguma coisa que ainda não aconteceu – é preciso calibrar o modelo de modo a capturar apenas o “essencial”, informações que realmente contribuem para uma boa previsão, em vez de captar por completo os padrões daquela amostra específica, pois ao fazer isso, informações inúteis (“<strong>ruído</strong>”) acabam sendo incorporadas ao mesmo tempo. Basicamente, ao forçar uma descrição muito fiel dos dados da amostra, acaba que se perde em capacidade de generalização, pois o futuro em geral <strong>não</strong> é uma extensão do passado.</p>
<p>Modelos que descrevem excessivamente bem os dados de uma amostra tendem a introduzir muita complexidade e volatilidade, de modo a prejudicar a capacidade de generalização. Na filosofia da ciência há um princípio chamado “navalha de Occam”, os estatísticos conhecem como “princípio da parcimônia”; a cultura popular adotou um mnemômico um tanto quanto ácido:</p>
<blockquote>
<p><em>“KISS – <strong>keep it simple, stupid</strong>“</em></p>
</blockquote>
<p>Basicamente, quer dizer que entre modelos com mesmo poder explicativo, o mais simples deles é o melhor, pois apresenta a mesma qualidade com um custo menor.</p>
<p>A essa altura, você já deve ter percebido que estamos diante de um cobertor curto, pois o cenário ideal que buscamos possui as duas características desejáveis, porém contraditórias: queremos um modelo que descreva bem os dados disponíveis <strong>E</strong> que seja capaz de generalizar para dados futuros. Se temos um modelo que se ajusta mal aos dados do passado (“under-fitting”), o modelo já começa com pouca confiabilidade, pois não está sendo fiel às informações disponíveis; por outro lado, um ajustamento excessivo (“over-fitting”) acaba assumindo que o futuro irá repetir o passado, de modo que o modelo tende a fornecer uma péssima previsão para observações que sejam apenas um pouquinho fora daquele padrão dos dados passados.</p>
<p>O dilema viés-variância é muito importante na construção de modelos matemáticos: a qualidade de um modelo depende diretamente das variáveis consideradas, e saber achar o meio-termo entre incorporar variáveis úteis e descartar variáveis inúteis pode ser um desafio e tanto. Vejamos um exemplo simplista: suponha que queremos construir um modelo para prever o preço de uma ação de uma empresa. É de se esperar que o desempenho econômico da empresa tenha uma influência decisiva no preço da ação, então podemos colocar como variáveis alguns indicadores como índice de lucratividade e liquidez, o <strong>market share</strong> da empresa, número de filiais, e por aí vai.</p>
<p>Poderíamos colocar por exemplo “escolaridade do CEO” como uma variável explicativa; é de se esperar que um gestor com uma formação acadêmica mais robusta possa incrementar o valor da companhia, mas a relação já não parece tão direta assim… Poderíamos colocar como variável se o CEO da empresa é destro, canhoto ou ambidestro, mas essa informação tende a não influenciar em nada na variável que se deseja prever, e a introdução dessa variável acabaria poluindo o modelo com uma <strong>complexidade desnecessária</strong>.</p>
<p>Note que não há limites para a criatividade do pesquisador, e teoricamente poderíamos colocar um número gigantesco de variáveis. Mas à medida que variáveis com menor relevância vão sendo inseridas, chega um momento em que a “variância” introduzida pela nova variável não compensa o <strong>poder explicativo</strong> que ela agrega ao modelo.</p>
<p>Saber encontrar o meio-termo ideal entre viés e variância não é uma tarefa fácil, há diversas técnicas para nos ajudar com isso, tais como validação cruzada e redução de dimensionalidade, podemos abordar esses tópicos em posts futuros.</p>
A Casual Look at the Bias-Variance Dilemma2017-04-29T23:59:07+00:00http://lamfo-unb.github.io/2017/04/29/A-Casual-Look-at-the-Bias-Variance-Dilemma<h1 id="a-casual-look-at-the-bias-variance-dilemma">A Casual Look at the Bias-Variance Dilemma</h1>
<p>Making predictions is one of the main ambitions of the human race. One may have the motivation to forecast almost anything from a sports event to the stock price or his girlfriend’s mood… But the future is a random variable – no one really knows how it’s gonna be, so any prediction is in essence a “guess”. Well, how to guess then? You can simply toss a coin, this is quite convenient, but it certainly does not give the best guess possible. This is where statistics comes to stage, as I define briefly that knowledge field as “the science of guessing”.</p>
<p>While the future is an inherent mystery, the past is an environment where uncertainty doesn’t exist anymore, so it’s only natural and reasonable trying to predict the future based on what has already happened. Roughly, based on elements (a list of <span>\(x_1,x_2,...,x_k\)</span> independent variables) that may have influence on the variable to be predicted (a dependent variable \(y\)), the goal is to try and guess future values of \(y\) by collecting new values of the \(x\)’s (in machine learning, the jargon for this is “supervised learning”). That is, statistics seek to provide the best guess, conditioned to the available information.</p>
<p>Think intuitively: even though the future may bring in stuff completely different from anything seen in the past, it’s reasonable to assume that both future and past share certain <strong>patterns</strong>, connections that make those two temporal instances a manifestation of the same phenomenon. To get good guesses, a very important concept is called <strong>bias-variance dilemma</strong>.</p>
<h4 id="what-does-it-mean-exactly">What does it mean exactly?</h4>
<p>Let’s first discuss “bias”. It’s easy to imagine that in order to accurately predict the future, one must first understand the past well. A predictor that fails to map clearly the characteristics of clearly observed data tends not perform badly for the future. What we call “bias” are the deviations between the observed in the past and the predicted by the proposed model – in short, how well the model is <strong>describing</strong> the observed data.</p>
<p><img src="/img/chunk-8.png" alt="alt text" title="Distribution" /></p>
<p>It is natural to think that the better the model describes the sample data, the better it is. But this is not true, since the primary purpose is <strong>not</strong> to describe the data, but rather to use those to make predictions (or <strong>inferences</strong>) about the future. This brings us to the “variance” side:</p>
<p>Our goal here is to be able to predict the variable of interest \(y\) based on <strong>some</strong> elements of the whole population, so we have a major problem from the start, for what we actually see in the sample is only part of the whole phenomenon; so if we simply stick onto describing the already available data, we essencially <strong>hoping that the same pattern will repeat in the future</strong>, which clearly doesn’t always happens. To be able to <strong>generalize</strong> what has been observed for future samples – that is, to anticipate something that has not yet happened – one must calibrate the model for it to capture only the “essential” information that actually contributes to a good prediction, instead of fully capturing the patterns of that particular sample, because in doing so, useless information (“<strong>noise</strong>”) is incorporated at the same time. Basically, by forcing a very accurate description of the sample data, we end up losing in generalization ability, since, in general, the future is <strong>not</strong> a mere extension of the past.</p>
<p>Models that describe the data of a sample excessively well tend to introduce a lot of complexity and volatility, thus hindering the generalization ability. In the philosophy of science there is a principle called <strong>Occam’s razor</strong> (the statisticians know it as the “principle of parsimony”, popular culture has adopted a rather pushy mnemonic:</p>
<blockquote>
<p><em>“KISS – <strong>keep it simple, stupid</strong>“</em></p>
</blockquote>
<p>Basically, it means that between models with the same explanatory power, the simplest of them is the best, because it presents the same quality with a lower cost.</p>
<p>By now, you should have realized that we indeed face a dilemma, as the ideal scenario demands two desirable but contradictory features: we want a model that describes well the available data <strong>AND</strong> is capable of generalizing for future data. If we fit a model that misrepresents past data (“under-fitting”), the model is kinda unreliable from the start. On the other hand, an over-adjustment (“over-fitting”) ends up assuming that the future will repeat the past, so the model tends to provide a poor prediction even for observations that follow just slightly different trends than the one showed in past data.</p>
<p>The bias-variance dilemma is very important in the mathematical modelling: the quality of a model depends directly on the variables considered, and the optimal middle ground between incorporating useful variables and discarding useless variables can be quite a challenge. Let’s look at a simple example: Suppose that we want to construct a model to predict a company’s stock price. Is to be expected that the economic performance of that company influences decisively on the stock price, so we can put as variables some indicators like index of profitability and liquidity, the company’s market share, number of subsidiaries, and so on.</p>
<p>For instance, we could put “CEO’s scholarity” as an explanatory variable; It is to be expected that a manager with a more robust academic background can increase the value of the company, but the relationship doesn’t seem that straightforward… We could insert as a variable whether the CEO is right-handed, left-handed or ambidextrous, but this information tends not to influence the predicted variable at all, and the introduction of this variable would end up polluting the model with an <strong>unnecessary complexity</strong>.</p>
<p>Note that there’re no limits to the researcher’s creativity, and theoretically we could put a gigantic number of variables. But as less relevant variables are inserted, there comes a time when the “variance” introduced by the new variable does not compensate for the <strong>explanatory power</strong> that it adds to the model.</p>
<p>Knowing how to find the ideal middle ground between bias and variance is not an easy task, there are several techniques to aid us with this, such as cross-validation and dimensionality reduction, we can address these topics in future posts.</p>