tag:blogger.com,1999:blog-42414144261029405002024-03-14T06:32:14.753-03:00ronoblogBlog pessoal do Ronoaldo José de Lana PereiraRonoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.comBlogger26125tag:blogger.com,1999:blog-4241414426102940500.post-26722778916825099682021-11-24T17:09:00.009-03:002021-11-25T08:22:29.508-03:00Atualizando o kernel do Linux no Debian<p> </p><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPnC3gUszwlqNrvSRIK3zBYMjfs4HvXzAaV5vVkRVtedpZ2OTPfDu66XoQKEXj9cO0qQ55BX_9_TlVDvwu0eQXKIgJsfx0ZMgsS_uJCwpbtznYWwP_VHXBPFBDkYVbJqk3lu__WNnNNtjv/s747/Screenshot_20211120_125339.png"><img alt="Image de início da construção do kernel utilizando o script "kernelbuild"" border="0" data-original-height="430" data-original-width="747" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPnC3gUszwlqNrvSRIK3zBYMjfs4HvXzAaV5vVkRVtedpZ2OTPfDu66XoQKEXj9cO0qQ55BX_9_TlVDvwu0eQXKIgJsfx0ZMgsS_uJCwpbtznYWwP_VHXBPFBDkYVbJqk3lu__WNnNNtjv/s16000/Screenshot_20211120_125339.png" /></a></div><br /><div>O Projeto <a href="https://www.debian.org/" target="_blank">Debian</a> é mais do que uma simples distribuição GNU/Linux. Entre suas principais características está a estabilidade, que é obtida por um <a href="https://www.debian.org/releases/index.en.html" target="_blank">ciclo de gerenciamento das versões</a> de cada pacote bem definido.</div><div><br /></div><div>A versão <b>estável</b> do Debian (<i><a href="https://www.debian.org/releases/stable/" target="_blank">Debian stable</a></i>) recebe um codinome inspirado em personagens do Toy Story e geralmente tem uma garantia de atualizações de segurança e manutenção por parte do Debian de vários anos. Por este motivo, ao usar o Debian stable você pode estar com o software <i>atrasado</i> em novidades, mas geralmente bem estável e largamente testado, além de contar com suporte de segurança por 3 anos (e em alguns casos, por mais 2 anos de <i>Long Term Support</i>).</div><h3 style="text-align: left;">Snap e Flatpak</h3><div>Para utilizar versões mais novas de alguns programas no Debian stable, existem algumas opções. Uma delas, que não interfere com o seu software no sistema, seria utilizar a versão do programa utilizando o <b>Snap</b> ou <b>Flatpak</b>. Ambos estão disponíveis no Debian como uma fonte de software alternativa, e você pode fazer isso facilmente pelo gerenciador de pacotes.</div><div><br /></div><div>No KDE por exemplo, você pode usar o Firefox ESR (<i>extented release support</i>) que está nos repositórios do Debian, ou utilizar o Firefox mais atual, instalando ele via Flatpak direto do Discover. Siga os passos no site oficial do <a href="https://snapcraft.io/docs/installing-snap-on-debian" target="_blank">Snapcraft</a> e do <a href="https://flatpak.org/setup/Debian/" target="_blank">Flatpak</a> para configurar seu Debian para usar essas fontes de programas.</div><div><h3>Backports</h3></div><div>Já para atualizar componentes <i>base</i> o processo de usar os canais Snap ou Flatpak não se aplica. Por exemplo, se você precisar de um kernel mais novo ou firmware mais recente para o seu hardware. Uma forma que o próprio projeto Debian oferece é por meio do canal de software <i><a href="https://backports.debian.org/Instructions/" target="_blank">backports</a></i>. Por meio deste canal, os desenvolvedores do Debian disponibilizam, para aqueles que preferirem, uma versão atualizada do pacote que é construída em cima da "base" do Debian stable.</div><div><br /></div><div>No Debian Backports você vai então encontrar uma versão do Kenel e Fimware mais nova. No momento da escrita deste artigo, o <a href="https://packages.debian.org/bullseye-backports/linux-image-amd64" target="_blank">Kernel 5.14.9</a> estava disponível no backports. Para usar o backports, primeiro é necessário adicionar a linha do repositório no seu arquivo sources.list e depois instalar o pacote do kernel de lá. Pelo terminal, você pode realizar isso da seguinte maneira:</div>
<pre class="prettyprint">echo "deb http://deb.debian.org/debian bullseye-backports main" |\
sudo tee /etc/apt/sources.list.d/backports.list
sudo apt update
sudo apt install <b>-t bullseye-backports</b> linux-image-amd64 -y
</pre>
<div>A diferença basicamente é utilizar o parametro extra <b>-t bullseye-backports</b> para instalar os pacotes. O mesmo pode ser feito para os pacotes <b>firmware-linux*</b>.</div><h3 style="text-align: left;">Na raça: compilando a partir do código-fonte!</h3><div>Já se você quer ter o kernel sempre atualizado, por exemplo, para tirar proveito de alguma funcionalidade introduzida recentemente nas releases estáveis, pode utilizar o guia de <a href="https://www.debian.org/doc/manuals/debian-kernel-handbook/" target="_blank">customização do Kernel do Debian</a> para aprender como criar um pacote <b>.deb</b> do kernel e integrar ele ao seu sistema.</div><div><br /></div><div>Mas este artigo não estaria completo sem uma ajudinha minha pra isso, não é mesmo? Você pode utilizar uma ferramenta simples que eu implementei que permite criar <b>seu kernel customizado com um único comando</b>. Para obter o script você pode clonar o repositório <a href="http://github.com/ronoaldo/tools" target="_blank">github.com/ronoaldo/tools</a> ou baixar apenas o script <a href="https://github.com/ronoaldo/tools/blob/master/bin/kernelbuild" target="_blank">bin/kernelbuild</a>.</div><div><br /></div><div>O script é bem simples e basicamente faz alguns passos pra você ter o kernel mais novo rapidamente:</div><div><ul style="text-align: left;"><li>Ele irá <b>baixar e verificar</b> o código fonte de kenel.org</li><li>O código é descompactado e <b>configurado usando utilizando o seu .config atual</b></li><li>O script irá <b>gerar os pacotes .deb</b> para que você possa instalar</li></ul><div>Baixe o script e coloque em um diretório local de executáveis que esteja em seu $PATH:</div>
<pre class="prettyprint">RAW="https://raw.githubusercontent.com/ronoaldo/tools/master/bin/kernelbuild"
curl -L $RAW | sudo tee /usr/local/bin/kernelbuild
sudo chmod +x /usr/local/bin/kernelbuild</pre>
<div>Teste a instalação da seguinte maneira:</div>
<pre class="prettyprint">kernelbuild --help</pre>
<div>Com o script instalado, você poderá então executar ele a partir de um diretório em seu $HOME. Por padrão, sem especificar nenhum parâmetro, ele irá baixar a versão mais recente do Kernel e permitir que você faça a configuração manual usando o <b>make menuconfig</b>. Isso pode não ser muito simples, e eu geralmente faço da seguinte maneira:</div>
<pre class="prettyprint">kernelbuild --safe-config --fast</pre>
<div>Desta forma, ele irá tentar usar o máximo de <i>threads </i>e vai auto-configurar o kernel com base no que você tem rodando atualmente. Ele irá mostrar um prompt antes de começa a compilar, basta responde 'y' e pessionar ENTER, e agora é só esperar 😄☕ ... O tempo de construir o pacote pode levar de 1h30 (como é o caso do meu laptop Ideapad com Ryzen 7 3700U) ou 11 minutos (se você der a louca e fize uma máquina muito <a href="https://www.youtube.com/watch?v=kjvsmD9dI6I" target="_blank">heavy metal</a> como eu fiz).</div></div><div><br /></div><div>Depois de construir o kernel, basta instalar ele com o dpkg e reiniciar a máquina para testar:</div>
<pre class="prettyprint">sudo dpkg -i *.deb</pre>
<div>Caso algo não dê certo, basta reiniciar e escolher no Grub a versão anterior.</div><div><br /></div><div><b>Agora é com você</b>: Faça seu kernel build customizado e compartilhe nos comentários abaixo como foi sua experiência de compilar e executar o kernel na raça!</div><div><br /></div><div><b>Observação:</b> neste kernel customizado, o <b><i>secure boot</i> deve estar desligado</b>. Em breve teremos aqui um post ensinando como fazer para criar as suas próprias chaves e manter o secure boot ligado! Deixem nos comentários as dúvidas ou sugestões!</div>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0São Paulo, SP, Brasil-23.5557714 -46.6395571-51.86600523617885 -81.79580709999999 4.7544624361788443 -11.483307099999998tag:blogger.com,1999:blog-4241414426102940500.post-531676048584536192021-11-09T20:41:00.005-03:002021-11-11T16:08:31.608-03:00Mudar de carreira aos 45 do segundo tempo? Sim!<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsJO8iGkH88L-eosLjYR6SJZ4J6Hy7Ns9GwT6fISkJ6C58-5sARUA6y0ftYLOivEyWwimnqG3LAPzyyl97ynj7Rx1zVKHnD63XeUfzvE39i7Qi1CjpzTtZLgJ7NeZyfx2SsBmLRQK1O2et/s700/header.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="400" data-original-width="700" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsJO8iGkH88L-eosLjYR6SJZ4J6Hy7Ns9GwT6fISkJ6C58-5sARUA6y0ftYLOivEyWwimnqG3LAPzyyl97ynj7Rx1zVKHnD63XeUfzvE39i7Qi1CjpzTtZLgJ7NeZyfx2SsBmLRQK1O2et/s16000/header.png" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><br /></div><p>Já faz um tempo desde que eu escrevi o último post... Foram tempos bem ocupados desde o último projeto que trabalhei apoiando a Benefício Fácil na integração para prestação de serviços junto à Sodexo. Afinal de contas, não é tão trivial assim processar <a href="https://cloud.google.com/customers/beneficio-facil" rel="nofollow" target="_blank">um milhão de benefícios a cada mês</a>!</p><p>Muita coisa aconteceu mesmo. A família cresceu com a chegada da Lívia, mudamos de apartamento (de novo!), e eu até virei <i>Diretor de Tecnologia da Informação! </i>Nada mau, para um menino nascido lá no interior de Minas Gerais! Depois de um longo período de desafios, e de um ano atípico como foi o ano de 2020, eu refleti muito. A reflexão na verdade começou em 2019, no último trimestre. </p><p>Eu tinha uma abordagem não muito convencional ao entrevistar os candidatos nas vagas de emprego que possuíamos em aberto. Gostava de ver a trajetória, repassando as experiências de trabalho da mais antiga até a mais recente. Sua trajetória diz muito sobre o que você é hoje. Querendo ou não, você carrega um pouco de cada uma dessas experiências e elas compõem o seu conjunto de valores, seu caráter. Ao terminar, pedia para o candidato responder à pergunta clichê: "onde você se vê daqui a dois anos?". Em uma das entrevistas, essa pergunta ficou ecoando na minha mente: "e você Bill, onde vai estar daqui a dois anos?". E o pior: eu não tinha resposta!</p><p>Eu estava insatisfeito com a minha atuação como diretor. Confesso que não havia me preparado para seguir essa linha de gestão. Foi tudo meio na linha do Zeca Pagodinho: deixando a vida me levar, e ela me levou até onde eu estava. Mas sabe quando você tenta encaixar um quadrado dentro de um círculo? Se o círculo for um pouco grande, até cabe. E se você ampliar o quadrado, preenche bem mas fica sempre faltando uma parte. Eu era um quadrado tentando estar em uma cadeira redonda. Não cabia.</p><p>Ora, eu havia feito graduação em Ciência da Computação, ministrado aulas, atuado como instrutor do Google e até mesmo <i>tentado</i> fazer a gestão de profissionais de tecnologia. Deveria ter algo que eu pudesse fazer! Seguir como diretor seria como começar uma carreira do zero, porque boa parte dos conhecimentos e experiências que eu havia acumulado, não eram tão úteis para a função. Em uma reunião de planejamento estratégico, o conhecimento técnico é pouco útil. Eu até pensei em estudar e me especializar. Cheguei a dizer que queria ser o <i>melhor Diretor de TI do mundo</i>. Mas ao ler a ementa da especialização, fiquei desanimado.</p><p>Tentei então sentar na cadeira acadêmica. Me matriculei em um curso rápido, de quatro sábados. Consegui assistir a três aulas do curso de <a href="https://haskell.pesquisa.ufabc.edu.br/cursos/04-estruturas-de-dados-puramente-funcionais-2019/" target="_blank">Estruturas de Dados Puramente Funcionais da UFABC</a>. Excelente curso, pena que eu só entendi o início da primeira aula: além de não me recordar mais nem o que era uma árvore rubro-negra (não, ela não é uma árvore com uma bandeira do flamengo), eu mal consegui instalar o Haskell e fazer um "olá mundo".</p><p>Até tentei programar de novo, algo que sempre foi minha paixão por mais de uma década. Mas o <i>burnout</i> estava me bloqueando de conseguir raciocinar. Ouvir a palavra "quando fica pronto" imediatamente me retirava a paixão e convertia ela por um ódio meio sinistro...</p><p>Nessa altura chegou a bater um desespero. Cadeira redonda, quadrada, triangular, nenhuma delas estava servindo. Eu já estava até me vendo sem perspectivas de progredir na carreira. Foi aí que eu encontrei uma nova oportunidade: a de ministrar treinamentos do Google Cloud com a Arki1, uma empresa parceira de treinamentos do Google Cloud.</p><p>Ah o Google. Chegava a brilhar os olhos ver e usar as tecnologias do Google Cloud, entender o modo diferente de pensar dos <i>googlers</i> ao implementar soluções, e dividir elas nos eventos do Google I/O. E, ensinar sempre foi também uma paixão. Refletindo, lembrei que sempre tive um pé na sala de aula, de um jeito ou de outro.</p><p>Na escola, logo ao entrar no ensino médio, comecei com a monitoria de física. Na faculdade, idem: monitor de física e geometria analítica. Após me formar, dava aulas de Compiladores e Inteligência Artificial de noite, e treinava professores da rede pública de Vitória aos finais de semana, no projeto Vix Linux. Ao me mudar para São Paulo, dividia o tempo entre o primeiro ano trabalhando na Benefício Fácil e dando aulas para os alunos do Colégio Técnico da Unicamp.</p><p>Mesmo depois de não estar mais formalmente trabalhando dando aulas, sempre promovia eventos de capacitação interna, participava de <i>meetups</i> e palestras, e até comecei em 2015 a dar treinamentos do Google Cloud.</p><p>Enfim, veio a decisão: trocar o <i>side-project</i> de ensinar para ele virar o meu <i>daily driver</i>. Em fevereiro de 2021 dei meu primeiro treinamento, e foi um dia de trabalho tão cheio de realização que consolidou a decisão: valeu a pena! E voltar a dar aulas também me vez voltar a ter a energia para aprender. Estudei bastante e já consegui 6 certificações do Google Cloud, ainda restam quatro que pretendo concluir ainda este ano.</p><p>Se você chegou até aqui, espero que este relato tenha te inspirado: <b>Nunca é tarde para começar, e tem horas que aquilo que mais precisamos, já estava conosco o tempo todo!</b></p>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com8tag:blogger.com,1999:blog-4241414426102940500.post-57307228578252233872015-10-26T08:00:00.000-02:002015-10-26T08:00:05.488-02:00Compilando imagens do Debian Live com Bitbucket, SourceForge e Google Cloud<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ2DFFC1mSCqkD9HElyXN04bvSMR3qeGNNntnA7taCAOPlH7gSho9MVH2AjHejW8AFkqeqXTnWqyowFL4rPVjolHRZRA3HNHYommxttloldhFOdj5xYpKzeyYB6e6EI8lea-GD3MQHT7C5/s1600/ronolinux.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="221" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZ2DFFC1mSCqkD9HElyXN04bvSMR3qeGNNntnA7taCAOPlH7gSho9MVH2AjHejW8AFkqeqXTnWqyowFL4rPVjolHRZRA3HNHYommxttloldhFOdj5xYpKzeyYB6e6EI8lea-GD3MQHT7C5/s320/ronolinux.jpg" width="320" /></a></div>
<br />
Recentemente, implantamos <a href="http://www.vivaolinux.com.br/linux/" target="_blank">Linux</a> em alguns dos computadores da empresa. Para esses usuários, que lidam a maior parte do tempo com o browser, a migração não foi problemática: não havia a necessidade de software específico para eles. Como utilizamos o <a href="http://goo.gl/DkIlgU" target="_blank">Google Apps for Work</a>, então não temos nenhum problema de compatibilidade, e podemos contar com backups, colaboração em tempo real, e portabilidade da informação.<br />
<br />
Para facilitar a implantação, eu precisava de uma forma de fazer uma seleção de scripts, aplicar algumas customizações e configurações internas para aderir à nossas políticas de software, e foi aí que tive a idéia de criar uma imagem customizada do Debian.<br />
<br />
Eu uso a nuvem do <a href="https://cloud.google.com/" target="_blank">Google</a> diariamente, seja em minhas atividades de trabalho ou seja em meus projetos pessoais. Neste post eu vou comentar como eu conectei diferentes serviços à nuvem do Google para viabilizar um desses projetos pessoais e sem fins lucrativos: o <i>ronolinux</i>.<br />
<br />
Esse projeto nada mais é do que de uma compilação de <a href="https://pt.wikipedia.org/wiki/Live_CD" target="_blank">imagens <i>live</i></a>, resultado de uma seleção minimalista de pacotes para facilitar a implantação do Linux em meus casos de uso. Ele também serve como um projeto modelo para quem deseja masterizar seu próprio DVD/USB-live com Debian personalizado.<br />
<br />
<h3>
Debian Live</h3>
O projeto que eu utilizei como base no <i>ronolinux</i> foi o <a href="http://live.debian.net/" target="_blank">Debian Live, agora Live Systems</a>. Este projeto consiste em um conjunto de scripts para a configuração e compilação de imagens <i>live</i> baseadas no Debian e derivados. Este é o projeto que produz as imagens <i>live</i> oficiais do Debian, então tem suporte no repositório e é mantido por um desenvolvedor Debian.<br />
<br />
Bom, mas o que tem o Debian Live a ver com a nuvem do Google? Eu tinha um pequeno problema com relação ao <i>ronolinux</i>. Compilar a imagem leva um tempo, requer uma boa conexão com a internet, um bom espaço em disco para cache. Fazer isso no notebook, via wifi, acabava por gerar alguns problemas:<br />
<ul>
<li>Eu tinha que levar meus dados de um lugar para o outro, estava tudo no notebook.</li>
<li>Eu tinha que aguardar o <i>build</i> terminar localmente para então desligar o notebook. Isso era ruim, porque eu queria deixar ele rodando no final do dia, pra não adiar uma correção pro dia seguinte.</li>
<li>O <i>build</i> consome muita memória e CPU em alguns estágios, e eu não conseguia prosseguir com outras atividades na máquina que estava compilando a imagem.</li>
<li>Eu queria iterar no desenvolvimento em momentos nos quais eu não tinha a máquina de <i>build</i> em mãos, ou quando ela não estava ligada.</li>
<li>Para testar as imagens, eu tinha que ou copiar em mídia, ou fazer o upload de arquivos de alguns <i>gigabytes</i>.</li>
</ul>
<h3>
Nuvem para o resgate!</h3>
Não só porque está na moda, no meu caso era a solução perfeita: rodar os <i>builds</i> na nuvem! Para isso eu fiz uma máquina virtual Debian Jessie no Compute Engine e começei a compilar as imagens por lá.<br />
<br />
Com isso eu tinha diversas vantagens. Como eu poderia apenas abrir o browser e <a href="https://cloud.google.com/compute/docs/ssh-in-browser" target="_blank">conectar por SSH na máquina virtual</a>, não precisava mais carregar o notebook pra lá e pra cá. Além disso, eu podia também contar com algumas vantagens do Compute Engine, tais como uma boa conexão de rede para baixar pacotes, e o disco persistente para fazer cache entre uma compilação e otura, além de poder escolher diferentes opções de disco, CPU e memória.<br />
<br />
O Compute Engine é tão bem integrado com o Debian que temos até um mirror do repositório acessível de dentro do Google Cloud, otimizando ainda mais o build. Mas eu não parei por aí. Afinal de contas, estamos na era da integração contínua, e compilar as imagens é feito a partir de um código-fonte simples que configura como e quais pacotes vão na ISO.<br />
<br />
<h3>
Push to deploy!</h3>
Eu queria implementar um recurso extra: fazer o <i>build</i> ser acionado por um <i>push</i> no repositório. Para isso, o que eu fiz foi implementar um <i>handler HTTP</i> em Go, utilizando o pacote <span style="font-family: "Courier New",Courier,monospace;"><a href="https://godoc.org/ronoaldo.gopkg.net/aetools/vmproxy" target="_blank">vmproxy</a></span>, que eu desenvolvi para permitir executar VMs do Compute Engine a partir do App Engine, sob-demanda, bem como "desligá-las" quando não estão mais em uso.<br />
<br />
Desta forma, não só eu pude configurar uma <i>webhook</i> no Bitbucket para automatizar o <i>build</i>, mas também publicar o resultado no SourceForge, que tem um bom espaço para armazenamento e uma integração por <span style="font-family: "Courier New",Courier,monospace;">rsync</span> para o upload, o que o tornou uma opção exclenente para hospedar o resultado das imagens.<br />
<br />
O melhor disso tudo é que eu posso usar máquinas virtuais com disco SSD, bom desempenho de CPU e Memória, e ainda contar com uma redução fantástica de custos: posso usar uma máquina <i>preemptível</i>, que é muito mais barata do que a máquina virtual convencional!<br />
<br />
Neste ponto você pergunta: <i>- Mas você não está fazendo imagens live? O problema do upload de imagens ficou resolvido, mas e pra testar, não tem que baixar tudo de novo?</i><br />
<br />
Exatamente! Para resolver isso, eu aprendi uma coisa ao trabalhar como Debian Live. Automaticamente, o sistema gera um arquivo <span style="font-family: "Courier New",Courier,monospace;">.zsync</span>. O zsync é uma ferramenta ideal para sincronizar arquivos, especialmente nesse caso que são arquivos ISO, alterados frequentemente. O zsync baixa o arquivo de controle, e depois só baixa os <i>pedaços</i> da imagem nova que você ainda não tem. Isso é ótimo, e eu pude comprovar: reaproveitei mais de 85% do arquivo de imagem entre um <i>build</i> e outro!<br />
<br />
Meu workflow agora ficou assim:<br />
<ol>
<li>De qualquer lugar, posso fazer apenas um push para o Bitbucket com uma mudança de configuração: incluir pacote, adicionar hook, etc.</li>
<li>O Bitbucket aciona meu webhook no App Engine, que liga a VM com o script de startup.</li>
<li>O script faz o checkout do Bitbucket, compila as imagens, e publica no SourceForge. No final, desliga a VM e salva um backup dos logs no Cloud Storage.</li>
<li>Eu configurei uma notificação no SourceForge, e sempre que ele recebe uma versão nova do <i>ronolinux</i>, eu recebo um email.</li>
<li>Para testar, eu baixo a versão atualizada do meu ISO com o <span style="font-family: "Courier New",Courier,monospace;">zsync</span>, reaproveitando o máximo da imagem anterior que eu já tinha na máquina de testes, ou baixando uma nova, pra testar em qualquer lugar.</li>
</ol>
<h3>
Conclusão</h3>
Utilizando recursos hoje já disponíveis, é possível elaborar mecanismos complexos para resolver problemas de forma simples e prática, e sem pagar muito por isso. O que eu vou ter de custos com o Google Cloud não compra um computador novo, que ainda me custaria energia pra rodar apenas esse projeto simples e sem fins lucrativos que é o <i>ronolinux</i>. Com a nuvem do Google e os serviços Bitbucket e SourceForge, eu pude conectar as peças e obter um workflow que otimiza o meu tempo e torna o build simples e rápido.<br />
<br />
Estou agora considerando reduzir o tempo de 1h pra gerar as duas "edições" do <i>ronolinux</i>, desktop e developer, em paralelo, o que deve deixar tudo em torno de 30min depois do commit.<br />
<br />
Você pode encontrar o código-fonte, incluindo os scripts de build do Compute Engine no meu projeto do <a href="https://bitbucket.org/ronoaldo/debian-custom/" target="_blank">Bitbucket</a>. As imagens que estou produzindo ainda estão em fase prelimitar de testes, mas caso queira conferir estão aqui no <a href="https://sourceforge.net/projects/ronolinux/" target="_blank">SourceForge</a>.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">:happy hacking!</span><br />
<br />
<br />Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-58508455312210845922015-09-01T23:05:00.001-03:002021-11-09T17:05:18.419-03:00Olá, Gopher!<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqrGW1kxqK7Ws1o8R0vFHaSyY-7jpTQV-qG7uxLEUXeBtIyXe3TaHgCGjf2k7mBEY6TngU9v42z0YR9NNzcalJqiVCmYEloIWxxIBSFz30GHyWElCnQqa3pA8hz2_hwnHXMimGvo1yxhP-/s900/gopher.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="426" data-original-width="900" height="189" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhqrGW1kxqK7Ws1o8R0vFHaSyY-7jpTQV-qG7uxLEUXeBtIyXe3TaHgCGjf2k7mBEY6TngU9v42z0YR9NNzcalJqiVCmYEloIWxxIBSFz30GHyWElCnQqa3pA8hz2_hwnHXMimGvo1yxhP-/w400-h189/gopher.png" width="400" /></a></div><br /><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: left;">O Google desenvolveu uma nova linguagem de programação, chamada Go, que tem uma proposta moderna e inovadora. Go é uma linguagem compilada, estaticamente tipada, e que foi inicialmente projetada para ser um substitudo de C. Com uma sintaxe simples e concisa, recursos de programação concorrente avançados, e com uma <i>runtime</i> e <i>garbage collector</i>, Go possui recursos avançados de programação.</div>
<br />
Neste artigo nós vamos dar os primeiros passos em Go, instalando o compilador em ambiente Linux e escrevendo nosso primeiro programa. Neste artigo vamos explorar também algumas das características do Go que o tornam atrativo para o programador de hoje em dia.<br />
<br />
<h3>
Obtendo o compilador Go</h3>
Como é uma linguagem compilada, você vai precisar de um compilador Go. Existem aqui duas opções: você pode utilizar o GCC, se já está acostumado, pois o <i>gccgo</i> já faz parte das edições mais recentes do compilador Gnu. Eu recomendo a segunda opção: utilizar a compilador e a coleção de ferramentas do próprio Go. Além de vários recursos extras, o compilador oficial recebe os recursos novos primeiro.<br />
<br />
Para obter o compilador Go, faça o download no site oficial da linguagem em <a href="https://golang.org/dl/" target="_blank">https://golang.org/dl/</a>. No site você pode escolher a versão correta para seu sistema operacional e arquitetura, e então seguir as instruções para instalar em seu sistema Operacional. Em sistemas Linux, basta extrair o arquivo baixado (.tar.gz) em sua pasta /usr/local. Em seguida, você pode então configurar a variável PATH para incluir a pasta onde o Go foi instalado.<br />
<br />
Se você utilizar Linux, e seu computador for de 64 bits, pode utilizar estes comandos:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">$ curl https://storage.googleapis.com/golang/go1.5.linux-amd64.tar.gz | sudo tar -C /usr/local -xzf -</span><br />
<span style="font-family: "Courier New",Courier,monospace;">$ echo 'export PATH=$PATH:/usr/local/go/bin' >> .bashrc</span><br />
<br />
Desta forma, basta você recarregar seu shell e confirmar que o Go está instalado:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">$ go version<br />go version go1.5 linux/amd64</span><br />
<br />
Agora vamos a uma etapa da isntalação que é importante. O Go assume que você vai guardar seus arquivos em uma pasta especial, chamada <i>GOPATH</i>. O compilador vai usar essa variável para encontrar seu código, bem como as dependências de terceiros que você utilizar. Imagine que isso é o equivalente à dezenas de milhares de -I e -L para compilar código C, ou configurar o CLASSPATH do compilador Java. Em Go, sempre preferimos <i>convenção</i> a <i>configuração</i>, e isso traz benefícios logo de início!<br />
<br />
Escolha uma pasta onde você vai guardar seus projetos Go. Se estiver com dúvidas, você pode fazer a sua pasta principal ser a pasta do GOPATH:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">$ echo 'export GOPATH=$HOME' >> .bashrc</span><br />
<span style="font-family: "Courier New",Courier,monospace;">$ echo 'export PATH=$PATH:$GOPATH/bin' >> .bashrc</span><br />
<br />
Note que na segunda linha, eu adicionei mais um diretório ao PATH: o GOPATH/bin, que é onde o Go instala os programas. Isso faz com que logo depois de compilar e instalar localmente seus programas Go, eles já estão prontos para uso! <br />
<br />
<h3>
Seu primeiro programa Go</h3>
Agora que você já tem o comando <i>go</i> instalado, vamos usá-lo para criar nosso primeiro programa. O programa deve ser salvo na pasta <i>src/hello</i> de seu <i>$GOPATH</i>. <br />
<br />
Vamos criar o arquivo hello.go com o seguinte conteúdo:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">package main<br /><br />import (<br /> "fmt"<br />)<br /><br />func main() {<br /> fmt.Println("Hello, world!")<br />}</span><br />
Salve o arquivo e em seguida, execute o comando <i>go build</i>:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">~/src/hello$ <b>go build</b></span><br />
<span style="font-family: "Courier New",Courier,monospace;">~/src/hello$ <b>ls</b><br />hello hello.go</span><br />
<br />
Agora vamos executar nosso programa:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">~/src/hello$ <b>./hello</b><br />Hello, world!</span><br />
<br />
Pronto! Você acaba de criar seu primeiro programa em Go. O comando <i>go build</i> executa o processo de compilar e linkar seu programa, ou seja, ele irá transformar seu código fonte em um arquivo binário executável, estaticamente linkado. Isso significa que você pode simplesmente copiá-lo e executá-lo em outro computador com a mesma arquitetura/sistema operacional, as biblitoecas, a Runtime do Go e o Garbage collector são todos inclusos em seu programa.<br />
<br />
Neste artigo não vamos entrar em detalhes sobre a sintaxe, mas como você pode notar no exemplo acima, ela é simples e elegante, direto ao ponto. Eu vou começar aqui uma série de posts sobre como programar em Go, todos com a tag <i>golang</i>, então fique de olho!<br />
<br />
Poste nos comentários o que gostaria de aprender sobre Go, ou se você já utiliza, compartlhe o que achou da linguagem!<br />
<br />
Happy Hacking!<br />
<br />
<i>The Go Gopher is a creation of Renee French, under Creative Commons 3.0</i>.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-53234192934316042732015-08-24T10:00:00.001-03:002021-11-09T17:07:57.208-03:00Primeiros passos com o Raspberry PiO <a href="http://www.raspberrypi.org/">Raspberry Pi</a> é um <i>mini computador</i> desenvolvido por pesquisadores da Universidade de Cambridge, com o objetivo de oferecer aos estudantes uma ferramenta de baixo custo, com o intuito de incentivar os estudos em programação de computadores. O Pi é um computador pessoal, como o que você compra em lojas, com alguns recursos limitados, tamanho reduzido e preço acessível: $35.<br />
<br />
O Pi é um computador completo: processador, memória RAM, portas USB, saída de vídeo componente e HDMI, saída de áudio, plug RJ45 para rede cabeada (ethernet). O <i>setup</i> básico consiste em você plugá-lo em sua TV pelo HDMI ou vídeo componente (RCA), plugar na porta USB um teclado e ligá-lo. O Pi não possui um <i>gabinete</i>, mas existem cases para protegê-lo.<br />
<br />
Propositalmente, ele possui alguns circuitos e pinos para conexão, os chamados <a href="https://pt.wikipedia.org/wiki/General_Purpose_Input/Output" target="_blank">GPIOs</a> (General-pourpose Input/Output - entrada e saída de propósito geral), permitindo usar o Pi em projetos de eletrônica diversos, conectando-o a componentes customizados, proto-boards, sensores, e outros.<br />
<br />
O primeiro passo é comprar um Pi. Se você estiver em uma viagem para os EUA (como foi o meu caso no Google I/O 2014), basta encomendar um pela Amazon. Se você não for viajar, pode também importar um dos resellers que possuem<i> international shipping</i>, mas leve em conta que o imposto a ser pago na alfândega é o de um computador. Aqui no Brasil você encontra ele a um preço um pouco mais salgado do que a proposta inglesa. O Pi deve sair em torno de R$ 120,00 a R$ 180,00, pesquise no Mercado Livre ou em lojas de eletrônica.<br />
<br />
Existem duas gerações de raspberry Pi. Na primeira geração, temos dois modelos, o Pi 1 Model A+, Pi 1 Model B+. Recentemente foi lançada a segunda geração, o Pi 2 Model B+. O Model Pi 1 A+ possui o menor consumo de energia dos três, mas um baixo poder de processamento e memória RAM, e o Pi 2 Model B+ é o que possui mais recursos. <br />
<br />
De posse do seu Pi, você primeiro deve instalar ou configurar o cartão de memória para <i>boot</i> com um sistema operacional. O Pi funciona geralmente com alguma versão do Linux, já que o kernel, módulos e o tamanho do sistema instalado podem ser otimizados para o hardware do Pi. No meu caso, eu comprei um <a href="http://amzn.com/B00CXACPN0" target="_blank">Kit da Amazon</a>, em uma viagem ao exterior, e o meu cartão de memória já veio formatado com o software para a instalação de diversos <i>sabores</i> de sistemas que funcionam no Pi. Ao ligar, o setup já lhe pergunta qual o sistema você quer instalar e faz o processo todo sozinho. Você também encontra tutoriais sobre como configurar o <a href="https://www.raspbian.org/" target="_blank">Raspbian</a>, versão do Debian para o Raspberry Pi, ou até locais que vendem o Raspbian pré-instalado no SD-Card. Recomendo comprar o cartão já instalado se você quiser ir direto para a implementação de algo útil.<br />
<br />
Com o cartão de memória configurado, basta plugar os componentes. Eu utilizei uma TV, com entrada HDMI, e um teclado USB sem fio da Logitec, que já vem com um Touch Pad (é, eu voltei dos EUA cheio de bugingangas...). O Pi, diferente de um computador convencional, não tem um botão liga/desliga: a fonte de alimentação já inicia o <i>boot</i>. Com ele ligado, basta seguir as orientações <i>on-screen</i>. Eu escolhi o Raspbian, a versão do Debian GNU/Linux compilada para o Pi. Eu gosto muito do Debian, já tenho vários anos de experiência e hoje ele está no meu computador de casa, trabalho e notebook. A instalação é bem simples a partir do SD card já formatado para o Pi, então basta esperar pela mensagem de que o SO foi instalado com sucesso.<br />
<br />
Depois de instalado, o sistema faz o boot. É um boot de Linux tradicional: mensagens de log ao carregar os módulos do kernel e inicializar os serviços. O primeiro boot tem algumas opções de configuração inicial, como expandir o cartão de memória para ter espaço de armazenamento, alterar a senha do usuário padrão (recomendado!), entre outros. Você pode voltar nesta tela novamente mais tarde usando os seguintes comando:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">sudo raspi-config</span><br />
<br />
Eu utilizei as opções de atualização de senha e habilitar a câmera, já que eu também comprei o módulo de câmera compatível com o Pi, bem como a de configurar opções locais, e ajustei o fuso horário e relógio do Pi, mas mantive o idioma em inglês. Eu também entrei nas opções avançadas, para habilitar o SSH, assim eu poderia usá-lo sem um monitor, pela rede, bem como configurar o <i>hostname</i>, nome como ele é visível na rede.<br />
<br />
Ao concluir as configurações do primeiro boot, eu recomendo reiniciar o Pi, quando ele lhe pergunta se você quer fazer isso, assim as suas configurações podem ser validadas logo no início. Minha recomendação é para que você já teste se os ajustes feitos entrão em efeito da forma correta.<br />
<br />
Depois de reiniciar o Pi, ele está pronto para uso. Ao ligar o Pi, ele inicializará em <i>modo texto</i>, ou seja, você não vai ver uma tela gráfica logo de início. Ele vai mostrar um prompt pedindo o nome de usuário. O Raspbian já vem com um usuário <i>pi</i> e a senha que você configurou no primeiro boot. Depios de digitar o usuário e senha, você pode digirar o comando<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">startx</span><br />
<br />
Para carregar a interface gráfica do sistema, que é o LXDE, já com vários softwares e configurações para o Pi disponíveis: o manual do Debian, IDLE, uma IDE para o Python, documentação sobre o desenvolvimento de jogos com PyGame, link para a loja do Pi, configuração de rede sem fio (se você tiver um <i>wifi usb</i>), e muito mais. Um item interessante é o Scratch, um aplicativo desenvolvido para o Pi, para ensinar programação para crianças. Você monta um algoritmo de forma visual, e executa ele no Scratch.<br />
<h3>
O que fazer com ele?</h3>
Por ser um computador completo, o céu é o limite! O seu tamanho pequeno e baixo consumo de energia proporcionam diversas aplicações onde um computador convencional não seria adequado. Eu já postei aqui no blog um tutorial de como usá-lo pra transformar uma <a href="http://blog.ronoaldo.net/2015/06/conectando-sua-impressora-convencional-ao-google-cloud-print-com-raspberry-pi-e-debian.html" target="_blank">impressora convencional em uma impressora do Cloud Printer</a> (na verdade, uma impressora de rede local também, via Cups).<br />
<br />
Eu tenho alguns projetos em mente para implementar, incluindo:<br />
<ul>
<li>Um vídeo-game com motion detection para controles.</li>
<li>Um roteador customizado com modens.</li>
<li>Ser a central de controle de um sistema de automação/monitoramento residencial.</li>
</ul>
E você, o que gostaria de implementar com um Pi? Poste aqui nos comentários! <br />
<br />
Happy hacking!<br />
<br />
<h2>
Referências</h2>
[1] Richardson, Matt, and Shawn P. Wallace. <i>Getting started with Raspberry Pi</i>. Sebastopol, CA: O'Reilly Media, 2012.<br />
[2] Raspberry Pi Hardware - https://www.raspberrypi.org/documentation/hardware/raspberrypi/Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0São Paulo - SP, Brasil-23.5505199 -46.633309399999973-24.4811409 -47.924202899999976 -22.619898900000003 -45.34241589999997tag:blogger.com,1999:blog-4241414426102940500.post-90491306503785361572015-06-12T12:00:00.000-03:002015-06-12T12:00:07.016-03:00Conectando sua impressora convencional ao Google Cloud Print com Raspberry PI e Debian<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNsrP_8B2szxXE8jSza2RL6JxcVS14z8ERgCvuM2Qx18QWYcz8TfwsD-8ODylFF5xBXCuWe2wV2tjpsbDz7Qd75957UoSrB_Csy3C7NFzparQlVmkU0Hpd9KfSe2OE_fvkZItsKMGpAK4a/s1600/cover.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNsrP_8B2szxXE8jSza2RL6JxcVS14z8ERgCvuM2Qx18QWYcz8TfwsD-8ODylFF5xBXCuWe2wV2tjpsbDz7Qd75957UoSrB_Csy3C7NFzparQlVmkU0Hpd9KfSe2OE_fvkZItsKMGpAK4a/s400/cover.jpg" width="400" /></a></div>
O Google Cloud Print é um serviço do Google que possibilita realizar impressão de documentos, fotos e outros tipos de arquivo utilizando a internet. Isso significa que você pode conectar suas impressoras em qualquer dispositivo compatível, como tablets e telefones, e realizar impressões diretamente deles. O mais bacana: é possível configurar tudo via software!<br />
<br />
Neste post nós vamos aprender como configurar o Google Cloud Print no Linux, utilizando o Raspberry PI. O motivo de eu utilizar este equipamento é que ele pode ficar ligado o tempo todo, gastando bem menos energia do que um computador convencional. Além disso, o Pi pode ser usado para outras tarefas, como servir arquivos de mídia ou rodar alguns joguinhos, ou servir de equipamento de vigilância com câmera. Isso ficará para os próximos posts :)<br />
<br />
Você vai precisar de:<br />
<br />
<ul>
<li>Uma impressora</li>
<li>Um Raspberry PI (com Raspbian) ou um Computador (com Debian/Ubuntu)</li>
<li>Conhecimentos básicos de comandos do Linux</li>
<li>Uma conta do Google</li>
</ul>
<div>
<br /></div>
<h3>
Conecte o Pi à internet</h3>
<div>
Estou assumindo que você já possui o Pi funcional ou um computador com Linux. Eu recomendo usar no Pi o Raspbian e em um computador convencional o Debian.</div>
<div>
<br /></div>
<div>
O primeiro passo é ligar e acessar seu Raspberry, e conectá-lo com a sua rede de internet. Você pode ligar o Pi e conectar nele um teclado, e ligar ele na TV pela saída HDMI. Se você possui um Wifi USB, pode deixar a conexão sem fio, senão, pode conectá-lo via rede cabeada mesmo. Com ele na rede, você também pode usar um computador para conectar-se via SSH no Pi.</div>
<div>
<br /></div>
<div>
<i>Importante</i>: o seu Pi precisa estar conectado à <u>internet</u>, caso contrário o Cloud Print não vai funcionar.</div>
<h3>
</h3>
<h3>
Instale o software necessário</h3>
<div>
<i>Importante: neste tutorial iremos executar diferentes comandos, como diferentes usuários: isso serve para garantir a adequada execução do Cloud Print Proxy. Eu vou assinalar os comandos a serem executados como o usuário padrão (geralmente pi) que possui o sudo habilitado, bem como os comandos que iremos executar com a conta dedicada ao Cloud Print (googlecloudprint). A parte em cinza serve apenas para isso, os comandos são apenas a parte em negrito.</i></div>
<div>
<br /></div>
<div>
Primeiro, faça um upgrade para obter as atualizações de segurança:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><span style="color: #999999;">pi@pi$ </span><b>sudo apt-get update && sudo apt-get upgrade</b></span></div>
<div>
<br /></div>
<div>
Em seguida, vamos instalar o Chromium, que é a versão do Google Chrome para o Debian, e o servidor de impressão chamado CUPS:</div>
<div>
<br /></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;"><span style="color: #999999;">pi@pi$ </span></span><span style="font-family: Courier New, Courier, monospace;"><b>sudo apt-get install chromium cups unzip</b></span></div>
<div>
<span style="font-family: 'Courier New', Courier, monospace;"><span style="color: #999999;">pi@pi$ </span></span><span style="font-family: Courier New, Courier, monospace;"><b>sudo apt-get clean</b></span></div>
<h3>
</h3>
<h3>
Adicione sua Impressora ao Pi</h3>
<div>
Agora que temos o software necessário, vamos à configuração. Primeiro, vamos criar uma conta dedicada à impressão, chamaremos o usuário de googlecloudprint e vamos dar a ele acesso à gestão de impressoras, pelo grupo <i>lpadmin</i>.</div>
<div>
<br /></div>
<div>
Para isso, execute o comando abaixo e preencha os campos para criar o usuário. Você definirá um senha para este usuário que iremos precisar logo em seguida, tome nota da mesma e não deixe essa ser uma senha <i>fraca</i>.</div>
<div>
<br /></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">pi@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>sudo adduser --ingroup lpadmin googlecloudprint</b></span></div>
<div>
<br /></div>
<div>
Agora, vamos configurar o CUPs para que possamos adicionar impressoras ao Pi, que serão depois configuradas como impressoras do Cloud Print. O CUPS possui uma interface web que permite gerenciar as impressoras, e nós vamos ativar esta interface web na rede local, assim podemos fazer a gestão das impressoras de outros computadores e o Pi não precisa ficar conectado a teclado ou monitor.</div>
<div>
<br /></div>
<div>
Para isso nós vamos editar o arquivo de configuração do CUPS que está na pasta /etc/cups:</div>
<div>
<br /></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">pi@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>sudo nano /etc/cups/cupsd.conf</b></span></div>
<div>
<br /></div>
<div>
A primeira modificação é no parâmetro <i>Listen</i>, que está restrito ao próprio computador, e nós vamos modificar para não restringir apenas à maquina local. No arquivo, procure por:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Only listen for connections from the local machine.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Listen localhost:631</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Listen /var/run/cups/cups.sock</span></div>
<div>
<br /></div>
</div>
<div>
E modifique para:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Only listen for connections from the local machine.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b># Listen localhost:631</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Listen /var/run/cups/cups.sock</span></div>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>Port 631</b></span></div>
<br />
Agora, mais abaixo no mesmo arquivo, vamos ajustar as configurações de segurança. Procure pelas linhas abaixo, e inclua <i>Allow @local</i>, semelhante ao que está destacado em negrito:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">< Location / ></span><br />
<br />
<span style="font-family: Courier New, Courier, monospace;"># Restrict access to the server...</span><br />
<span style="font-family: Courier New, Courier, monospace;">Order allow,deny</span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>Allow @local</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">< /Location ></span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">< Location /admin ></span><br />
<span style="font-family: Courier New, Courier, monospace;"># Restrict access to the admin pages...</span><br />
<span style="font-family: Courier New, Courier, monospace;">Order allow,deny</span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>Allow @local</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">< /Location ></span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;">< Location /admin/conf ></span><br />
<span style="font-family: Courier New, Courier, monospace;">AuthType Default</span><br />
<span style="font-family: Courier New, Courier, monospace;">Require user @SYSTEM</span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: Courier New, Courier, monospace;"># Restrict access to the configuration files...</span><br />
<span style="font-family: Courier New, Courier, monospace;">Order allow,deny</span><br />
<span style="font-family: Courier New, Courier, monospace;"><b>Allow @local</b></span><br />
<span style="font-family: Courier New, Courier, monospace;">< /Location ></span><br />
<span style="font-family: Courier New, Courier, monospace;"><br /></span>
<span style="font-family: inherit;">Depois de salvar as alterações no arquivo (no </span><span style="font-family: Courier New, Courier, monospace;">nano</span><span style="font-family: inherit;">, utilize <i>CTRL+X</i> depois <i>Y ENTER</i>), reinicie o CUPS:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">pi@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>sudo service cups restart</b></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Agora que está tudo configurado, tente acessar o CUPS pelo endereço IP do seu Raspberry, na porta 631, a partir de qualquer outro computador na rede ou mesmo de se seu smartphone, se ele estiver conectado à mesma rede que o Pi: </span><span style="font-family: inherit;">https://</span><i style="font-family: inherit;">ip-do-seu-raspberry</i><span style="font-family: inherit;">:631/. </span><i style="font-family: inherit;">Dica</i><span style="font-family: inherit;">: conecte-se via HTTPS, e confirme a exceção de segurança se o navegador exibir essa pergunta.</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Uma vez conectado ao CUPS, clique em <i>Administration</i>:</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://docs.google.com/uc?id=0B9NjifSUullgZzQ2X18wamJmQzA&export=download" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="249" src="https://docs.google.com/uc?id=0B9NjifSUullgZzQ2X18wamJmQzA&export=download" width="320" /></a></div>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">E em seguida, no botão <i>Add Printer</i>:</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://docs.google.com/uc?id=0B9NjifSUullgT0N2cDhqZGpncDQ&export=download" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="226" src="https://docs.google.com/uc?id=0B9NjifSUullgT0N2cDhqZGpncDQ&export=download" width="320" /></a></div>
<span style="font-family: inherit;"><br /></span>
<br />
O CUPS vai pedir uma usuário e senha. Informe o usuário e senha que criamos antereiormente: <i>googlecloudprint</i>. Escolha a impressora na lista. Você pode adicionar impressoras de rede que estiverem acessíveis ao Pi, ou a impressora conectada por USB. Em seguida, clique em <i>Continue</i>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://docs.google.com/uc?id=0B9NjifSUullgcEJ6M2FGTlZNdW8&export=download" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="218" src="https://docs.google.com/uc?id=0B9NjifSUullgcEJ6M2FGTlZNdW8&export=download" width="320" /></a></div>
<br />
Informe um nome para sua impressora, sem espaços, informe uma descrição, que pode ter espaços, e uma localização, com "Casa" ou "Escritório". Clique em <i>Continue</i>. <i>Dica</i>: ao marcar Share this printer, sua impressora ficará visível para outros computadores da rede local, assim você poderá utilizá-la como impressora de rede, mesmo sem o Cloud Print.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://docs.google.com/uc?id=0B9NjifSUullgQzdDMjNSQkRqNk0&export=download" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="172" src="https://docs.google.com/uc?id=0B9NjifSUullgQzdDMjNSQkRqNk0&export=download" width="320" /></a></div>
<div>
<br /></div>
Escolha o modelo, normalmente ele estará pré-selecionado, dê um nome para ela e em seguida clique em <i>Add Printer</i>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://docs.google.com/uc?id=0B9NjifSUullgc2t1Tk5IbnpqX2M&export=download" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="249" src="https://docs.google.com/uc?id=0B9NjifSUullgc2t1Tk5IbnpqX2M&export=download" width="320" /></a></div>
<div>
<br /></div>
Pode ser que o CUPS exiba também uma página para configurar alguns valores padrão, como orientação de papel, etc. Faça as escolhas que julgar necessário e clique em <i>Set Default Options</i>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://docs.google.com/uc?id=0B9NjifSUullgN3k2WUlhSHk1TVE&export=download" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="193" src="https://docs.google.com/uc?id=0B9NjifSUullgN3k2WUlhSHk1TVE&export=download" width="400" /></a></div>
<br />
Eu sugiro que você imprima uma página de testes via CUPS, só para ter certeza que está tudo OK e que o Pi consegue enviar a impressão corretamente.<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<h3>
Configure o serviço do Google Cloud Print</h3>
<div>
Agora, para por nossa impressora <i>na núvem</i>, vamos utilizar o Chromium. As etapas para configurar o Cloud Print em modo servidor podem ser obtidas <a href="https://support.google.com/a/answer/2906017?hl=en" target="_blank">na documentação oficial</a>, mas eu traduzi e adicionei algumas etapas para a configuração ficar mais robusta.</div>
<div>
<br /></div>
<div>
Primeiro, vamos <i>trocar de usuário</i> para o que criamos anteriormente. Observe que no seu shell, o nome do usuário vai mudar de <i>pi</i> para <i>googlecloudprint</i>:</div>
<div>
<br /></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;"><u>pi</u>@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>sudo su googlecloudprint</b></span></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;"><u>googlecloudprint</u>@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>cd ~/</b></span></div>
<div>
<br /></div>
<div>
Agora, faça o download do arquivo <a href="http://www.google.com/support/enterprise/static/chromeos/docs/admin/en/generate_cloudprint_config.py.zip" target="_blank">generate_cloudprint_config.py.zip</a>:</div>
<div>
<br /></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">googlecloudprint@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>wget http://www.google.com/support/enterprise/static/chromeos/docs/admin/en/generate_cloudprint_config.py.zip</b></span></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">googlecloudprint@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>unzip generate_cloudprint_config.py.zip</b></span></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">googlecloudprint@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>chmod +x generate_cloudprint_config.py</b></span></div>
<div>
<br /></div>
<div>
Agora, para concluir, nós vamos utilizar este script para configurar nossa conta do Google para nosso servidor de impressão:</div>
<div>
<br /></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">googlecloudprint@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>./generate_cloudprint_config.py</b></span></div>
<div>
<br /></div>
<div>
<div>
<i>Dica</i>: se você utiliza Two Factor Authentication, vai ter que definir uma Senha de Aplicativo para utilizar. Não se engane: ao por a sua senha do Google o script acima termina sem erros, mas não gera tokens de acesso.</div>
</div>
<div>
<br /></div>
<div>
Siga os passos apresentados pelo script. Informe seu usuário e senha do Google, ou senha de aplicativo se tiver two factor authentication ativo. A sua saída será algo mais ou menos assim:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Email Address: ******@gmail.com</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Password for </span><span style="font-family: 'Courier New', Courier, monospace;">******</span><span style="font-family: 'Courier New', Courier, monospace;">@</span><span style="font-family: 'Courier New', Courier, monospace;">gmail.com</span><span style="font-family: 'Courier New', Courier, monospace;">: </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Connector Id: <b>raspberrypi</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Printserver URL with port (keep empty to skip): <b>http://localhost:631/</b></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">Config file raspberrypi.conf generated for proxy raspberrypi</span></div>
</div>
<div>
<br /></div>
<div>
É importante que você informe o nome do conector <b>raspberrypi</b> e a URL do servidor de impressão CUPS na configuração. Depois que o comando terminar, você terá um arquivo chamado <i>raspberrypi.conf</i>, que deve ser renomeado para <span style="font-family: Courier New, Courier, monospace;"><i>Service State</i></span>:</div>
<div>
<br /></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">googlecloudprint@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>mv raspberrypi.conf 'Service State'</b></span></div>
<div>
<br /></div>
<div>
Agora, vamos criar um script de configuração para o serviço iniciar automaticamente quando ligarmos o Pi.</div>
<div>
<br /></div>
<div>
<i>Dica:</i> Você pode usar o comando: <span style="color: #999999; font-family: 'Courier New', Courier, monospace;">googlecloudprint@pi$ </span> <span style="font-family: Courier New, Courier, monospace;"><b>cat > google-cloud-print</b></span> e em seguida colar o conteúdo e pressionar <b>CTRL+D</b> para salvar. </div>
<div>
<div>
<br /></div>
<div>
Salve o arquivo abaixo com o nome <span style="font-family: Courier New, Courier, monospace;">google-cloud-print</span> na pasta <span style="font-family: Courier New, Courier, monospace;">/home/googlecloudprint</span>:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">#!/bin/bash</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">### BEGIN INIT INFO</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Provides: google-cloud-print</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Required-Start: $remote_fs $syslog $networking</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Required-Stop: $remote_fs $syslog $networking</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Default-Start: 2 3 4 5</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Default-Stop: 0 1 6</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Short-Description: Google Cloud Print Service</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"># Description: This service launches a Google Cloud Print.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">### END INIT INFO</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">export HOME="/home/googlecloudprint/"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">unset DISPLAY</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">start_service() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> echo "Starting service ..."</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> cd $HOME</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> start-stop-daemon --start \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --chuid googlecloudprint \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --chdir /home/googlecloudprint \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --background --verbose \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> -x /usr/lib/chromium/chromium -- \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --type=service \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --enable-cloud-print-proxy \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --no-service-autorun \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --noerrdialogs \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --user-data-dir=/home/googlecloudprint/ \</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> --enable-logging --v=1</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">find_pid() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ps fax | grep enable-cloud-print-proxy |\</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> grep -v grep | awk '{print $1}'</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">stop_service() {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> echo "Stopping service ..."</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> PID="$(find_pid)"</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> case "$PID" in</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> [0-9]*)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> echo "Killing $PID ..."</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> kill -9 $PID 2>/dev/null</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ;;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> *)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> echo "Not running ..."</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ;;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> esac</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">case $1 in</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> start)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> start_service</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ;;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> stop)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> stop_service</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ;;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> restart)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> stop_service</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> start_service</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> ;;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">esac</span></div>
</div>
</div>
<div>
<br /></div>
<div>
Agora, vamos instalar este script que criamos como um serviço no sistema:</div>
<div>
<br /></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">googlecloudprint@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>chmod +x google-cloud-print</b></span></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;"><u>googlecloudprint</u>@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>exit</b> </span><span style="color: #666666; font-family: inherit;"><i>#para retornar ao usuário que possui acesso sudo (pi no meu caso)</i></span></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;"><u>pi</u>@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>sudo ln -s /home/googlecloudprint/google-cloud-print /etc/init.d/google-cloud-print</b></span></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">pi@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>sudo update-rc.d google-cloud-print defaults</b></span></div>
<div>
<span style="color: #999999; font-family: 'Courier New', Courier, monospace;">pi@pi$ </span><span style="font-family: Courier New, Courier, monospace;"><b>sudo service google-cloud-print start</b></span></div>
<div>
<br /></div>
<div>
Agora, navegue até a página do Google Cloud Print e confirme se a impressora está disponível e online:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://docs.google.com/uc?id=0B9NjifSUullgcVZDWWZ0Smgtbk0&export=download" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="313" src="https://docs.google.com/uc?id=0B9NjifSUullgcVZDWWZ0Smgtbk0&export=download" width="400" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
Veja nos detalhes avançados da impressora, e note que o campo Proxy será o mesmo nome que definimos em nossa configuração.</div>
<div>
<br /></div>
<div>
Prontinho, agora você pode enviar trabalhos de impressão a partir de qualquer programa ou equipamento compatível com o Google Cloud Print, e eles são encaminhados à sua impressora via internet.</div>
<div>
<br /></div>
<div>
Happy hacking!</div>
Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-55113670342314442172013-04-10T00:37:00.001-03:002013-04-10T00:37:40.448-03:00Transformando o VIM em uma IDE completa.<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPvBAvU9mL8ZqGJpB5R6ILTHaOX2HpAuK5wN02fbuxy4V7_rF1PedDmzE4XQacpHXq3I8lPtp-vQJfPihtIBa_5nZtuw7JuwItfN096Y3w70SoSXxLfSfo9Ajxkd7gpdASvO-lZ5yZzh-W/s1600/vim.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" height="395" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPvBAvU9mL8ZqGJpB5R6ILTHaOX2HpAuK5wN02fbuxy4V7_rF1PedDmzE4XQacpHXq3I8lPtp-vQJfPihtIBa_5nZtuw7JuwItfN096Y3w70SoSXxLfSfo9Ajxkd7gpdASvO-lZ5yZzh-W/s640/vim.png" width="640" /></a><br />
<br />
O VIM (Vi IMproved) é o meu editor favorito para inúmeras tarefas. Ele é a combinação perfeita entre robustez e eficiência. Em outras palavras, ele é simplesmente meu canivete suiço.<br />
<br />
Muito provavelmente, o seu primeiro contato com o Vim será aterrorizante. Felizmente, depois de entender alguns dos conceitos básicos, você perceberá com detalhes que ele é, como diria minha mãe: <i>pau pra toda obra</i>.<br />
<br />
Se você já estudou em algum curso superior em informática, provavelmente já passou por alguma disciplina em que teve de implementar um <i>editor de texto</i>. Foi implementando o meu próprio editor de texto na faculdade que percebi o quão poderoso o Vim pode ser.<br />
<br />
Se o Vim é algo muito novo para você, eu recomendo executar o tutorial que já vem nos pacotes das distribuições mais novas. É um excelente tutorial interativo, utilizando a própria ajuda do vim.<br />
<br />
<h3>
Instalação</h3>
Se você usa alguma distribuição baseada em Debian, como o Ubuntu, basta instalar o vim com o apt-get:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ apt-get install vim vim-gnome</span><br />
<br />
Se você for apenas utilizar o Vim pelo terminal, não precisa do vim-gnome. Eu recomendo o Vim-gnome porque ele lhe permite utilizar algumas integrações com o ambiente gráfico, além de ter uma barra de ferramentas e uma boa integração com o mouse, ideal para principiantes. Se você ainda não encontrou a luz, e ainda está usando Windows, pode instalar o Vim no seu computador, baixando diretamente do site do projeto [0].<br />
<br />
<h3>
Um pouco do básico</h3>
O ideal para você iniciar é seguir o passo a passo do <span style="font-family: Courier New, Courier, monospace;"><b>vimtutor</b></span>. Depios de instalar o Vim, você poderá iiciar o vimtutor do terminal por meio do comando:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">$ vimtutor</span><br />
<br />
De qualquer forma, seguem algumas dicas importantes para começar:<br />
<br />
<ol>
<li>O vim possui uma "barra de status", no rodapé da janela. Ela também é a barra na qual você digita os "comandos" do editor. Pense nestes comandos como o equivalente a uma dezena de botões e menus que normalmente você encontra nos programas: eles lhe dão acesso aos recursos do software, a única diferença é que você vai digitá-los ao invés de clicar neles.</li>
<li>O vim possui modos, e isso é, muitas vezes o primeiro obstáculo. O modo <i>normal</i> pode ser entendido como um modo de somente leitura, no qual você digita instruções na barra de comandos. O modo de <i>inserção</i> é o modo que você usa para editar o conteúdo do arquivo e o modo<i> visual</i> é o modo que você poderá fazer seleções no texto para copiar ou recortar partes do mesmo.</li>
<li>Ao entrar no vim, você terá acesso ao modo <i>normal</i>, e se começar a digitar pode acionar acidentalmente comandos indesejados. Pressionando a letra <b><span style="font-family: Courier New, Courier, monospace;">i</span></b> ou o botão<span style="font-family: Courier New, Courier, monospace;"> <b>INSERT</b></span>, você entra no modo de inserção, e pressionando <i><b>v</b></i> no modo visual. Estando nos modos de inserção ou visual, pressionando <b><span style="font-family: Courier New, Courier, monospace;">ESC</span></b> você retorna para o modo normal.</li>
<li>Os comandos do vim são, normalmente, digitados no modo normal, prefixados pelo caractere dois pontos: <i style="font-weight: bold;">:</i>. Por exemplo, para encerrar o vim utilize o comando <b><span style="font-family: Courier New, Courier, monospace;">:q</span></b>. Para salvar o texto atual (muitas vezes chamado de <i>buffer</i> na documentação do Vim) utilize o comando <span style="font-weight: bold;"><span style="font-family: Courier New, Courier, monospace;">:w</span></span>. Um atalho para sair do vim, já salvando, é o comando <b><span style="font-family: Courier New, Courier, monospace;">:x</span></b>. Lembre-se que, normalmente, você vai apertar um <b><span style="font-family: Courier New, Courier, monospace;">ESC</span></b> antes de digitar os comandos, já que assim garante que está no modo normal.</li>
<li>O vim possui um manual de ajuda <i>embutido</i>, que dá detalhes completos sobre o programa. Para abrir o manual, utilize o comando <span style="font-weight: bold;"><span style="font-family: Courier New, Courier, monospace;">:help</span></span>. Também é possível ler um tópico específico do manual utilizando o comando help seguido do tópico, comando ou função desejado. Experimente ler os tópicos <b><span style="font-family: Courier New, Courier, monospace;">:help q</span></b>, <b><span style="font-family: Courier New, Courier, monospace;">:help w</span></b> e <b><span style="font-family: Courier New, Courier, monospace;">:help x</span></b></li>
</ol>
<div>
Essas dicas simples servem para ajudara a entender o funcionamento básico, apenas para que você fique mais familiarizado com o Vim. Utilize o <span style="font-family: Courier New, Courier, monospace;">vimtutor</span> para aprender mais sobre a ferramenta se você está apenas iniciando.</div>
<br />
<h3>
Mais do que um editor de textos</h3>
O vim não é apenas um simples editor de buffers de texto. Por exemplo, você pode fazer coisas como:<br />
<br />
<ul>
<li>Executar comandos no prompt.</li>
<li>Abrir abas, dividir a tela em janelas horizontal e verticalmente, e tudo isso combinado diversas vezes.</li>
<li>Compilar o código fonte.</li>
<li>Criar scripts e funções.</li>
<li>Mapear atalhos do teclado para comandos do editor.</li>
<li>Visualizar diretórios, arquivos .zip, .tar.gz, e arquivos binários (se você souber o que está fazendo, é muito útil).</li>
<li>Pesquisar / substituir utilizando expressões regulares.</li>
<li>Auto-completar código (assim como nas IDEs mais famosas).</li>
<li>Utilizar (e customizar!) o <i>syntax highlight</i> de todo e qualquer tipo de arquivo.</li>
<li>Navegar pelo código fonte (com o auxílio de um arquivo de tags).</li>
<li>... e muito, muito mais!</li>
</ul>
<div>
Combinando uma boa seleção de plugins, mapeamentos confortáveis no teclado, e entendendo a dinâmicda do Vim, você poderá utilizá-lo como um substituto excelente para programar em diversas linguagens.</div>
<br />
<br />
<h3>
Personalizando</h3>
<div>
Você pode customizar o Vim por meio do arquivo <span style="font-family: Courier New, Courier, monospace;"><b>.vimrc</b></span>, salvo em seu diretório pessoal (~/.vimrc no *nix). Este arquivo consiste, basicamente, em comandos que você poderia digitar diretamente na barra de status do Vim, combinados na forma de um pequeno <i>vimscript</i>. Neste arquivo, assim como em qualquer outro script do Vim, uma linha iniciada por aspas é um comentário.</div>
<div>
<br /></div>
<div>
Neste post, vou lhes mostar algumas configurações que eu geralmente uso para tornar o Vim mais agradável.</div>
<div>
<br /></div>
<div>
<b style="font-family: 'Courier New', Courier, monospace;">syntax on</b></div>
<div>
Ativa a sintaxe por padrão, ao carregar o vim. O recurso vem desabilitado porque pode demorar para carregar arquivos grandes. É útil ele estar ativo já que nos arquivos muito grandes, você pode pressionar <span style="font-family: Courier New, Courier, monospace;">CTRL+C</span> para interromper o parser do hilight, e depois desabilitar com <span style="font-family: Courier New, Courier, monospace;">syntax off</span>.</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><b>set number</b></span></div>
<div>
Ativa a numeração das linhas. Muito interessante especialmente para edição de código-fonte. Por padrão desabilitado, e você também pode desligar com o comando <span style="font-family: Courier New, Courier, monospace;">:set nonumber</span></div>
<br />
<b><span style="font-family: Courier New, Courier, monospace;">set mouse=a</span></b><br />
Ativa (mesmo em conexões por SSH!) as funcionalidades do mouse para a sua sessão do Vim.<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">set hlsearch</span></b><br />
Ativa o hilight das pesquisas. Basicamente, quando você efetua uma busca, busca e substituição, o vim irá deixar as ocorrências em destaque, parecido ao <i>amarelão</i> do Gedit/Kwrite quando você pesquisa por algo.<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">set nomousehide</span></b><br />
Não sei porque, mas tem horas que o mouse no Gvim dá uma sumida, e parece que você está ficando doido. Não tem efeito se você abrir o vim no terminal.<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">set sw=8 ts=8 st=8 noet si ai</span></b><br />
Esta sequência "mágica", configura a tabulação para o equivalente a 8 espaços, sem expandir o tab, ou seja, sem substituir tudo por espaços. Na prática, cada comando separado por um espaço faz uma coisa. Fica como uma tarefa para o leitor consultar o manual de cada um. Todos juntos são úteis para que as quebras de linha no código já identem corretamente. Troque o 8 por 4 ou 2 se você preferir visualizar as tabulações com menos espaços, e troque <span style="font-family: Courier New, Courier, monospace;"><b>noet</b></span> por <span style="font-family: Courier New, Courier, monospace;"><b>et</b></span> para inserir espaços quando você pressionar a tecla tab (não faça isso em Makefiles!).<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"><b>au</b></span><br />
Aqui começa um pouco de "mágica" na sua configuração. O <span style="font-family: Courier New, Courier, monospace;">au</span> ou <span style="font-family: Courier New, Courier, monospace;">autocommand</span> permite que <i>eventos</i> sejam mapeados para comandos do editor que permite que a customização seja dinâmica, conforme o tipo de arquivo que você está editando, por exemplo. Vamos supor que você queira utilizar espaços no lugar de tabulações, e que sejam 4 espaços ao invés de 8 para a maior parte dos arquivos, mas quando você estiver editando um Makefile, você quer que a configuração seja para usar as tabulações mesmo, e queira visualizar com 8 espaços. Para atingir este objetivo, basta usar as linhas abaixo em seu vimrc:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">set sw=4 ts=4 st=4 et si ai</span><br />
<span style="font-family: Courier New, Courier, monospace;">au BufRead,BufNewFile Makefile set sw=8 ts=8 st=8 noet si ai</span><br />
<br />
A primeira linha configura como padrão a tabulação de 4 espaços, e a segunda, configura um <i>autocommand</i>, para toda vez que um arquivo for lido ou aberto, com o nome Makefile, configurar a tabulação normal. Veja mais detalhes em <b><span style="font-family: Courier New, Courier, monospace;">:help au</span></b>.<br />
<br />
Em seu vimrc, além de comandos como os acima, você também poderá criar funções (que são executadas com o comando <b><span style="font-family: Courier New, Courier, monospace;">:call</span></b>) e criar comandos personalizados, que basicamente agrupam outros comandos ou chamam outras funções. Comandos definidos pelo usuário devem ser iniciados por uma letra maiúscula.<br />
<br />
<h3>
Criando funções</h3>
Vamos supor que você queira criar uma função para fazer o pull de seu repositório mercurial, sem deixar o editor. Para isso, você pode incluir o seguinte em seu vimrc:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">function HgPull()</span><br />
<span style="font-family: Courier New, Courier, monospace;"> echo "Trazendo revisões do servidor remoto ..."</span><br />
<span style="font-family: Courier New, Courier, monospace;"> !hg pull</span><br />
<span style="font-family: Courier New, Courier, monospace;">endfunction</span><br />
<br />
Para executar esta função, basta digitar o comando <b style="font-family: 'Courier New', Courier, monospace;">:call HgPull()</b><span style="font-family: 'Courier New', Courier, monospace;">. </span>A primeira linha inicia uma função, a segunda e terciera contêm o corpo da função e a quarta, encerra a função. Um atalho para as palavras chaves <span style="font-family: Courier New, Courier, monospace;">function</span> e <span style="font-family: Courier New, Courier, monospace;">endfunction</span> são, respectivamente <span style="font-family: Courier New, Courier, monospace;">fu</span> e <span style="font-family: Courier New, Courier, monospace;">endfu</span>. O comando <b><span style="font-family: Courier New, Courier, monospace;">!</span></b> é um comando do vim que executa uma função no shell (ou prompt), e por padrão exibe a saída do comando que o segue.<br />
<br />
<h3>
Plugins</h3>
Os plugins são instalados em seu diretório ~/.vim/plugins. Para plugins que nem sempre são utilizados, você poderá instalá-los no ~/.vim/autoload, desde que o script do plugin tenha suporte para isso. Uma lista interessante de plugins para você ir brincando pode ser encontrada em [3].<br />
<br />
<h3>
<span style="font-family: inherit;">Um vimrc que já está quase virando plugin</span></h3>
Eu e outros amigos usuários do Vim estamos montando um vimrc que compartilhamos no Bitbucket. Tive esta iniciativa para uniformizar o meu vimrc de casa, do notebook e do trabalho, e também para tornar o trabalho de programar em Java com o Vim um pouco menos laborioso. Como efeito colateral, à medida em que fui utilizando o vim para programar e fui incrementando o vimrc com vários recursos, fui aprendendo cada vez mais sobre <i>vimscript</i>.<br />
<br />
Nom momento em que escrevo, o vimrc está hospedado junto com outros scripts bem interessantes que eu estou publicando no projeto <a href="https://bitbucket.org/ronoaldo/ronoaldo-utils">https://bitbucket.org/ronoaldo/ronoaldo-utils</a>. Atualmente, ele traz as configurações acima, uma coletânea com pequenas funções que eu uso diariamente, e alguns mapeamentos de teclado interessantes, como o CTRL+S para salvar o arquivo. Também inclui ma seleção de plugins instaláveis facilmente por funções definidas no próprio vimrc por meio do script pathogen.vim, e uma configuração especial para projetos Java/Maven em ~/workspace/<i>projeto</i>.<br />
<br />
Com esta configuração, você pode:<br />
<br />
<ul>
<li>Instalar a coletânea de plugins com o comando <span style="font-family: Courier New, Courier, monospace;">:call InstallAllPlugins</span>.</li>
<li>Utilizar o <span style="font-family: Courier New, Courier, monospace;">CTRL+F12</span> para abrir um navegador de arquivos (plugin NERDTree).</li>
<li>Salvar pressionando <span style="font-family: Courier New, Courier, monospace;">CTRL+S</span>.</li>
<li>Utilizar o comando <span style="font-family: Courier New, Courier, monospace;">:IndexWorkspace</span> para indexar todos os arquivos .java de sua workspace (requer exuberant-ctags).</li>
<li>Utilizar CTRL+P para fazer pull e CTRL+U para fazer push no Mercurial.</li>
<li>Executar testes de projetos Maven em sua workspace com o comando <span style="font-family: Courier New, Courier, monospace;">:Junit</span></li>
<li>Compilar um projeto Maven utilizando CTRL+F8, ou arquivos Java standalone utilizando o mesmo atalho.</li>
<li>Utilizar templates de código estilo os do Textmate (plugin snipmate).</li>
<li>Criar atalhos de forma bem simples, com o comando <span style="font-family: Courier New, Courier, monospace;">:call KeyMap("atalho", "ação")</span></li>
<li>E mais está por vir ...</li>
</ul>
<br />
O script está crescendo em funcionalidades e eu estou considerando a possibilidade de que ele seja, por si só, um plugin. Estou recebendo patches ;)<br />
<br />
<h3>
Conclusão</h3>
Se você está procurando por uma alternative eficiente e leve, mas sem perder a robustez, o Vim pode ser uma excelente escolha, depois que você quebrar a barreira do <i>como eu começo a digitar nesta coisa?</i>.<br />
<br />
<b><span style="font-family: Courier New, Courier, monospace;">:echo "Happy hacking!"</span></b><br />
<br />
<h3>
Referencias</h3>
<br />
<div>
[0] Site oficial: <a href="http://www.vim.org/">http://www.vim.org/</a></div>
[1] Vim Tips Wiki: <a href="http://vim.wikia.com/wiki/Vim_Tips_Wiki">http://vim.wikia.com/wiki/Vim_Tips_Wiki</a><br />[2] Ótimo tutorial sobre Vimscript: <a href="http://learnvimscriptthehardway.stevelosh.com/">http://learnvimscriptthehardway.stevelosh.com/</a><br />[3] Lista com plugins úteis: <a href="http://www.catonmat.net/series/vim-plugins-you-should-know-about">http://www.catonmat.net/series/vim-plugins-you-should-know-about</a>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-54919233663379225002011-12-21T17:53:00.001-02:002021-11-09T17:09:08.921-03:00Instalando features do Eclipse via linha de comando com Provision Platform, p2O <a href="http://www.eclipse.org/">Eclipse</a> é a minha IDE favorita, por algumas razões:<br />
<ul>
<li><strong>OpenSource</strong>: sendo uma ferramenta de código livre, além de ser possível contribuir, analisar, reutilizar o código-fonte e aprender com o mesmo, a comunidade de desenvolvedores ao redor do mundo pode ampliar os horizontes da plataforma com suas contribuições.</li>
<li><strong>Multi-plataforma</strong>: assim como a maior parte das ferramentas open-source, o Eclipse também é multi-plataforma, oferecendo assim ainda mais liberdade para que você trabalhe no ambiente que lhe proporciona mais segurança e mais recursos.</li>
<li><strong>Multi-linguagem</strong>: como todo bom programador, eu não sou viciado em uma única linguagem, e procuro sempre utilizar a linguagem apenas como ferramenta. Apesar de ter trabalhando recentemente mais com a linguagem Java, Python, C e C++, PHP são outros sabores que eu aprecio. Claro, um pouco de shell script para automatizar tarefas corriqueiras são uma boa pedida. O Eclipse lhe oferece um ambiente uniforme para trabalhar com as linguagens, o que para mim é um fator importante, evitando atritos ao programar em mais de uma linguagem em curtos intervalos de tempo.</li>
</ul>
Por estes e outros motivos, me tornei um <a href="http://www.ronoaldo.net/noticias/friendofeclipse">Amigo do Eclipse</a>, e fiz uma modesta contribuição para o projeto. Recentemente, descobri um recurso da plataforma que facilita automatizar a instalação de plugins via linha de comando. Este recurso permite que você faça a instalação de uma série de plugins de uma única vez, realize deploys ou até mesmo, construa a partir de sua própria seleção de plugins, uma versão customizada da IDE.<br />
<br />
<span style="font-size: large;">Background</span><br />
O processo faz uso de um recurso da plataforma do Eclipse chamado Provisioning Platform (p2). Especificamente, uma aplicação do p2 chamada Director [1]. Com esta aplicação, é possível automatizar o processo via linha de comando.<br />
<br />
Basicamente, tudo que você tem a fazer é executar a aplicação org.eclipse.equinox.p2.director, e informar as features a serem instaladas, bem como os repositórios a serem consultados para resolução de dependências.<br />
<br />
Tecnicamente, este é o mesmo processo que a interface gráfica realiza, com exceção de que você está automaticamente concordando com as licenças dos softwares que está instalando, uma vez que a tela de confirmação não é exibida.<br />
<br />
<span style="font-size: large;">Passo a passo</span><br />
Terminologia básica para o processo de instalação:<br />
<ul>
<li><b>Director</b>: a aplicação do Eclipse que está realizando a instalação ou remoção de software. Ela está no bundle org.eclipse.equinox.p2.director.app.</li>
<li><b>Builder</b>: uma aplicação baseada na plataforma do Eclipse que contém o bundle do Director e suas dependências. Pode ser utilizado, por exemplo, para criar uma nova instalação de plugins (modo shared) ou da IDE completa em um diretório diferente.</li>
<li><b>Produto alvo</b>: uma aplicação alvo onde o software será instalado. Pode ser o mesmo do Builder, quando você quer instalar plugins e features em uma versão da IDE, como o Java EE.</li>
</ul>
Tudo que precisamos é do <b>p2 Director</b> para começar. O modo mais fácil é você já ter baixado o Eclipse para Java, Java EE ou qualquer outro de sua preferência, e começar a adicionar um conjunto de plugins. Você também pode, por exemplo, criar também uma aplicação mínima do eclipse que tenha apenas o Director e então, criar um instalador para baixar um pacote completo.<br />
<br />
Vamos supor que você tenha baixado o Eclipse for Java EE Developers, e queira adicionar o Mobile Tools For Java (MTJ). Para isso, você precisará utilizar o seguinte comando (supondo que o binário ou script launcher do Eclipse esteja em seu PATH):<br />
<br />
<pre class="pretty"></pre>
<pre class="pretty">$ eclipse -nosplash -application org.eclipse.equinox.p2.director \</pre><pre class="pretty"> -repository http://download.eclipse.org/releases/indigo/ \</pre><pre class="pretty"> -installIU org.eclipse.mtj.feature.group \</pre><pre class="pretty"> -tag “Added-org.eclipse.mtj.feature.group”
</pre>
<br />
O parâmetro <strong>-nosplash</strong> evita que a tela de splash seja exibida e fique congelada, já que não precisamos de interface gráfica. Com o parâmetro <strong>-application</strong> indicamos que o Director deve ser iniciado e não a Workbench. Os parâmetros seguintes, <strong>-repository</strong> e <strong>-installIU</strong>, permitem configurar, respectivamente, de onde os plugins e features serão baixados e quais <em>instalation units</em> devem ser adicionadas (plugins, features ou feature-groups). Esses dois parâmetros recebem uma lista separada por vírgulas, o que permite instalar vários plugins de diferentes fontes ao mesmo tempo. O parãmetro <strong>-tag</strong> permite marcar o que foi feito nesta operação, assim fica fácil “reverter” pela itnerface gráfica do Eclipse (ou mesmo pelo director) para uma tag mais antiga caso a instalação falhe.<br />
<br />
Depois de rodar este comando, você vai ver algumas linhas no prompt:<br />
<pre></pre>
<pre class="pretty">Installing org.eclipse.mtj.feature.group 1.1.2.201109111413.
Operation completed in 337201 ms.
</pre>
<br />
Ao iniciar novamente o Eclipse, você vai poder confirmar que o MTJ foi adicionado com sucesso ao sistema:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVCWukRqpF4Rzov5uWVYTNW72pa70TPBOBoEhGfuO3nWWb0s7ogo05pnO8beXWN_oUSXKhDxQtp5Hk6vq_yG-X6WHLN0D8ePOtV83h-XkwMVWXjwveaKocZJm7MFlQa6rauNvpRtn8aM_2/s1600/eclipse-p2-fig1.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVCWukRqpF4Rzov5uWVYTNW72pa70TPBOBoEhGfuO3nWWb0s7ogo05pnO8beXWN_oUSXKhDxQtp5Hk6vq_yG-X6WHLN0D8ePOtV83h-XkwMVWXjwveaKocZJm7MFlQa6rauNvpRtn8aM_2/s1600/eclipse-p2-fig1.png" /></a></div>
<br />
Você pdoe conferir nossa tag clicando em <em>Help → About Eclipse</em>, depois no botão <em>Instalation Details</em>. Na aba <em>Instalation History</em>, você vai ver:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjS87m9Txb7kF4XKAWht2Yggng6XGJRHdfrzEcO8mqSZu8oYpTHTGh8L7L81ZKZ3oXnHfc-f7GWJQ2uJ4cwcUIwIXiMPNp5h6nGE1yz_1HzIiv_NDxd0KIKTsCMty42tda80apO8R2bqCi/s1600/eclipse-p2-fig2.png" style="margin-left: 1em; margin-right: 1em;"><img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjS87m9Txb7kF4XKAWht2Yggng6XGJRHdfrzEcO8mqSZu8oYpTHTGh8L7L81ZKZ3oXnHfc-f7GWJQ2uJ4cwcUIwIXiMPNp5h6nGE1yz_1HzIiv_NDxd0KIKTsCMty42tda80apO8R2bqCi/s1600/eclipse-p2-fig2.png" /></a></div>
<br />
Apesar dos parâmetros -repository e -feature aceitarem multiplas opções separadas por vírgula, eu notei que ao tentar instalar muitos plugins em uma única vez pode resultar em conflitos. Eu acredito que o <i>resolvedor</i> de dependências começa a ficar confuso. Eu também notei isso na própria interface gráfica, via Eclipse Marketplace ao tentar instalar o Google Plugin + SDKs, Apache Ivy e Pydev ao mesmo tempo.<br />
<br />
<span style="font-size: large;">p2-install</span><br />
O que me motivou a descobrir este recurso foi ter que, nas últimas semanas, configurar várias vezes uma mesma instalação do Eclipse padrão com as ferramentas do Google Plugin for Eclipse, SDKs do AppEngine e Google Webtoolkit, Apache Ivy e IvyDE, e o MercurialEclipse. Este conjunto de ferramentas é o mínimo essencial no meu emprego atual. Como erros intermitentes ao baixar todas de uma vez só pelo Eclipse Marketplace, tive que procurar uma alternativa.<br />
<br />
O trabalho rendeu até um pequeno script que eu compartilhei no Bitbucket no projeto <a href="http://code.ronoaldo.net/ronoaldo-utils/">ronoaldo-utils</a>. O script já facilita um pouco com alguns defaults, prevê multiplas instalações do Eclipse e permite que você faça também um “discover” pelos feature-groups disponíveis.<br />
<br />
Veja o <a href="http://code.ronoaldo.net/ronoaldo-utils/src/505f862f2b28/p2-install.sh">código-fonte aqui</a>. Se tiver alguma sugestão ou melhoria, crie um fork e submita um patch!<br />
<br />
<span style="font-size: large;">Próximos Passos</span><br />
<div>
Além de instalar plugins e feature groups (Uma feature ou grupo de features composta por vários plugins), o Director permite que você instale em um outro diretório: ou seja, instale a partir de uma aplicação, tendo uma aplicação diferente como alvo. O interessante é que você pode baixar e construir a IDE inteira com este recurso. Outra ferramenta interessante do p2 é que você pode também fazer mirror e gerenciar repositório com os plugins. Ao ler isso, imaginei uma forma bem interessante de realizar o deploy de versões já pré-configuradas do Eclipse via linha de comando, para diversas máquinas, como em um laboratório ou departamento de TI. Mas, isso é assunto para outro post...<br />
<br />
Happy hacking!<br />
<br />
<span style="font-size: large;">Referências</span></div>
<div>
[1] Provisioning Platform, p2 - Instalation management <a href="http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/guide/p2_director.html">http://help.eclipse.org/indigo/topic/org.eclipse.platform.doc.isv/guide/p2_director.html</a></div>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-20145919264142810182011-09-17T15:17:00.001-03:002011-09-18T23:43:15.996-03:00Calculando MD5 e SHA1 em Java<a href="http://pt.wikipedia.org/wiki/Hash">Hashes</a> são extremamente úteis para representar em uma pequena cadeia de bits uma outra cadeia de bits que pode ser bem maior. Podemos considerá-lo uma forma de <i>criptografia assimétrica</i>, uma vez que não é possível (a não ser por meio de algoritmos de força bruta) recuperar a cadeia original a partir do hash.<br />
<br />
Existem diversos algoritmos para o cálculo de hashes, e em Java utilizamos a classe <a href="http://download.oracle.com/javase/1,5.0/docs/api/java/security/MessageDigest.html" target="_blank"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">MessageDigest</span></a> para recuperar a implementação desejada. Por exemplo, para calcular o MD5 de uma string, podemos utilizar:<br />
<br />
<pre class="prettyprint notranslate">MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update("string original".getBytes());
byte[] digest = md5.digest();
</pre>
<br />
Para exibir os dados como string, recurso util quando você pretende utilizar o MD5 para conferir se todos os bytes de um arquivo foram baixados, basta formatá-lo com:<br />
<br />
<pre class="prettyprint notranslate">String.format("%1$032x", new BigInteger(1, digest));</pre>
<br />
O resultado é exatamente o hash MD5 da string:<br />
<br />
<pre class="prettyprint notranslate">~$ echo "string original" | md5sum
3ced9d1f470cd18f06a8b6492d3ea94e -
</pre>
<br />
Neste exemplo, utilizamos a string de formatação "%1$032x", porque queremos o resultado em hexadecimal, alinhado em 32 casas à esquerda. Construímos um BigInteger positivo, com os bits resultantes da soma, e isso nos permite converter os bytes do array para hexadecimal de forma simples.<br />
<br />
Podemos fazer de forma semelhante ao calcular o SHA1:<br />
<br />
<pre class="prettyprint notranslate"><span class="Apple-style-span">MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
</span><span class="Apple-style-span">sha1.update("string original".getBytes());
byte[] digest = </span>sha1.digest();
<span class="Apple-style-span">String.format("%1$040x", new BigInteger(1, digest));</span></pre>
<br />
Generalizando, você pode também utilizar os seguinte métodos:<br />
<br />
<pre class="prettyprint notranslate">public static String computeHash(String data, String algoritm,
Integer resultSize) {
try {
MessageDigest digest = MessageDigest.getInstance(algoritm);
digest.update(data.getBytes());
return hexdigits(digest.digest(), resultSize);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Unable to hash with " + algoritm);
}
}
public static String hexdigits(byte[] data, Integer resultSize) {
return String
.format("%1$0" + resultSize + "x", new BigInteger(1, data));
}
</pre>
<br />
Até a próxima dica!Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-54607631652482513282011-08-25T08:29:00.001-03:002021-11-25T07:52:02.345-03:00Coletânea de Soluções do GDD-BRO <a href="http://www.google.com.br/events/developerday/2011/sao-paulo/">Google Developer Day Brasil 2011</a> teve suas inscrições encerradas na última sexta-feira. Na empresa onde trabalho, eu e meus colegas fizemos <a href="http://code.ronoaldo.net/gddbr-2011/overview">uma coletânea de soluções em Java</a> e estamos compartilhando com o mundo hoje!<br />
<br />
As soluções são apenas para fins de <i>exercício</i> e oferecem diferentes visões de como podemos resolver o problema. Obviamente, para publicar nossas respostas o mais rápido possível, não <i>otimizamos</i> o código, e resolvemos as questões da primeira forma que nos veio em mente.<br />
<br />
Deixem suas opiniões e comentários! E, claro, podem ficar à vontade para clonar o repositório de códigos de exemplo.<br />
<br />
Se você gostaria de contribuir com sua solução, deixe um comentário que eu entro em contato para habilitar push no repositório. Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com3tag:blogger.com,1999:blog-4241414426102940500.post-33223605731394192122011-07-26T23:41:00.002-03:002021-11-25T07:51:36.600-03:00Pelo mundo (virtual) aforaNo ano passado tive um <i>acesso de inspiração</i> e publiquei alguns cliparts no OpenCliparts.org, um portal de hospedagem de ilustrações vetoriais sob <a href="http://creativecommons.org/publicdomain/zero/1.0/">domínio público</a>.<br />
<br />
Algumas semanas depois, o <a href="http://images.google.com/images?q=ronoaldo">Google começou a mostrar estes cliparts nos resultados de pesquisa por imagens com meu nome</a>. Dias depois, cada clipart passou a aparecer várias vezes na mesma busca por imagens. Notei que os desenhos estavam se espalhando pela web de portal em portal, e como o OpenClipart adicionou meu nome no nome do arquivo e nos seus meta-dados, eu tive certeza que eram os mesmos.<br />
<br />
Tudo bem, publiquei no OpenClipart com esse objetivo mesmo: divulgar os desenhos. Hoje fui até o OpenClipart novamente, e agora eles exibem os <a href="https://openclipart.org/artist/ronoaldo"><i>top 10 downloads</i> na página de cada artista</a>. Para minha surpresa, alguns cliparts já passaram dos mil downloads! Claro, a maior parte deve ser dos robozinhos dos sites que republicaram o trabalho, mas já é gratificante.<br />
<br />
Também achei interessante que alguns dos modelos de documento do Google Docs que eu publiquei já foram utilizados diversas vezes. Agora os templates já não possuem mais a contagem de utilizações, apenas a avaliação dos usuários, <a href="https://docs.google.com/templates?view=public&authorId=16982550004529957053">que até agora foi de 4 estrelas</a>.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-41766743888176571692010-12-04T20:48:00.000-02:002011-09-18T23:47:37.544-03:00Hacks para o BloggerSe você também utiliza o Blogger para os seus posts, aqui vão algumas dicas que eu descobri recentemente <i>googlando</i> por aí.<br />
<br />
<h3>
Remover barra de navegação</h3>
<br />
<a href="http://www.google.com/support/blogger/bin/answer.py?hl=br&answer=42269">Neste tópico da ajuda</a>, você vai encontrar informações a respeito de como ativar a barra de navegação, e vai notar que a desativação é feita publicando seu blog por FTP. Eu nem sabia que poderia publicar via FTP, e não quero isso. Uma forma mais simples de <i>escondê-la</i> é alterar a folha de estilos padrão para deixá-la invisível. Acesse o painel de configurações, e em seguida:<br />
<ul>
<li>Clique na aba Design, e depois em "Designer do Modelo"</li>
<li>Em seguida, vá em "Avançado", e clique na seção "Adicionar CSS"</li>
<li>Insira a seguinte regra CSS ao modelo escolhido:<br />
</li>
</ul>
<pre class="prettyprint notranslate">body .navbar {
display: none !important;
}
</pre>
<br />
Pronto, agora a barra não estará visível. Note que ela continua lá, na verdade, mas ninguém deve vê-la.<br />
<br />
<h3>
Adicionar coloração de sintaxe</h3>
<br />
Se você vai postar trechos de código, provavelmente vai preferir que eles estejam com a sintaxe em destaque, pois isso ajuda (e muito) na leitura. Existem algumas formas de se fazer isso, e a que eu achei mais simples é a de utilizar o <code>prettyprint</code>. Ele é bem mais simples, e detecta automaticamente a linguagem utilizada para inserir a coloração.<br />
<br />
Você precisa baixá-lo e hospedá-lo em algum lugar. Se você tem uma conta do <a href="http://code.google.com/apis/storage">Google Storage for Developers</a> ou em algum dos serviços como o <a href="http://www.dropbox.com/">Dropbox</a> ou simliares, pode publicar o arquivo na Web.<br />
<br />
Uma forma de inserí-lo em seu Blog é editar o HTML do seu modelo. Os novos modelos são bem interessantes, e construídos em formato XML. Entretanto, ao trocar de modelo ou realizar alguma configuração mais avançada, você pode acabar perdendo este código e ter de refazê-lo.<br />
<br />
Outra alternativa é inserir um <i>gadget</i> no Blog que permita inserir código JavaScript e que não é perdido ao trocar/alterar seu modelo. Para isso, em seu painel de controle:<br />
<br />
<ul>
<li>Clique na aba "Design", e em seguida na seção "Elementos da página".</li>
<li>Na área do rodapé (para evitar que o carregamento dos posts fique muito lento), adicione um gadget do tipo <b>HTML/JavaScript</b> com o seguinte conteúdo:</li>
</ul>
<pre class="prettyprint notranslate"><script type="text/javascript"
src="http://<local onde hospedou o script>/prettify/prettify.js"></script>
<script type="text/javascript" language="javascript">
(function() {
var css = document.createElement('link');
css.rel = 'stylesheet'; css.type = 'text/css';
css.href = 'http://<local onde hospedou o script>/prettify/prettify.css';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(css, s);
})();
prettyPrint();
</script></pre>
<br />
Substitua os campos marcados com <i><local onde hospedou o script></i> apropriadamente para a sua situação.<br />
<br />
Pronto, agora basta inserir em seus posts os trechos de código envolvidos por uma tag <code>pre</code> ou <code>code</code>, com o elemento <code>class="prettyprint"</code>. Por exemplo:<br />
<br />
<pre class="prettyprint notranslate"><pre class="prettyprint">
<b>Sintaxe HTML</b>
</pre>
</pre>
<br />
<h3>
Alterar o favicon</h3>
<br />
Semelhante ao processo acima, você pode alterar o favicon do seu Blog utilizando um gadget de Script, agora com o seguinte conteúdo:<br />
<br />
<pre class="prettyprint notranslate"><script>
var icon = document.createElement('link');
icon.rel = 'shortcut icon'; icon.type = 'image/vnd.microsoft.icon';
icon.href = 'http://<local onde voce hospedou>/favicon.ico';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(icon, s);
</script>
</pre>
<br />
Ao acessar o seu blog, ele terá um ícone customizado. Utilizei esta abordagem porque estava com uma certa preguiça em procurar as opções de configuração, mas eu acredito que isso seja possível de ser realizado de forma diferente.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-87970691808292108762010-12-02T22:11:00.001-02:002021-11-11T16:40:34.291-03:00Implementando o pattern Composite View com Tags JSP<b>Update 1</b>: Atualizei o nome deste post, uma vez que "Templates estilo Django para páginas JSP" não refletia muito o conteúdo. O código também está disponível no repositório de códigos-fonte <a href="https://github.com/ronoaldo/composite-view">github.com/ronoaldo/composite-view</a><br />
<br />
Uma das ferramentas do Django que eu admiro é a sua engine de templates, pois com ele produzimos layouts uniformes para toda a sua aplicação web de maneira estruturada.<br />
<br />
<h3>
O problema</h3>
<br />
Em Django, você define um <i>template base</i>, que geralmente contém o cabeçalho de suas páginas, e <i>define blocos</i> onde o conteúdo será inserido. Nas páginas de conteúdo, você utiliza uma tag para indicar que você está <i>estendendo</i> o template base, e preenche apenas os blocos de conteúdo a serem alterados.<br />
<br />
<a href="https://docs.google.com/drawings/pub?id=10fX2A7ApnIBKVet_az58FG_8fG7jse0Q3Wu11WTFTgs&w=594&h=414" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"></a>Isso funciona como uma <i>herança</i> de templates, onde o template filho apenas sobrescreve os blocos de conteúdo do template pai, ao mesmo tempo que permite ter um blocos de conteúdo padrão em um só arquivo. E mais, você pode criar uma hierarquia de quantos níveis forem necessários (e razoáveis!), proporcionando reuso inclusive de sua marcação HTML.<br />
<br />
<a href="https://docs.google.com/drawings/pub?id=10fX2A7ApnIBKVet_az58FG_8fG7jse0Q3Wu11WTFTgs&w=594&h=414" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" height="222" src="https://docs.google.com/drawings/pub?id=10fX2A7ApnIBKVet_az58FG_8fG7jse0Q3Wu11WTFTgs&w=594&h=414" width="320" /></a>O problema aparece quando você tenta realizar algo semelhante em outras tecnologias com as quais acaba trabalhando. Estamos portando uma aplicação Django para o AppEngine, e por restrições diversas, a tecnologia escolhida foi Java<i>.<br />
</i><br />
<br />
Optamos por causar o mínimo de overhead, e escolhemos usar apenas as tecnologias estritamente necessárias. Além do mais, temos poucas interfaces distintas, uma meia dúzia de <i>jsps</i> já resolveria o problema, e criamos uma interface administrativa utilizando o Google Web Toolkit, que nos permitiu criar uma interface rica e reutilizar diversos códigos de validação <i>server-side</i> em uma versão <i>client-side</i>.<br />
<br />
Por questões de simplicidade, geralmente criamos blocos reutilizáveis em JSP da seguinte maneira. No arquivo cabecalho.jsp:<br />
<pre class="prettyprint notranslate"><h1>Cabecalho</h1>
</pre>
<br />
No arquivo rodape.jsp:<br />
<pre class="prettyprint notranslate"><i>Todos os direitos reservados</i></pre>
<br />
No arquivo index.jsp:<br />
<pre class="prettyprint notranslate"><%@ include file="cabecalho.jsp" %>
Conteúdo
<%@ include file="rodape.jsp" %></pre>
<br />
Obviamente, isso chega a ofender. Pesquisando um pouco, encontrei algumas soluções, quase todas baseadas no pattern <i>Composite View</i>. Basta fazer uma busca e você vai encontrar implementações, mas a maioria delas <a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/CompositeView.html">dá muito trabalho</a> e não é tão intuitiva quanto a solução <i>Django</i>.<br />
<br />
Resolvi desenvolver algo um pouco mais simples, a partir da seguinte idéia: criar uma <i>custom tag</i> que define um <i>bloco</i>, e criar uma outra tag que permite <i>extender</i> um template (outra página JSP). A tag que define um bloco, o registra no contexto da requisição e salva um <i>buffer</i> com o conteúdo do mesmo, e em seguida, passa o controle da página para o template pai.<br />
<br />
A idéia seria utilizar nossas tags de template da seguinte forma:<br />
<br />
No arquivo base.jsp, temos a definição dos blocos:<br />
<pre class="prettyprint notranslate"><%@ page language="java" pageEncoding="utf-8" %>
<%@ taglib prefix="t" uri="/templates.tld" %>
<html>
<head>
<title>
<t:block name="title">Título padrão</t:block>
</title>
</head>
</body>
<h1>
<t:block name="header">Cabeçalho Padrão</t:block>
</h1>
<div id="left-box">
<t:block name="left">Navegação</t:block>
</div>
<div id="main-box">
<t:block name="main">Bloco de conteúdo</t:block>
</div>
</body>
</html>
</pre>
<br />
E na página index.jsp, teríamos apenas:<br />
<pre class="prettyprint notranslate"><%@page language="java" pageEncoding="utf-8" %>
<%@taglib prefix="t" uri="/templates.tld" %>
<t:extends template="base.jsp">
<t:block name="main">
Conteúdo da Index
</t:block>
</t:extends> </pre>
<br />
<h3>
Implementação</h3>
<br />
Primeiro, vamos à definição da tag <i>block</i>:<br />
<br />
<pre class="prettyprint lang-java notranslate">package net.ronoaldo.tools.templateutils.tags;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import javax.servlet.jsp.JspContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;
/**
* Tag simples que define um bloco de template.
*
* @author Ronoaldo Pereira &lt;ronoaldo@ronoaldo.net&gt;
*/
public class Block extends SimpleTagSupport {
/**
* Chave para recuperar o buffer, no escopo da requisição.
*/
private static final String BLOCK_REGISTRY_KEY = Block.class.getName()
+ "-BLOCK_REGISTRY_KEY";
/**
* {@link Logger} para depuração.
*/
protected Logger logger = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
/**
* Nome do bloco.
*/
private String blockName;
/**
* <i>Setter</i> para o atributo <b>name</b>, que identifica unicamente o
* bloco.
*
* @param name
* o nome do bloco.
*/
public void setName(String name) {
this.blockName = name;
}
/**
* Realiza a implementação da Tag propriamente dita.
*/
@Override
public void doTag() throws JspException, IOException {
if (withinExtendsBlock()) {
updateBlockContent();
} else {
renderBlock();
}
}
/**
* Atualiza o conteúdo em cache do bloco, caso ele ainda não tenha sido
* definido.
*
* @throws JspException
* @throws IOException
*/
private void updateBlockContent() throws JspException, IOException {
// Renderiza o bloco caso ele ainda não exista
if (getRegistry().get(blockName) != null)
return;
StringWriter sw = new StringWriter();
JspFragment body = getJspBody();
if (body != null) {
body.invoke(sw);
}
getRegistry().put(blockName, sw.toString());
logger.info(String.format("Content for block %s updated to %s",
blockName, sw.toString()));
}
/**
* Renderiza o bloco na página JSP.
*
* @throws JspException
* @throws IOException
*/
private void renderBlock() throws JspException, IOException {
// Insere o bloco na página
updateBlockContent();
JspWriter out = getJspContext().getOut();
out.print(getRegistry().get(blockName));
}
/**
* Identifica se esta tag {@link Block} está dentro de uma tag
* {@link Extends}.
*
* @return
*/
private boolean withinExtendsBlock() {
return (getParent() instanceof Extends);
}
/**
* Recupera ou cria um registro no escopo da requisição, para armazenar os
* buffers dos blocos da página a ser exibida.
*
* @return um {@link Map} contendo os valores associados ao nome do bloco.
*/
private Map<String, String> getRegistry() {
JspContext ctx = getJspContext();
@SuppressWarnings("unchecked")
Map<String, String> registry = (Map<String, String>) ctx.getAttribute(
Block.BLOCK_REGISTRY_KEY, PageContext.REQUEST_SCOPE);
if (registry == null) {
registry = new HashMap<String, String>();
ctx.setAttribute(Block.BLOCK_REGISTRY_KEY, registry,
PageContext.REQUEST_SCOPE);
}
return registry;
}
}</pre>
<br />
Esta tag é bem simples. Neste caso, estamos utilizando uma implementação baseada em um Map<String, String>, para armazenar apenas um valor para o bloco durante o processamento de todas as tags das páginas envolvidas.<br />
<br />
Se utilizarmos apenas esta Tag, já conseguimos criar um efeito bem interessante. Basta definir os blocos antes de qualquer outra coisa, e finalizar a página com a diretiva <%@include %>. Isso já nos dá o resultado esperado, exceto para aninhar páginas.<br />
<br />
Para uma implementação mais completa, vamos definir a tag Extends:<br />
<br />
<pre class="prettyprint notranslate">package net.ronoaldo.tools.templateutils.tags;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;
/**
* Tag simples que realiza um <i>include</i> após realizar o processamento de
* seu conteúdo.
*
* @author Ronoaldo Pereira &lt;ronoaldo@ronoaldo.net&gt;
*/
public class Extends extends SimpleTagSupport {
/**
* Nome do template a ser utilizado para inclusão.
*/
private String template;
/**
* <i>Setter</i> para que o atributo <code>template</code> funcione.
*
* @param template
* o nome do template a ser extendido.
*/
public void setTemplate(String template) {
this.template = template;
}
/**
* Implementação da Tag.
*/
@Override
public void doTag() throws JspException, IOException {
// Processa o body (definição de blocos)
getJspBody().invoke(null);
// Realiza o include do template
try {
PageContext pageContext = (PageContext) getJspContext();
pageContext.include(template);
} catch (ServletException e) {
throw new JspException(e);
}
}
}
</pre>
<br />
Para finalizar com chave de ouro, basta agora realizar a implementação de um arquivo <i>tld</i>:<br />
<br />
<pre class="prettyprint notranslate"><?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE taglib PUBLIC
"-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"
"http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
<taglib>
<tlib-version>1.2</tlib-version>
<jsp-version>2.0</jsp-version>
<short-name>template-utils</short-name>
<description>Several utilities for templating with JSP and JSTL</description>
<tag>
<name>extends</name>
<tag-class>net.ronoaldo.tools.templateutils.tags.Extends</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>template</name>
<required>true</required>
<type>java.lang.String</type>
<description>Indicates the parent template to extends from.</description>
</attribute>
</tag>
<tag>
<name>block</name>
<tag-class>net.ronoaldo.tools.templateutils.tags.Block</tag-class>
<body-content>scriptless</body-content>
<attribute>
<name>name</name>
<required>true</required>
<type>java.lang.String</type>
<description>The block name, unique across all template and its extensions</description>
</attribute>
</tag>
</taglib></pre>
<br />
Você pode até criar um pequeno <code>jar</code> com estas classes e este arquivo taglib.tld dentro de <coe>META-INF, e ele pode ser incluído no seu diretório <code>WEB-INF/lib</code> como biblioteca reutilizável.</coe>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com5tag:blogger.com,1999:blog-4241414426102940500.post-35912677140388136722009-09-01T23:38:00.000-03:002010-11-23T00:11:03.286-02:00O dia em que a Terra parou... Ou foi o Gmail?Era uma tarde comum de trabalho. Tudo estava normalmente bem. Calor, ar condicionado, computadores, cadeiras e mesas. Tudo irritantemente normal. Até que um funcionário do departamento de vendas indagou:<br />- ... a internet caiu?<br /><br />De prontidão, o técnico respondeu:<br />- Não, a internet está funcionando normalmente. Estou conectado.<br /><br />O gerente retruca:<br />- Não, não está funcionando, venha ver.<br /><br />O técnico tinha razão. Se não era a Internet, então o que havia "caído"? O mistério durou alguns instantes. Aos poucos, notamos que o Gmail de nosso Google Apps não estava conseguindo estabelecer uma conexão com o servidor. Mas ao contrário das outras vezes, o problema não era com nossa conexão à internet.<br /><br />Estranho. Começamos a ficar preocupados. Até que alguém resolveu apertar o atalho F5 do <span style="font-style: italic;">browser</span>. Desespero com o resultado: "<span style="font-style: italic;">Server Error</span>". Com assim? O <span style="font-style: italic;">server</span> não poderia ter dado um <span style="font-style: italic;">error</span> como resposta! Inacreditável. Durou bem mais de 30 segundos.<br /><br />Foi estranho. Era como se a energia elétrica tivesse acabado. Ou a comida. Ou a água potável. Ou a vida no planeta. Sem poder enviar ou receber a correspondência eletrônica com os clientes, o final da tarde foi tenso. A cada vez que acionávamos a tecla F5, mais tensa a tarde ficava.<br /><br />No finalzinho do expediente, quando alguns já iam embora, o último F5 do dia informava que, aparentemente, a Terra tinha voltado a girar.<br /><br />Um momento para reflexão. Talvez seja hora de fazer aquele backup dos seus dados da nuvem, pois pode chover a qualquer hora.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-72825595142094475062009-08-14T08:08:00.000-03:002010-12-04T01:17:18.791-02:00HIPHONE!Estava acessando as notícias do UOL, quando me deparei com uma oferta de aparelho telefônico Dual SIM.<br />
<br />
O melhor foi ler o texto descritivo do produto. Veja o trecho mais "relevante":<br />
<div style="text-align: center;"><br />
<blockquote>O UNICO MP12 M8 COM WI-FI ( INTERNET SEM FIO GRATIS )O UNICO COM JAVA 2.0 O UNICO COM MSN e YAHOO O UNICO COM 2 CAMERAS E FLASH O UNICO COM OPERA O UNICO COM MESSANGER <br />
<br />
O UNICO COM DOIS CHIPS, DOIS EMEIS, CHIPS SIMULTANEOS,</blockquote></div><br />
<span style="background-color: white;">Não sei qual foi a melhor, entre "MESS</span><span style="background-color: white; font-weight: bold;">A</span><span style="background-color: white;">NGER" e "</span><span style="background-color: white; font-weight: bold;">E</span><span style="background-color: white;">MEI" (não era </span><a href="http://pt.wikipedia.org/wiki/IMEI" style="background-color: white;">IMEI</a><span style="background-color: white;">?) . </span>Confesso que fiquei na dúvida entre "UNICO" e "GRATIS" ainda terem ou não acento depois do novo acordo... Alguém poderia me ajudar?<br />
<br />
Tomara que o aparelho tenha ao menos corretor ortográfico ou gramatical.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-22587525911293996802009-08-13T08:29:00.000-03:002010-11-23T00:11:03.286-02:00Amar é ...Esquecer,<br />dos problemas cotidianos<br />para dividir o que há de bom.<br /><br />Partilhar,<br />a alegria de cada momento<br />por mais simples que ele seja.<br /><br />Aceitar,<br />as virtudes e também os<br />defeitos.<br /><br />Dividir,<br />tudo.<br /><br />Enfim,<br />Amar é viver ao lado da<br />minha esposa, Juliana!Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-80917831822315588542009-08-12T08:07:00.000-03:002010-11-23T00:11:03.286-02:00CasamentoNo último dia 19 de julho completei um ano de casamento. Passou muito rápido. Mas é assim mesmo: quando agente ama de verdade, o tempo é uma unidade de medida imprecisa.<br /><br />Claro, como vocês já devem saber, também fiquei um ano mais velho. Neste meu ano de vida, tive muitas realizações. A primeira deles, o casamento, foi um sucesso. O <a href="http://ulissesleitao.blogspot.com/2008/11/lanamento-vix-linux.html">lançamento do Vix Linux</a>, do qual tive a alegria de participar. Minha mudança para São Paulo. Minhas aulas em Campinas. A pós-graduação da minha amada. O aluguel do apartamento... Estes são alguns exemplos.<br /><br />Agradeço a todos que fizeram e fazem parte de minha vida, com quem pude dividir estas realizações. E espero que novas conquistas estejam próximas.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com3tag:blogger.com,1999:blog-4241414426102940500.post-77160108754982270652009-06-13T13:08:00.000-03:002010-11-23T00:11:17.219-02:00Tá bom, tá bom, eu escrevo<div style="text-align: left;">Eu sei, deixo muito tempo entre uma postagem e outra. Já entendi, vou escrever mais.<br /></div><br />Não sou um <span style="font-style: italic;">repórter</span>, mas vou tentar. Escrever faz bem. Você pensa, digita, e depois lê. Apaga tudo, porque não ficou bom, pensa mais um pouco, normalmente digita menos do que a última vez, e lê de novo. Apaga só a parte do meio, que ficou estranha e desconexa, escreve uma ou duas linhas em seu lugar e então lê novamente. Ai você acha que está bom, publica e aguarda os comentários.<br /><br />Gosto de escrever, apesar de não ser <span style="font-style: italic;">expert</span> no assunto. Acho que me sinto mais à vontade escrevendo textos técnicos. Mas como sou de carne e osso (mais do segundo elemento, como já devem ter notado), também escrevo para os mortais. Não que os técnicos sejam imortais, mas ... Bem, vocês entenderam.<br /><br />Sim, eu deveria ter apagado o parágrafo do meio, ficou estranho e desconexo. Mas aí eu teria escrito muito pouco, e você teria desistido logo. Ok... acho que está bom por hoje. Vou terminar meus afazeres. Depois agente se fala mais.<br /><br /><span style="font-style: italic;"><span style="font-weight: bold;">PS</span>: Para aqueles querendo saber novidades, aqui em Sampa está tudo bem, apesar do frio e, é claro, da garoa. Temos casa sem móveis (por enquanto) e muito trabalho. Estou ansioso pelo próximo semestre, que promete ser muito bom. E minha irmã vai se casar. Mas isso vocês já devem saber.</span>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com2tag:blogger.com,1999:blog-4241414426102940500.post-57250933656932855592009-05-03T21:49:00.000-03:002010-11-23T00:11:03.287-02:00PalavrasSão a unidade básica da comunicação.<br />Empregadas com sabedoria, são um excelente remédio.<br />Elguns casos, são a principal causa da doença.<br /><br />Se usadas para o bem, as palavras podem compor<br />excelentes discursos.<br />No aniversário do melhor amigo,<br />no dia das mães.<br />Podem trazer lágrimas nos aos olhos<br />dos colegas de formatura.<br />Podem fazer sorrir um doente internado.<br />Podem fazer feliz aquele depressivo à beira do suicídio.<br /><br />Se usadas para o mal, as mesmas palavras<br />podem fazer grandes estragos.<br />Palavras que são ditas para ofender.<br />Palavras gravadas em escutas telefônicas.<br />Palavras em um plano de invasão militar.<br /><br />A dualidade acontece mesmo quando não há palavras.<br />Seja no silêncio que conforta na dor,<br />ou na omissão que pode até matar.<br /><br />Palavras mudam.<br />Palavras podem causar mudanças.<br />Palavras podem ser modificadas.<br />Palavras podem até deixar de ser palavras,<br />para ser sonho, gesto ou ação.<br /><br />Palavras podem ser pequenas,<br />simples como um "oi".<br />Podem abrigar complexidade como<br />uma "cadeia polipeptídica".<br />Podem ser tristes e alegres.<br /><br />Palavras podem ser apenas ... palavras.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com1tag:blogger.com,1999:blog-4241414426102940500.post-24663458317179071202009-02-01T14:23:00.000-02:002010-11-23T00:09:36.250-02:00Programadores de verdade usam borboletasEsta é para os nerds de plantão.<br />
<br />
Estava procurando uma boa IDE para o desenvolvimento de aplicativos em Python, e me surpreendi com alguns comentários em fóruns.<br />
<br />
Resolvi usar as borboletas mesmo, depois de ler este quadrinho:<br />
<br />
<a href="http://xkcd.com/378/">http://xkcd.com/378/</a><br />
<br />
Logo que der um tempinho, faço uma versão em português ...Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-49728555982253854712009-01-27T00:43:00.000-02:002010-11-23T00:11:03.287-02:00Guarda-chuva: não saia de casa sem ele!Coisa difícil deve ser o trabalho dos meteorologistas da selva de pedra. Sem nenhum exagero, ao levantar de manhã e olhar o dia nascendo, manhoso, vá preparado para o trabalho.<br /><br />Vista uma camisa confortável, e fresquinha. Leve na bolsa ou maleta uma blusa de frio e um guarda-chuva. Apesar do sol nascendo, a previsão é de uma frente fria com tempo nublado a parcialmente nublado, com pancadas de chuva no meio ou final da tarde. Há ainda a probabilidade de que os rios, córregos e esgotos transbordem com a chuva, causando as desoladoras enchentes. Se ainda não estiver satisfeito, o tempo pode esfriar também, é claro, especialmente se você trabalhar dentro do ar condicionado do escritório. E para finalizar o dia, um calor medonho, como diriam na minha terra.<br /><br />Mas tudo isso é apenas para testar a resistência do seu organismo, somando um pouco de poluição e correria.<br /><br />Outro fato curioso nesta selva, são as filas. Em todo e qualquer lugar onde você vai em São Paulo, você provavelmente verá filas. Seja na padaria para comprar pão, na farmácia para a injeção ou na hora do almoço. É claro, o que você vê na televisão sendo chamado de trânsito, nada mais é do que uma fila de carros. Tem também a fila para entrar no elevador. E aquela outra fila que ninguém sabe onde vai dar, mas já que é uma fila, não podemos ficar de fora.<br /><br />Mas nem tudo na selva de pedra se resume em efeito estufa e filas. Tem também toda a diversão de almoçar um Beirute no Habib's em plena segunda-feira. De ganhar uma partida de boliche do seu cunhado, mesmo sendo as suas primeiras jogadas. Ou de atravessar a rua usufruindo da infra-estrutura da estação do metrô. Ao menos neste trecho não tem semáforo. Por enquanto.<br /><br />E como todo bom brasileiro, agente não desiste nunca! Mas no fundo, no fundo, eu gosto desta selva. Parece que sempre pertenci a este lugar. Mesmo não entendendo tudo. Enfim, como diria minha amada mãe: a vida só é dura para quem e mole!<br /><br />P.S.: Ju, meu anjo, vem logo! Tô com saudades :)Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com1tag:blogger.com,1999:blog-4241414426102940500.post-45671550860409024022009-01-12T10:11:00.000-02:002010-11-23T00:11:03.287-02:00Pode crerEstou em São Paulo, este território chuvoso repleto de edificações monstruosas e de uma população de cotidiano corriqueiro e agitado.<br /><br />Já estou me adaptando. Apesar de não ser muita novidade já que tive uma infância paulistana, eu estou novamente me habituando a andar vários quilômetros para ir nos locais desejados. Pegar metrô, trem, enfim ... coisas de cidade grande.<br /><br />Felizmente, ainda não tive de enfrentar o temeroso trânsito, mas eu também espero que me "acostume".<br /><br />Recebi hoje uma boa notícia. Acabo de ser aprovado no concurso do COTUCA, Colégio Técnico da Universidade Estadual de Campinas, para professor substituto. Já estou com trabalho garantido para o primeiro semestre, e com boas expectativas de continuar minha carreira de docente.<br /><br />Minha digníssima esposa foi bem na entrevista, e estamos aguardando o resultado do programa de aprimoramento profissional pela USP que ela esta almejando. Dia 17 teremos o resultado.<br /><br />E a vida na selva de pedra está começando a se ajeitar. Me disseram na TV que inovemos este ano de <span style="font-style: italic;">2000 inove</span>. Eu já comecei, e você?Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com3tag:blogger.com,1999:blog-4241414426102940500.post-49169585634331357562008-11-30T21:02:00.000-02:002010-11-23T00:11:03.288-02:00Mudanças...Segundo o dicionário, <span style="font-weight: bold; font-style: italic;">mudança</span> é:<br /><br />(...)<br /><span class="sq">■</span> <span class="abrev">substantivo feminino</span><br /><span class="preto"> ato ou efeito de mudar(-se); muda, mudamento.<br /><span class="preto"> <b><br />1</b> troca de um lugar (país, região, localidade, residência etc. ) para outro<br /><span class="exemplo"> Ex.: está de m. para São Paulo<br />(...)<br /><br />A mudança também é inerente ao ser humano, em diferentes estágios de sua vida.<br /><br />Então, quem sou eu para contrariar? Vou me embora para São Paulo!<br /></span></span></span>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com2tag:blogger.com,1999:blog-4241414426102940500.post-73161947887879943302008-08-21T16:28:00.000-03:002010-11-23T00:11:03.288-02:00Hello Scrible<div xmlns='http://www.w3.org/1999/xhtml'>Nunca tive muito tempo para postar informações no meu Blog. Engraçado. Até que descobri o ScribleFire, uma extensão para o <a href='http;//br.mozdev.org/'>Mozilla Firefox</a> que permite criar meus <i>posts</i> sem muito trabalho. Basta dar um clique, escrever e em seguida publicar. Simples e prático. Além de contar com um editor WYSIWYG, há uma série de ferramentas que ainda nem descobri.<br/><br/>Esse post é, como de praxe na computação, o Hello World para o ScribleFire. Espero que a partir de agora eu consiga manter o Blog atualizado.</div>Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0tag:blogger.com,1999:blog-4241414426102940500.post-90804536952137089342008-05-05T03:33:00.000-03:002010-11-23T00:11:03.288-02:00Pense em coisas boas. Elas acontecemParece estranho, mas pensar em coisas boas realmente faz elas acontecerem. Cheguei à esta conclusão depois de passar um ano inteiro pensando que tudo sairia errado. E adivinhem: saiu tudo errado. Depois de 365 dias, exatamente 365 dias de aflições, desencontros, problemas, abacaxis, e todo o tipo de coisa ruim que você possa imaginar, eu cheguei à conclusão de que pior do que eu estava não poderia ficar. Aí, comecei a pensar em coisas boas. E adivinhem: elas aconteceram. Parece ironicamente tola essa observação, mas comece a reparar mais o seu dia-a-dia. Cada pequena coisa que você pensa que vai dar certo fará diferença no futuro.<br />Não precisa acreditar em mim, é claro. Comprove você mesmo.Ronoaldo Pereirahttp://www.blogger.com/profile/02620222149209242748noreply@blogger.com0