1 Introdução

Bancos de dados NoSQL se tornaram muito populares nos últimos anos. Grandes empresas dependem deles para guardar centenas de petabytes de memória e rodar milhões de queries por segundo. Mas o que é um banco de dados NoSQL? Como ele funciona e como ele “escala” tão melhor que um banco de dados relacional tradicional?

Para responder essa pergunta, vamos começar explicando rapidamente o problema com bancos de dados relacionais como MySQL, MariaDB, SQL Server e outros.

Esses são construídos para guardar dados relacionais o mais eficiente possível.

Você pode ter uma tabela para clientes, para pedidos, para produtos e ligar eles logicamente: clientes fazem pedidos e pedidos contém produtos. Essa forma enxuta é ótima para manusear seus dados, porém tem um grande custo: bancos de dados relacionais tem problemas com grandes volumes de dados. Eles precisam manter essas relações, e isto é um processo intenso, requerendo muita memória e poder computacional.

Por um período, você consegue atualizar o servidor de seu banco de dados, porém em algum momento, ele não vai ser capaz de aguentar a demanda. Em termos técnicos, dizemos que bancos de dados relacionais “escalam” verticalmente, mas não horizontalmente, onde banco de dados NoSQL podem “escalar” tanto verticalmente quanto horizontalmente.

Você pode comparar isso a um prédio: “escala” vertical signigica adicionar mais andares a um prédio existente, enquanto “escala” horizontal significa adicionar mais prédios. Intutitivamente, é compreensível que “escalagem” vertical é possível até certo ponto, enquanto “escalagem” horizontal é muito mais poderosa.

Mas, por que NoSQL “escalam” tão bem?

2 Entendendo NoSQL

Em primeiro lugar, eles lidam melhor com essas relações onerosas. Em NoSQL, cada item do banco de dados está por si próprio. Esta modificação simples significa que eles são basicamente itens chaves-valor e cada item no banco de dados possui apenas dois campos: uma chave e um valor.

Por exemplo: quando você quer guardar a informação de um produto, você pode usar o códico de barra do produto como a chave e o nome do produto como valor.

Isso parece restritivo, mas um valor pode ser algo como um documento JSON contendo mais dados, como preço e descrição. Esse design mais simples é a razão pela qual bancos de dados NoSQL “escalam” melhor. Se um único servidor de banco de dados não é suficiente para guardar todos seus dados ou rodar todas as queries, você pode dividir a demanda entre dois ou mais servidores. Cada servidor então será responsável por apenas uma parte do seu banco de dados. Um exemplo, a Apple roda um banco de dados NoSQL que consiste em 75000 servidores.

Em termos NoSQL, essas partes do teu banco de dados são chamados de partições, e isso nos trás uma questão: se teu banco de dados está divido em potencialmente milhares de partições, como você sabe onde um item está salvo?

Nesse momento que a chave primária entra em ação.

Lembre-se, bancos de dados NoSQL são itens chave-valor, e a chave determina em qual partição um item estará salvo.

Atrás das cortinas, bancos de dados NoSQL usam “hash function” para converter a chave primária de cada item em um número que fica fixo numa série, por exemplo, entre 0 e 100. Esse “hash value” e a série são usados para determinar onde salvar um item. Se teu banco de daods é pequeno ou não têm muitas requisições, você pode colocar tudo num único servidor. Ele sozinho será responsável por toda a série.

Se esse servidor ficar sobrecarregado, você pode adicionar um segundo servidor, o que significa que a série será dividida pela metade. O servidor 1 será responsável pelos itens com uma “hash” entre 0 e 50, enquanto o servidor 2 salvará tudo entre 50 e 100. Teoricamente, você dobrou a capacidade do teu banco de dados: tanto em termos de capacidade quanto em quantidade de queries que você pode executar.

Essa série também é chamada de “keyspace”.

É um sistema simples que resolve dois problemas: onde gravar itens novos e onde encontrar os existentes. Nesse novo exemplo, a série de 0 a 100 é um pouco pequena. Isso permitiria que você dividisse seu banco de dados em no máximo 100 partições. Dessa forma, bancos de dados NoSQL reais tem “keyspaces” muito maiores, permitindo o “escalonamento” quase que sem restrições.

Além de grande “escalabilidade”, NoSQL não possuem esquemas, o que significa que itens no banco de dados não precisam ter a mesma estrutura. Cada um pode ser completamente diferente. Num banco de dados relacional, você tem que definir a estrutura de sua tabela, e cada item deve respeitar essa estrutura. Mudar essa estrutura não é fácil e pode levar à perda de dados. Não ter um esquema pré-determinado pode ser uma grande vantagem se a tua aplicação e estrutura de dados está constantemente evoluindo. Neste ponto, é claro que bancos de dados NoSQL tem certas vantagens em relacão à bancos de dados relacionais.

Mas isso não quer dizer que bancos de dados relacionais são obsoletos, longe disso. NoSQL é mais limitado na forma como você recupera seus dados, apenas permitindo que você pesquise por itens através de sua chave primária. Achar pedidos através de sua ID não é problema, porém achar todos os pedidos acima de certa quantidade pode ser ineficiente. Bancos de dados relacionais, por outro lado, tem pouco problema com isto. Existem formas de burlar este problema, porém apenas se você sabe como acessar seus dados e isso pode não ser sempre o caso.

Outro ponto negativo é que bancos de dados NoSQL possuem consistência eventual. Quando você escreve um novo item no banco de dados e tenta lê-lo diretamente, ele pode não retornar. Como explicado anteriormente, NoSQL divide o seu banco de dados em partições, porém cada partição é espelhada através de diversos servidores. Dessa forma, um servidor pode cair sem muito impacto. Quando você escreve um novo item no seu banco de dados, uma dessas cópias vai salvar o novo item e copiar à outras partições em segundo plano e esse processo leva certo tempo. Então quando você requisitar um item, o banco de dados NoSQL pode tentar ler de uma cópia que ainda não salvou este item nela. Na prática este não é um problema grande pois dados são replicados em apenas alguns milisegundos e se vocês busca consistência, a maioria dos bancos de dados NoSQL possuem essa opção.

