You are on page 1of 10

Controle de versão com Bazaar

Marcelo Barros de Almeida <marcelobarrosalmeida@gmail.com>

The contents of this document are licensed under the Creative Commons - Attribution / Share Alike license.
See http://creativecommons.org/licenses/by-sa/2.0/
Controle de versão com Bazaar
Sumário
1 Abrindo o Bazaar 3

2 Instalando e obtendo suporte 4

3 Trabalhando com o Bazaar 4


3.1 Conceitos básicos em controle de versão . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.2 Criando um repositório local . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3.3 Modificando arquivos e diretórios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.4 Trabalhando com ramos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.5 Atualizando um ramo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.6 Exportando versões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

4 Conclusão 10

Marcelo Barros de Almeida 2 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar
1 Abrindo o Bazaar
Apesar do nome sugestivo, o Bazaar não tem nenhuma relação direta com lojas de bugigangas ou amiúdes.
A idéia do nome foi inspirada no livro “A catedral e o bazar”, escrito por nada menos do que Eric S.
Raymond. É difı́cil até mesmo mostrar a relevância do trabalho de Eric, com inúmeras contribuições para
o software livre desde o inı́cio da década de oitenta. Basicamente, Eric Raymond discute neste livro formas
de distribuição e desenvolvimento de software. O estilo “catedral” é aquele onde o software é desenvolvido
por um grupo restrito de gurus jedis magos, com prazos próprios e liberações de versões escassas que
só acontecem quando o produto beira a perfeição. Já o modelo “bazar” segue a linha aparentemente
caótica de programas feito a várias mãos, usando a polı́tica “libere cedo, lance frequentemente”, que
acaba paralelizando o trabalho e unindo centenas de desenvolvedores e milhares de testadores e usuários.
Uma leitura agradável, por sinal, com traduções para várias lı́nguas1 .
Bom, e porque criar mais um sistema de controle de versão ? Realmente, não existem grandes
novidades conceituais no Bazaar. Nem mesmo a caracterı́stica de ser distribuı́do o coloca num patamar
diferenciado: vários sistemas de controle de versão atuais possuem também esta caracterı́stica. Vou
arriscar alguns palpites a este respeito então, já que não existe uma boa resposta no FAQ do Bazaar que
eu possa copiar.
Uma caracterı́stica forte do Bazaar é facilidade de uso. Ele apresenta uma estrutura de comandos
parecida com o bom e velho CVS, ou melhor, com a parte boa e fácil dos comandos do CVS. Mas acres-
centa uma forma peculiar de uso que torna tudo mais intuitivo. Talvez um reflexo direto da linguagem
Python, usada no desenvolvimento do Bazaar. Basta uma lida no “Zen do Python”, de Tim Peters, para
entender exatamente o que estou querendo dizer2 . Aliás, o uso de Python como linguagem permitiu
um avanço rápido no desenvolvimento, sustentado pela vasta API do Python e pela forma prazerosa e
concisa de programar oferecida. Uma prova disso disso é a forma como se pode estender os comandos
básicos do Bazaar, através de scripts de poucas linhas em Python. Desespero só em pensar como seria
fazer isto no CVS, por exemplo.
Descentralizar o controle é outro fator bastante interessante. Por exemplo, imagine que você faça um
checkout de um projeto controlado com bazaar. Uma vez feito isto, você pode continuar desenvolvendo
localmente, realizando adições, gerando revisões, ramos, etc. Não é necessário uma conexão com nenhum
servidor especı́fico. As suas modificações podem voltar para a derivação original um dia se você tiver
direitos de escrita no repositório. Uma situação corriqueira que se encaixa neste caso de uso é a do
desenvolvedor que está longe do trabalho, em viagem, por exemplo. Não existe motivo para que se
perca o controle de versão. Algo similar acontece quando começamos “aquele projeto caseiro só para
teste”, sem controle de versão ou rigor e que acaba crescendo muito além do que esperávamos. Nesse
meio tempo, versões são armazenadas como arquivos compactados e, com frequência, alguma alteração
é perdida.
Pra finalizar, apesar de não ser tão difı́cil assim, configurar um repositório de CVS ou Subversion
toma um tempo que muitas vezes não estamos dispostos a perder. Com o Bazaar é possı́vel começar a
trabalhar sem esta preocupação. Para mais detalhes, uma lista completa das caracterı́sticas do Bazaar
pode ser obtida em http://bazaar-vcs.org/BzrFeatures.
O projeto em Python, na versão como conhecemos hoje, foi iniciado em janeiro de 1995 por Martin
Pool e patrocinado pela Canonical Limited. A Canonical já havia tentado uma ramificação do GNU
Arch mas a idéia parece não ter vingado. Hoje, existem versões do Bazaar para Windows, Mac e Linux.
A última versão liberada foi a 0.9, com várias melhorias relacionadas ao desempenho do programa.
O desempenho ainda deixa a desejar e algumas operações são realmente um pouco lentas no Bazaar,
principalmente se estiverem relacionadas com arquivos binários. E, como é de esperar, o custo de
manutenção de um repositório individualizado para cada projeto é o uso de espaço em disco. Para cada
ramo ou repositório criado, um diretório .bzr será criado, para que o controle de versão seja feito
1 Disponı́vel em http://www.catb.org/∼esr/writings/cathedral-bazaar/.
2 Veja http://www.python.org/doc/Humor.html ou então digite import this num shell do Python.

