Apresentação

Nesta primeira seção irei apresentar as principais ferramentas que utilizaremos para nos ajudar na organização computacional de dados, scripts, análises e projetos científicos em geral. Estas ferramentas irão auxiliar desde a organização local de seus dados até a disponibilização destes dados em plataformas de acesso aberto. Várias delas já devem ser velhas conhecidas por vocês, por exemplo, o RStudio, então dispensam maiores apresentações. Por isso, grande parte deste documento vai tratar de uma ferramenta até bem conhecida pelo nome, mas que pra muita gente pode parecer coisa de outro mundo: o Git. Vocês verão que conhecem mais dele do que imaginam, e que muitas das funções que ele possibilita realizar nós já fazemos em nosso dia-a-dia através de outros aplicativos, porém, com mais eficiência e controle das ações.

Pacotes necessários

Para executar os códigos desta parte é importante ter os seguintes pacotes instalados: usethis, devtools e gitcreds

Você pode realizar a instalação utilizando a seguinte linha de código:

libs <- c("usethis", "devtoos", "gitcreds")
if (!requireNamespace(libs, quietly = TRUE)){
    install.packages(libs)
  }

Caso você não tenha os pacotes acima citados a instalação será realizada. Caso já tenha em seu computador, nada irá acontecer.

Hello Git - Introdução ao uso de sistema de controle de versões

O Git trata-se de um sistema de controle de versões, mas afinal, o que é um sistema de controle de versões? Estamos mais acostumados do que imaginamos quando o assunto é controle de versões, apesar de parecer algo de outro mundo. Um exemplo que todos nós estamos acostumados é oferecido pelo editor de texto Word, quando ligamos a opção “Track changes”. Ao fazermos isso estamos controlando todas as modificações que fazemos em um documento. O Git faz a mesma coisa, porém para uma pasta inteira (ou diretório, na linguagem do controle de versões).

Portanto, o Git nada mais é que um sistema criado para realizar o rastreio de toda e qualquer modificação de arquivos dentro de uma pasta, utilizando a terminologia do versionamento, tudo o que é feito em um diretório associado ao Git é observado (watch na linguagem do versionamento).

Git e GitHub

Ter a possibilidade de controlar as versões dos documentos já é bom, imagine, além disso, ter um local remoto onde tudo isso fica guardado. Ou seja, se seu computador quebrar, for roubado, pifar, ou se você troca-lo, tudo estará seguro em um lugar chamado GitHub.

Portanto, Git e GitHub são coisas distintas. O GitHub é o GoogleDrive (ou o OneDrive) dos códigos. Ele tem como função armazenar remotamente todos os trabalhos que são feitos localmente e que estão sendo monitorados pelo Git, mas com muito mais potencialidades e controle de armazenamento que as ferramentas do Bill Gates. Por exemplo, imagine guardar um site inteiro no Google Drive, ou um pacote estatístico que você escreveu, e ainda disponibilizar essas coisas para outras pessoas… parece complicado se usarmos as ferramentas comerciais mais comuns, mas com o GitHub tudo isso se torna possível ser realizado com facilidade

Git e Git client

Temos uma ferramenta que possibilita o versionamento (o Git), outra que possibilita o armazenamento, colaboração, compartilhamento (GitHub), mas como controlamos essas ferramentas? É aí que entra o que chamamos de Git client

Uma simples analogia para entender a diferença entre um Git client e o Git é a diferença entre R e RStudio. O R é a ferramenta onde os processos são realizados, o RStudio é uma interface específica e amigável para o uso do R. Da mesma forma o Git é a ferramenta que realiza o controle de versão, já o Git client é a interface específica para que o usuário possa interagir de maneira mais amigável com o Git e GitHub. Existem vários Git clients que podemos utilizar para realizar essa interação, por exemplo, o GitKraken e GitLab. Cada um tem suas vantagens e desvantagens.

Neste curso usaremos um Git client que é um velho conhecido nosso, o RStudio. Faremos isso pois o RStudio (agora chamado Posit, mas vamos manter o velho nome) é a interface mais comum utilizada nos estudos de ecologia e evolução, além de apresentar uma grande quantidade de materiais disponíveis na internet e também por ser aquela que o instrutor que vos fala tem mais familiaridade.

Integrando Git, GitHub e RStudio

Agora que conhecemos as ferramentas, imagine se conseguíssemos colocar elas em um só lugar. Imagine um sistema que integra o seu programa favorito de análises estatísticas, o seu programa favorito de controle de versões e também o seu repositório remoto favorito. Pois é disso que se trata a integração do Git com o GitHub e RStudio. Tudo (quase tudo) pode ser feito no Git através do RStudio. Portanto, nas próximas seções irei apresentar como podemos integrar o controle de versão (Git) com o repositório remoto (GitHub) e o RStudio.

Mãos no teclado - Instalando e configurando o Git

O primeiro passo antes de instalar o Git é saber se você já tem ele instalado em seu computador. Para tanto você deve acessar a linha de comando de seu sistema operacional (bash, prompt, isso vai variar dependendo do tipo de sistema que usa) e digitar o comando:

which git

Caso retorne uma mensagem indicando o local do git no seu computador, ótimo, uma tarefa a menos, caso contrário você terá que instalar o git de acordo com as especificidades do seu sistema operacional que serão apresentadas a seguir.

Instalação do Git no Windows

Instale o Git acessando aqui e siga as informações do auxiliar de instalação que foi baixado.

Instação do Git no Mac OS

Instale o Git no seu Mac baixando o Xcode command line tools caso você ainda não o tenha. Esta aplicação já vem com o git. Aceite as configurações e clique em instalar

Em seguida configure o git usando a linha de comando seguinte no seu terminal:

git --version
git config --global user.name "Your name here"
git config --global user.email "your_email@example.com"

Instalação do Git no Linux

Digite a seguinte linha de comando caso você tenha Ubuntu ou Debian Linux

sudo apt-get install git

Se tem Fedora ou HatLinux use:

sudo yum install git

Algumas coisas podem ser diferentes dependendo do seu sistema operacional e versão do Linux, caso se depare com algum problema tente abrir um Issue no repositório desta apostila no GitHub e tentaremos resolver :)

Configuração do Git e integração com RStudio

Utilizando o pacote usethis

Após a instalação do Git devemos configur o GitHub no nosso computador. Para configurar o GitHub, ou seja, para que o Git e GitHub saiba quem está usando, vamos utilizar a configuração com auxílio do ótimo pacote usethis. Portanto, abra o RStudio e digite:

library(usethis)
use_git_config(user.name = "SeuNomeDeUsuario", user.email = "seuMail@example.br")

Lembre de substituir os campos que aparecerão no console do seu R com suas informações. “SeuNomeDeUsuario” é o nome que você cadastrou no GitHub

Nome do usuário destacado em vermelho

Nome do usuário destacado em vermelho

Utilizando o pacote gitcreds - Mais recomendada

Apesar de estarmos falando de ciência aberta, o seu perfil no GitHub é pessoal, portanto é importante que haja uma forma de autenticação onde o GitHub saiba que você é o dono do perfil. Isso geralmente é feito através do uso de senhas, porém senhas nem sempre são seguras (ok, provavelmente ninguém vai querer invadir nosso GitHub para tomar informações sobre uma função que calcula a dimensionalidade da biodiversidade, mas outras coisas são desenvolvidas e hospedadas no GitHub), e por isso a forma padrão de autenticação utilizada pelo GitHub é o chamado PAT (Personal Access Token). Segundo o próprio GitHub um PAT é:

“Personal access tokens are an alternative to using passwords for authentication to GitHub when using the GitHub API or the command line.”

O PAT nada mais é que uma “senha” gerada pelo próprio github e que deve ser renovada com certa periodicidade. O GitHub não permite mais autenticações via senha, apenas usando o PAT. Portanto, o último passo para integrar o R, RStudio, Git e GitHub é informar o PAT. Precisaremos fazer isso apenas uma vez, e repetir apenas quando o PAT expirar. Vamos começar gerando o PAT. Para informações mais detalhadas sobre o PAT você pode acessar esta página.

Para configurar o PAT vamos usar primeiro o pacote usethis e depois vamos utilizar as funcionalidades do pacote gitcreds.Digite a linha de código no seu console do R:

library(usethis)
create_github_token()

Isso abrirá uma guia no seu navegador para que você gere um token, tal como mostrado na imagem abaixo

Exemplo da página do GitHub para gerar um token

Exemplo da página do GitHub para gerar um token

Você verá inúmeras opções de acesso. As caixinhas que vamos escolher vai depender do grau de controle que você deseja ter para usar o GitHub via Rstudio.

Após gerado, guarde esse token com carinho, pois ele vai ser sua nova senha de entrada para o GitHub via RStudio, quando for requerido. Para armazenar senhas e dados eu sugiro o programa LastPass.

Próximo passo é registar esse token gerado em nosso computador. Para tanto, faça o seguinte:

library(gitcreds)
gitcreds::gitcreds_set()

No console aparecerá a mensagem para digitar o token, copie o token e cole direto no navegador, pressione enter e pronto, seu RStudio está autenticado e agora está devidamente conectado com o repositório remoto. Estamos pronto para o nosso primeiro commit!!!!

Conectando Git, RStudio e Github pela primeira vez

Antes de começar a utilizar o Git e GitHib via RStudio vamos primeiro dar uma olhadinha no site do GitHub. Abra o GitHub, faça o seu login e vamos dar uma explorada por lá.

Após esse passeio pelo GitHub, vamos criar nosso repositório para esta aula. Só lembrando que para fazer isso você já precisa ter uma conta criada no GitHub e o Git instalado. Tendo sua conta feita vá o seu navegador de internet, acesse o site do GitHub e faça o login. Feito isso:

1 - Crie um repositório

Crie um novo repositório clicando no botão destacado na figura abaixo

Criando um novo repositório a partir do GitHub

Criando um novo repositório a partir do GitHub

Existem outras formas de iniciar um repositório, inclusive direto pelo RStudio, mas vamos pelo caminho mais simples por enquanto.

O ABC do versionamento: Clone, Pull, Push and Commits

Vimos nas aulas teóricas que essas palavrinhas não são nada mais que ações que praticamos no nosso dia-a-dia. Agora é hora de colocar em prática.

Já temos um repositório remoto, agora precisamos que ele exista em nossos computadores para que possamos sincronizar nosso trabalho local e remoto. De maneira geral o que queremos fazer a partir de agora está ilustrado na figura seguinte

A partir de agora iremos, passo a passo, realizar todas as funções básicas essenciais para organização computacional de um projeto científico.

O primeiro passo é realizar uma clonagem!

O Clone

Referência de velho

Referência de velho

Para que nosso repositório local esteja ligado ao nosso repositório remoto precisamos primeiro conectá-los. Fazemos isso ao clonar o repositório remoto em nossa máquina. Clonar (clone) nesse caso não é nada mais que criar uma cópia exata de um repositório remoto em sua máquina. A partir desse momento esses repositórios estarão conectados até que o Git os separe.

Para clonar vá até o repositório remoto de interesse, e copie a chave https, como mostrado na figura a seguir:

Clique no botão de cópia e vamos para o RStudio. No RStudio vá em File e depois New Project. A partir daí siga as imagens abaixo:

1. Copiando a chave https no GitHub