Assim, em resumo, tanto bancos de dados NoSQL e bancos de dados relacionais estarão presentes no mercado por um bom tempo. Cada um tem seus pontos fortes e pontos fracos.

Agora sabemos como funciona NoSQL, vamos olhar alguns exemplos.

3 Exemplos

3.1 Cloud Services

Servidores em nuvem promovem de forma pesada o uso de NoSQL porque eles podem “escalar” mais facilmente. A Amazon possui o DynamoDB, o Google Cloud possui o BigTable e o Microsoft Azure possui o CosmosDB. Para dar um exemplo de “escalabilidade”: durante o Amazon Prime Day de 2019, o banco de dados NoSQL da Amazon chegou suportar 45 milhões de pedidos por segundo!

3.1.1 DynamoDB

Serviço oferecido pela Amazon.com como parte do portfólio da Amazon Web Services. DynamoDB usa replicação síncrona através de diversos data centers para ter alta durabilidade e disponibilidade.

Para mais informações:

3.1.2 BigTable:

Sistema de armazenamento de dados de alta performance do Google que começou a ser desenvolvido em 2004 e hoje é utilizado em inúmeras aplicações da empresa como indexador online, Google Maps, Google Earth, Youtube, Gmail entre outros serviçoes oferecidos.

Para mais informações:

3.1.3 CosmosDB:

De propriedade da Microsoft e distribuído globalmente, este serviço de database multi-model “para gerenciamento de dados em escala planetária” foi lançado em 2017. Ele é esquema-agnóstico, com escalamento horizontal e classificado como um banco de dados NoSQL.

Para mais informações:

3.2 Self Hosted

Porém você também pode rodar bancos de dados NoSQL no seu próprio computador com softwares como Cassandra (desenvolvido pelo Facebook), Scylla, CouchDB, MongoDB, entre outros.

3.2.1 Cassandra:

Criado por Avinash Lakshman, um dos criadores do Dynamo da Amazon e Prashant Malik foi inicialmente desenvolvido dentro do Facebook como ferramenta para o auxílio da ferramenta de pesquisa do site. Após, foi liberado como um projeto de código aberto e desde 2009 faz parte do projeto Apache Incubator. Cassandra é um sistema de manuseio de banco de dados NoSQL, livre e de código aberto projetado para suportar grandes quantidades de dados através de diversos servidores, fornecendo alta disponibilidade e sem falhas.

Para mais informações:

3.2.2 Scylla:

É um sistema de código livre desenhado para ser compatível com o Apache Cassandra, mesmo tendo desempenho mais robusto. Ele roda os mesmos protocolos que o Cassandra e do DynamoDB, entretanto sua implementação foi feita usando C++20 ao invés de Java do Cassandra. Scylla foi projetado para utilizar escalonamento horizontal em cada nó, de forma que cada núcleo de CPU é responsável por diferentes subconjuntos de dados. Esses núcleos não compartilham os mesmos dados, porém se comunicam entre si explicitamente apenas quando é necessário. Os autores do sistema afirmam que esse design diferente permite ao Scylla ser 10 vezes mais veloz que o Cassandra.

Para mais informações:

3.2.3 CouchDB:

É um sistema de código aberto implementado na linguagem de programação Erlang, utiliza JSON para guardar os dados e queries de JavaScript para o manuseio dos mesmos. Foi lançado em 2005 e hoje também faz parte do projeto Apache.

Para mais informações:

3.2.4 MongoDB:

Imagina se um bolsista já fez um markdown sobre esse assunto?

( ͡° ͜ʖ ͡°)

4 Considerações finais

Antes de terminar este texto, vamos falar rapidamente do nome “NoSQL”. Isso é um pouco confuso e pode ser interpretado de duas formas. Primeiro, “NoSQL” pode significar “not only SQL” (não apenas SQL), direcionado ao fato que alguns bancos de dados NoSQL entendem parcialmente as queries de linguagem SQL, além de suas próprias capacidades. Em segundo lugar, é chamado de “NoSQL” no sentido de “non-relational” (não relacional) porque ele não pode salvar dados relacionais facilmente.

Eras isso!

Texto traduzido de: How do NoSQL databases work? Simply Explained!