Marcelo Barros de Almeida 3 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar
2 Instalando e obtendo suporte
As versões do Bazaar podem ser baixadas diretamente do site3 , principalmente para usuário de Windows
ou MacOS. Para os que usam distribuições Linux, a forma mais fácil de instalar é procurar pelo pacote
bzr. O instalador Windows irá adicionar um interpretador Python ao sistema para a execução do Bazaar.
Em sistemas Linux é usada a instalação existente do Pyhton.
O bazaar é composto apenas de um programa chamado bzr. Este programa pode ser invocado com
uma série de comandos, cada um deles com um conjunto de opções diferentes. Uma forma de ganhar
familiaridade com o Bazaar é através do comando help, que pode ser acessado com bzr help ou então
bzr help comando, para uma descrição mais detalhada sobre um comando especı́fico. Existem alguns
documentos introdutórios no próprio site e programas para conversão de repositórios4 .

3 Trabalhando com o Bazaar


Esta seção irá demonstrar como o Bazaar pode ser usado através de um exemplo fictı́cio de gerência de
projeto, descrito mais adiante. Os conceitos básicos necessários são também apresentados a seguir. Caso
você já tenha familiaridade com o uso de ferramentas de controle de versão, pode pular para a Seção 3.2.

3.1 Conceitos básicos em controle de versão


Desenvolvedores acostumados a trabalhar com programas de controle de revisão (RCS - Revision Control
Software), como CVS ou Subversion, em geral adotam modelos de desenvolvimento centralizados. Nestes
modelos, é comum ter desenvolvedores trabalhando em ramos. Por exemplo, eles podem estar desenvol-
vendo as caracterı́sticas novas da próxima versão no ramo head enquanto outros estão trabalhando em
correções de erro de versões mais antigas em outros ramos. Cada desenvolvedor inicia o seu trabalho
fazendo uma cópia de trabalho do que existe de mais novo no ramo desejado (head do ramo). A cópia
de trabalho é geralmente realizada através de uma operação conhecida como checkout. Toda operação
de envio de atualizações (denominada commit) é centralizada e passa pelo servidor do repositório. Este
desenvolvimento pode ser conjunto, já que existem formas de controle para que vários desenvolvedores
possam trabalhar em um mesmo ramo. Problemas de conflito, isto é, arquivos alterados por mais de
um desenvolvedor, são geralmente resolvidos com atualizações da imagem local (update) e mesclagem do
código local com o do repositório (merge).
Já modelos descentralizados de desenvolvimento permitem commits locais, ou seja, o desenvolvedor
pode gerar a sua cópia local de trabalho e realizar um controle local das alterações, sem a necessidade
de se conectar ao servidor central a cada operação.
Ambos modos de operação, ou até mesmo uma mistura entre eles, são possı́veis com o Bazaar. A
decisão sobre qual usar depende apenas do desenvolvedor. Neste artigo será explorada a caracterı́stica
descentralizada do Bazaar, justamente por se contrapor aos programas tradicionais de RCS, enfatizando
novos conceitos e formas de operação.

