Visão geral

Como os códigos de análises em ecologia, junto com os dados, se tornaram também um produto do projeto de pesquisa, boas práticas devem levar em conta a revisão não só da publicação científica, mas também do código de análises.

Nesta aula discutimos a revisão de código com um olhar sobre códigos de análises de dados, suas vantagens e também formas de incentivar e fomentar esta prática dentro dos grupos de pesquisa.

Geralmente, vamos revisar um repositório/código que está associado a uma publicação científica, ou que pelo menos, você conhece o projeto e tem mais informações sobre. Logo, esta ideia de revisão de repositório tem algumas diferenças dos padrões formais de revisão de código para desenvolvedores e outros profissionais da área de programação.

Por que fazer revisão de código?

  • PROBLEMA:

    • Códigos e análises estão se tornando cada vez mais complicados e complexos na ciência, principalmente ecologia (Touchon & McCoy, 2016)
    • Revisão de código é praticamente inexistente na maioria dos trabalhos publicados em ecologia hoje em dia.
  • CONSEQUÊNCIA:

    • Muitas retratações de artigos de alto impacto por erros em código que mudam resultados e conclusões
  • SOLUÇÃO:

    • Mudanças culturais para trazer a revisão de código em todos os estágio da pesquisa.
  • IMPEDIMENTO:

    • Poucos (ou nenhum) incentivos para a realização de revisão de códigos.

Vantagens da revisão do seu código de análise (Lee & Foster-Marks, 2024):

  • Aumentar qualidade do código:

    • Clareza
    • Documentação
    • Detecção de erros
  • Aumentar benefícios sociocognitivos da equipe/grupo/laboratório a longo prazo:

    • Transferência de conhecimentos e aprendizado
    • Soluções criativas e colaborativas de problemas
    • Confiança
    • Formação de comunidade
    • Aprendizado não só através de conteúdo, mas também com feedbacks construtivos
  • Trazer mudança na cultura da pesquisa!

Culina et al. (2020) mostraram que 75% das revistas em Ecologia e Evolução contém políticas obrigatórias de compartilhamento de código e dados, apesar de que as políticas de compartilhamento de código não serem seguidas pela maioria dos autores (27% dos artigos).

Quando realizar a revisão do código/repositório de análise?

  • Pré-publicação

    • Revisão feita por colegas, colaboradores, orientadores.
  • Durante publicação / submissão

    • Revisão formal do código junto com o artigo submetido
  • Pós-publicação

    • Revisar código em artigos já publicados. Esta revisão pode ser feita direto no GitHub via Issue ou Pull Request ou mesmo contactando inicialmente os autores (e talvez editores da revista onde o trabalho foi publicado)

Dicas para autores

Ajude o revisor a te ajudar!

Por que escrever um código bonito?

Mesmo que o código seja executado por máquina, ele também vai ser lido por humanos! Clareza, limpeza, estética consistente vão tornar a leitura mais fácil e também mais “barato” de se fazer ou propor modificações.

Eu acredito na criação do hábito de escrever desde o início códigos sempre pensnado que alguém (um estranho ou mesmo você no futuro) vai revisá-lo. Resista à tentação de achar que vai organizar o código depois que fizer todas as análises! Por isso a importância de se incorporar hábitos e dicas para escrita de código bonito, limpo e organizado.

Estilo de código é um conjunto de regras sobre sobre estética (alinhamento e espaçamento do código), nomenclatura (de variáveis, funções etc.), comentários, estruturação (por exemplo, evitar lógica complexa) etc. Essas regras ajudam a melhorar a clareza do código e a colaboração.

Ao longo da escrita do código, é saudável fazer uma pausa de vez em quando e revisar o estilo de escrita e o padrão de organização que você adotou no início e ver se você manteve ou não a consistência ao longo do tempo. É muito fácil começar adotanto uma padronização e terminar com outra diferente, principalmente se o código está sendo escrito ao longo de meses. Mas existem ferramentas para fazer isso de forma mais automatizada e rápida!

Existem vários estilos de escrita de código, e várias dicas por aí para seguir ou adaptar ao seu gosto. Alguns dos mais usados são o estilo de escrita do tidyverse, que tem o pacote R styler que pode ajustar seu código ao estilo usando um addin do Rstudio.

Styler - pacote R que ajusta seu código ao estilo tydverse

Outro pacote, além do styler que ajuda a padronizar um arquivo o pedaço de código a um estilo é o formatR.

O pacote lintr é muito útil para verificar o código quanto ao estilo, erros de sinstaxe e semântica, mas não vai modificar o arquivo por você. Ele faz um relatório de consistência do código

Veja algumas dicas beem gerais nesse e nesse roteiro para pensar e avaliar qual estilo de código você prefere seguir ou criar!

Comente/documente seus passos

Comentários ao longo dos scripts explicando porquê você está fazendo certas coisas ajuda muito a guiar o revisor/leitor ao longo do código. Escrever código em Rmarkdown e/ou Quarto resolve essa necessidade de explicar o passo a passo das análises, pois você pode separar a parte de explicação (texto) da parte de código Roteiro aqui.

Em arquivos .R você pode usar o bom e velho # para escrever comentários ao longo do código. Porém, a ideia aqui é diferente de um arquivo .Rmd ou .Qmd. Tenha cuidado com comentários demais que podem distrair o revisor/leitor ou poluir o código. Neste caso, os comentários no código devem ser pequenos alertas. Quanto mais comentários houver, mais provável será que o leitor os ignore.

Os comentários de código não devem ser um “band-aid” para nomes ruins ou código excessivamente complexo: em vez de adicionar um comentário, você pode renomear uma variável ou refatorar um trecho de código?

Assista essa brilhante palestra “Code smell and feels” da rainha, Jenny Bryan, sobre estilo de código!

Dicas para revisores

Lembre-se que há várias formas de se abordar um mesmo problema, o revisor não precisa impor sua forma. E cuidado para não impor estilo de escrita! Mas pode verificar inconsistências que venham a atrapalhar a leitura do código.

O que deve ser avaliado na revisão do código? Seguindo Ivimey-Cook et al. (2023), existem 3 tipos de erros em código:

  • conceitual – implementando a função ou argumento errado

  • programático – chamando o objeto ou coluna errada

  • sintático – grafia incorreta de um estado ou função

E eles propõem uma forma organizada de revisar o código seguindo 4 Rs (em inglês):