Copiando chave https

Copiando chave https

2. Criando um novo projeto localmente

Abrindo um novo projeto

Abrindo um novo projeto

3. Colando a chave para ligar o repositório remoto com o local

Colando a chave https

Colando a chave https

Ao clicar em Create project o repositório remoto será imediatamente transferido para o seu computador. Uma pasta (o diretório local) será criado no local que você escolheu e, assim, RStudio, Git e Github estarão plenamente conectados. Tudo certo até aqui? Uma pausa para descanso com um vídeo.

Pull, Commits e Push

Se você chegou até aqui sem erros isso quer dizer que Git e GitHub já estão integrados no RStudio. Portanto, qualquer coisa que fizermos nesta pasta está sendo observado a partir de agora pelo git. Para certirficar-se disso, habilite a visualização de arquivos ocultos no seu computador, você vai notar que na raiz desta pasta clonada existe uma pasta .git, como na figura a seguir

Se você consegue ver esta pasta quer dizer que está tudo certo, e o git está observando (watch no jargão do versionamento) cada modificação e cada arquivo dentro desta pasta (a menos que você inclua o arquivo no .gitignore, mas isso é assunto para outro momento).

Agora iremos executar funções que, até o fim deste curso, serão quase automáticas no nosso fluxo de trabalho com versionamento.

Meu primeiro commit

O que é um commit?

Commit, ou “revisão”, é uma mudança individual em um arquivo ou um conjunto de arquivos dentro da pasta observada pelo git. Os commits são como check-points para o nosso repositório. Uma analogia interessante para os commits foi apresentada na aula e está ilustrada aqui, na figura seguinte

Vamos pensar que nosso projeto é uma montanha, e estamos escalando ele. Nosso objetivo final é, obviamente, finalizar o projeto, chegando ao topo da montanha. A medida que progredimos,caso venhamos a cometer um erro, a queda pode ser grande. Desta maneira, utilizamos grampos onde ancoramos nossa corda a medida que a escalada progride. Em caso de erro, a queda será apenas até o grampo anterior onde a corda foi ancorada. Os commits servem como os clipes que ancoram a corda a medida que progredimos no projeto. Se cometermos um erro em algum arquivo, tudo certo, podemos voltar no commit anterior, ou anteriores, para tentar descobrir onde o erro foi cometido.

Da mesma forma que na escalada, se utilizarmos clipes muito pertinhos uns dos outros vamos ficar lentos demais, e o progresso até o topo será comprometido, se fizermos muitos commits será difícil voltar em momentos específicos do projeto, visto que terão muitos commits para serem checados. Portanto, a regra é: faça commits com parcimonia, ou seja, nem muitos, nem poucos.

Vamos fazer uma modificação na nossa pasta. Podemos adicionar arquivos, já que ela está vazia. Para tanto vamos usar os arquivos do pacote de dados palmer penguins que estão nesse repositório. Lembre-se de ler os arquivos utilizando o {here} e utilizar o Rproject para abrir o diretório

data_penguins <- read.csv(here::here("data", "data-penguins.csv")) 

Obs se quiserem usar seus próprios dados fiquem a vontade, o uso do palmerpenguins é apenas opcional e a título de procedimento didático.

Caso estejam trabalhando com seus próprios dados, jogue os arquivos para dentro do diretório que clonamos. O próximo passo é fazer nosso primeiro commit.

Explorando commits

Existem duas formas de fazer versionamento usando o Git e Github via RStudio. Uma delas é a linha de comando, a outra é via uma interface visual, que nesse caso é o próprio RStudio. Vamos começar fazendo o versionamento via interface visual. A opção para isso é que ninguém se assuste num primeiro momento com a linha de comando, e que isso não seja um impeditivo para utilizar o versionamento no seu fluxo de trabalho. A maioria dos comandos básicos podem ser executados através desta interface gráfica que chamamos de Git Client

Repare que seu RStudio agora tem algumas coisas novas. Especificamente, veja que agora ele tem uma aba chamada Git, como ilustrado na figura abaixo

Isso indica que o git está funcionando no seu diretório, e agora podemos fazer o versionamento deste diretório local e sincronizá-lo com o repositório remoto.

Tudo e qualquer coisa que for adicionado ou modificado na sua pasta vai aparecer na janela abaixo da aba git. Como mostrado na figura abaixo

Como eu mencionei na aula teórica e aqui acima, o commit é como um track changes do word, mas melhor. Precisamos fazer um track change manual, indicando o que foi modificado, isso é o nosso commit. Para realizar um commit via a interface do RStudio você precisa:

1 - Clicar no botão commit pending changes (ou em qualquer botão naquela aba), como mostrado abaixo

2 - Isso vai abrir uma nova janela, nela você deve selecionar nos checkbox os arquivos (vamos dar uma olhada nessa janela antes de prosseguir)

3 - Escreva uma mensagem informativa. Como este é o primeiro commit geralmente selecionamos todos os arquivos e escrevemos a mensagem First commit para indicar que é o primeiro commit deste repositório

OBS A mensagem deve ser realmente informativa, o commit fica armazenado no seu repositório e aparecerá publicamente caso o repositório seja público.

Pronto, o que fizemos agora foi basicamente colocar nossos arquivos na stagging area (marcar as checking box) e prepará-los para a entrega com uma mensagem informativa, o commit. Agora precisamos enviar os arquivos para o repositório remoto (upstream)

Meu primeiro push

Temos um diretório functionando com o git, ligado ao github, com documentos dentro, mas, até agora ele apenas vive em nossos computadores. Chegou a hora de empurrar estes documentos para o diretório remoto, ou seja, aquele que clonamos lá no início. Para tanto vamos fazer um push

O push nada mais é que empurrar os documentos para o repositório do github, chamado as vezes de origin/master e outras vezes origin/main, mas ambos querem dizer “um repositório remoto o qual o diretório que estou trabalhando está ligado”.

Sem mais delongas, para fazer um push precisamos apenas apertar o botão verde como mostrado na figura abaixo

Duas coisas são importantes notar nesse momento. Primeiro o botão de push, que vai empurrar os arquivos para o repositório remoto (origin). Segundo, a mensagem destacada com a seta. Ela diz que o branch está a frente do origin/master por um commit. Traduzindo, nosso diretório local (branch), está uma versão a frente (pois modificamos coisas aqui) em relação ao nosso repositório remoto (origin/master). Ao empurrar (push) as modificações, essa mensagem desaparecerá, indicando que tanto branch quanto origin estão na mesma linha do tempo!

Extras

Aqui algumas dicas extras caso você queira seguir caminhos diferentes que os apresentados até agora para montar um repositório e conectar com o github. Vamos supor que você já tenha um projeto local em seu computador que já está monitorado pelo git, contém alguns commits, e você não quer perder estes commit. A forma mais fácil de fazer isso é através do pacote {usethis}. Para utilizar esta abordagem você precisa ter o PAT (Personal Access Token que criamos lá em cima).

1 - verifique se o git está funcionando em seu repositório (veja se aparece a tab git no seu RStudio). Caso não veja você precisa iniciar o git no diretório que está trabalhando. Para fazer isso:

usethis::use_git()

Outras opções existem, por exemplo, usando o terminal diretamente. Mas vamos manter a consistência e utilizar sempre o pacote usethis quando possível.

2 - uma vez que o git está funcionando neste repositório, precisamos criar um repositório remoto para ele no nosso perfil do GitHub. Para tanto precisamos apenas digitar:

usethis::use_github()

Atividade

Hora de praticar com seus dados, ou ainda com os dados do palmerpenguins. Faça algumas modificações na tabela, salve um novo objeto, faça um commit e um push. Após fazer isso verifique na página do repositório no GitHub o que aconteceu.