3.2 Criando um repositório local


Bom, como estamos num tutorial, nada melhor que um bom exemplo prático de uso. Para isso, considere
a seguinte estrutura de diretórios e arquivos:
goto
| - - Makefile
| - - thedoc
| ‘-- newbie . txt
‘-- thesource
‘-- luke . c

Supondo que esta seja a estrutura inicial criada pelo desenvolvedor, ele pode colocá-la no controle de
versão do bazar após criar um repositório novo, adicionar arquivos e salvar as modificações (commit).
Estes passos estão detalhados a seguir.
3 http://bazaar-vcs.org/Download.
4 http://bazaar-vcs.org/Documentation

Marcelo Barros de Almeida 4 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar
A criação do repositório pode ser feita com o comando init que gera um diretório .bzr para controle
do repositório:
barros@dexter$ cd goto
barros@dexter$ bzr init
barros@dexter$ ls - lad . bzr
drwxr - xr - x 6 barros barros 64 2006 -11 -18 19:40 . bzr

O comando status irá indicar a condição atual do repositório, evidenciando que não existe nenhum
arquivo ou diretório sob controle:
barros@dexter$ bzr status
unknown :
Makefile
thedoc
thesource

Com o comando add é possı́vel fazer a adição recursiva dos arquivos que estão dentro do diretório
goto, conforme indicado a seguir:
barros@dexter$ bzr add
added Makefile
added thedoc
added thesource
added thedoc / newbie . txt
added thesource / luke . c

Para finalização da adição, as operações tem que ser efetivadas no repositório através do comando
commit. Além disso, é necessário adicionar uma mensagem (opção -m) para documentar a alteração.
Este é um processo comum que acontece também quando um arquivo é modificado, como veremos
mais adiante. É importante acostumar-se a colocar boas mensagens descrevendo as alterações, para
documentar o projeto e facilitar qualquer recuperação de histórico. O commit e sua saı́da estão no passo
seguinte:
barros@dexter$ bzr commit -m " Versao inicial "
added Makefile
added thedoc
added thedoc / newbie . txt
added thesource
added thesource / luke . c
Committed revision 1.

Finalmente, pode-se ver o histórico de alterações através do comando log. Neste momento do desen-
volvimento, apenas o último commit está representado no histórico, indicado pela revisão 1. A cada novo
commit o número de revisão será incrementado. É através deste número que versões antigas poderão ser
recuperadas.
barros@dexter$ bzr log
------------------------------------------------------------
revno : 1
committer : Marcelo Barros de Almeida < barros@dexter >
branch nick : goto
timestamp : Sat 2006 -11 -18 19:44:33 -0200
message :
Versao inicial

Uma observação a ser feita é que o comando add adicionar apenas arquivos texto. Arquivos binários
devem ser adicionados explicitamente. Em geral, recomenda-se que eles não sejam mantidos sob controle,
já que acabam consumindo muito espaço e tomando mais tempo de processamento. Apenas quando
estritamente necessário adicione arquivos binários ao seu repositório.

Marcelo Barros de Almeida 5 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar
3.3 Modificando arquivos e diretórios
Vamos supor que os arquivos luke.c e Makefile foram alterados como descritos a seguir:
barros@dexter$ echo -e " # include \" yoda . h \" " >> thesource / luke . c
barros@dexter$ echo -e " int main ( void )\ n {\ n \ treturn 0;\ n } " >> thesource / luke . c
barros@dexter$ echo -e " all :\ n \ tgcc thesource / luke . c -o bin / luke " >> Makefile

Além disso, um novo arquivo, yoda.h, foi criado:


barros@dexter$ touch thesource / yoda . h

Compile o projeto dando o comando make no diretório onde está o makefile. Um arquivo executável
luke será gerado. Ao verificar o status do repositório, o Bazaar irá indicar que existem dois arquivos
modificados e dois novos:
barros@dexter$ bzr status
modified :
Makefile
thesource / luke . c
unknown :
luke
thesource / yoda . h