Os 4 Rs principais para revisão de código

  • O código está como Reportado?

    • Verificação de consistência.
    • Métodos (no texto principal) e código devem coincidir.
    • Evita erros conceituais, como por exemplo, reportar que fez um modelo linear com distribuição de Possion, mas no código esquecer de especificar o argumento family=“Poisson” em um glm().
  • O código Roda?

    • Erros programáticos e sintáticos podem fazer o código, ou partes dele, não rodar.
    • Pacotes não instalados (fora do ambiente) também ou versão diferente do revisor:
      • Pacotes que ajudam: renv, groundhog
    • Solução para outputs de análises que demoram muito: salvar arquivos intermediários para facilitar reprodutibilidade (e.g. extensão .rds)
  • O código é Confiável (Reliable)?

    • Erros ainda podem se propagar mesmo que o código rode (produzir resultado incorreto mas reprodutível)
    • Confiança é examinar resultados intermediários do código para garantir que não há erros
    • Erros conceituais ou programáticos
      • ex: código seleciona/modifica a coluna errada
      • Esse tipo de erros (que rodam, mas estão conceitualmente errados ou indexados errado) escalonam com o número de linhas e complexidade do código
  • Os resultados são Reprodutíveis?

    • Garantir que os resultados finais, quando o código é rodado novamente, correspondam àqueles reportados na análise e resultados do texto principal.
    • Tolerância com análises que lidam com estocasticidade: set.seed()
      • também levar em conta quantas casas decimas espera-se o mesmo resultado (precisão)

Baseado no checklist de revisão de código criado por Ivimey-Cook et al. (2023), nós elaboramos um arquivo de texto para guiar revisores de código:

Um exemplo de checklist para revisão de código (tirado de Ivimey-Cook et al. 2023)
Um exemplo de checklist para revisão de código (tirado de Ivimey-Cook et al. 2023)

Motivação final para revisão de código

  • Ajuda a criar uma cultura de revisão de código entre colegas

    • Encoraja colaborações
    • Normaliza a existência de erros
  • Incentivos para revisão:

    • co-autoria, agradecimentos, futuras colaborações…
  • Crie um grupo de revisão de código!!

    • no lab
    • entre amigos/colegas
  • Exemplo Peer Code Review group – SORTEE: https://github.com/SORTEE/peer-code-review/issues/8

Referências