LS0tCnRpdGxlOiAnQ29udHJvbGUgZGUgdmVyc8OjbycKYXV0aG9yOiAiR2FicmllbCBOYWthbXVyYSIKZGF0ZTogImByIFN5cy5EYXRlKClgIgpvdXRwdXQ6IGh0bWxfZG9jdW1lbnQKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBmaWcuYWxpZ24gPSAiY2VudGVyIikKYGBgCgpgYGB7ciBrbGlwcHksIGVjaG89RkFMU0UsIGluY2x1ZGU9VFJVRX0Ka2xpcHB5OjprbGlwcHkoKQpgYGAKCiMgQXByZXNlbnRhw6fDo28KCk5lc3RhIHByaW1laXJhIHNlw6fDo28gaXJlaSBhcHJlc2VudGFyIGFzIHByaW5jaXBhaXMgZmVycmFtZW50YXMgcXVlIHV0aWxpemFyZW1vcyBwYXJhIG5vcyBhanVkYXIgbmEgb3JnYW5pemHDp8OjbyBjb21wdXRhY2lvbmFsIGRlIGRhZG9zLCBzY3JpcHRzLCBhbsOhbGlzZXMgZSBwcm9qZXRvcyBjaWVudMOtZmljb3MgZW0gZ2VyYWwuIEVzdGFzIGZlcnJhbWVudGFzIGlyw6NvIGF1eGlsaWFyIGRlc2RlIGEgb3JnYW5pemHDp8OjbyBsb2NhbCBkZSBzZXVzIGRhZG9zIGF0w6kgYSBkaXNwb25pYmlsaXphw6fDo28gZGVzdGVzIGRhZG9zIGVtIHBsYXRhZm9ybWFzIGRlIGFjZXNzbyBhYmVydG8uIFbDoXJpYXMgZGVsYXMgasOhIGRldmVtIHNlciB2ZWxoYXMgY29uaGVjaWRhcyBwb3Igdm9jw6pzLCBwb3IgZXhlbXBsbywgbyBSU3R1ZGlvLCBlbnTDo28gZGlzcGVuc2FtIG1haW9yZXMgYXByZXNlbnRhw6fDtWVzLiBQb3IgaXNzbywgZ3JhbmRlIHBhcnRlIGRlc3RlIGRvY3VtZW50byB2YWkgdHJhdGFyIGRlIHVtYSBmZXJyYW1lbnRhIGF0w6kgYmVtIGNvbmhlY2lkYSBwZWxvIG5vbWUsIG1hcyBxdWUgcHJhIG11aXRhIGdlbnRlIHBvZGUgcGFyZWNlciBjb2lzYSBkZSBvdXRybyBtdW5kbzogbyAqKkdpdCoqLiBWb2PDqnMgdmVyw6NvIHF1ZSBjb25oZWNlbSBtYWlzIGRlbGUgZG8gcXVlIGltYWdpbmFtLCBlIHF1ZSBtdWl0YXMgZGFzIGZ1bsOnw7VlcyBxdWUgZWxlIHBvc3NpYmlsaXRhIHJlYWxpemFyIG7Ds3MgasOhIGZhemVtb3MgZW0gbm9zc28gZGlhLWEtZGlhIGF0cmF2w6lzIGRlIG91dHJvcyBhcGxpY2F0aXZvcywgcG9yw6ltLCBjb20gbWFpcyBlZmljacOqbmNpYSBlIGNvbnRyb2xlIGRhcyBhw6fDtWVzLgoKIyMgUGFjb3RlcyBuZWNlc3PDoXJpb3MgCgpQYXJhIGV4ZWN1dGFyIG9zIGPDs2RpZ29zIGRlc3RhIHBhcnRlIMOpIGltcG9ydGFudGUgdGVyIG9zIHNlZ3VpbnRlcyBwYWNvdGVzIGluc3RhbGFkb3M6IGB1c2V0aGlzYCwgYGRldnRvb2xzYCBlIGBnaXRjcmVkc2AKClZvY8OqIHBvZGUgcmVhbGl6YXIgYSBpbnN0YWxhw6fDo28gdXRpbGl6YW5kbyBhIHNlZ3VpbnRlIGxpbmhhIGRlIGPDs2RpZ286CgpgYGB7ciBsaWJyYXJpZXNSZWFkLCBlY2hvPVRSVUUsIGV2YWw9VFJVRX0KbGlicyA8LSBjKCJ1c2V0aGlzIiwgImRldnRvb3MiLCAiZ2l0Y3JlZHMiKQppZiAoIXJlcXVpcmVOYW1lc3BhY2UobGlicywgcXVpZXRseSA9IFRSVUUpKXsKICAgIGluc3RhbGwucGFja2FnZXMobGlicykKICB9CmBgYAoKQ2FzbyB2b2PDqiBuw6NvIHRlbmhhIG9zIHBhY290ZXMgYWNpbWEgY2l0YWRvcyBhIGluc3RhbGHDp8OjbyBzZXLDoSByZWFsaXphZGEuIENhc28gasOhIHRlbmhhIGVtIHNldSBjb21wdXRhZG9yLCBuYWRhIGlyw6EgYWNvbnRlY2VyLgoKIyBIZWxsbyBHaXQgLSBJbnRyb2R1w6fDo28gYW8gdXNvIGRlIHNpc3RlbWEgZGUgY29udHJvbGUgZGUgdmVyc8O1ZXMKCk8gR2l0IHRyYXRhLXNlIGRlIHVtIHNpc3RlbWEgZGUgY29udHJvbGUgZGUgdmVyc8O1ZXMsIG1hcyBhZmluYWwsIG8gcXVlIMOpIHVtIHNpc3RlbWEgZGUgY29udHJvbGUgZGUgdmVyc8O1ZXM/IEVzdGFtb3MgbWFpcyBhY29zdHVtYWRvcyBkbyBxdWUgaW1hZ2luYW1vcyBxdWFuZG8gbyBhc3N1bnRvIMOpIGNvbnRyb2xlIGRlIHZlcnPDtWVzLCBhcGVzYXIgZGUgcGFyZWNlciBhbGdvIGRlIG91dHJvIG11bmRvLiBVbSBleGVtcGxvIHF1ZSB0b2RvcyBuw7NzIGVzdGFtb3MgYWNvc3R1bWFkb3Mgw6kgb2ZlcmVjaWRvIHBlbG8gZWRpdG9yIGRlIHRleHRvIFdvcmQsIHF1YW5kbyBsaWdhbW9zIGEgb3DDp8OjbyAiVHJhY2sgY2hhbmdlcyIuIEFvIGZhemVybW9zIGlzc28gZXN0YW1vcyBjb250cm9sYW5kbyB0b2RhcyBhcyBtb2RpZmljYcOnw7VlcyBxdWUgZmF6ZW1vcyBlbSB1bSBkb2N1bWVudG8uIE8gR2l0IGZheiBhIG1lc21hIGNvaXNhLCBwb3LDqW0gcGFyYSB1bWEgcGFzdGEgaW50ZWlyYSAob3UgKmRpcmV0w7NyaW8qLCBuYSBsaW5ndWFnZW0gZG8gY29udHJvbGUgZGUgdmVyc8O1ZXMpLgoKUG9ydGFudG8sIG8gR2l0IG5hZGEgbWFpcyDDqSBxdWUgdW0gc2lzdGVtYSBjcmlhZG8gcGFyYSByZWFsaXphciBvIHJhc3RyZWlvIGRlIHRvZGEgZSBxdWFscXVlciBtb2RpZmljYcOnw6NvIGRlIGFycXVpdm9zIGRlbnRybyBkZSB1bWEgcGFzdGEsIHV0aWxpemFuZG8gYSB0ZXJtaW5vbG9naWEgZG8gdmVyc2lvbmFtZW50bywgdHVkbyBvIHF1ZSDDqSBmZWl0byBlbSB1bSBkaXJldMOzcmlvIGFzc29jaWFkbyBhbyBHaXQgw6kgKm9ic2VydmFkbyogKCp3YXRjaCogbmEgbGluZ3VhZ2VtIGRvIHZlcnNpb25hbWVudG8pLgoKIyMgR2l0IGUgR2l0SHViCgpUZXIgYSBwb3NzaWJpbGlkYWRlIGRlIGNvbnRyb2xhciBhcyB2ZXJzw7VlcyBkb3MgZG9jdW1lbnRvcyBqw6Egw6kgYm9tLCBpbWFnaW5lLCBhbMOpbSBkaXNzbywgdGVyIHVtIGxvY2FsIHJlbW90byBvbmRlIHR1ZG8gaXNzbyBmaWNhIGd1YXJkYWRvLiBPdSBzZWphLCBzZSBzZXUgY29tcHV0YWRvciBxdWVicmFyLCBmb3Igcm91YmFkbywgcGlmYXIsIG91IHNlIHZvY8OqIHRyb2NhLWxvLCB0dWRvIGVzdGFyw6Egc2VndXJvIGVtIHVtIGx1Z2FyIGNoYW1hZG8gR2l0SHViLgoKUG9ydGFudG8sIEdpdCBlIFtHaXRIdWJdKGh0dHBzOi8vZ2l0aHViLmNvbS8pIHPDo28gY29pc2FzIGRpc3RpbnRhcy4gTyBHaXRIdWIgw6kgbyBHb29nbGVEcml2ZSAob3UgbyBPbmVEcml2ZSkgZG9zIGPDs2RpZ29zLiBFbGUgdGVtIGNvbW8gZnVuw6fDo28gYXJtYXplbmFyIHJlbW90YW1lbnRlIHRvZG9zIG9zIHRyYWJhbGhvcyBxdWUgc8OjbyBmZWl0b3MgbG9jYWxtZW50ZSBlIHF1ZSBlc3TDo28gc2VuZG8gbW9uaXRvcmFkb3MgcGVsbyBHaXQsIG1hcyBjb20gbXVpdG8gbWFpcyBwb3RlbmNpYWxpZGFkZXMgZSBjb250cm9sZSBkZSBhcm1hemVuYW1lbnRvIHF1ZSBhcyBmZXJyYW1lbnRhcyBkbyBCaWxsIEdhdGVzLiBQb3IgZXhlbXBsbywgaW1hZ2luZSBndWFyZGFyIHVtIHNpdGUgaW50ZWlybyBubyBHb29nbGUgRHJpdmUsIG91IHVtIHBhY290ZSBlc3RhdMOtc3RpY28gcXVlIHZvY8OqIGVzY3JldmV1LCBlIGFpbmRhIGRpc3BvbmliaWxpemFyIGVzc2FzIGNvaXNhcyBwYXJhIG91dHJhcyBwZXNzb2FzLi4uIHBhcmVjZSBjb21wbGljYWRvIHNlIHVzYXJtb3MgYXMgZmVycmFtZW50YXMgY29tZXJjaWFpcyBtYWlzIGNvbXVucywgbWFzIGNvbSBvIEdpdEh1YiB0dWRvIGlzc28gc2UgdG9ybmEgcG9zc8OtdmVsIHNlciByZWFsaXphZG8gY29tIGZhY2lsaWRhZGUKCiMjIEdpdCBlIEdpdCBjbGllbnQKClRlbW9zIHVtYSBmZXJyYW1lbnRhIHF1ZSBwb3NzaWJpbGl0YSBvIHZlcnNpb25hbWVudG8gKG8gR2l0KSwgb3V0cmEgcXVlIHBvc3NpYmlsaXRhIG8gYXJtYXplbmFtZW50bywgY29sYWJvcmHDp8OjbywgY29tcGFydGlsaGFtZW50byAoR2l0SHViKSwgbWFzIGNvbW8gY29udHJvbGFtb3MgZXNzYXMgZmVycmFtZW50YXM/IMOJIGHDrSBxdWUgZW50cmEgbyBxdWUgY2hhbWFtb3MgZGUgKipHaXQgY2xpZW50KioKClVtYSBzaW1wbGVzIGFuYWxvZ2lhIHBhcmEgZW50ZW5kZXIgYSBkaWZlcmVuw6dhIGVudHJlIHVtIEdpdCBjbGllbnQgZSBvIEdpdCDDqSBhIGRpZmVyZW7Dp2EgZW50cmUgUiBlIFJTdHVkaW8uIE8gUiDDqSBhIGZlcnJhbWVudGEgb25kZSBvcyBwcm9jZXNzb3Mgc8OjbyByZWFsaXphZG9zLCBvIFJTdHVkaW8gw6kgdW1hIGludGVyZmFjZSBlc3BlY8OtZmljYSBlIGFtaWfDoXZlbCBwYXJhIG8gdXNvIGRvIFIuIERhIG1lc21hIGZvcm1hIG8gR2l0IMOpIGEgZmVycmFtZW50YSBxdWUgcmVhbGl6YSBvIGNvbnRyb2xlIGRlIHZlcnPDo28sIGrDoSBvIEdpdCBjbGllbnQgw6kgYSBpbnRlcmZhY2UgZXNwZWPDrWZpY2EgcGFyYSBxdWUgbyB1c3XDoXJpbyBwb3NzYSBpbnRlcmFnaXIgZGUgbWFuZWlyYSBtYWlzIGFtaWfDoXZlbCBjb20gbyBHaXQgZSBHaXRIdWIuIEV4aXN0ZW0gdsOhcmlvcyBHaXQgY2xpZW50cyBxdWUgcG9kZW1vcyB1dGlsaXphciBwYXJhIHJlYWxpemFyIGVzc2EgaW50ZXJhw6fDo28sIHBvciBleGVtcGxvLCBvIFtHaXRLcmFrZW5dKGh0dHBzOi8vd3d3LmdpdGtyYWtlbi5jb20vKSBlIFtHaXRMYWJdKGh0dHBzOi8vYWJvdXQuZ2l0bGFiLmNvbS8pLiBDYWRhIHVtIHRlbSBzdWFzIHZhbnRhZ2VucyBlIGRlc3ZhbnRhZ2Vucy4KCk5lc3RlIGN1cnNvIHVzYXJlbW9zIHVtIEdpdCBjbGllbnQgcXVlIMOpIHVtIHZlbGhvIGNvbmhlY2lkbyBub3NzbywgbyAqKlJTdHVkaW8qKi4gRmFyZW1vcyBpc3NvICBwb2lzIG8gUlN0dWRpbyAoYWdvcmEgY2hhbWFkbyBQb3NpdCwgbWFzIHZhbW9zIG1hbnRlciBvIHZlbGhvIG5vbWUpIMOpIGEgaW50ZXJmYWNlIG1haXMgY29tdW0gdXRpbGl6YWRhIG5vcyBlc3R1ZG9zIGRlIGVjb2xvZ2lhIGUgZXZvbHXDp8OjbywgYWzDqW0gZGUgYXByZXNlbnRhciB1bWEgZ3JhbmRlIHF1YW50aWRhZGUgZGUgbWF0ZXJpYWlzIGRpc3BvbsOtdmVpcyBuYSBpbnRlcm5ldCBlIHRhbWLDqW0gcG9yIHNlciBhcXVlbGEgcXVlIG8gaW5zdHJ1dG9yIHF1ZSB2b3MgZmFsYSB0ZW0gbWFpcyBmYW1pbGlhcmlkYWRlLiAKCiMjIEludGVncmFuZG8gR2l0LCBHaXRIdWIgZSBSU3R1ZGlvCgpBZ29yYSBxdWUgY29uaGVjZW1vcyBhcyBmZXJyYW1lbnRhcywgaW1hZ2luZSBzZSBjb25zZWd1w61zc2Vtb3MgY29sb2NhciBlbGFzIGVtIHVtIHPDsyBsdWdhci4gSW1hZ2luZSB1bSBzaXN0ZW1hIHF1ZSBpbnRlZ3JhIG8gc2V1IHByb2dyYW1hIGZhdm9yaXRvIGRlIGFuw6FsaXNlcyBlc3RhdMOtc3RpY2FzLCBvIHNldSBwcm9ncmFtYSBmYXZvcml0byBkZSBjb250cm9sZSBkZSB2ZXJzw7VlcyBlIHRhbWLDqW0gbyBzZXUgcmVwb3NpdMOzcmlvIHJlbW90byBmYXZvcml0by4gUG9pcyDDqSBkaXNzbyBxdWUgc2UgdHJhdGEgYSBpbnRlZ3Jhw6fDo28gZG8gR2l0IGNvbSBvIEdpdEh1YiBlIFJTdHVkaW8uIFR1ZG8gKHF1YXNlIHR1ZG8pIHBvZGUgc2VyIGZlaXRvIG5vIEdpdCBhdHJhdsOpcyBkbyBSU3R1ZGlvLiBQb3J0YW50bywgbmFzIHByw7N4aW1hcyBzZcOnw7VlcyBpcmVpIGFwcmVzZW50YXIgY29tbyBwb2RlbW9zIGludGVncmFyIG8gY29udHJvbGUgZGUgdmVyc8OjbyAoR2l0KSBjb20gbyByZXBvc2l0w7NyaW8gcmVtb3RvIChHaXRIdWIpIGUgbyBSU3R1ZGlvLgoKIyBNw6NvcyBubyB0ZWNsYWRvIC0gSW5zdGFsYW5kbyBlIGNvbmZpZ3VyYW5kbyBvIEdpdAoKTyBwcmltZWlybyBwYXNzbyBhbnRlcyBkZSBpbnN0YWxhciBvIEdpdCDDqSBzYWJlciBzZSB2b2PDqiBqw6EgdGVtIGVsZSBpbnN0YWxhZG8gZW0gc2V1IGNvbXB1dGFkb3IuIFBhcmEgdGFudG8gdm9jw6ogZGV2ZSBhY2Vzc2FyIGEgbGluaGEgZGUgY29tYW5kbyBkZSBzZXUgc2lzdGVtYSBvcGVyYWNpb25hbCAoYmFzaCwgcHJvbXB0LCBpc3NvIHZhaSB2YXJpYXIgZGVwZW5kZW5kbyBkbyB0aXBvIGRlIHNpc3RlbWEgcXVlIHVzYSkgZSBkaWdpdGFyIG8gY29tYW5kbzoKCmBgYHtyIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0Kd2hpY2ggZ2l0CmBgYAoKQ2FzbyByZXRvcm5lIHVtYSBtZW5zYWdlbSBpbmRpY2FuZG8gbyBsb2NhbCBkbyBnaXQgbm8gc2V1IGNvbXB1dGFkb3IsIMOzdGltbywgdW1hIHRhcmVmYSBhIG1lbm9zLCBjYXNvIGNvbnRyw6FyaW8gdm9jw6ogdGVyw6EgcXVlIGluc3RhbGFyIG8gZ2l0IGRlIGFjb3JkbyBjb20gYXMgZXNwZWNpZmljaWRhZGVzIGRvIHNldSBzaXN0ZW1hIG9wZXJhY2lvbmFsIHF1ZSBzZXLDo28gYXByZXNlbnRhZGFzIGEgc2VndWlyLgoKIyMgSW5zdGFsYcOnw6NvIGRvIEdpdCBubyBXaW5kb3dzCgpJbnN0YWxlIG8gR2l0IGFjZXNzYW5kbyBbYXF1aV0oaHR0cHM6Ly9naXRmb3J3aW5kb3dzLm9yZy8pIGUgc2lnYSBhcyBpbmZvcm1hw6fDtWVzIGRvIGF1eGlsaWFyIGRlIGluc3RhbGHDp8OjbyBxdWUgZm9pIGJhaXhhZG8uCgojIyBJbnN0YcOnw6NvIGRvIEdpdCBubyBNYWMgT1MKCkluc3RhbGUgbyBHaXQgbm8gc2V1IE1hYyBiYWl4YW5kbyBvIFhjb2RlIGNvbW1hbmQgbGluZSB0b29scyBjYXNvIHZvY8OqIGFpbmRhIG7Do28gbyB0ZW5oYS4gRXN0YSBhcGxpY2HDp8OjbyBqw6EgdmVtIGNvbSBvIGdpdC4gQWNlaXRlIGFzIGNvbmZpZ3VyYcOnw7VlcyBlIGNsaXF1ZSBlbSBpbnN0YWxhcgoKRW0gc2VndWlkYSBjb25maWd1cmUgbyBnaXQgdXNhbmRvIGEgbGluaGEgZGUgY29tYW5kbyBzZWd1aW50ZSBubyBzZXUgdGVybWluYWw6CgpgYGB7ciBlY2hvPVRSVUUsIGV2YWw9RkFMU0V9CmdpdCAtLXZlcnNpb24KZ2l0IGNvbmZpZyAtLWdsb2JhbCB1c2VyLm5hbWUgIllvdXIgbmFtZSBoZXJlIgpnaXQgY29uZmlnIC0tZ2xvYmFsIHVzZXIuZW1haWwgInlvdXJfZW1haWxAZXhhbXBsZS5jb20iCmBgYAoKIyMgSW5zdGFsYcOnw6NvIGRvIEdpdCBubyBMaW51eCAKCkRpZ2l0ZSBhIHNlZ3VpbnRlIGxpbmhhIGRlIGNvbWFuZG8gY2FzbyB2b2PDqiB0ZW5oYSBVYnVudHUgb3UgRGViaWFuIExpbnV4CgpgYGB7ciBlY2hvPVRSVUUsIGV2YWw9RkFMU0V9CnN1ZG8gYXB0LWdldCBpbnN0YWxsIGdpdApgYGAKClNlIHRlbSBGZWRvcmEgb3UgSGF0TGludXggdXNlOgoKYGBge3IgZWNobz1UUlVFLCBldmFsPUZBTFNFfQpzdWRvIHl1bSBpbnN0YWxsIGdpdApgYGAKCioqQWxndW1hcyBjb2lzYXMgcG9kZW0gc2VyIGRpZmVyZW50ZXMgZGVwZW5kZW5kbyBkbyBzZXUgc2lzdGVtYSBvcGVyYWNpb25hbCBlIHZlcnPDo28gZG8gTGludXgqKiwgY2FzbyBzZSBkZXBhcmUgY29tIGFsZ3VtIHByb2JsZW1hIHRlbnRlIGFicmlyIHVtICoqSXNzdWUqKiBubyByZXBvc2l0w7NyaW8gZGVzdGEgYXBvc3RpbGEgbm8gR2l0SHViIGUgdGVudGFyZW1vcyByZXNvbHZlciA6KQoKIyBDb25maWd1cmHDp8OjbyBkbyBHaXQgZSBpbnRlZ3Jhw6fDo28gY29tIFJTdHVkaW8KCiMjIFV0aWxpemFuZG8gbyBwYWNvdGUgYHVzZXRoaXNgCgpBcMOzcyBhIGluc3RhbGHDp8OjbyBkbyBHaXQgZGV2ZW1vcyBjb25maWd1ciBvIEdpdEh1YiBubyBub3NzbyBjb21wdXRhZG9yLiBQYXJhIGNvbmZpZ3VyYXIgbyBHaXRIdWIsIG91IHNlamEsIHBhcmEgcXVlIG8gR2l0IGUgR2l0SHViIHNhaWJhIHF1ZW0gZXN0w6EgdXNhbmRvLCB2YW1vcyB1dGlsaXphciBhIGNvbmZpZ3VyYcOnw6NvIGNvbSBhdXjDrWxpbyBkbyDDs3RpbW8gcGFjb3RlIGB1c2V0aGlzYC4gUG9ydGFudG8sIGFicmEgbyBSU3R1ZGlvIGUgZGlnaXRlOgoKYGBge3IgZWNobz1UUlVFLCBldmFsPUZBTFNFfQpsaWJyYXJ5KHVzZXRoaXMpCnVzZV9naXRfY29uZmlnKHVzZXIubmFtZSA9ICJTZXVOb21lRGVVc3VhcmlvIiwgdXNlci5lbWFpbCA9ICJzZXVNYWlsQGV4YW1wbGUuYnIiKQpgYGAKCkxlbWJyZSBkZSBzdWJzdGl0dWlyIG9zIGNhbXBvcyBxdWUgYXBhcmVjZXLDo28gbm8gY29uc29sZSBkbyBzZXUgUiBjb20gc3VhcyBpbmZvcm1hw6fDtWVzLiAiU2V1Tm9tZURlVXN1YXJpbyIgw6kgbyBub21lIHF1ZSB2b2PDqiBjYWRhc3Ryb3Ugbm8gR2l0SHViCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxmaWcuY2FwPSJOb21lIGRvIHVzdcOhcmlvIGRlc3RhY2FkbyBlbSB2ZXJtZWxobyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWdzL05vbWVVc3VhcmlvLnBuZyIpCmBgYAoKCiMjIFV0aWxpemFuZG8gbyBwYWNvdGUgYGdpdGNyZWRzYCAtICoqTWFpcyByZWNvbWVuZGFkYSoqCgpBcGVzYXIgZGUgZXN0YXJtb3MgZmFsYW5kbyBkZSBjacOqbmNpYSBhYmVydGEsIG8gc2V1IHBlcmZpbCBubyBHaXRIdWIgw6kgcGVzc29hbCwgcG9ydGFudG8gw6kgaW1wb3J0YW50ZSBxdWUgaGFqYSB1bWEgZm9ybWEgZGUgYXV0ZW50aWNhw6fDo28gb25kZSBvIEdpdEh1YiBzYWliYSBxdWUgdm9jw6ogw6kgbyBkb25vIGRvIHBlcmZpbC4gSXNzbyBnZXJhbG1lbnRlIMOpIGZlaXRvIGF0cmF2w6lzIGRvIHVzbyBkZSBzZW5oYXMsIHBvcsOpbSBzZW5oYXMgbmVtIHNlbXByZSBzw6NvIHNlZ3VyYXMgKG9rLCBwcm92YXZlbG1lbnRlIG5pbmd1w6ltIHZhaSBxdWVyZXIgaW52YWRpciBub3NzbyBHaXRIdWIgcGFyYSB0b21hciBpbmZvcm1hw6fDtWVzIHNvYnJlIHVtYSBmdW7Dp8OjbyBxdWUgY2FsY3VsYSBhIGRpbWVuc2lvbmFsaWRhZGUgZGEgYmlvZGl2ZXJzaWRhZGUsIG1hcyBvdXRyYXMgY29pc2FzIHPDo28gZGVzZW52b2x2aWRhcyBlIGhvc3BlZGFkYXMgbm8gR2l0SHViKSwgZSBwb3IgaXNzbyBhIGZvcm1hIHBhZHLDo28gZGUgYXV0ZW50aWNhw6fDo28gdXRpbGl6YWRhIHBlbG8gR2l0SHViIMOpIG8gY2hhbWFkbyBQQVQgKFBlcnNvbmFsIEFjY2VzcyBUb2tlbikuIFNlZ3VuZG8gbyBwcsOzcHJpbyBHaXRIdWIgdW0gUEFUIMOpOgoKPiAiUGVyc29uYWwgYWNjZXNzIHRva2VucyBhcmUgYW4gYWx0ZXJuYXRpdmUgdG8gdXNpbmcgcGFzc3dvcmRzIGZvciBhdXRoZW50aWNhdGlvbiB0byBHaXRIdWIgd2hlbiB1c2luZyB0aGUgR2l0SHViIEFQSSBvciB0aGUgY29tbWFuZCBsaW5lLiIKCk8gUEFUIG5hZGEgbWFpcyDDqSBxdWUgdW1hICJzZW5oYSIgZ2VyYWRhIHBlbG8gcHLDs3ByaW8gZ2l0aHViIGUgcXVlIGRldmUgc2VyIHJlbm92YWRhIGNvbSBjZXJ0YSBwZXJpb2RpY2lkYWRlLiAqKk8gR2l0SHViIG7Do28gcGVybWl0ZSBtYWlzIGF1dGVudGljYcOnw7VlcyB2aWEgc2VuaGEsIGFwZW5hcyB1c2FuZG8gbyBQQVQqKi4gUG9ydGFudG8sIG8gw7psdGltbyBwYXNzbyBwYXJhIGludGVncmFyIG8gUiwgUlN0dWRpbywgR2l0IGUgR2l0SHViIMOpIGluZm9ybWFyIG8gUEFULiBQcmVjaXNhcmVtb3MgZmF6ZXIgaXNzbyBhcGVuYXMgdW1hIHZleiwgZSByZXBldGlyIGFwZW5hcyBxdWFuZG8gbyBQQVQgZXhwaXJhci4gVmFtb3MgY29tZcOnYXIgZ2VyYW5kbyBvIFBBVC4gUGFyYSBpbmZvcm1hw6fDtWVzIG1haXMgZGV0YWxoYWRhcyBzb2JyZSBvIFBBVCB2b2PDqiBwb2RlIGFjZXNzYXIgW2VzdGFdKGh0dHBzOi8vZG9jcy5naXRodWIuY29tL2VuL2F1dGhlbnRpY2F0aW9uL2tlZXBpbmcteW91ci1hY2NvdW50LWFuZC1kYXRhLXNlY3VyZS9tYW5hZ2luZy15b3VyLXBlcnNvbmFsLWFjY2Vzcy10b2tlbnMpIHDDoWdpbmEuCgpQYXJhIGNvbmZpZ3VyYXIgbyBQQVQgdmFtb3MgdXNhciBwcmltZWlybyBvIHBhY290ZSBgdXNldGhpc2AgZSBkZXBvaXMgdmFtb3MgdXRpbGl6YXIgYXMgZnVuY2lvbmFsaWRhZGVzIGRvIHBhY290ZSBgZ2l0Y3JlZHNgLkRpZ2l0ZSBhIGxpbmhhIGRlIGPDs2RpZ28gbm8gc2V1IGNvbnNvbGUgZG8gUjoKCmBgYHtyIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0KbGlicmFyeSh1c2V0aGlzKQpjcmVhdGVfZ2l0aHViX3Rva2VuKCkKYGBgCgpJc3NvIGFicmlyw6EgdW1hIGd1aWEgbm8gc2V1IG5hdmVnYWRvciBwYXJhIHF1ZSB2b2PDqiBnZXJlIHVtIHRva2VuLCB0YWwgY29tbyBtb3N0cmFkbyBuYSBpbWFnZW0gYWJhaXhvCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxmaWcuY2FwPSJFeGVtcGxvIGRhIHDDoWdpbmEgZG8gR2l0SHViIHBhcmEgZ2VyYXIgdW0gdG9rZW4ifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZmlncy9QQVQtY3JlYXRpb24ucG5nIikKYGBgCgpWb2PDqiB2ZXLDoSBpbsO6bWVyYXMgb3DDp8O1ZXMgZGUgYWNlc3NvLiBBcyBjYWl4aW5oYXMgcXVlIHZhbW9zIGVzY29saGVyIHZhaSBkZXBlbmRlciBkbyBncmF1IGRlIGNvbnRyb2xlIHF1ZSB2b2PDqiBkZXNlamEgdGVyIHBhcmEgdXNhciBvIEdpdEh1YiB2aWEgUnN0dWRpby4KCkFww7NzIGdlcmFkbywgKipndWFyZGUgZXNzZSB0b2tlbiBjb20gY2FyaW5obyoqLCBwb2lzIGVsZSB2YWkgc2VyIHN1YSBub3ZhIHNlbmhhIGRlIGVudHJhZGEgcGFyYSBvIEdpdEh1YiB2aWEgUlN0dWRpbywgcXVhbmRvIGZvciByZXF1ZXJpZG8uIFBhcmEgYXJtYXplbmFyIHNlbmhhcyBlIGRhZG9zIGV1IHN1Z2lybyBvIHByb2dyYW1hICoqTGFzdFBhc3MqKi4KClByw7N4aW1vIHBhc3NvIMOpIHJlZ2lzdGFyIGVzc2UgdG9rZW4gZ2VyYWRvIGVtIG5vc3NvIGNvbXB1dGFkb3IuIFBhcmEgdGFudG8sIGZhw6dhIG8gc2VndWludGU6CgpgYGB7ciBQQVQsIGVjaG89VFJVRSwgZXZhbD1GQUxTRX0KbGlicmFyeShnaXRjcmVkcykKZ2l0Y3JlZHM6OmdpdGNyZWRzX3NldCgpCmBgYAoKTm8gY29uc29sZSBhcGFyZWNlcsOhIGEgbWVuc2FnZW0gcGFyYSBkaWdpdGFyIG8gdG9rZW4sIGNvcGllIG8gdG9rZW4gZSBjb2xlIGRpcmV0byBubyBuYXZlZ2Fkb3IsIHByZXNzaW9uZSBlbnRlciBlIHByb250bywgc2V1IFJTdHVkaW8gZXN0w6EgYXV0ZW50aWNhZG8gZSBhZ29yYSBlc3TDoSBkZXZpZGFtZW50ZSBjb25lY3RhZG8gY29tIG8gcmVwb3NpdMOzcmlvIHJlbW90by4gRXN0YW1vcyBwcm9udG8gcGFyYSBvIG5vc3NvIHByaW1laXJvIGNvbW1pdCEhISEKCgojIENvbmVjdGFuZG8gR2l0LCBSU3R1ZGlvIGUgR2l0aHViIHBlbGEgcHJpbWVpcmEgdmV6CgpBbnRlcyBkZSBjb21lw6dhciBhIHV0aWxpemFyIG8gR2l0IGUgR2l0SGliIHZpYSBSU3R1ZGlvIHZhbW9zIHByaW1laXJvIGRhciB1bWEgb2xoYWRpbmhhIG5vIHNpdGUgZG8gR2l0SHViLiBBYnJhIG8gR2l0SHViLCBmYcOnYSBvIHNldSBsb2dpbiBlIHZhbW9zIGRhciB1bWEgZXhwbG9yYWRhIHBvciBsw6EuCgpBcMOzcyBlc3NlIHBhc3NlaW8gcGVsbyBHaXRIdWIsIHZhbW9zIGNyaWFyIG5vc3NvIHJlcG9zaXTDs3JpbyBwYXJhIGVzdGEgYXVsYS4gU8OzIGxlbWJyYW5kbyBxdWUgcGFyYSBmYXplciBpc3NvIHZvY8OqIGrDoSBwcmVjaXNhIHRlciB1bWEgY29udGEgY3JpYWRhIG5vIEdpdEh1YiBlIG8gR2l0IGluc3RhbGFkby4gVGVuZG8gc3VhIGNvbnRhIGZlaXRhIHbDoSBvIHNldSBuYXZlZ2Fkb3IgZGUgaW50ZXJuZXQsIGFjZXNzZSBvIHNpdGUgZG8gR2l0SHViIGUgZmHDp2EgbyBsb2dpbi4gRmVpdG8gaXNzbzoKCjEgLSBDcmllIHVtIHJlcG9zaXTDs3JpbyAKCkNyaWUgdW0gbm92byByZXBvc2l0w7NyaW8gY2xpY2FuZG8gbm8gYm90w6NvIGRlc3RhY2FkbyBuYSBmaWd1cmEgYWJhaXhvCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxmaWcuY2FwPSJDcmlhbmRvIHVtIG5vdm8gcmVwb3NpdMOzcmlvIGEgcGFydGlyIGRvIEdpdEh1YiJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWdzL0NyZWF0ZS1SZXBwby5wbmciKQpgYGAKCkV4aXN0ZW0gb3V0cmFzIGZvcm1hcyBkZSBpbmljaWFyIHVtIHJlcG9zaXTDs3JpbywgaW5jbHVzaXZlIGRpcmV0byBwZWxvIFJTdHVkaW8sIG1hcyB2YW1vcyBwZWxvIGNhbWluaG8gbWFpcyBzaW1wbGVzIHBvciBlbnF1YW50by4KCiMgTyBBQkMgZG8gdmVyc2lvbmFtZW50bzogQ2xvbmUsIFB1bGwsIFB1c2ggYW5kIENvbW1pdHMgCgpWaW1vcyBuYXMgYXVsYXMgdGXDs3JpY2FzIHF1ZSBlc3NhcyBwYWxhdnJpbmhhcyBuw6NvIHPDo28gbmFkYSBtYWlzIHF1ZSBhw6fDtWVzIHF1ZSBwcmF0aWNhbW9zIG5vIG5vc3NvIGRpYS1hLWRpYS4gQWdvcmEgw6kgaG9yYSBkZSBjb2xvY2FyIGVtIHByw6F0aWNhLgoKSsOhIHRlbW9zIHVtIHJlcG9zaXTDs3JpbyByZW1vdG8sIGFnb3JhIHByZWNpc2Ftb3MgcXVlIGVsZSBleGlzdGEgZW0gbm9zc29zIGNvbXB1dGFkb3JlcyBwYXJhIHF1ZSBwb3NzYW1vcyBzaW5jcm9uaXphciBub3NzbyB0cmFiYWxobyBsb2NhbCBlIHJlbW90by4gRGUgbWFuZWlyYSBnZXJhbCBvIHF1ZSBxdWVyZW1vcyBmYXplciBhIHBhcnRpciBkZSBhZ29yYSBlc3TDoSBpbHVzdHJhZG8gbmEgZmlndXJhIHNlZ3VpbnRlCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxvdXQud2lkdGg9IjU1JSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWdzL3ZlcnNpb24tY29udHJvbC1hbGwucG5nIikKYGBgCgpBIHBhcnRpciBkZSBhZ29yYSBpcmVtb3MsIHBhc3NvIGEgcGFzc28sIHJlYWxpemFyIHRvZGFzIGFzIGZ1bsOnw7VlcyBiw6FzaWNhcyBlc3NlbmNpYWlzIHBhcmEgb3JnYW5pemHDp8OjbyBjb21wdXRhY2lvbmFsIGRlIHVtIHByb2pldG8gY2llbnTDrWZpY28uCgpPIHByaW1laXJvIHBhc3NvIMOpIHJlYWxpemFyIHVtYSBjbG9uYWdlbSEKCiMjIE8gQ2xvbmUKCmBgYHtyIGVjaG89RkFMU0UsZXZhbD1UUlVFLGZpZy5jYXA9IlJlZmVyw6puY2lhIGRlIHZlbGhvIixvdXQud2lkdGg9IjU1JSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWdzL28tY2xvbmUuanBlZyIpCmBgYAoKUGFyYSBxdWUgbm9zc28gcmVwb3NpdMOzcmlvIGxvY2FsIGVzdGVqYSBsaWdhZG8gYW8gbm9zc28gcmVwb3NpdMOzcmlvIHJlbW90byBwcmVjaXNhbW9zIHByaW1laXJvIGNvbmVjdMOhLWxvcy4gRmF6ZW1vcyBpc3NvIGFvIGNsb25hciBvIHJlcG9zaXTDs3JpbyByZW1vdG8gZW0gbm9zc2EgbcOhcXVpbmEuIENsb25hciAoY2xvbmUpIG5lc3NlIGNhc28gbsOjbyDDqSBuYWRhIG1haXMgcXVlIGNyaWFyIHVtYSBjw7NwaWEgZXhhdGEgZGUgdW0gcmVwb3NpdMOzcmlvIHJlbW90byBlbSBzdWEgbcOhcXVpbmEuIEEgcGFydGlyIGRlc3NlIG1vbWVudG8gZXNzZXMgcmVwb3NpdMOzcmlvcyBlc3RhcsOjbyBjb25lY3RhZG9zIGF0w6kgcXVlIG8gR2l0IG9zIHNlcGFyZS4KClBhcmEgY2xvbmFyIHbDoSBhdMOpIG8gcmVwb3NpdMOzcmlvIHJlbW90byBkZSBpbnRlcmVzc2UsIGUgY29waWUgYSBjaGF2ZSBodHRwcywgY29tbyBtb3N0cmFkbyBuYSBmaWd1cmEgYSBzZWd1aXI6CgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRX0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoImZpZ3MvZ2l0aHViLWNvcHktaHR0cHMucG5nIikKYGBgCgpDbGlxdWUgbm8gYm90w6NvIGRlIGPDs3BpYSBlIHZhbW9zIHBhcmEgbyBSU3R1ZGlvLiBObyBSU3R1ZGlvIHbDoSBlbSBgRmlsZWAgZSBkZXBvaXMgYE5ldyBQcm9qZWN0YC4gQSBwYXJ0aXIgZGHDrSBzaWdhIGFzIGltYWdlbnMgYWJhaXhvOgoKIyMjIDEuIENvcGlhbmRvIGEgY2hhdmUgaHR0cHMgbm8gR2l0SHViCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxmaWcuY2FwPSJDb3BpYW5kbyBjaGF2ZSBodHRwcyJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWdzL2dpdGh1Yi1jb3B5LWh0dHBzLnBuZyIpCmBgYAoKIyMjIDIuIENyaWFuZG8gdW0gbm92byAqKnByb2pldG8qKiBsb2NhbG1lbnRlCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxmaWcuY2FwPSJBYnJpbmRvIHVtIG5vdm8gcHJvamV0byJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWdzL2dpdGh1Yi12ZXJzaW9uY29udHJvbC1vcHRpb24ucG5nIikKYGBgCgojIyMgMy4gQ29sYW5kbyBhIGNoYXZlIHBhcmEgbGlnYXIgbyByZXBvc2l0w7NyaW8gcmVtb3RvIGNvbSBvIGxvY2FsCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxmaWcuY2FwPSJDb2xhbmRvIGEgY2hhdmUgaHR0cHMifQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZmlncy9naXRodWItcGFzdGUtaHR0cHMucG5nIikKYGBgCgpBbyBjbGljYXIgZW0gYENyZWF0ZSBwcm9qZWN0YCBvIHJlcG9zaXTDs3JpbyByZW1vdG8gc2Vyw6EgaW1lZGlhdGFtZW50ZSB0cmFuc2ZlcmlkbyBwYXJhIG8gc2V1IGNvbXB1dGFkb3IuIFVtYSBwYXN0YSAobyBkaXJldMOzcmlvIGxvY2FsKSBzZXLDoSBjcmlhZG8gbm8gbG9jYWwgcXVlIHZvY8OqIGVzY29saGV1IGUsIGFzc2ltLCBSU3R1ZGlvLCBHaXQgZSBHaXRodWIgZXN0YXLDo28gcGxlbmFtZW50ZSBjb25lY3RhZG9zLiBUdWRvIGNlcnRvIGF0w6kgYXF1aT8gVW1hIHBhdXNhIHBhcmEgZGVzY2Fuc28gY29tIHVtIHbDrWRlby4KCmBgYHtyIGVjaG89RkFMU0UsZXZhbD1UUlVFfQp2ZW1iZWRyOjplbWJlZF91cmwoImh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9ajdLM3NfdmlfMVkiKQpgYGAKCgojIyBQdWxsLCBDb21taXRzIGUgUHVzaCAKClNlIHZvY8OqIGNoZWdvdSBhdMOpIGFxdWkgc2VtIGVycm9zIGlzc28gcXVlciBkaXplciBxdWUgR2l0IGUgR2l0SHViIGrDoSBlc3TDo28gaW50ZWdyYWRvcyBubyBSU3R1ZGlvLiBQb3J0YW50bywgcXVhbHF1ZXIgY29pc2EgcXVlIGZpemVybW9zIG5lc3RhIHBhc3RhIGVzdMOhIHNlbmRvIG9ic2VydmFkbyBhIHBhcnRpciBkZSBhZ29yYSBwZWxvIGdpdC4gUGFyYSBjZXJ0aXJmaWNhci1zZSBkaXNzbywgaGFiaWxpdGUgYSB2aXN1YWxpemHDp8OjbyBkZSBhcnF1aXZvcyBvY3VsdG9zIG5vIHNldSBjb21wdXRhZG9yLCB2b2PDqiB2YWkgbm90YXIgcXVlIG5hIHJhaXogZGVzdGEgcGFzdGEgY2xvbmFkYSBleGlzdGUgdW1hIHBhc3RhIGAuZ2l0YCwgY29tbyBuYSBmaWd1cmEgYSBzZWd1aXIKCmBgYHtyIGVjaG89RkFMU0UsZXZhbD1UUlVFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygiZmlncy9naXQtaW5zaWRlLWZvbGRlci5wbmciKQpgYGAKClNlIHZvY8OqIGNvbnNlZ3VlIHZlciBlc3RhIHBhc3RhIHF1ZXIgZGl6ZXIgcXVlIGVzdMOhIHR1ZG8gY2VydG8sIGUgbyBnaXQgZXN0w6Egb2JzZXJ2YW5kbyAoKip3YXRjaCoqIG5vIGphcmfDo28gZG8gdmVyc2lvbmFtZW50bykgY2FkYSBtb2RpZmljYcOnw6NvIGUgY2FkYSBhcnF1aXZvIGRlbnRybyBkZXN0YSBwYXN0YSAoYSBtZW5vcyBxdWUgdm9jw6ogaW5jbHVhIG8gYXJxdWl2byBubyAuZ2l0aWdub3JlLCBtYXMgaXNzbyDDqSBhc3N1bnRvIHBhcmEgb3V0cm8gbW9tZW50bykuCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxvdXQud2lkdGg9IjU1JSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKCJmaWdzL2JpZy1icm90aGVyLXdhdGNoaW5nLnBuZyIpCmBgYAoKQWdvcmEgaXJlbW9zIGV4ZWN1dGFyIGZ1bsOnw7VlcyBxdWUsIGF0w6kgbyBmaW0gZGVzdGUgY3Vyc28sIHNlcsOjbyBxdWFzZSBhdXRvbcOhdGljYXMgbm8gbm9zc28gZmx1eG8gZGUgdHJhYmFsaG8gY29tIHZlcnNpb25hbWVudG8uCgojIyMgTWV1IHByaW1laXJvIGNvbW1pdAoKTyBxdWUgw6kgdW0gY29tbWl0PwoKQ29tbWl0LCBvdSAicmV2aXPDo28iLCDDqSB1bWEgbXVkYW7Dp2EgaW5kaXZpZHVhbCBlbSB1bSBhcnF1aXZvIG91IHVtIGNvbmp1bnRvIGRlIGFycXVpdm9zIGRlbnRybyBkYSBwYXN0YSBvYnNlcnZhZGEgcGVsbyBnaXQuIE9zIGNvbW1pdHMgc8OjbyBjb21vIGNoZWNrLXBvaW50cyBwYXJhIG8gbm9zc28gcmVwb3NpdMOzcmlvLiBVbWEgYW5hbG9naWEgaW50ZXJlc3NhbnRlIHBhcmEgb3MgY29tbWl0cyBmb2kgYXByZXNlbnRhZGEgbmEgYXVsYSBlIGVzdMOhIGlsdXN0cmFkYSBhcXVpLCBuYSBmaWd1cmEgc2VndWludGUKCgpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPUZBTFNFLG91dC53aWR0aD0iNjAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiZmlncyIsICJjb21taXQtb25seS1jb25jZXB0LnBuZyIpKQpgYGAKClZhbW9zIHBlbnNhciBxdWUgbm9zc28gcHJvamV0byDDqSB1bWEgbW9udGFuaGEsIGUgZXN0YW1vcyBlc2NhbGFuZG8gZWxlLiBOb3NzbyBvYmpldGl2byBmaW5hbCDDqSwgb2J2aWFtZW50ZSwgZmluYWxpemFyIG8gcHJvamV0bywgY2hlZ2FuZG8gYW8gdG9wbyBkYSBtb250YW5oYS4gQSBtZWRpZGEgcXVlIHByb2dyZWRpbW9zLGNhc28gdmVuaGFtb3MgYSBjb21ldGVyIHVtIGVycm8sIGEgcXVlZGEgcG9kZSBzZXIgZ3JhbmRlLiBEZXN0YSBtYW5laXJhLCB1dGlsaXphbW9zIGdyYW1wb3Mgb25kZSBhbmNvcmFtb3Mgbm9zc2EgY29yZGEgYSBtZWRpZGEgcXVlIGEgZXNjYWxhZGEgcHJvZ3JpZGUuIEVtIGNhc28gZGUgZXJybywgYSBxdWVkYSBzZXLDoSBhcGVuYXMgYXTDqSBvIGdyYW1wbyBhbnRlcmlvciBvbmRlIGEgY29yZGEgZm9pIGFuY29yYWRhLiBPcyBjb21taXRzIHNlcnZlbSBjb21vIG9zIGNsaXBlcyBxdWUgYW5jb3JhbSBhIGNvcmRhIGEgbWVkaWRhIHF1ZSBwcm9ncmVkaW1vcyBubyBwcm9qZXRvLiBTZSBjb21ldGVybW9zIHVtIGVycm8gZW0gYWxndW0gYXJxdWl2bywgdHVkbyBjZXJ0bywgcG9kZW1vcyB2b2x0YXIgbm8gY29tbWl0IGFudGVyaW9yLCBvdSBhbnRlcmlvcmVzLCBwYXJhIHRlbnRhciBkZXNjb2JyaXIgb25kZSBvIGVycm8gZm9pIGNvbWV0aWRvLgoKRGEgbWVzbWEgZm9ybWEgcXVlIG5hIGVzY2FsYWRhLCBzZSB1dGlsaXphcm1vcyBjbGlwZXMgbXVpdG8gcGVydGluaG9zIHVucyBkb3Mgb3V0cm9zIHZhbW9zIGZpY2FyIGxlbnRvcyBkZW1haXMsIGUgbyBwcm9ncmVzc28gYXTDqSBvIHRvcG8gc2Vyw6EgY29tcHJvbWV0aWRvLCBzZSBmaXplcm1vcyBtdWl0b3MgY29tbWl0cyBzZXLDoSBkaWbDrWNpbCB2b2x0YXIgZW0gbW9tZW50b3MgZXNwZWPDrWZpY29zIGRvIHByb2pldG8sIHZpc3RvIHF1ZSB0ZXLDo28gbXVpdG9zIGNvbW1pdHMgcGFyYSBzZXJlbSBjaGVjYWRvcy4gUG9ydGFudG8sIGEgcmVncmEgw6k6IGZhw6dhIGNvbW1pdHMgY29tIHBhcmNpbW9uaWEsIG91IHNlamEsIG5lbSBtdWl0b3MsIG5lbSBwb3Vjb3MuCgpWYW1vcyBmYXplciB1bWEgbW9kaWZpY2HDp8OjbyBuYSBub3NzYSBwYXN0YS4gUG9kZW1vcyBhZGljaW9uYXIgYXJxdWl2b3MsIGrDoSBxdWUgZWxhIGVzdMOhIHZhemlhLiBQYXJhIHRhbnRvIHZhbW9zIHVzYXIgb3MgYXJxdWl2b3MgZG8gcGFjb3RlIGRlIGRhZG9zIHBhbG1lciBwZW5ndWlucyBxdWUgZXN0w6NvIG5lc3NlIHJlcG9zaXTDs3Jpby4gTGVtYnJlLXNlIGRlIGxlciBvcyBhcnF1aXZvcyB1dGlsaXphbmRvIG8gYHtoZXJlfWAgZSB1dGlsaXphciBvIFJwcm9qZWN0IHBhcmEgYWJyaXIgbyBkaXJldMOzcmlvCgpgYGB7ciBlY2hvPVRSVUUsZXZhbD1GQUxTRX0KZGF0YV9wZW5ndWlucyA8LSByZWFkLmNzdihoZXJlOjpoZXJlKCJkYXRhIiwgImRhdGEtcGVuZ3VpbnMuY3N2IikpIApgYGAKCioqT2JzKiogc2UgcXVpc2VyZW0gdXNhciBzZXVzIHByw7NwcmlvcyBkYWRvcyBmaXF1ZW0gYSB2b250YWRlLCBvIHVzbyBkbyBwYWxtZXJwZW5ndWlucyDDqSBhcGVuYXMgb3BjaW9uYWwgZSBhIHTDrXR1bG8gZGUgcHJvY2VkaW1lbnRvIGRpZMOhdGljby4gCgpDYXNvIGVzdGVqYW0gdHJhYmFsaGFuZG8gY29tIHNldXMgcHLDs3ByaW9zIGRhZG9zLCBqb2d1ZSBvcyBhcnF1aXZvcyBwYXJhIGRlbnRybyBkbyBkaXJldMOzcmlvIHF1ZSBjbG9uYW1vcy4gTyBwcsOzeGltbyBwYXNzbyDDqSBmYXplciBub3NzbyBwcmltZWlybyBjb21taXQuCgoKIyMjIEV4cGxvcmFuZG8gY29tbWl0cwoKYGBge3IgZWNobz1GQUxTRSwgZXZhbD1UUlVFLG91dC53aWR0aD0iNzAlIn0Ka25pdHI6OmluY2x1ZGVfZ3JhcGhpY3MoaGVyZTo6aGVyZSgiZmlncyIsICJjb21taXQtc2FmZS5wbmciKSkKYGBgCkV4aXN0ZW0gZHVhcyBmb3JtYXMgZGUgZmF6ZXIgdmVyc2lvbmFtZW50byB1c2FuZG8gbyBHaXQgZSBHaXRodWIgdmlhIFJTdHVkaW8uIFVtYSBkZWxhcyDDqSBhIGxpbmhhIGRlIGNvbWFuZG8sIGEgb3V0cmEgw6kgdmlhIHVtYSBpbnRlcmZhY2UgdmlzdWFsLCBxdWUgbmVzc2UgY2FzbyDDqSBvIHByw7NwcmlvIFJTdHVkaW8uIFZhbW9zIGNvbWXDp2FyIGZhemVuZG8gbyB2ZXJzaW9uYW1lbnRvIHZpYSBpbnRlcmZhY2UgdmlzdWFsLiBBIG9ww6fDo28gcGFyYSBpc3NvIMOpIHF1ZSBuaW5ndcOpbSBzZSBhc3N1c3RlIG51bSBwcmltZWlybyBtb21lbnRvIGNvbSBhIGxpbmhhIGRlIGNvbWFuZG8sIGUgcXVlIGlzc28gbsOjbyBzZWphIHVtIGltcGVkaXRpdm8gcGFyYSB1dGlsaXphciBvIHZlcnNpb25hbWVudG8gbm8gc2V1IGZsdXhvIGRlIHRyYWJhbGhvLiBBIG1haW9yaWEgZG9zIGNvbWFuZG9zIGLDoXNpY29zIHBvZGVtIHNlciBleGVjdXRhZG9zIGF0cmF2w6lzIGRlc3RhIGludGVyZmFjZSBncsOhZmljYSBxdWUgY2hhbWFtb3MgZGUgKipHaXQgQ2xpZW50KioKClJlcGFyZSBxdWUgc2V1IFJTdHVkaW8gYWdvcmEgdGVtIGFsZ3VtYXMgY29pc2FzIG5vdmFzLiBFc3BlY2lmaWNhbWVudGUsIHZlamEgcXVlIGFnb3JhIGVsZSB0ZW0gdW1hIGFiYSBjaGFtYWRhIEdpdCwgY29tbyBpbHVzdHJhZG8gbmEgZmlndXJhIGFiYWl4bwoKCmBgYHtyIGVjaG89RkFMU0UsZXZhbD1UUlVFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJmaWdzIiwgImdpdC10YWItcnN0dWRpby5wbmciKSkKYGBgCgpJc3NvIGluZGljYSBxdWUgbyBnaXQgZXN0w6EgZnVuY2lvbmFuZG8gbm8gc2V1IGRpcmV0w7NyaW8sIGUgYWdvcmEgcG9kZW1vcyBmYXplciBvIHZlcnNpb25hbWVudG8gZGVzdGUgZGlyZXTDs3JpbyBsb2NhbCBlIHNpbmNyb25pesOhLWxvIGNvbSBvIHJlcG9zaXTDs3JpbyByZW1vdG8uCgpUdWRvIGUgcXVhbHF1ZXIgY29pc2EgcXVlIGZvciBhZGljaW9uYWRvIG91IG1vZGlmaWNhZG8gbmEgc3VhIHBhc3RhIHZhaSBhcGFyZWNlciBuYSBqYW5lbGEgYWJhaXhvIGRhIGFiYSBnaXQuIENvbW8gbW9zdHJhZG8gbmEgZmlndXJhIGFiYWl4bwoKYGBge3IgZWNobz1GQUxTRSxldmFsPVRSVUV9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImZpZ3MiLCAiZ2l0LXRhYi1yc3R1ZGlvMi5wbmciKSkKYGBgCgpDb21vIGV1IG1lbmNpb25laSBuYSBhdWxhIHRlw7NyaWNhIGUgYXF1aSBhY2ltYSwgbyBjb21taXQgw6kgY29tbyB1bSB0cmFjayBjaGFuZ2VzIGRvIHdvcmQsIG1hcyBtZWxob3IuIFByZWNpc2Ftb3MgZmF6ZXIgdW0gdHJhY2sgY2hhbmdlIG1hbnVhbCwgaW5kaWNhbmRvIG8gcXVlIGZvaSBtb2RpZmljYWRvLCBpc3NvIMOpIG8gbm9zc28gY29tbWl0LiBQYXJhIHJlYWxpemFyIHVtIGNvbW1pdCB2aWEgYSBpbnRlcmZhY2UgZG8gUlN0dWRpbyB2b2PDqiBwcmVjaXNhOgoKMSAtIENsaWNhciBubyBib3TDo28gYGNvbW1pdCBwZW5kaW5nIGNoYW5nZXNgIChvdSBlbSBxdWFscXVlciBib3TDo28gbmFxdWVsYSBhYmEpLCBjb21vIG1vc3RyYWRvIGFiYWl4bwoKYGBge3IgZWNobz1GQUxTRSxldmFsPVRSVUV9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImZpZ3MiLCAiZ2l0LXRhYi1yc3R1ZGlvMy5wbmciKSkKYGBgCgoyIC0gSXNzbyB2YWkgYWJyaXIgdW1hIG5vdmEgamFuZWxhLCBuZWxhIHZvY8OqIGRldmUgc2VsZWNpb25hciBub3MgY2hlY2tib3ggb3MgYXJxdWl2b3MgKHZhbW9zIGRhciB1bWEgb2xoYWRhIG5lc3NhIGphbmVsYSBhbnRlcyBkZSBwcm9zc2VndWlyKQoKYGBge3IgZWNobz1GQUxTRSxldmFsPVRSVUV9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImZpZ3MiLCAiZ2l0LXRhYi1yc3R1ZGlvNC5wbmciKSkKYGBgCgozIC0gRXNjcmV2YSB1bWEgbWVuc2FnZW0gaW5mb3JtYXRpdmEuIENvbW8gZXN0ZSDDqSBvIHByaW1laXJvIGNvbW1pdCBnZXJhbG1lbnRlIHNlbGVjaW9uYW1vcyB0b2RvcyBvcyBhcnF1aXZvcyBlIGVzY3JldmVtb3MgYSBtZW5zYWdlbSBgRmlyc3QgY29tbWl0YCBwYXJhIGluZGljYXIgcXVlIMOpIG8gcHJpbWVpcm8gY29tbWl0IGRlc3RlIHJlcG9zaXTDs3JpbwoKYGBge3IgZWNobz1GQUxTRSxldmFsPVRSVUV9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImZpZ3MiLCAiZ2l0LXRhYi1yc3R1ZGlvNS5wbmciKSkKYGBgCgoqKk9CUyoqIEEgbWVuc2FnZW0gZGV2ZSBzZXIgcmVhbG1lbnRlIGluZm9ybWF0aXZhLCBvIGNvbW1pdCBmaWNhIGFybWF6ZW5hZG8gbm8gc2V1IHJlcG9zaXTDs3JpbyBlIGFwYXJlY2Vyw6EgcHVibGljYW1lbnRlIGNhc28gbyByZXBvc2l0w7NyaW8gc2VqYSBww7pibGljby4gCgpgYGB7ciBlY2hvPUZBTFNFLGV2YWw9VFJVRSxvdXQud2lkdGg9IjYwJSJ9CmtuaXRyOjppbmNsdWRlX2dyYXBoaWNzKGhlcmU6OmhlcmUoImZpZ3MiLCAiY29tbWl0LW1lbWUucG5nIikpCmBgYAoKUHJvbnRvLCBvIHF1ZSBmaXplbW9zIGFnb3JhIGZvaSBiYXNpY2FtZW50ZSBjb2xvY2FyIG5vc3NvcyBhcnF1aXZvcyBuYSAqKnN0YWdnaW5nIGFyZWEqKiAobWFyY2FyIGFzIGNoZWNraW5nIGJveCkgZSBwcmVwYXLDoS1sb3MgcGFyYSBhIGVudHJlZ2EgY29tIHVtYSBtZW5zYWdlbSBpbmZvcm1hdGl2YSwgbyBjb21taXQuIEFnb3JhIHByZWNpc2Ftb3MgZW52aWFyIG9zIGFycXVpdm9zIHBhcmEgbyByZXBvc2l0w7NyaW8gcmVtb3RvICh1cHN0cmVhbSkKCiMjIyBNZXUgcHJpbWVpcm8gcHVzaAoKVGVtb3MgdW0gZGlyZXTDs3JpbyBmdW5jdGlvbmFuZG8gY29tIG8gZ2l0LCBsaWdhZG8gYW8gZ2l0aHViLCBjb20gZG9jdW1lbnRvcyBkZW50cm8sIG1hcywgYXTDqSBhZ29yYSBlbGUgYXBlbmFzIHZpdmUgZW0gbm9zc29zIGNvbXB1dGFkb3Jlcy4gQ2hlZ291IGEgaG9yYSBkZSBlbXB1cnJhciBlc3RlcyBkb2N1bWVudG9zIHBhcmEgbyBkaXJldMOzcmlvIHJlbW90bywgb3Ugc2VqYSwgYXF1ZWxlIHF1ZSBjbG9uYW1vcyBsw6Egbm8gaW7DrWNpby4gUGFyYSB0YW50byB2YW1vcyBmYXplciB1bSBgcHVzaGAKCk8gcHVzaCBuYWRhIG1haXMgw6kgcXVlIGVtcHVycmFyIG9zIGRvY3VtZW50b3MgcGFyYSBvIHJlcG9zaXTDs3JpbyBkbyBnaXRodWIsIGNoYW1hZG8gYXMgdmV6ZXMgZGUgYG9yaWdpbi9tYXN0ZXJgIGUgb3V0cmFzIHZlemVzIGBvcmlnaW4vbWFpbmAsIG1hcyBhbWJvcyBxdWVyZW0gZGl6ZXIgInVtIHJlcG9zaXTDs3JpbyByZW1vdG8gbyBxdWFsIG8gZGlyZXTDs3JpbyBxdWUgZXN0b3UgdHJhYmFsaGFuZG8gZXN0w6EgbGlnYWRvIi4KClNlbSBtYWlzIGRlbG9uZ2FzLCBwYXJhIGZhemVyIHVtIHB1c2ggcHJlY2lzYW1vcyBhcGVuYXMgYXBlcnRhciBvIGJvdMOjbyB2ZXJkZSBjb21vIG1vc3RyYWRvIG5hIGZpZ3VyYSBhYmFpeG8KCmBgYHtyIGVjaG89RkFMU0UsZXZhbD1UUlVFfQprbml0cjo6aW5jbHVkZV9ncmFwaGljcyhoZXJlOjpoZXJlKCJmaWdzIiwgImdpdC10YWItcnN0dWRpbzYucG5nIikpCmBgYAoKRHVhcyBjb2lzYXMgc8OjbyBpbXBvcnRhbnRlcyBub3RhciBuZXNzZSBtb21lbnRvLiBQcmltZWlybyBvIGJvdMOjbyBkZSBwdXNoLCBxdWUgdmFpIGVtcHVycmFyIG9zIGFycXVpdm9zIHBhcmEgbyByZXBvc2l0w7NyaW8gcmVtb3RvIChvcmlnaW4pLiBTZWd1bmRvLCBhIG1lbnNhZ2VtIGRlc3RhY2FkYSBjb20gYSBzZXRhLiBFbGEgZGl6IHF1ZSBvICpicmFuY2gqIGVzdMOhIGEgZnJlbnRlIGRvICpvcmlnaW4vbWFzdGVyKiBwb3IgdW0gKmNvbW1pdCouIFRyYWR1emluZG8sIG5vc3NvIGRpcmV0w7NyaW8gbG9jYWwgKGJyYW5jaCksIGVzdMOhIHVtYSB2ZXJzw6NvIGEgZnJlbnRlIChwb2lzIG1vZGlmaWNhbW9zIGNvaXNhcyBhcXVpKSBlbSByZWxhw6fDo28gYW8gbm9zc28gcmVwb3NpdMOzcmlvIHJlbW90byAob3JpZ2luL21hc3RlcikuIEFvIGVtcHVycmFyIChwdXNoKSBhcyBtb2RpZmljYcOnw7VlcywgZXNzYSBtZW5zYWdlbSBkZXNhcGFyZWNlcsOhLCBpbmRpY2FuZG8gcXVlIHRhbnRvIGJyYW5jaCBxdWFudG8gb3JpZ2luIGVzdMOjbyBuYSBtZXNtYSBsaW5oYSBkbyB0ZW1wbyEKCiMgRXh0cmFzCgpBcXVpIGFsZ3VtYXMgZGljYXMgZXh0cmFzIGNhc28gdm9jw6ogcXVlaXJhIHNlZ3VpciBjYW1pbmhvcyBkaWZlcmVudGVzIHF1ZSBvcyBhcHJlc2VudGFkb3MgYXTDqSBhZ29yYSBwYXJhIG1vbnRhciB1bSByZXBvc2l0w7NyaW8gZSBjb25lY3RhciBjb20gbyBnaXRodWIuIFZhbW9zIHN1cG9yIHF1ZSB2b2PDqiBqw6EgdGVuaGEgdW0gcHJvamV0byBsb2NhbCBlbSBzZXUgY29tcHV0YWRvciBxdWUgasOhIGVzdMOhIG1vbml0b3JhZG8gcGVsbyBnaXQsIGNvbnTDqW0gYWxndW5zIGNvbW1pdHMsIGUgdm9jw6ogbsOjbyBxdWVyIHBlcmRlciBlc3RlcyBjb21taXQuIEEgZm9ybWEgbWFpcyBmw6FjaWwgZGUgZmF6ZXIgaXNzbyDDqSBhdHJhdsOpcyBkbyBwYWNvdGUgYHt1c2V0aGlzfWAuIFBhcmEgdXRpbGl6YXIgZXN0YSBhYm9yZGFnZW0gdm9jw6ogcHJlY2lzYSB0ZXIgbyBQQVQgKFBlcnNvbmFsIEFjY2VzcyBUb2tlbiBxdWUgY3JpYW1vcyBsw6EgZW0gY2ltYSkuCgoxIC0gdmVyaWZpcXVlIHNlIG8gZ2l0IGVzdMOhIGZ1bmNpb25hbmRvIGVtIHNldSByZXBvc2l0w7NyaW8gKHZlamEgc2UgYXBhcmVjZSBhIHRhYiBnaXQgbm8gc2V1IFJTdHVkaW8pLiBDYXNvIG7Do28gdmVqYSB2b2PDqiBwcmVjaXNhIGluaWNpYXIgbyBnaXQgbm8gZGlyZXTDs3JpbyBxdWUgZXN0w6EgdHJhYmFsaGFuZG8uIFBhcmEgZmF6ZXIgaXNzbzoKCmBgYHtyIGVjaG89VFJVRSxldmFsPUZBTFNFfQp1c2V0aGlzOjp1c2VfZ2l0KCkKYGBgCgpPdXRyYXMgb3DDp8O1ZXMgZXhpc3RlbSwgcG9yIGV4ZW1wbG8sIHVzYW5kbyBvIHRlcm1pbmFsIGRpcmV0YW1lbnRlLiBNYXMgdmFtb3MgbWFudGVyIGEgY29uc2lzdMOqbmNpYSBlIHV0aWxpemFyIHNlbXByZSBvIHBhY290ZSB1c2V0aGlzIHF1YW5kbyBwb3Nzw612ZWwuCgoyIC0gdW1hIHZleiBxdWUgbyBnaXQgZXN0w6EgZnVuY2lvbmFuZG8gbmVzdGUgcmVwb3NpdMOzcmlvLCBwcmVjaXNhbW9zIGNyaWFyIHVtIHJlcG9zaXTDs3JpbyByZW1vdG8gcGFyYSBlbGUgbm8gbm9zc28gcGVyZmlsIGRvIEdpdEh1Yi4gUGFyYSB0YW50byBwcmVjaXNhbW9zIGFwZW5hcyBkaWdpdGFyOgoKYGBge3IgZWNobz1UUlVFLGV2YWw9RkFMU0V9CnVzZXRoaXM6OnVzZV9naXRodWIoKQpgYGAKCgojIEF0aXZpZGFkZQoKSG9yYSBkZSBwcmF0aWNhciBjb20gc2V1cyBkYWRvcywgb3UgYWluZGEgY29tIG9zIGRhZG9zIGRvIHBhbG1lcnBlbmd1aW5zLiBGYcOnYSBhbGd1bWFzIG1vZGlmaWNhw6fDtWVzIG5hIHRhYmVsYSwgc2FsdmUgdW0gbm92byBvYmpldG8sIGZhw6dhIHVtIGNvbW1pdCBlIHVtIHB1c2guIEFww7NzIGZhemVyIGlzc28gdmVyaWZpcXVlIG5hIHDDoWdpbmEgZG8gcmVwb3NpdMOzcmlvIG5vIEdpdEh1YiBvIHF1ZSBhY29udGVjZXUuCgojIFJlZmVyw6puY2lhcyBpbXBvcnRhbnRlcwoKW0RvdWdsYXMgTWNEb25hbGQgd2Vic2l0ZV0oaHR0cHM6Ly93d3cuZG91Z2FuZGRhdGEuY29tLzIwMjIvMDcvb24tbmFtaW5nLXRoaW5ncy8pCgpbSmVubnkgQnJ5YW5dKGh0dHA6Ly93d3cyLnN0YXQuZHVrZS5lZHUvfnJjczQ2L2xlY3R1cmVzXzIwMTUvMDEtbWFya2Rvd24tZ2l0L3NsaWRlcy9uYW1pbmctc2xpZGVzL25hbWluZy1zbGlkZXMucGRmKQoKW0hhZGxleSBXaWNraGFtXShodHRwOi8vYWR2LXIuaGFkLmNvLm56L1N0eWxlLmh0bWwpCgoK