Caso deseje, neste ponto do desenvolvimento, enviar para o repositório as mudanças atuais, adicione
os arquivos novos e faça um commit das alterações. A operação de commit pode ser feita arquivo por
arquivo, quando se deseja ter mensagens personalizadas por arquivo alterado ou em grupo, quando isto
não é necessário. Para simplificar, iremos fazer commit em grupo. Assim, cada nova revisão irá indicar
uma revisão de todo o projeto e não de apenas um arquivo. Manter registro de alterações em arquivos
do tipo ChangeLog é uma boa prática também. O executável gerado não será mantido em controle de
versão.
barros@dexter$ rm luke
barros@dexter$ bzr add thesource / yoda . h
added thesource / yoda . h
barros@dexter$ bzr commit -m " Adicionando definicoes de Yoda "
modified Makefile
modified thesource / luke . c
added thesource / yoda . h
Committed revision 2.

O comando log indica agora mais uma revisão do projeto:


barros@dexter$ bzr log
------------------------------------------------------------
revno : 2
committer : Marcelo Barros de Almeida < barros@dexter >
branch nick : goto
timestamp : Sat 2006 -11 -18 19:51:24 -0200
message :
Adicionando definicoes de Yoda
------------------------------------------------------------
revno : 1
committer : Marcelo Barros de Almeida < barros@dexter >
branch nick : goto
timestamp : Sat 2006 -11 -18 19:44:33 -0200
message :
Versao inicial

Finalmente, seria interessante criar um diretório e colocá-lo em controle também. Suponha que o
diretório bin seja usado como o local de armazenamento do executável luke. Os passos envolvidos na
criação e controle estão a seguir, inclusive a modificação do makefile.

Marcelo Barros de Almeida 6 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar

barros@dexter$ mkdir bin


barros@dexter$ echo -e " all :\ n \ tgcc thesource / luke . c -o bin / luke " > Makefile
barros@dexter$ bzr add bin
barros@dexter$ bzr commit -m " Adicionando diretorio de saida "

Finalmente, o log do respositório até o momento é seguinte:


barros@dexter$ bzr log -- short
3 Marcelo Barros de Almeida 2006 -11 -19
Adicionando diretorio de saida

2 Marcelo Barros de Almeida 2006 -11 -18


Adicionando definicoes de Yoda

1 Marcelo Barros de Almeida 2006 -11 -18


Versao inicial

Parte do ciclo de desenvolvimento irá então seguir esta lógica de operação, com arquivos sendo adi-
cionados, removidos ou editados, com a posterior efetivação das mudanças através do commit. Cabe
ao desenvolvedor definir o melhor momento para que o este commit seja feito. Em geral, ele irá indi-
car momentos importantes no projeto, que serão marcados através da revisão gerada, permitindo uma
recuperação posterior. Um erro bastante comum é achar que o commit é uma espécie de backup. Por
exemplo, que o desenvolvedor deva usá-lo para salvar alterações ao final de um dia de trabalho ou a cada
modificação no código. Fique atento e crie revisões com parcimônia e bom senso.

3.4 Trabalhando com ramos