LS0tDQp0aXRsZTogIkNvbW8gRnVuY2lvbmFtIEJhbmNvcyBkZSBEYWRvcyBOb1NRTCINCmF1dGhvcjogIkx1aXogWmFuZWxsYSBlIFRhaWFuZSBQcmFzcyINCmRhdGU6ICIyOC8wMS8yMDIyIg0Kb3V0cHV0Og0KICBodG1sX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiA2DQogICAgbnVtYmVyX3NlY3Rpb25zOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIHRoZW1lOiBmbGF0bHkNCiAgICBjb2RlX2Rvd25sb2FkOiB5ZXMNCiAgcGRmX2RvY3VtZW50Og0KICAgIHRvYzogeWVzDQogICAgdG9jX2RlcHRoOiAnNicNCi0tLQ0KDQojIEludHJvZHXDp8Ojbw0KDQpCYW5jb3MgZGUgZGFkb3MgTm9TUUwgc2UgdG9ybmFyYW0gbXVpdG8gcG9wdWxhcmVzIG5vcyDDumx0aW1vcyBhbm9zLiBHcmFuZGVzIGVtcHJlc2FzIGRlcGVuZGVtIGRlbGVzIHBhcmEgZ3VhcmRhciBjZW50ZW5hcyBkZSBwZXRhYnl0ZXMgZGUgbWVtw7NyaWEgZSByb2RhciBtaWxow7VlcyBkZSBxdWVyaWVzIHBvciBzZWd1bmRvLiBNYXMgbyBxdWUgw6kgdW0gYmFuY28gZGUgZGFkb3MgTm9TUUw/IENvbW8gZWxlIGZ1bmNpb25hIGUgY29tbyBlbGUgImVzY2FsYSIgdMOjbyBtZWxob3IgcXVlIHVtIGJhbmNvIGRlIGRhZG9zIHJlbGFjaW9uYWwgdHJhZGljaW9uYWw/DQoNClBhcmEgcmVzcG9uZGVyIGVzc2EgcGVyZ3VudGEsIHZhbW9zIGNvbWXDp2FyIGV4cGxpY2FuZG8gcmFwaWRhbWVudGUgbyBwcm9ibGVtYSBjb20gYmFuY29zIGRlIGRhZG9zIHJlbGFjaW9uYWlzIGNvbW8gTXlTUUwsIE1hcmlhREIsIFNRTCBTZXJ2ZXIgZSBvdXRyb3MuDQoNCkVzc2VzIHPDo28gY29uc3RydcOtZG9zIHBhcmEgZ3VhcmRhciBkYWRvcyByZWxhY2lvbmFpcyBvIG1haXMgZWZpY2llbnRlIHBvc3PDrXZlbC4NCg0KVm9jw6ogcG9kZSB0ZXIgdW1hIHRhYmVsYSBwYXJhIGNsaWVudGVzLCBwYXJhIHBlZGlkb3MsIHBhcmEgcHJvZHV0b3MgZSBsaWdhciBlbGVzIGxvZ2ljYW1lbnRlOiBjbGllbnRlcyBmYXplbSBwZWRpZG9zIGUgcGVkaWRvcyBjb250w6ltIHByb2R1dG9zLiBFc3NhIGZvcm1hIGVueHV0YSDDqSDDs3RpbWEgcGFyYSBtYW51c2VhciBzZXVzIGRhZG9zLCBwb3LDqW0gdGVtIHVtIGdyYW5kZSBjdXN0bzogYmFuY29zIGRlIGRhZG9zIHJlbGFjaW9uYWlzIHRlbSBwcm9ibGVtYXMgY29tIGdyYW5kZXMgdm9sdW1lcyBkZSBkYWRvcy4gRWxlcyBwcmVjaXNhbSBtYW50ZXIgZXNzYXMgcmVsYcOnw7VlcywgZSBpc3RvIMOpIHVtIHByb2Nlc3NvIGludGVuc28sIHJlcXVlcmVuZG8gbXVpdGEgbWVtw7NyaWEgZSBwb2RlciBjb21wdXRhY2lvbmFsLg0KDQpQb3IgdW0gcGVyw61vZG8sIHZvY8OqIGNvbnNlZ3VlIGF0dWFsaXphciBvIHNlcnZpZG9yIGRlIHNldSBiYW5jbyBkZSBkYWRvcywgcG9yw6ltIGVtIGFsZ3VtIG1vbWVudG8sIGVsZSBuw6NvIHZhaSBzZXIgY2FwYXogZGUgYWd1ZW50YXIgYSBkZW1hbmRhLiBFbSB0ZXJtb3MgdMOpY25pY29zLCBkaXplbW9zIHF1ZSBiYW5jb3MgZGUgZGFkb3MgcmVsYWNpb25haXMgImVzY2FsYW0iIHZlcnRpY2FsbWVudGUsIG1hcyBuw6NvIGhvcml6b250YWxtZW50ZSwgb25kZSBiYW5jbyBkZSBkYWRvcyBOb1NRTCBwb2RlbSAiZXNjYWxhciIgdGFudG8gdmVydGljYWxtZW50ZSBxdWFudG8gaG9yaXpvbnRhbG1lbnRlLg0KDQpWb2PDqiBwb2RlIGNvbXBhcmFyIGlzc28gYSB1bSBwcsOpZGlvOiAiZXNjYWxhIiB2ZXJ0aWNhbCBzaWduaWdpY2EgYWRpY2lvbmFyIG1haXMgYW5kYXJlcyBhIHVtIHByw6lkaW8gZXhpc3RlbnRlLCBlbnF1YW50byAiZXNjYWxhIiBob3Jpem9udGFsIHNpZ25pZmljYSBhZGljaW9uYXIgbWFpcyBwcsOpZGlvcy4gSW50dXRpdGl2YW1lbnRlLCDDqSBjb21wcmVlbnPDrXZlbCBxdWUgImVzY2FsYWdlbSIgdmVydGljYWwgw6kgcG9zc8OtdmVsIGF0w6kgY2VydG8gcG9udG8sIGVucXVhbnRvICJlc2NhbGFnZW0iIGhvcml6b250YWwgw6kgbXVpdG8gbWFpcyBwb2Rlcm9zYS4NCg0KTWFzLCBwb3IgcXVlIE5vU1FMICJlc2NhbGFtIiB0w6NvIGJlbT8NCg0KDQojIEVudGVuZGVuZG8gTm9TUUwNCg0KRW0gcHJpbWVpcm8gbHVnYXIsIGVsZXMgbGlkYW0gbWVsaG9yIGNvbSBlc3NhcyByZWxhw6fDtWVzIG9uZXJvc2FzLiBFbSBOb1NRTCwgY2FkYSBpdGVtIGRvIGJhbmNvIGRlIGRhZG9zIGVzdMOhIHBvciBzaSBwcsOzcHJpby4gRXN0YSBtb2RpZmljYcOnw6NvIHNpbXBsZXMgc2lnbmlmaWNhIHF1ZSBlbGVzIHPDo28gYmFzaWNhbWVudGUgaXRlbnMgIGNoYXZlcy12YWxvciBlIGNhZGEgaXRlbSBubyBiYW5jbyBkZSBkYWRvcyBwb3NzdWkgYXBlbmFzIGRvaXMgY2FtcG9zOiB1bWEgY2hhdmUgZSB1bSB2YWxvci4NCg0KUG9yIGV4ZW1wbG86IHF1YW5kbyB2b2PDqiBxdWVyIGd1YXJkYXIgYSBpbmZvcm1hw6fDo28gZGUgdW0gcHJvZHV0bywgdm9jw6ogcG9kZSB1c2FyIG8gY8OzZGljbyBkZSBiYXJyYSBkbyBwcm9kdXRvIGNvbW8gYSBjaGF2ZSBlIG8gbm9tZSBkbyBwcm9kdXRvIGNvbW8gdmFsb3IuDQoNCklzc28gcGFyZWNlIHJlc3RyaXRpdm8sIG1hcyB1bSB2YWxvciBwb2RlIHNlciBhbGdvIGNvbW8gdW0gZG9jdW1lbnRvIEpTT04gY29udGVuZG8gbWFpcyBkYWRvcywgY29tbyBwcmXDp28gZSBkZXNjcmnDp8Ojby4gRXNzZSBkZXNpZ24gbWFpcyBzaW1wbGVzIMOpIGEgcmF6w6NvIHBlbGEgcXVhbCBiYW5jb3MgZGUgZGFkb3MgTm9TUUwgImVzY2FsYW0iIG1lbGhvci4gU2UgdW0gw7puaWNvIHNlcnZpZG9yIGRlIGJhbmNvIGRlIGRhZG9zIG7Do28gw6kgc3VmaWNpZW50ZSBwYXJhIGd1YXJkYXIgdG9kb3Mgc2V1cyBkYWRvcyBvdSByb2RhciB0b2RhcyBhcyBxdWVyaWVzLCB2b2PDqiBwb2RlIGRpdmlkaXIgYSBkZW1hbmRhIGVudHJlIGRvaXMgb3UgbWFpcyBzZXJ2aWRvcmVzLiBDYWRhIHNlcnZpZG9yIGVudMOjbyBzZXLDoSByZXNwb25zw6F2ZWwgcG9yIGFwZW5hcyB1bWEgcGFydGUgZG8gc2V1IGJhbmNvIGRlIGRhZG9zLiBVbSBleGVtcGxvLCBhIEFwcGxlIHJvZGEgdW0gYmFuY28gZGUgZGFkb3MgTm9TUUwgcXVlIGNvbnNpc3RlIGVtIDc1MDAwIHNlcnZpZG9yZXMuDQoNCkVtIHRlcm1vcyBOb1NRTCwgZXNzYXMgcGFydGVzIGRvIHRldSBiYW5jbyBkZSBkYWRvcyBzw6NvIGNoYW1hZG9zIGRlIHBhcnRpw6fDtWVzLCBlIGlzc28gbm9zIHRyw6FzIHVtYSBxdWVzdMOjbzogc2UgdGV1IGJhbmNvIGRlIGRhZG9zIGVzdMOhIGRpdmlkbyBlbSBwb3RlbmNpYWxtZW50ZSBtaWxoYXJlcyBkZSBwYXJ0acOnw7VlcywgY29tbyB2b2PDqiBzYWJlIG9uZGUgdW0gaXRlbSBlc3TDoSBzYWx2bz8NCg0KTmVzc2UgbW9tZW50byBxdWUgYSBjaGF2ZSBwcmltw6FyaWEgZW50cmEgZW0gYcOnw6NvLg0KDQpMZW1icmUtc2UsIGJhbmNvcyBkZSBkYWRvcyBOb1NRTCBzw6NvIGl0ZW5zIGNoYXZlLXZhbG9yLCBlIGEgY2hhdmUgZGV0ZXJtaW5hIGVtIHF1YWwgcGFydGnDp8OjbyB1bSBpdGVtIGVzdGFyw6Egc2Fsdm8uDQoNCkF0csOhcyBkYXMgY29ydGluYXMsIGJhbmNvcyBkZSBkYWRvcyBOb1NRTCB1c2FtICJoYXNoIGZ1bmN0aW9uIiBwYXJhIGNvbnZlcnRlciBhIGNoYXZlIHByaW3DoXJpYSBkZSBjYWRhIGl0ZW0gZW0gdW0gbsO6bWVybyBxdWUgZmljYSBmaXhvIG51bWEgc8OpcmllLCBwb3IgZXhlbXBsbywgZW50cmUgMCBlIDEwMC4gRXNzZSAiaGFzaCB2YWx1ZSIgZSBhIHPDqXJpZSBzw6NvIHVzYWRvcyBwYXJhIGRldGVybWluYXIgb25kZSBzYWx2YXIgdW0gaXRlbS4gU2UgdGV1IGJhbmNvIGRlIGRhb2RzIMOpIHBlcXVlbm8gb3UgbsOjbyB0w6ptIG11aXRhcyByZXF1aXNpw6fDtWVzLCB2b2PDqiBwb2RlIGNvbG9jYXIgdHVkbyBudW0gw7puaWNvIHNlcnZpZG9yLiBFbGUgc296aW5obyBzZXLDoSByZXNwb25zw6F2ZWwgcG9yIHRvZGEgYSBzw6lyaWUuDQoNClNlIGVzc2Ugc2Vydmlkb3IgZmljYXIgc29icmVjYXJyZWdhZG8sIHZvY8OqIHBvZGUgYWRpY2lvbmFyIHVtIHNlZ3VuZG8gc2Vydmlkb3IsIG8gcXVlIHNpZ25pZmljYSBxdWUgYSBzw6lyaWUgc2Vyw6EgZGl2aWRpZGEgcGVsYSBtZXRhZGUuIE8gc2Vydmlkb3IgMSBzZXLDoSByZXNwb25zw6F2ZWwgcGVsb3MgaXRlbnMgY29tIHVtYSAiaGFzaCIgZW50cmUgMCBlIDUwLCBlbnF1YW50byBvIHNlcnZpZG9yIDIgc2FsdmFyw6EgdHVkbyBlbnRyZSA1MCBlIDEwMC4gVGVvcmljYW1lbnRlLCB2b2PDqiBkb2Jyb3UgYSBjYXBhY2lkYWRlIGRvIHRldSBiYW5jbyBkZSBkYWRvczogdGFudG8gZW0gdGVybW9zIGRlIGNhcGFjaWRhZGUgcXVhbnRvIGVtIHF1YW50aWRhZGUgZGUgcXVlcmllcyBxdWUgdm9jw6ogcG9kZSBleGVjdXRhci4NCg0KRXNzYSBzw6lyaWUgdGFtYsOpbSDDqSBjaGFtYWRhIGRlICJrZXlzcGFjZSIuDQoNCsOJIHVtIHNpc3RlbWEgc2ltcGxlcyBxdWUgcmVzb2x2ZSBkb2lzIHByb2JsZW1hczogb25kZSBncmF2YXIgaXRlbnMgbm92b3MgZSBvbmRlIGVuY29udHJhciBvcyBleGlzdGVudGVzLiBOZXNzZSBub3ZvIGV4ZW1wbG8sIGEgc8OpcmllIGRlIDAgYSAxMDAgw6kgdW0gcG91Y28gcGVxdWVuYS4gSXNzbyBwZXJtaXRpcmlhIHF1ZSB2b2PDqiBkaXZpZGlzc2Ugc2V1IGJhbmNvIGRlIGRhZG9zIGVtIG5vIG3DoXhpbW8gMTAwIHBhcnRpw6fDtWVzLiBEZXNzYSBmb3JtYSwgYmFuY29zIGRlIGRhZG9zIE5vU1FMIHJlYWlzIHRlbSAia2V5c3BhY2VzIiBtdWl0byBtYWlvcmVzLCBwZXJtaXRpbmRvIG8gImVzY2Fsb25hbWVudG8iIHF1YXNlIHF1ZSBzZW0gcmVzdHJpw6fDtWVzLg0KDQpBbMOpbSBkZSBncmFuZGUgImVzY2FsYWJpbGlkYWRlIiwgTm9TUUwgbsOjbyBwb3NzdWVtIGVzcXVlbWFzLCBvIHF1ZSBzaWduaWZpY2EgcXVlIGl0ZW5zIG5vIGJhbmNvIGRlIGRhZG9zIG7Do28gcHJlY2lzYW0gdGVyIGEgbWVzbWEgZXN0cnV0dXJhLiBDYWRhIHVtIHBvZGUgc2VyIGNvbXBsZXRhbWVudGUgZGlmZXJlbnRlLiBOdW0gYmFuY28gZGUgZGFkb3MgcmVsYWNpb25hbCwgdm9jw6ogdGVtIHF1ZSBkZWZpbmlyIGEgZXN0cnV0dXJhIGRlIHN1YSB0YWJlbGEsIGUgY2FkYSBpdGVtIGRldmUgcmVzcGVpdGFyIGVzc2EgZXN0cnV0dXJhLiAgTXVkYXIgZXNzYSBlc3RydXR1cmEgbsOjbyDDqSBmw6FjaWwgZSBwb2RlIGxldmFyIMOgIHBlcmRhIGRlIGRhZG9zLiBOw6NvIHRlciB1bSBlc3F1ZW1hIHByw6ktZGV0ZXJtaW5hZG8gcG9kZSBzZXIgdW1hIGdyYW5kZSB2YW50YWdlbSBzZSBhIHR1YSBhcGxpY2HDp8OjbyBlIGVzdHJ1dHVyYSBkZSBkYWRvcyBlc3TDoSBjb25zdGFudGVtZW50ZSBldm9sdWluZG8uIE5lc3RlIHBvbnRvLCDDqSBjbGFybyBxdWUgYmFuY29zIGRlIGRhZG9zIE5vU1FMIHRlbSBjZXJ0YXMgdmFudGFnZW5zIGVtIHJlbGFjw6NvIMOgIGJhbmNvcyBkZSBkYWRvcyByZWxhY2lvbmFpcy4NCg0KTWFzIGlzc28gbsOjbyBxdWVyIGRpemVyIHF1ZSBiYW5jb3MgZGUgZGFkb3MgcmVsYWNpb25haXMgc8OjbyBvYnNvbGV0b3MsIGxvbmdlIGRpc3NvLiBOb1NRTCDDqSBtYWlzIGxpbWl0YWRvIG5hIGZvcm1hIGNvbW8gdm9jw6ogcmVjdXBlcmEgc2V1cyBkYWRvcywgYXBlbmFzIHBlcm1pdGluZG8gcXVlIHZvY8OqIHBlc3F1aXNlIHBvciBpdGVucyBhdHJhdsOpcyBkZSBzdWEgY2hhdmUgcHJpbcOhcmlhLiBBY2hhciBwZWRpZG9zIGF0cmF2w6lzIGRlIHN1YSBJRCBuw6NvIMOpIHByb2JsZW1hLCBwb3LDqW0gYWNoYXIgdG9kb3Mgb3MgcGVkaWRvcyBhY2ltYSBkZSBjZXJ0YSBxdWFudGlkYWRlIHBvZGUgc2VyIGluZWZpY2llbnRlLiBCYW5jb3MgZGUgZGFkb3MgcmVsYWNpb25haXMsIHBvciBvdXRybyBsYWRvLCB0ZW0gcG91Y28gcHJvYmxlbWEgY29tIGlzdG8uIEV4aXN0ZW0gZm9ybWFzIGRlIGJ1cmxhciBlc3RlIHByb2JsZW1hLCBwb3LDqW0gYXBlbmFzIHNlIHZvY8OqIHNhYmUgY29tbyBhY2Vzc2FyIHNldXMgZGFkb3MgZSBpc3NvIHBvZGUgbsOjbyBzZXIgc2VtcHJlIG8gY2Fzby4NCg0KT3V0cm8gcG9udG8gbmVnYXRpdm8gw6kgcXVlIGJhbmNvcyBkZSBkYWRvcyBOb1NRTCBwb3NzdWVtIGNvbnNpc3TDqm5jaWEgZXZlbnR1YWwuIFF1YW5kbyB2b2PDqiBlc2NyZXZlIHVtIG5vdm8gaXRlbSBubyBiYW5jbyBkZSBkYWRvcyBlIHRlbnRhIGzDqi1sbyBkaXJldGFtZW50ZSwgZWxlIHBvZGUgbsOjbyByZXRvcm5hci4gQ29tbyBleHBsaWNhZG8gYW50ZXJpb3JtZW50ZSwgTm9TUUwgZGl2aWRlIG8gc2V1IGJhbmNvIGRlIGRhZG9zIGVtIHBhcnRpw6fDtWVzLCBwb3LDqW0gY2FkYSBwYXJ0acOnw6NvIMOpIGVzcGVsaGFkYSBhdHJhdsOpcyBkZSBkaXZlcnNvcyBzZXJ2aWRvcmVzLiBEZXNzYSBmb3JtYSwgdW0gc2Vydmlkb3IgcG9kZSBjYWlyIHNlbSBtdWl0byBpbXBhY3RvLiBRdWFuZG8gdm9jw6ogZXNjcmV2ZSB1bSBub3ZvIGl0ZW0gbm8gc2V1IGJhbmNvIGRlIGRhZG9zLCB1bWEgZGVzc2FzIGPDs3BpYXMgdmFpIHNhbHZhciBvIG5vdm8gaXRlbSBlIGNvcGlhciDDoCBvdXRyYXMgcGFydGnDp8O1ZXMgZW0gc2VndW5kbyBwbGFubyBlIGVzc2UgcHJvY2Vzc28gbGV2YSBjZXJ0byB0ZW1wby4gRW50w6NvIHF1YW5kbyB2b2PDqiByZXF1aXNpdGFyIHVtIGl0ZW0sIG8gYmFuY28gZGUgZGFkb3MgTm9TUUwgcG9kZSB0ZW50YXIgbGVyIGRlIHVtYSBjw7NwaWEgcXVlIGFpbmRhIG7Do28gc2Fsdm91IGVzdGUgaXRlbSBuZWxhLiBOYSBwcsOhdGljYSBlc3RlIG7Do28gw6kgdW0gcHJvYmxlbWEgZ3JhbmRlIHBvaXMgZGFkb3Mgc8OjbyByZXBsaWNhZG9zIGVtIGFwZW5hcyBhbGd1bnMgbWlsaXNlZ3VuZG9zIGUgc2Ugdm9jw6pzIGJ1c2NhIGNvbnNpc3TDqm5jaWEsIGEgbWFpb3JpYSBkb3MgYmFuY29zIGRlIGRhZG9zIE5vU1FMIHBvc3N1ZW0gZXNzYSBvcMOnw6NvLg0KDQpBc3NpbSwgZW0gcmVzdW1vLCB0YW50byBiYW5jb3MgZGUgZGFkb3MgTm9TUUwgZSBiYW5jb3MgZGUgZGFkb3MgcmVsYWNpb25haXMgZXN0YXLDo28gcHJlc2VudGVzIG5vIG1lcmNhZG8gcG9yIHVtIGJvbSB0ZW1wby4gQ2FkYSB1bSB0ZW0gc2V1cyBwb250b3MgZm9ydGVzIGUgcG9udG9zIGZyYWNvcy4NCg0KQWdvcmEgc2FiZW1vcyBjb21vIGZ1bmNpb25hIE5vU1FMLCB2YW1vcyBvbGhhciBhbGd1bnMgZXhlbXBsb3MuDQoNCg0KIyBFeGVtcGxvcw0KDQojIyBDbG91ZCBTZXJ2aWNlcw0KDQoqKlNlcnZpZG9yZXMgZW0gbnV2ZW0qKiBwcm9tb3ZlbSBkZSBmb3JtYSBwZXNhZGEgbyB1c28gZGUgTm9TUUwgcG9ycXVlIGVsZXMgcG9kZW0gImVzY2FsYXIiIG1haXMgZmFjaWxtZW50ZS4gQSBBbWF6b24gcG9zc3VpIG8gRHluYW1vREIsIG8gR29vZ2xlIENsb3VkIHBvc3N1aSBvIEJpZ1RhYmxlIGUgbyBNaWNyb3NvZnQgQXp1cmUgcG9zc3VpIG8gQ29zbW9zREIuIFBhcmEgZGFyIHVtIGV4ZW1wbG8gZGUgImVzY2FsYWJpbGlkYWRlIjogZHVyYW50ZSBvIEFtYXpvbiBQcmltZSBEYXkgZGUgMjAxOSwgbyBiYW5jbyBkZSBkYWRvcyBOb1NRTCBkYSBBbWF6b24gY2hlZ291IHN1cG9ydGFyIDQ1IG1pbGjDtWVzIGRlIHBlZGlkb3MgcG9yIHNlZ3VuZG8hDQoNCiMjIyBEeW5hbW9EQg0KDQpTZXJ2acOnbyBvZmVyZWNpZG8gcGVsYSBBbWF6b24uY29tIGNvbW8gcGFydGUgZG8gcG9ydGbDs2xpbyBkYSBBbWF6b24gV2ViIFNlcnZpY2VzLiBEeW5hbW9EQiB1c2EgcmVwbGljYcOnw6NvIHPDrW5jcm9uYSBhdHJhdsOpcyBkZSBkaXZlcnNvcyBkYXRhIGNlbnRlcnMgcGFyYSB0ZXIgYWx0YSBkdXJhYmlsaWRhZGUgZSBkaXNwb25pYmlsaWRhZGUuDQoNClBhcmEgbWFpcyBpbmZvcm1hw6fDtWVzOg0KDQotIFtXaWtpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BbWF6b25fRHluYW1vREIjUXVlcnlfZXhlY3V0aW9uKQ0KLSBbUMOhZ2luYSBPZmljaWFsIGVtIHBvcnR1Z3XDqnNdKGh0dHBzOi8vYXdzLmFtYXpvbi5jb20vcHQvZHluYW1vZGIvKQ0KDQoNCiMjIyBCaWdUYWJsZToNCg0KU2lzdGVtYSBkZSBhcm1hemVuYW1lbnRvIGRlIGRhZG9zIGRlIGFsdGEgcGVyZm9ybWFuY2UgZG8gR29vZ2xlIHF1ZSBjb21lw6dvdSBhIHNlciBkZXNlbnZvbHZpZG8gZW0gMjAwNCBlIGhvamUgw6kgdXRpbGl6YWRvIGVtIGluw7ptZXJhcyBhcGxpY2HDp8O1ZXMgZGEgZW1wcmVzYSBjb21vIGluZGV4YWRvciBvbmxpbmUsIEdvb2dsZSBNYXBzLCBHb29nbGUgRWFydGgsIFlvdXR1YmUsIEdtYWlsIGVudHJlIG91dHJvcyBzZXJ2acOnb2VzIG9mZXJlY2lkb3MuDQoNClBhcmEgbWFpcyBpbmZvcm1hw6fDtWVzOg0KDQotIFtXaWtpXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9CaWd0YWJsZSkNCi0gW1DDoWdpbmEgT2ZpY2lhbCBlbSBwb3J0dWd1w6pzXShodHRwczovL2Nsb3VkLmdvb2dsZS5jb20vYmlndGFibGUvKQ0KDQoNCiMjIyBDb3Ntb3NEQjoNCg0KRGUgcHJvcHJpZWRhZGUgZGEgTWljcm9zb2Z0IGUgZGlzdHJpYnXDrWRvIGdsb2JhbG1lbnRlLCBlc3RlIHNlcnZpw6dvIGRlIGRhdGFiYXNlIG11bHRpLW1vZGVsICJwYXJhIGdlcmVuY2lhbWVudG8gZGUgZGFkb3MgZW0gZXNjYWxhIHBsYW5ldMOhcmlhIiBmb2kgbGFuw6dhZG8gZW0gMjAxNy4gRWxlIMOpIGVzcXVlbWEtYWduw7NzdGljbywgY29tIGVzY2FsYW1lbnRvIGhvcml6b250YWwgZSBjbGFzc2lmaWNhZG8gY29tbyB1bSBiYW5jbyBkZSBkYWRvcyBOb1NRTC4NCg0KUGFyYSBtYWlzIGluZm9ybWHDp8O1ZXM6DQoNCi0gW1dpa2ldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0Nvc21vc19EQikNCi0gW1DDoWdpbmEgT2ZpY2lhbCBlbSBpbmdsw6pzXShodHRwczovL2F6dXJlLm1pY3Jvc29mdC5jb20vZW4tdXMvc2VydmljZXMvY29zbW9zLWRiLyNvdmVydmlldykNCg0KDQojIyBTZWxmIEhvc3RlZA0KDQpQb3LDqW0gdm9jw6ogdGFtYsOpbSBwb2RlIHJvZGFyIGJhbmNvcyBkZSBkYWRvcyBOb1NRTCBubyBzZXUgKipwcsOzcHJpbyBjb21wdXRhZG9yKiogY29tIHNvZnR3YXJlcyBjb21vIENhc3NhbmRyYSAoZGVzZW52b2x2aWRvIHBlbG8gRmFjZWJvb2spLCBTY3lsbGEsIENvdWNoREIsIE1vbmdvREIsIGVudHJlIG91dHJvcy4NCg0KIyMjIENhc3NhbmRyYToNCg0KQ3JpYWRvIHBvciBBdmluYXNoIExha3NobWFuLCB1bSBkb3MgY3JpYWRvcmVzIGRvIER5bmFtbyBkYSBBbWF6b24gZSBQcmFzaGFudCBNYWxpayBmb2kgaW5pY2lhbG1lbnRlIGRlc2Vudm9sdmlkbyBkZW50cm8gZG8gRmFjZWJvb2sgY29tbyBmZXJyYW1lbnRhIHBhcmEgbyBhdXjDrWxpbyBkYSBmZXJyYW1lbnRhIGRlIHBlc3F1aXNhIGRvIHNpdGUuIEFww7NzLCBmb2kgbGliZXJhZG8gY29tbyB1bSBwcm9qZXRvIGRlIGPDs2RpZ28gYWJlcnRvIGUgZGVzZGUgMjAwOSBmYXogcGFydGUgZG8gcHJvamV0byBBcGFjaGUgSW5jdWJhdG9yLiBDYXNzYW5kcmEgw6kgdW0gc2lzdGVtYSBkZSBtYW51c2VpbyBkZSBiYW5jbyBkZSBkYWRvcyBOb1NRTCwgbGl2cmUgZSBkZSBjw7NkaWdvIGFiZXJ0byBwcm9qZXRhZG8gcGFyYSBzdXBvcnRhciBncmFuZGVzIHF1YW50aWRhZGVzIGRlIGRhZG9zIGF0cmF2w6lzIGRlIGRpdmVyc29zIHNlcnZpZG9yZXMsIGZvcm5lY2VuZG8gYWx0YSBkaXNwb25pYmlsaWRhZGUgZSBzZW0gZmFsaGFzLg0KDQpQYXJhIG1haXMgaW5mb3JtYcOnw7VlczoNCg0KLSBbV2lraV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQXBhY2hlX0Nhc3NhbmRyYSkNCi0gW1DDoWdpbmEgT2ZpY2lhbCBlbSBpbmdsw6pzXShodHRwczovL2Nhc3NhbmRyYS5hcGFjaGUub3JnL18vaW5kZXguaHRtbCkNCg0KDQojIyMgU2N5bGxhOg0KDQrDiSB1bSBzaXN0ZW1hIGRlIGPDs2RpZ28gbGl2cmUgZGVzZW5oYWRvIHBhcmEgc2VyIGNvbXBhdMOtdmVsIGNvbSBvIEFwYWNoZSBDYXNzYW5kcmEsIG1lc21vIHRlbmRvIGRlc2VtcGVuaG8gbWFpcyByb2J1c3RvLiBFbGUgcm9kYSBvcyBtZXNtb3MgcHJvdG9jb2xvcyBxdWUgbyBDYXNzYW5kcmEgZSBkbyBEeW5hbW9EQiwgZW50cmV0YW50byBzdWEgaW1wbGVtZW50YcOnw6NvIGZvaSBmZWl0YSB1c2FuZG8gQysrMjAgYW8gaW52w6lzIGRlIEphdmEgZG8gQ2Fzc2FuZHJhLiBTY3lsbGEgZm9pIHByb2pldGFkbyBwYXJhIHV0aWxpemFyIGVzY2Fsb25hbWVudG8gaG9yaXpvbnRhbCBlbSBjYWRhIG7DsywgZGUgZm9ybWEgcXVlIGNhZGEgbsO6Y2xlbyBkZSBDUFUgw6kgcmVzcG9uc8OhdmVsIHBvciBkaWZlcmVudGVzIHN1YmNvbmp1bnRvcyBkZSBkYWRvcy4gRXNzZXMgbsO6Y2xlb3MgbsOjbyBjb21wYXJ0aWxoYW0gb3MgbWVzbW9zIGRhZG9zLCBwb3LDqW0gc2UgY29tdW5pY2FtIGVudHJlIHNpIGV4cGxpY2l0YW1lbnRlIGFwZW5hcyBxdWFuZG8gw6kgbmVjZXNzw6FyaW8uIE9zIGF1dG9yZXMgZG8gc2lzdGVtYSBhZmlybWFtIHF1ZSBlc3NlIGRlc2lnbiBkaWZlcmVudGUgcGVybWl0ZSBhbyBTY3lsbGEgc2VyIDEwIHZlemVzIG1haXMgdmVsb3ogcXVlIG8gQ2Fzc2FuZHJhLg0KDQpQYXJhIG1haXMgaW5mb3JtYcOnw7VlczoNCg0KLSBbV2lraV0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2N5bGxhXyhkYXRhYmFzZSkpDQotIFtQw6FnaW5hIE9maWNpYWwgZW0gaW5nbMOqc10oaHR0cHM6Ly9zY3lsbGFkYi5jb20vKQ0KDQoNCiMjIyBDb3VjaERCOg0KDQrDiSB1bSBzaXN0ZW1hIGRlIGPDs2RpZ28gYWJlcnRvIGltcGxlbWVudGFkbyBuYSBsaW5ndWFnZW0gZGUgcHJvZ3JhbWHDp8OjbyBFcmxhbmcsIHV0aWxpemEgSlNPTiBwYXJhIGd1YXJkYXIgb3MgZGFkb3MgZSBxdWVyaWVzIGRlIEphdmFTY3JpcHQgcGFyYSBvIG1hbnVzZWlvIGRvcyBtZXNtb3MuIEZvaSBsYW7Dp2FkbyBlbSAyMDA1IGUgaG9qZSB0YW1iw6ltIGZheiBwYXJ0ZSBkbyBwcm9qZXRvIEFwYWNoZS4NCg0KUGFyYSBtYWlzIGluZm9ybWHDp8O1ZXM6DQoNCi0gW1dpa2ldKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0FwYWNoZV9Db3VjaERCKQ0KLSBbUMOhZ2luYSBPZmljaWFsIGVtIGluZ2zDqnNdKGh0dHBzOi8vY291Y2hkYi5hcGFjaGUub3JnLykNCg0KDQojIyMgTW9uZ29EQjogDQoNCkltYWdpbmEgc2UgdW0gYm9sc2lzdGEgasOhIGZleiB1bSBtYXJrZG93biBzb2JyZSBlc3NlIGFzc3VudG8/DQoNCiggzaHCsCDNnMqWIM2hwrApDQoNCg0KIyBDb25zaWRlcmHDp8O1ZXMgZmluYWlzDQoNCkFudGVzIGRlIHRlcm1pbmFyIGVzdGUgdGV4dG8sIHZhbW9zIGZhbGFyIHJhcGlkYW1lbnRlIGRvIG5vbWUgIk5vU1FMIi4gSXNzbyDDqSB1bSBwb3VjbyBjb25mdXNvIGUgcG9kZSBzZXIgaW50ZXJwcmV0YWRvIGRlIGR1YXMgZm9ybWFzLiBQcmltZWlybywgIk5vU1FMIiBwb2RlIHNpZ25pZmljYXIgIm5vdCBvbmx5IFNRTCIgKG7Do28gYXBlbmFzIFNRTCksIGRpcmVjaW9uYWRvIGFvIGZhdG8gcXVlIGFsZ3VucyBiYW5jb3MgZGUgZGFkb3MgTm9TUUwgZW50ZW5kZW0gcGFyY2lhbG1lbnRlIGFzIHF1ZXJpZXMgZGUgbGluZ3VhZ2VtIFNRTCwgYWzDqW0gZGUgc3VhcyBwcsOzcHJpYXMgY2FwYWNpZGFkZXMuIEVtIHNlZ3VuZG8gbHVnYXIsIMOpIGNoYW1hZG8gZGUgIk5vU1FMIiBubyBzZW50aWRvIGRlICJub24tcmVsYXRpb25hbCIgKG7Do28gcmVsYWNpb25hbCkgcG9ycXVlIGVsZSBuw6NvIHBvZGUgc2FsdmFyIGRhZG9zIHJlbGFjaW9uYWlzIGZhY2lsbWVudGUuDQoNCkVyYXMgaXNzbyENCg0KVGV4dG8gdHJhZHV6aWRvIGRlOg0KW0hvdyBkbyBOb1NRTCBkYXRhYmFzZXMgd29yaz8gU2ltcGx5IEV4cGxhaW5lZCFdKGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9MGJ1S1FIb2tMSzgp