Culina, A., Berg, I. van den, Evans, S. & Sánchez-Tójar, A. (2020). Low availability of code in ecology: A call for urgent action. PLOS Biology 18, e3000763.
Ivimey-Cook, E.R., Pick, J.L., Bairos-Novak, K.R., Culina, A., Gould, E., Grainger, M., Marshall, B.M., Moreau, D., Paquet, M., Royauté, R., Sánchez-Tójar, A., Silva, I. & Windecker, S.M. (2023). Implementing code review in the scientific workflow: Insights from ecology and evolutionary biology. Journal of Evolutionary Biology 36, 1347–1356.
Lee, C.S. & Foster-Marks, K. (2024). The Code Review Anxiety Workbook.
Touchon, J.C. & McCoy, M.W. (2016). The mismatch between current statistical practice and doctoral training in ecology. Ecosphere 7, e01394.
LS0tDQp0aXRsZTogIlJldmlzw6NvIGRlIGPDs2RpZ28gcG9yIHBhcmVzIg0KYXV0aG9yOiAiTWVsaW5hIExlaXRlIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0KYmlibGlvZ3JhcGh5OiByZWZzL2NpZW5jaWFfYWJlcnRhLmJpYg0KY3NsOiByZWZzL3JlZmVyZW5jZXMtc3R5bGUuY3NsDQpvdXRwdXQ6IGh0bWxfZG9jdW1lbnQNCi0tLQ0KDQojIFZpc8OjbyBnZXJhbA0KDQpDb21vIG9zIGPDs2RpZ29zIGRlIGFuw6FsaXNlcyBlbSBlY29sb2dpYSwganVudG8gY29tIG9zIGRhZG9zLCBzZSB0b3JuYXJhbSB0YW1iw6ltIHVtIHByb2R1dG8gZG8gcHJvamV0byBkZSBwZXNxdWlzYSwgYm9hcyBwcsOhdGljYXMgZGV2ZW0gbGV2YXIgZW0gY29udGEgYSByZXZpc8OjbyBuw6NvIHPDsyBkYSBwdWJsaWNhw6fDo28gY2llbnTDrWZpY2EsIG1hcyB0YW1iw6ltIGRvIGPDs2RpZ28gZGUgYW7DoWxpc2VzLg0KDQpOZXN0YSBhdWxhIGRpc2N1dGltb3MgYSByZXZpc8OjbyBkZSBjw7NkaWdvIGNvbSB1bSBvbGhhciBzb2JyZSBjw7NkaWdvcyBkZSBhbsOhbGlzZXMgZGUgZGFkb3MsIHN1YXMgdmFudGFnZW5zIGUgdGFtYsOpbSBmb3JtYXMgZGUgaW5jZW50aXZhciBlIGZvbWVudGFyIGVzdGEgcHLDoXRpY2EgZGVudHJvIGRvcyBncnVwb3MgZGUgcGVzcXVpc2EuDQoNCkdlcmFsbWVudGUsIHZhbW9zIHJldmlzYXIgdW0gcmVwb3NpdMOzcmlvL2PDs2RpZ28gcXVlIGVzdMOhIGFzc29jaWFkbyBhIHVtYSBwdWJsaWNhw6fDo28gY2llbnTDrWZpY2EsIG91IHF1ZSBwZWxvIG1lbm9zLCB2b2PDqiBjb25oZWNlIG8gcHJvamV0byBlIHRlbSBtYWlzIGluZm9ybWHDp8O1ZXMgc29icmUuIExvZ28sIGVzdGEgaWRlaWEgZGUgcmV2aXPDo28gZGUgcmVwb3NpdMOzcmlvIHRlbSBhbGd1bWFzIGRpZmVyZW7Dp2FzIGRvcyBwYWRyw7VlcyBmb3JtYWlzIGRlIHJldmlzw6NvIGRlIGPDs2RpZ28gcGFyYSBkZXNlbnZvbHZlZG9yZXMgZSBvdXRyb3MgcHJvZmlzc2lvbmFpcyBkYSDDoXJlYSBkZSBwcm9ncmFtYcOnw6NvLg0KDQojIyBQb3IgcXVlIGZhemVyIHJldmlzw6NvIGRlIGPDs2RpZ28/DQoNCi0gICBQUk9CTEVNQToNCg0KICAgIC0gICBDw7NkaWdvcyBlIGFuw6FsaXNlcyBlc3TDo28gc2UgdG9ybmFuZG8gY2FkYSB2ZXogbWFpcyBjb21wbGljYWRvcyBlIGNvbXBsZXhvcyBuYSBjacOqbmNpYSwgcHJpbmNpcGFsbWVudGUgZWNvbG9naWEgW0B0b3VjaG9uMjAxNl0NCiAgICAtICAgUmV2aXPDo28gZGUgY8OzZGlnbyDDqSBwcmF0aWNhbWVudGUgaW5leGlzdGVudGUgbmEgbWFpb3JpYSBkb3MgdHJhYmFsaG9zIHB1YmxpY2Fkb3MgZW0gZWNvbG9naWEgaG9qZSBlbSBkaWEuDQoNCi0gICBDT05TRVFVw4pOQ0lBOg0KDQogICAgLSAgIE11aXRhcyByZXRyYXRhw6fDtWVzIGRlIGFydGlnb3MgZGUgYWx0byBpbXBhY3RvIHBvciBlcnJvcyBlbSBjw7NkaWdvIHF1ZSBtdWRhbSByZXN1bHRhZG9zIGUgY29uY2x1c8O1ZXMNCg0KLSAgIFNPTFXDh8ODTzoNCg0KICAgIC0gICBNdWRhbsOnYXMgY3VsdHVyYWlzIHBhcmEgdHJhemVyIGEgcmV2aXPDo28gZGUgY8OzZGlnbyBlbSB0b2RvcyBvcyBlc3TDoWdpbyBkYSBwZXNxdWlzYS4NCiAgICANCi0gSU1QRURJTUVOVE86DQoNCiAgICAtICAgUG91Y29zIChvdSBuZW5odW0pIGluY2VudGl2b3MgcGFyYSBhIHJlYWxpemHDp8OjbyBkZSByZXZpc8OjbyBkZSBjw7NkaWdvcy4NCg0KVmFudGFnZW5zIGRhIHJldmlzw6NvIGRvIHNldSBjw7NkaWdvIGRlIGFuw6FsaXNlIFtAbGVlQ29kZVJldmlld0FueGlldHkyMDI0XToNCg0KLSAgIEF1bWVudGFyIHF1YWxpZGFkZSBkbyBjw7NkaWdvOg0KDQogICAgLSAgIENsYXJlemENCiAgICAtICAgRG9jdW1lbnRhw6fDo28NCiAgICAtICAgRGV0ZWPDp8OjbyBkZSBlcnJvcw0KDQotICAgQXVtZW50YXIgYmVuZWbDrWNpb3Mgc29jaW9jb2duaXRpdm9zIGRhIGVxdWlwZS9ncnVwby9sYWJvcmF0w7NyaW8gYSBsb25nbyBwcmF6bzoNCg0KICAgIC0gICBUcmFuc2ZlcsOqbmNpYSBkZSBjb25oZWNpbWVudG9zIGUgYXByZW5kaXphZG8NCiAgICAtICAgU29sdcOnw7VlcyBjcmlhdGl2YXMgZSBjb2xhYm9yYXRpdmFzIGRlIHByb2JsZW1hcw0KICAgIC0gICBDb25maWFuw6dhDQogICAgLSAgIEZvcm1hw6fDo28gZGUgY29tdW5pZGFkZQ0KICAgIC0gICBBcHJlbmRpemFkbyBuw6NvIHPDsyBhdHJhdsOpcyBkZSBjb250ZcO6ZG8sIG1hcyB0YW1iw6ltIGNvbSBmZWVkYmFja3MgY29uc3RydXRpdm9zDQoNCi0gICBUcmF6ZXIgbXVkYW7Dp2EgbmEgY3VsdHVyYSBkYSBwZXNxdWlzYSENCg0KQGN1bGluYUxvd0F2YWlsYWJpbGl0eUNvZGUyMDIwIG1vc3RyYXJhbSBxdWUgNzUlIGRhcyByZXZpc3RhcyBlbSBFY29sb2dpYSBlIEV2b2x1w6fDo28gY29udMOpbSBwb2zDrXRpY2FzIG9icmlnYXTDs3JpYXMgZGUgY29tcGFydGlsaGFtZW50byBkZSBjw7NkaWdvIGUgZGFkb3MsIGFwZXNhciBkZSBxdWUgYXMgcG9sw610aWNhcyBkZSBjb21wYXJ0aWxoYW1lbnRvIGRlIGPDs2RpZ28gbsOjbyBzZXJlbSBzZWd1aWRhcyBwZWxhIG1haW9yaWEgZG9zIGF1dG9yZXMgKDI3JSBkb3MgYXJ0aWdvcykuDQoNClF1YW5kbyByZWFsaXphciBhIHJldmlzw6NvIGRvIGPDs2RpZ28vcmVwb3NpdMOzcmlvIGRlIGFuw6FsaXNlPw0KDQotICAgUHLDqS1wdWJsaWNhw6fDo28NCg0KICAgIC0gICBSZXZpc8OjbyBmZWl0YSBwb3IgY29sZWdhcywgY29sYWJvcmFkb3Jlcywgb3JpZW50YWRvcmVzLg0KDQotICAgRHVyYW50ZSBwdWJsaWNhw6fDo28gLyBzdWJtaXNzw6NvDQoNCiAgICAtICAgUmV2aXPDo28gZm9ybWFsIGRvIGPDs2RpZ28ganVudG8gY29tIG8gYXJ0aWdvIHN1Ym1ldGlkbw0KDQotICAgUMOzcy1wdWJsaWNhw6fDo28NCg0KICAgIC0gICBSZXZpc2FyIGPDs2RpZ28gZW0gYXJ0aWdvcyBqw6EgcHVibGljYWRvcy4gRXN0YSByZXZpc8OjbyBwb2RlIHNlciBmZWl0YSBkaXJldG8gbm8gR2l0SHViIHZpYSBJc3N1ZSBvdSBQdWxsIFJlcXVlc3Qgb3UgbWVzbW8gY29udGFjdGFuZG8gaW5pY2lhbG1lbnRlIG9zIGF1dG9yZXMgKGUgdGFsdmV6IGVkaXRvcmVzIGRhIHJldmlzdGEgb25kZSBvIHRyYWJhbGhvIGZvaSBwdWJsaWNhZG8pDQoNCiMjIERpY2FzIHBhcmEgYXV0b3Jlcw0KDQpBanVkZSBvIHJldmlzb3IgYSB0ZSBhanVkYXIhDQoNCiMjIyBQb3IgcXVlIGVzY3JldmVyIHVtIGPDs2RpZ28gYm9uaXRvPw0KDQpNZXNtbyBxdWUgbyBjw7NkaWdvIHNlamEgZXhlY3V0YWRvIHBvciBtw6FxdWluYSwgZWxlIHRhbWLDqW0gdmFpIHNlciBsaWRvIHBvciBodW1hbm9zISBDbGFyZXphLCBsaW1wZXphLCBlc3TDqXRpY2EgY29uc2lzdGVudGUgdsOjbyB0b3JuYXIgYSBsZWl0dXJhIG1haXMgZsOhY2lsIGUgdGFtYsOpbSBtYWlzICJiYXJhdG8iIGRlIHNlIGZhemVyIG91IHByb3BvciBtb2RpZmljYcOnw7Vlcy4NCg0KRXUgYWNyZWRpdG8gbmEgY3JpYcOnw6NvIGRvIGjDoWJpdG8gZGUgZXNjcmV2ZXIgZGVzZGUgbyBpbsOtY2lvIGPDs2RpZ29zIHNlbXByZSBwZW5zbmFkbyBxdWUgYWxndcOpbSAodW0gZXN0cmFuaG8gb3UgbWVzbW8gdm9jw6ogbm8gZnV0dXJvKSB2YWkgcmV2aXPDoS1sby4gUmVzaXN0YSDDoCB0ZW50YcOnw6NvIGRlIGFjaGFyIHF1ZSB2YWkgb3JnYW5pemFyIG8gY8OzZGlnbyBkZXBvaXMgcXVlIGZpemVyIHRvZGFzIGFzIGFuw6FsaXNlcyEgUG9yIGlzc28gYSBpbXBvcnTDom5jaWEgZGUgc2UgaW5jb3Jwb3JhciBow6FiaXRvcyBlIGRpY2FzIHBhcmEgZXNjcml0YSBkZSBjw7NkaWdvIGJvbml0bywgbGltcG8gZSBvcmdhbml6YWRvLg0KDQoqKkVzdGlsbyBkZSBjw7NkaWdvKiogw6kgdW0gY29uanVudG8gZGUgcmVncmFzIHNvYnJlIHNvYnJlIGVzdMOpdGljYSAoYWxpbmhhbWVudG8gZSBlc3Bhw6dhbWVudG8gZG8gY8OzZGlnbyksIG5vbWVuY2xhdHVyYSAoZGUgdmFyacOhdmVpcywgZnVuw6fDtWVzIGV0Yy4pLCBjb21lbnTDoXJpb3MsIGVzdHJ1dHVyYcOnw6NvIChwb3IgZXhlbXBsbywgZXZpdGFyIGzDs2dpY2EgY29tcGxleGEpIGV0Yy4gRXNzYXMgcmVncmFzIGFqdWRhbSBhIG1lbGhvcmFyIGEgY2xhcmV6YSBkbyBjw7NkaWdvIGUgYSBjb2xhYm9yYcOnw6NvLg0KDQpBbyBsb25nbyBkYSBlc2NyaXRhIGRvIGPDs2RpZ28sIMOpIHNhdWTDoXZlbCBmYXplciB1bWEgcGF1c2EgZGUgdmV6IGVtIHF1YW5kbyBlIHJldmlzYXIgbyBlc3RpbG8gZGUgZXNjcml0YSBlIG8gcGFkcsOjbyBkZSBvcmdhbml6YcOnw6NvIHF1ZSB2b2PDqiBhZG90b3Ugbm8gaW7DrWNpbyBlIHZlciBzZSB2b2PDqiBtYW50ZXZlIG91IG7Do28gYSBjb25zaXN0w6puY2lhIGFvIGxvbmdvIGRvIHRlbXBvLiDDiSBtdWl0byBmw6FjaWwgY29tZcOnYXIgYWRvdGFudG8gdW1hIHBhZHJvbml6YcOnw6NvIGUgdGVybWluYXIgY29tIG91dHJhIGRpZmVyZW50ZSwgcHJpbmNpcGFsbWVudGUgc2UgbyBjw7NkaWdvIGVzdMOhIHNlbmRvIGVzY3JpdG8gYW8gbG9uZ28gZGUgbWVzZXMuIE1hcyBleGlzdGVtIGZlcnJhbWVudGFzIHBhcmEgZmF6ZXIgaXNzbyBkZSBmb3JtYSBtYWlzIGF1dG9tYXRpemFkYSBlIHLDoXBpZGEhDQoNCkV4aXN0ZW0gdsOhcmlvcyBlc3RpbG9zIGRlIGVzY3JpdGEgZGUgY8OzZGlnbywgZSB2w6FyaWFzIGRpY2FzIHBvciBhw60gcGFyYSBzZWd1aXIgb3UgYWRhcHRhciBhbyBzZXUgZ29zdG8uIEFsZ3VucyBkb3MgbWFpcyB1c2Fkb3Mgc8OjbyBvIGVzdGlsbyBkZSBlc2NyaXRhIGRvIFt0aWR5dmVyc2VdKGh0dHBzOi8vc3R5bGUudGlkeXZlcnNlLm9yZy8pLCBxdWUgdGVtIG8gcGFjb3RlIFIgW2BzdHlsZXJgXShodHRwczovL3N0eWxlci5yLWxpYi5vcmcvKSBxdWUgcG9kZSBhanVzdGFyIHNldSBjw7NkaWdvIGFvIGVzdGlsbyB1c2FuZG8gdW0gYWRkaW4gZG8gUnN0dWRpby4NCg0KWyFbU3R5bGVyIC0gcGFjb3RlIFIgcXVlIGFqdXN0YSBzZXUgY8OzZGlnbyBhbyBlc3RpbG8gdHlkdmVyc2VdKGZpZ3Mvc3R5bGVyX2xvZ28ucG5nKXt3aWR0aD0iMTAwIn1dKGh0dHBzOi8vc3R5bGVyLnItbGliLm9yZy8pDQoNCk91dHJvIHBhY290ZSwgYWzDqW0gZG8gYHN0eWxlcmAgcXVlIGFqdWRhIGEgcGFkcm9uaXphciB1bSBhcnF1aXZvIG8gcGVkYcOnbyBkZSBjw7NkaWdvIGEgdW0gZXN0aWxvIMOpIG8gW2Bmb3JtYXRSYF0oaHR0cHM6Ly95aWh1aS5vcmcvZm9ybWF0ci8pLg0KDQpPIHBhY290ZSBgbGludHJgIMOpIG11aXRvIMO6dGlsIHBhcmEgdmVyaWZpY2FyIG8gY8OzZGlnbyBxdWFudG8gYW8gZXN0aWxvLCBlcnJvcyBkZSBzaW5zdGF4ZSBlIHNlbcOibnRpY2EsIG1hcyBuw6NvIHZhaSBtb2RpZmljYXIgbyBhcnF1aXZvIHBvciB2b2PDqi4gRWxlIGZheiB1bSByZWxhdMOzcmlvIGRlIGNvbnNpc3TDqm5jaWEgZG8gY8OzZGlnbw0KDQpWZWphIGFsZ3VtYXMgZGljYXMgYmVlbSBnZXJhaXMgW25lc3NlXShodHRwczovL3JvcGVuc2NpLm9yZy9ibG9nLzIwMjQvMDIvMjIvYmVhdXRpZnVsLWNvZGUvKSBlIFtuZXNzZV0oaHR0cHM6Ly9ibG9nLnItaHViLmlvLzIwMjIvMDMvMjEvY29kZS1zdHlsZS8pIHJvdGVpcm8gcGFyYSBwZW5zYXIgZSBhdmFsaWFyIHF1YWwgZXN0aWxvIGRlIGPDs2RpZ28gdm9jw6ogcHJlZmVyZSBzZWd1aXIgb3UgY3JpYXIhDQoNCmBgYGB7PWh0bWx9DQo8IS0tIGNvbnRlw7pkbyBleHRyYSBxdWUgbsOjbyB2YWkgZW50cmFyIG5lc3NhIGVkacOnw6NvIHBvciBlc3RhciBpbmNvbXBsZXRvDQoNCi0gKipFc3Bhw6dhbWVudG8gZW50cmUgZWxlbWVudG9zKio6IMOpIHNlbXByZSBib20gZGVpeGFyIGVzcGHDp28gZW50cmUgb3MgZWxlbWVudG9zIHBhcmEgZmFjaWxpdGFyIGEgbGVpdHVyYSBodW1hbmEuIENvbXBhcmUgb3Mgc2VndWludGVzIGPDs2RpZ29zDQoNCmBgYHtyLCBldmFsPUZ9DQpzdGFyd2FycyU+JQ0KICBzZWxlY3QobmFtZSxoZWlnaHQsIG1hc3MsaG9tZXdvcmxkKSAlPiUNCiAgbXV0YXRlKA0KICAgIG1hc3M9TlVMTCwNCiAgICBoZWlnaHQgPWhlaWdodCAqMC4wMzI4MDg0ICMgY29udmVydCB0byBmZWV0DQogICkNCmBgYA0KDQpgYGB7ciwgZXZhbD1GfQ0Kc3RhcndhcnMgJT4lDQogIHNlbGVjdChuYW1lLCBoZWlnaHQsIG1hc3MsIGhvbWV3b3JsZCkgJT4lDQogIG11dGF0ZSgNCiAgICBtYXNzID0gTlVMTCwNCiAgICBoZWlnaHQgPSBoZWlnaHQgKiAwLjAzMjgwODQgIyBjb252ZXJ0IHRvIGZlZXQNCiAgKQ0KYGBgDQoNCk8gc2VndW5kbyBjaHVuayB0ZW0gZXNwYcOnYW1lbnRvIGNvbnNpc3RlbnRlIGVudHJlIG9zIGVsZW1lbnRvcyBkYSBmdW7Dp8OjbywgZW50cmUgc8OtbWJvbG9zIGRlIGA9YCBvdSBgJT4lYCAocGlwZSkuIFRhbWLDqW0gbm90YW1vcyB1bWEgcXVlYnJhIGRlIGxpbmhhIGVudHJlIG8gb2JqZXRvIGEgc2VyIG1vZGlmaWNhZG8gKGBzdGFyd2Fyc2ApIGUgYXMgZnVuw6fDtWVzIGEgc2VyZW0gYXBsaWNhZGFzIHNlcXVlbmNpYWxtZW50ZSAoYHNlbGVjdGAgZSBgbXV0YXRlYCkuDQoNClVtYSBvcMOnw6NvIHNlcmlhIGNvbG9jYXIgb3MgYXJndW1lbnRvcyBkZSBgbXV0YXRlYCBuYSBtZXNtYSBsaW5oYSwgasOhIHF1ZSB0b2RvcyBjYWJlbSBkZW50cm8gZG8gcXVlIGNvbnNpZGVyYW1vcyBlc3Bhw6dhbWVudG8gZGUgODAgY2FyYWN0ZXJlcyAoIjgwLWNvbHVtbnMiKSwgcXVlIMOpIHVtIHRpcG8gZGUgcGFkcm9uaXphw6fDo28gZW0gY8OzZGlnbyBleGlzdGVudGUgaMOhIG1haXMgZGUgODAgYW5vcyBjb21vIHVtIHBhZHLDo28gcGFyYSB0YW1hbmhvIGRlIGxpbmhhICh2ZWphIGVzc2EgW2Rpc2N1c3PDo28gbm8gU3RhY2tvdmVyZmxvd10oaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMTY2Nzk2MS9pcy10aGVyZS1hLXN0YW5kYXJkLWZvci1jb2RlLW1hcmdpbnMpKS4NCg0KYGBge3IsIGV2YWw9Rn0NCnN0YXJ3YXJzICU+JQ0KICBzZWxlY3QobmFtZSwgaGVpZ2h0LCBtYXNzLCBob21ld29ybGQpICU+JQ0KICBtdXRhdGUobWFzcyA9IE5VTEwsIGhlaWdodCA9IGhlaWdodCAqIDAuMDMyODA4NCkgIyBjb252ZXJ0IHRvIGZlZXQNCmBgYA0KDQoNCioqRElDQSoqOiBwYXJhIHVzYXIgZXNzZSBwYWRyw6NvIGRlIGxhcmd1cmEgZGUgbGluaGEgZGUgODAgY2FyYWN0ZXJlcyBubyBSc3R1ZGlvLCB2b2PDqiBwb2RlIGFkaWNpb25hciB1bWEgbGluaGEgZGUgdmlzdWFsaXphw6fDo28gcXVlIHZhaSB0ZSBndWlhciBhbyBlc2NyZXZlciBvIGPDs2RpZ28gaW5kbyBlbSBUb29scyA+IEdsb2JhbCBPcHRpb25zID4gQ29kZSA+IERpc3BsYXkuIEUgY2xpY2FuZG8gZW0gc2hvdyBtYXJnaW4gKG1hcmdpbiBjb2x1bW46IDgwKS4gDQoNCiFbXShmaWdzL21hcmdpbl9zZXR1cF9yc3R1ZGlvLnBuZykNCg0KU3VnaXJvIGRlaXhhciBhIGxhcmd1cmEgZGEgamFuZWxhIGRlIGPDs2RpZ28gbm8gUnN0dWRpbyBwcsOzeGltbyBkZXNzYSBtYXJjYSBwYXIgcXVlIHZvY8OqIHBvc3NhIHZpc3VhbGl6w6EtbGEgZSBzYWJlciBxdWFuZG8gcGFyYXIgZGUgZXNjcmV2ZXIgZW0gdW1hIGxpbmhhIGUgY29tZcOnYXIgYSBsaW5oYSBzZWd1aW50ZS4NCg0KIVtdKGZpZ3Mvc2NyaXB0XzgwLWNvbHVtbl9yc3R1ZGlvLnBuZykNCg0KDQoNCi0gKipJbmRlbnRhw6fDo28qKjogc2Ugdm9jw6ogcmVwYXJhciBubyBjw7NkaWdvIGFjaW1hLCB2YWkgdmVyIHF1ZSBleGlzdGUgdW0gZXNwYcOnbyBkZSAyIGNhcmFjdGVyZXMgY2FkYSB2ZXogcXVlIGZvaSBhZGljaW9uYWRvIHVtIG7DrXZlbCBoaWVyw6FycXVpY28gbm8gY8OzZGlnby4gTyBwYWRyw6NvIGRlIGluZGVudGHDp8OjbyBnZXJhbG1lbnRlIMOpIDIsIG1hcyBow6EgcXVlbSBjb2xvcXVlIG1haXMgcGFyYSBjb25zZWd1aXIgdmlzdWFsaXphciBhIGVzdHJ1dHVyYSBoaWVyw6FycXVpY2EgZG8gY8OzZGlnbyAobyBxdWUgZXN0w6EgZGVudHJvIGRvIHF1w6ogZSBxdWFsIGEgb3JkZW0gcXVlIHNlZ3VlbSBvcyBjb21hbmRvcykuIE91IHNlamEsIHBhcnRpbmRvIGRvIG9iamV0byBgc3RhcndhcnNgLCBxdWUgZXN0w6Egc296aW5obyBkZXN0YWNhZG8gbnVtYSBsaW5oYSAoaW5kaWNhbmRvIHF1ZSBlc3RlIMOpIG8gb2JqZXRvIHF1ZSB2YWlzIGVyIG1hbmlwdWxhZG8pLCBhcyBmdW7Dp8O1ZXMgcXVlIHbDo28gbW9kaWZpY2FyIG8gb2JqZXRvIGVzdMOjbyBpbmRlbnRhZGFzIG5hcyBsaW5oYXMgc2VndWludGVzIGUsIG5vIHByaW1laXJvIGUgc2VndW5kbyBjaHVuayB2ZW1vcyBxdWUgb3MgYXJndW1lbnRvcyBkYSBmdW7Dp8OjbyBgbXV0YXRlYCB0YW3DqW0gZXN0w6NvIGVtIGxpbmhhcyBzZXBhcmFzIGNvbSBtYWlzIHVtIG7DrXZlbCBkZSBpZGVudGHDp8Ojby4gDQpQYXJhIG1vZGlmaWNhciBvIHBhZHLDo28gZGUgaW5kZW50YcOnw6NvIG5vIFJzdHVkaW8gc2lnYSBbZXNzYSBkaWNhXShodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy82MTM3NjUyMC9yc3R1ZGlvLWNoYW5nZS1udW1iZXItb2Ytc3BhY2VzLWluLWEtdGFiKS4gDQoNCi0gKipzZXBhcmFuZG8gInBhcsOhZ3JhZm9zIiBkZSBjw7NkaWdvKio6IERhciBlc3Bhw6dvcyBlbnRyZSBsaW5oYXMgZGUgY8OzZGlnbyDDqSB1bWEgYm9hIGZvcm1hIGRlIG1lbGhvcmFyIGEgbGVpdHVyYSBlc3RldGljYW1lbnRlIHd1YW5kbyBzZSBxdWVyIHNlcGFyYXIgYmxvY29zIGRlIGPDs2RpZ28gcXVlIGNvcnJlc3BvbmRlbSBhICJpZGVpYXMiL2Z1bsOnw7VlcyBkaWZlcmVudGVzLg0KDQotLT4NCmBgYGANCg0KIyMjIENvbWVudGUvZG9jdW1lbnRlIHNldXMgcGFzc29zDQoNCkNvbWVudMOhcmlvcyBhbyBsb25nbyBkb3Mgc2NyaXB0cyBleHBsaWNhbmRvIHBvcnF1w6ogdm9jw6ogZXN0w6EgZmF6ZW5kbyBjZXJ0YXMgY29pc2FzIGFqdWRhIG11aXRvIGEgZ3VpYXIgbyByZXZpc29yL2xlaXRvciBhbyBsb25nbyBkbyBjw7NkaWdvLiBFc2NyZXZlciBjw7NkaWdvIGVtIFJtYXJrZG93biBlL291IFF1YXJ0byByZXNvbHZlIGVzc2EgbmVjZXNzaWRhZGUgZGUgZXhwbGljYXIgbyBwYXNzbyBhIHBhc3NvIGRhcyBhbsOhbGlzZXMsIHBvaXMgdm9jw6ogcG9kZSBzZXBhcmFyIGEgcGFydGUgZGUgZXhwbGljYcOnw6NvICh0ZXh0bykgZGEgcGFydGUgZGUgY8OzZGlnbyBbUm90ZWlybyBhcXVpXShodHRwczovL2dhYnJpZWxuYWthbXVyYS5naXRodWIuaW8vVVNQX3JlcHJvZHVjaWJpbGl0eV9CSUU1Nzk4L3JtYXJrZG93bi1iYXNpY3MuaHRtbCkuDQoNCkVtIGFycXVpdm9zIGAuUmAgdm9jw6ogcG9kZSB1c2FyIG8gYm9tIGUgdmVsaG8gXCMgcGFyYSBlc2NyZXZlciBjb21lbnTDoXJpb3MgYW8gbG9uZ28gZG8gY8OzZGlnby4gUG9yw6ltLCBhIGlkZWlhIGFxdWkgw6kgZGlmZXJlbnRlIGRlIHVtIGFycXVpdm8gLlJtZCBvdSAuUW1kLiBUZW5oYSBjdWlkYWRvIGNvbSBjb21lbnTDoXJpb3MgZGVtYWlzIHF1ZSBwb2RlbSBkaXN0cmFpciBvIHJldmlzb3IvbGVpdG9yIG91IHBvbHVpciBvIGPDs2RpZ28uIE5lc3RlIGNhc28sIG9zIGNvbWVudMOhcmlvcyBubyBjw7NkaWdvIGRldmVtIHNlciBwZXF1ZW5vcyBhbGVydGFzLiBRdWFudG8gbWFpcyBjb21lbnTDoXJpb3MgaG91dmVyLCBtYWlzIHByb3bDoXZlbCBzZXLDoSBxdWUgbyBsZWl0b3Igb3MgaWdub3JlLg0KDQpPcyBjb21lbnTDoXJpb3MgZGUgY8OzZGlnbyBuw6NvIGRldmVtIHNlciB1bSAiYmFuZC1haWQiIHBhcmEgbm9tZXMgcnVpbnMgb3UgY8OzZGlnbyBleGNlc3NpdmFtZW50ZSBjb21wbGV4bzogZW0gdmV6IGRlIGFkaWNpb25hciB1bSBjb21lbnTDoXJpbywgdm9jw6ogcG9kZSByZW5vbWVhciB1bWEgdmFyacOhdmVsIG91IHJlZmF0b3JhciB1bSB0cmVjaG8gZGUgY8OzZGlnbz8NCg0KQXNzaXN0YSBlc3NhIGJyaWxoYW50ZSBwYWxlc3RyYSBbIkNvZGUgc21lbGwgYW5kIGZlZWxzIl0oaHR0cHM6Ly93d3cueW91dHViZS5jb20vd2F0Y2g/dj03b3lpUEJqTEFXWSkgZGEgcmFpbmhhLCBKZW5ueSBCcnlhbiwgc29icmUgZXN0aWxvIGRlIGPDs2RpZ28hDQoNCiMjIERpY2FzIHBhcmEgcmV2aXNvcmVzDQoNCkxlbWJyZS1zZSBxdWUgaMOhIHbDoXJpYXMgZm9ybWFzIGRlIHNlIGFib3JkYXIgdW0gbWVzbW8gcHJvYmxlbWEsIG8gcmV2aXNvciBuw6NvIHByZWNpc2EgaW1wb3Igc3VhIGZvcm1hLiBFIGN1aWRhZG8gcGFyYSBuw6NvIGltcG9yIGVzdGlsbyBkZSBlc2NyaXRhISBNYXMgcG9kZSB2ZXJpZmljYXIgaW5jb25zaXN0w6puY2lhcyBxdWUgdmVuaGFtIGEgYXRyYXBhbGhhciBhIGxlaXR1cmEgZG8gY8OzZGlnby4NCg0KKipPIHF1ZSBkZXZlIHNlciBhdmFsaWFkbyBuYSByZXZpc8OjbyBkbyBjw7NkaWdvPyoqIFNlZ3VpbmRvIEBpdmltZXktY29va0ltcGxlbWVudGluZ0NvZGVSZXZpZXcyMDIzYSwgZXhpc3RlbSAzIHRpcG9zIGRlIGVycm9zIGVtIGPDs2RpZ286DQoNCi0gICAqKmNvbmNlaXR1YWwqKiDigJMgaW1wbGVtZW50YW5kbyBhIGZ1bsOnw6NvIG91IGFyZ3VtZW50byBlcnJhZG8NCg0KLSAgICoqcHJvZ3JhbcOhdGljbyoqIOKAkyBjaGFtYW5kbyBvIG9iamV0byBvdSBjb2x1bmEgZXJyYWRhDQoNCi0gICAqKnNpbnTDoXRpY28qKiDigJMgZ3JhZmlhIGluY29ycmV0YSBkZSB1bSBlc3RhZG8gb3UgZnVuw6fDo28NCg0KRSBlbGVzIHByb3DDtWVtIHVtYSBmb3JtYSBvcmdhbml6YWRhIGRlIHJldmlzYXIgbyBjw7NkaWdvIHNlZ3VpbmRvIDQgUnMgKGVtIGluZ2zDqnMpOg0KDQpbIVtPcyA0IFJzIHByaW5jaXBhaXMgcGFyYSByZXZpc8OjbyBkZSBjw7NkaWdvXShmaWdzL2NvZGUtcmV2aWV3XzRSLnBuZyldKGh0dHBzOi8vZG9pLm9yZy8xMC4xMTExL2plYi4xNDIzMCkNCg0KLSAgIE8gY8OzZGlnbyBlc3TDoSBjb21vICoqUmVwb3J0YWRvKio/DQoNCiAgICAtICAgVmVyaWZpY2HDp8OjbyBkZSBjb25zaXN0w6puY2lhLlwNCiAgICAtICAgTcOpdG9kb3MgKG5vIHRleHRvIHByaW5jaXBhbCkgZSBjw7NkaWdvIGRldmVtIGNvaW5jaWRpci4NCiAgICAtICAgRXZpdGEgKiplcnJvcyBjb25jZWl0dWFpcyoqLCBjb21vIHBvciBleGVtcGxvLCByZXBvcnRhciBxdWUgZmV6IHVtIG1vZGVsbyBsaW5lYXIgY29tIGRpc3RyaWJ1acOnw6NvIGRlIFBvc3Npb24sIG1hcyBubyBjw7NkaWdvIGVzcXVlY2VyIGRlIGVzcGVjaWZpY2FyIG8gYXJndW1lbnRvIGZhbWlseT0iUG9pc3NvbiIgZW0gdW0gYGdsbSgpYC4NCg0KLSAgIE8gY8OzZGlnbyAqKlJvZGEqKj8NCg0KICAgIC0gICBFcnJvcyAqKnByb2dyYW3DoXRpY29zKiogZSAqKnNpbnTDoXRpY29zKiogcG9kZW0gZmF6ZXIgbyBjw7NkaWdvLCBvdSBwYXJ0ZXMgZGVsZSwgbsOjbyByb2Rhci4NCiAgICAtICAgUGFjb3RlcyBuw6NvIGluc3RhbGFkb3MgKGZvcmEgZG8gYW1iaWVudGUpIHRhbWLDqW0gb3UgdmVyc8OjbyBkaWZlcmVudGUgZG8gcmV2aXNvcjoNCiAgICAgICAgLSAgIFBhY290ZXMgcXVlIGFqdWRhbTogYHJlbnZgLCBgZ3JvdW5kaG9nYA0KICAgIC0gICBTb2x1w6fDo28gcGFyYSBvdXRwdXRzIGRlIGFuw6FsaXNlcyBxdWUgZGVtb3JhbSBtdWl0bzogc2FsdmFyIGFycXVpdm9zIGludGVybWVkacOhcmlvcyBwYXJhIGZhY2lsaXRhciByZXByb2R1dGliaWxpZGFkZSAoZS5nLiBleHRlbnPDo28gLnJkcykNCg0KLSAgIE8gY8OzZGlnbyDDqSAqKkNvbmZpw6F2ZWwqKiAoUmVsaWFibGUpPw0KDQogICAgLSAgIEVycm9zIGFpbmRhIHBvZGVtIHNlIHByb3BhZ2FyIG1lc21vIHF1ZSBvIGPDs2RpZ28gcm9kZSAocHJvZHV6aXIgcmVzdWx0YWRvIGluY29ycmV0byBtYXMgcmVwcm9kdXTDrXZlbCkNCiAgICAtICAgQ29uZmlhbsOnYSDDqSBleGFtaW5hciByZXN1bHRhZG9zIGludGVybWVkacOhcmlvcyBkbyBjw7NkaWdvIHBhcmEgZ2FyYW50aXIgcXVlIG7Do28gaMOhIGVycm9zDQogICAgLSAgIEVycm9zIGNvbmNlaXR1YWlzIG91IHByb2dyYW3DoXRpY29zDQogICAgICAgIC0gICBleDogY8OzZGlnbyBzZWxlY2lvbmEvbW9kaWZpY2EgYSBjb2x1bmEgZXJyYWRhDQogICAgICAgIC0gICBFc3NlIHRpcG8gZGUgZXJyb3MgKHF1ZSByb2RhbSwgbWFzIGVzdMOjbyBjb25jZWl0dWFsbWVudGUgZXJyYWRvcyBvdSBpbmRleGFkb3MgZXJyYWRvKSBlc2NhbG9uYW0gY29tIG8gbsO6bWVybyBkZSBsaW5oYXMgZSBjb21wbGV4aWRhZGUgZG8gY8OzZGlnbw0KDQotICAgT3MgcmVzdWx0YWRvcyBzw6NvICoqUmVwcm9kdXTDrXZlaXMqKj8NCg0KICAgIC0gICBHYXJhbnRpciBxdWUgb3MgcmVzdWx0YWRvcyBmaW5haXMsIHF1YW5kbyBvIGPDs2RpZ28gw6kgcm9kYWRvIG5vdmFtZW50ZSwgY29ycmVzcG9uZGFtIMOgcXVlbGVzIHJlcG9ydGFkb3MgbmEgYW7DoWxpc2UgZSByZXN1bHRhZG9zIGRvIHRleHRvIHByaW5jaXBhbC4NCiAgICAtICAgVG9sZXLDom5jaWEgY29tIGFuw6FsaXNlcyBxdWUgbGlkYW0gY29tIGVzdG9jYXN0aWNpZGFkZTogYHNldC5zZWVkKClgDQogICAgICAgIC0gICB0YW1iw6ltIGxldmFyIGVtIGNvbnRhIHF1YW50YXMgY2FzYXMgZGVjaW1hcyBlc3BlcmEtc2UgbyBtZXNtbyByZXN1bHRhZG8gKHByZWNpc8OjbykNCg0KQmFzZWFkbyBubyBjaGVja2xpc3QgZGUgcmV2aXPDo28gZGUgY8OzZGlnbyBjcmlhZG8gcG9yIEBpdmltZXktY29va0ltcGxlbWVudGluZ0NvZGVSZXZpZXcyMDIzYSwgbsOzcyBlbGFib3JhbW9zIHVtIGFycXVpdm8gZGUgdGV4dG8gcGFyYSBndWlhciByZXZpc29yZXMgZGUgY8OzZGlnbzoNCg0KYGBge3IsIGVjaG89Rn0NCmRvd25sb2FkdGhpczo6ZG93bmxvYWRfZmlsZSgNCiAgcGF0aCA9IGhlcmU6OmhlcmUoImRhdGEiLCAicmV2aXNhb19jb2RpZ29fY2hlY2tsaXN0LmRvY3giKSwNCiAgb3V0cHV0X25hbWUgPSAicmV2aXNhb19jb2RpZ29fY2hlY2tsaXN0IiwNCiAgYnV0dG9uX2xhYmVsID0gIkJhaXhhciBjaGVja2xpc3QiLA0KICBidXR0b25fdHlwZSA9ICJzdWNjZXNzIiwNCiAgaGFzX2ljb24gPSBUUlVFLA0KICBpY29uID0gImZhIGZhLXNhdmUiLA0KICBzZWxmX2NvbnRhaW5lZCA9IEZBTFNFDQopDQpgYGANCg0KIVtVbSBleGVtcGxvIGRlIGNoZWNrbGlzdCBwYXJhIHJldmlzw6NvIGRlIGPDs2RpZ28gKHRpcmFkbyBkZSBJdmltZXktQ29vayBldCBhbC4gMjAyMyldKGZpZ3MvY2hlY2tsaXN0X2NvZGUtcmV2aWV3LnBuZykNCg0KIyMgTW90aXZhw6fDo28gZmluYWwgcGFyYSByZXZpc8OjbyBkZSBjw7NkaWdvDQoNCi0gICBBanVkYSBhIGNyaWFyIHVtYSBjdWx0dXJhIGRlIHJldmlzw6NvIGRlIGPDs2RpZ28gZW50cmUgY29sZWdhcw0KDQogICAgLSAgIEVuY29yYWphIGNvbGFib3Jhw6fDtWVzDQogICAgLSAgIE5vcm1hbGl6YSBhIGV4aXN0w6puY2lhIGRlIGVycm9zDQoNCi0gICBJbmNlbnRpdm9zIHBhcmEgcmV2aXPDo286DQoNCiAgICAtICAgY28tYXV0b3JpYSwgYWdyYWRlY2ltZW50b3MsIGZ1dHVyYXMgY29sYWJvcmHDp8O1ZXPigKYNCg0KLSAgIENyaWUgdW0gZ3J1cG8gZGUgcmV2aXPDo28gZGUgY8OzZGlnbyEhDQoNCiAgICAtICAgbm8gbGFiDQogICAgLSAgIGVudHJlIGFtaWdvcy9jb2xlZ2FzDQoNCi0gICBFeGVtcGxvIFBlZXIgQ29kZSBSZXZpZXcgZ3JvdXAg4oCTIFNPUlRFRTogPGh0dHBzOi8vZ2l0aHViLmNvbS9TT1JURUUvcGVlci1jb2RlLXJldmlldy9pc3N1ZXMvOD4NCg0KIyMgUmVmZXLDqm5jaWFzDQo=