Em determinados momentos da vida de um projeto é necessário criar ramos (branches), isto é, derivações
do projeto original que também precisam ser mantidas e, por algum motivo, não podem ser agregadas
naquele estágio. Isto pode ocorrer, por exemplo, quando se está trabalhando em uma versão futura
do projeto. Ou ainda quando é necessário dar manutenção em uma versão antiga e o cliente não pode
simplesmente passar a usar a versão mais atual do software. Através de ramos torna-se possı́vel paralelizar
o processo de desenvolvimento, mesmo que isto aumente o número de mesclagens (merges) entre códigos
de ramos diferentes.
O Bazaar permite que novos ramos sejam criados e mantidos através do comando branch. Uma
difereça em relação a outros programas, como o CVS, é que cada ramo tem vida própria, ou seja, cada
ramo cria o seu própria repositório (diretório .bzr) e passa a controlá-lo de forma independente. Isto
decorre do modelo distribuı́do de controle de versão adotado pelo Bazaar. Adicionalmente, através do
comando merge, o trabalho executado em ramos diferentes pode ser combinados. Os exemplos a seguir
devem tornar estes conceitos mais claros.
Suponha que um novo ramo, denominado de darkside, precise ser criado. Novas caracterı́sticas serão
adicionadas neste ramos, como os arquivos sith.h, vader.c e modificações no arquivo Makefile.
A criação do ramo é relativamente simples, basicamente devem ser especificados na linha de comando
o ramo original e o novo. Note que optou-se por se subir um nı́vel de diretório para realizar esta operação.
No entanto, caminhos relativos são também permitidos.
barros@dexter$ cd ..
barros@dexter$ bzr branch goto darkside
Branched 3 revision ( s ).
barros@dexter$ ls -l
total 0
drwxr - xr - x 6 barros barros 40 2006 -11 -19 10:58 darkside
drwxr - xr - x 6 barros barros 80 2006 -11 -19 10:20 goto
barros@dexter$ ls - la darkside /
total 8
drwxr - xr - x 6 barros barros 40 2006 -11 -19 10:58 .
drwxr - xr - x 4 barros barros 40 2006 -11 -19 10:58 ..
drwxr - xr - x 2 barros barros 1 2006 -11 -19 10:58 bin
drwxr - xr - x 6 barros barros 64 2006 -11 -19 10:58 . bzr

Marcelo Barros de Almeida 7 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar
-rw -r - -r - - 1 barros barros 39 2006 -11 -19 10:58 Makefile
drwxr - xr - x 2 barros barros 8 2006 -11 -19 10:58 thedoc
drwxr - xr - x 2 barros barros 16 2006 -11 -19 10:58 thesource

Sempre é usada a última revisão no processo de ramificação, a menos que uma outra seja especifica
através da opção -r NUM REVIS~AO. Como pode ser visto, o diretório darkside tem uma estrutura idêntica
ao ramo original. As alterações no ramo darkside estão a seguir, todas executadas através do comando
echo para permitir uma reprodução sem erros dos resultados.
barros@dexter$ cd darkside
barros@dexter$ echo -e " int darth ( void ); " > thesource / sith . h
barros@dexter$ echo -e " # include \" sith . h \" " > thesource / vader . c
barros@dexter$ echo -e " int darth ( void )\ n {\ n \ treturn 1;\ n } " >> thesource / vader . c
barros@dexter$ echo -e " # include \" sith . h \" " > thesource / luke . c
barros@dexter$ echo -e " # include \" yoda . h \" " >> thesource / luke . c
barros@dexter$ echo -e " int main ( void )\ n {\ n \ treturn darth ();\ n } " >> thesource / luke . c
barros@dexter$ echo -e " all :\ n \ tgcc -c thesource / vader . c -o bin / vader . o " > Makefile
barros@dexter$ echo -e " \ tgcc thesource / luke . c -o bin / luke bin / vader . o " >> Makefile

O estatus atual repositório é o seguinte:


barros@dexter$ bzr status
modified :
Makefile
thesource / luke . c
unknown :
bin / luke
thesource / sith . h
thesource / vader . c

Antes de efetivar as alterações, é interessante introduzir o comando diff, que permite visualizar as
alterações realizadas em um arquivo em relação a uma revisão qualquer. Como exemplo, considere o
arquivo thesource/luke.c.
barros@dexter$ bzr diff thesource / luke . c
=== modified file ’ thesource / luke . c ’
--- thesource / luke . c 2006 -11 -18 21:51:24 +0000
+++ thesource / luke . c 2006 -11 -19 13:31:31 +0000
@@ -1 ,5 +1 ,6 @@
+#i n c l u d e ” s i t h . h ”
#i n c l u d e ” yoda . h ”
int main ( void )
{
- return 0;
+ return darth ();
}

É possı́vel perceber que a data e o conteúdo do arquivo foram alterados. As linhas adicionadas ou
removidas são indicadas pelos caracteres (+) e (-), respectivamente. Com relação à data, é importante
notar que o arquivo foi recriado com o comando echo. Em geral, é preferı́vel que o arquivo seja apenas
editado. A mudança na data pode gerar problemas com programas como CVS. Caso a revisão não seja
especificada com a opção -r NUM REVIS~ AO, a última revisão é usada.
Efetivando as alterações no ramo:
barros@dexter$ rm bin /*
barros@dexter$ bzr add thesource / sith . h
added thesource / sith . h
barros@dexter$ bzr add thesource / vader . c
added thesource / vader . c
barros@dexter$ bzr commit -m " Adicionando o lado negro "
modified Makefile
modified thesource / luke . c

Marcelo Barros de Almeida 8 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar
added thesource / sith . h
added thesource / vader . c
Committed revision 4.

3.5 Atualizando um ramo


A mesclagem de código entre ramos é facilitada pelo comando merge. Com este comando, mudanças
proveniente de outros ramos podem ser inseridas no ramo corrente. No entanto, alguns cuidados devem
ser tomados uma vez que, nem sempre, o Bazaar conseguirá resolver sozinho todos os casos de mesclagem.
Em algumas situações, o Bazaar irá marcar o arquivo como em conflito e o usuário precisará resolver o
conflito manualmente. Os comandos conflicts e resolve, não abordados neste documento, irão ajudar
o usuário neste processo. Existem algumas ferramentas Linux para merge manual, como o Meld e kdiff,
além do próprio utilitário diff. Para Windows, recomenda-se o WinMerge.
Supondo que se queira trezar todas as mudanças do ramo darkside para o ramo goto, a seguinte
sequência de comandos pode ser utilizada:
barros@dexter$ cd ../ goto /
barros@dexter$ bzr merge ../ darkside /
All changes applied successfully .
barros@dexter$ bzr status
added :
thesource / sith . h
thesource / vader . c
modified :
Makefile
thesource / luke . c
pending merges :
Marcelo Barros de ... 2006 -11 -19 Adicionando o lado negro
barros@dexter$ bzr commit -m " Merge com darkside "
modified Makefile
modified thesource / luke . c
added thesource / sith . h
added thesource / vader . c
Committed revision 4.

Neste caso, como o ramo goto não sofreu nenhuma alteração enquanto novas caracterı́sticas eram
adicionadas no ramo darkside, todo o processo de merge é bastante facilitado.

3.6 Exportando versões


Uma funcionalidade interessante prevista no Bazaar é a exportação de uma revisão qualquer, já em
formato compactado, mas sem o diretório de controle. É bastante útil para criação de cópias de segurança
ou para disponibilização de código fonte. Tudo é feito através do comando export, onde se especifica o
arquivo desejado e a revisão.
Por exemplo, para exportar um arquivo .zip com o código mais atual, bastaria o comando a seguir:
barros@dexter$ bzr export starwars_cur . zip
barros@dexter$ ls -l st *
-rw -r - -r - - 1 barros barros 1378 2006 -11 -19 15:52 starwars_cur . zip

Ou, se fosse necessário a revisão 3 em formato .tar.bz2:


barros@dexter$ bzr export -r 3 starwars_rev3 . tar . bz2
barros@dexter$ ls -l st *
-rw -r - -r - - 1 barros barros 363 2006 -11 -19 15:54 starwars_rev3 . tar . bz2
-rw -r - -r - - 1 barros barros 1378 2006 -11 -19 15:52 starwars_cur . zip

Marcelo Barros de Almeida 9 <marcelobarrosalmeida@gmail.com>


Controle de versão com Bazaar
4 Conclusão
Este artigo abordou os principais comandos do Bazaar, uma nova alternativa para controle de versão
distribuı́do. Por se tratar de um artigo introdutório, várias caracterı́sticas foram propositalmente omiti-
das. Por exemplo, trabalhou-se apenas com repositórios locais, apesar de o Bazaar suportar repositórios
remotos também. Além disso, os comandos apresentados possuem geralmente bem mais opções do que
as usadas. No entanto, espera-se que o usuário, com os conceitos aprendidos aqui, possa ir aprendendo
o restante sozinho, ganhando conhecimento à medida que as dificuldades surgem.

Marcelo Barros de Almeida 10 <marcelobarrosalmeida@gmail.com>

You might also like