Cowsay: a vaquinha falante do Linux

Teste aí:

sudo apt-get install cowsay

Depois rode:

cowsay Funciona...

O cowsay também pode receber texto na entrada padrão:

date|cowsay

Isso permite usos razoavelmente criativos:

lynx --dump http://news.google.com.br | grep "^\[" | grep -v "»" \
| sed -e "s/.*\]//g" | sort -R | head -n 1|cowsay

Você pode colocar seu Ubuntu para te dar uma dica de Linux toda vez que você abre o terminal, assim:

sudo apt-get install fortunes-ubuntu-server

Depois edite o arquivo ~/.bashrc e inclua no final:

fortune|cowsay

E pronto! Cada vez que você abrir um terminal vai receber uma dica de Ubuntu.

API gratuita de consulta de CEP

Nosso presente de natal para os desenvolvedores do Brasil: API gratuita de consulta de CEP.

A Visie é parceira de tecnologia da Aviso Brasil. Nós fornecemos tecnologia para o Correio Control, e como parte do negócio, precisamos ter a base de endereços sempre atualizada e sincronizada com o Diretório Nacional de Endereços.

Vimos que muita gente oferece aquele cômodo recurso de auto completar o endereço pelo CEP, mas usando bases de dados desatualizadas. Existem até uns serviços pagos que oferecem esses dados.

Por isso, decidimos oferecer um serviço gratuito de consulta de endereços pelo CEP, para que você possa usar em sua aplicação. Os resultados podem ser retornados usando o modelo JSONp, de modo que o próprio navegador do usuário requisite diretamente o endereço de nossos servidores.

Aproveite!

Em tempo: se você faz software que de alguma maneira envia e controla encomendas, você precisa conhecer o Correio Control. É um software de baixo custo para usuários corporativos dos Correios que oferece o controle de faixas de registro, geração de etiquetas e AR, monitoramento e rastreamento estendido, solicitação automatizada de pedidos de informação e indenização, relatórios de status e muito mais.

 

Pequena dica de Python: as classes são dinâmicas

Veja:

>>> class Class:
...   def um(self):
...     return 1
... 
>>> c=Class()
>>> c.um()
1
>>> def dois(self):
...   return 2
... 
>>> Class.dois=dois
>>> c.dois()
2
>>> Class.tres=lambda self:3
>>> c.tres()
3
>>> Class.um=lambda self:'Um modificado.'
>>> c.um()
'Um modificado.'

As classes em Python são completamente dinâmicas. Você pode acrescentar métodos quando quiser e isso se refletirá em todos os objetos criados com aquela classe (mais ou menos como o que você faz em Javascript com prototype.)

Pequena dica de Python: leia os fontes

Python é uma linguagem open-source, com uma extensa biblioteca. E os módulos da biblioteca são escritos em Python. Alguns módulos, como pickle e StringIO, tem versões em C mais rápidas (cPickle e cStringIO) mas as versões em Python são mantidas para que você possa ler os fontes.

Veja como descobrir onde estão os fontes de um módulo qualquer:

>>> import glob
>>> glob.__file__
'/usr/lib/python2.7/glob.pyc'

O nome do arquivo tem a extensão pyc. É um compilado. Tire o último “c” e você terá o caminho do arquivo com o código fonte. Dê uma lida no conteúdo do glob.py, por exemplo, e você deve achar muito simples mas bastante interessante.

Se você está aprendendo Python agora, sempre que for resolver uma tarefa sobre determinado assunto, dê uma olhada no código dos módulos relacionados aquele assunto. Você vai ver como a comunidade Python tem abordado problemas semelhantes aos seus e com certeza vai aprender muito.

Pequena dica de Python: string formatting com locals()

Há muitas situações em que uma função faz cálculos e operações para obter valores e, ao final, deve montar uma string com esses valores. Nesta situação, muita gente monta um dicionário com os valores e usa string formatting para gerar a string a ser retornada. Por exemplo:

# -*- encoding: utf-8 -*-
import string,random

template='''Sugestões para %(nome)s:
 - login: %(login)s
 - email: %(email)s
 - site: www.%(domain)s.com
 - senha: %(passwd)s
'''

def sugere_logins(nome):
    login=nome.split(' ')[0].lower()
    domain=nome.split(' ')[-1].lower()
    email=login+'@'+domain+'.com'
    chars=string.letters+string.digits
    passwd=''.join(random.sample(chars,10))
    dados={'login':login,
           'email':email,
           'nome':nome,
           'domain':domain,
           'passwd':passwd}
    print template % dados

Você pode substituir todo o trecho em que monta o dicionário, usando o resultado da função locals(). A função locals() retorna um dicionário com todas as variáveis locais. No exemplo acima, isso ficaria assim:

# -*- encoding: utf-8 -*-
import string,random

template='''Sugestões para %(nome)s:
 - login: %(login)s
 - email: %(email)s
 - site: www.%(domain)s.com
 - senha: %(passwd)s
'''

def sugere_logins(nome):
    login=nome.split(' ')[0].lower()
    domain=nome.split(' ')[-1].lower()
    email=login+'@'+domain+'.com'
    chars=string.letters+string.digits
    passwd=''.join(random.sample(chars,10))
    print template % locals()

Uso muito esse truque ao trabalhar com web2py, fazendo com que os controllers, ao invés de retornar um dicionário montado por mim, retornem locals().

Números bem torturados

Dizem que Delfim Neto dizia que números, quando bem torturados, são capazes de confessar qualquer coisa. Eu concordo. Sempre que você ouvir números impressionantes gaste algum tempo pensando, aplique um pouco de matemática básica e duvide um pouco do que você ouviu.

Vi no Facebook hoje o pessoal compartilhando esse artigo:

Paulistas compram mais carros por hora do que roraimenses o mês todo

O artigo destaca o fato de que “São Paulo vendeu em agosto o dobro do segundo colocado e 212 vezes mais do que Roraima, o último do ranking”, dando a impressão ao leitor de que isso é reflexo de uma tremenda desigualdade social.

Acontece que a população de São Paulo é maior que o dobro que a de Minas Gerais, segundo colocado no ranking de venda de carros. Assim, per-capita, o mineiro comprou quase a mesma quantidade de carro que o paulista em agosto.

Veja, para cada dez mil habitantes em São Paulo foram vendidos 28 veículos, e em Minas 26. E quanto a Roraima? Bem, as diferenças sociais são gritantes. Mas o artigo coloca as coisas assim:

São Paulo vende por hora 621 unidades, mais do que Roraima vende por mês: 538.

Olhando assim, parece que o paulista ganha dezenas de vezes mais dinheiro que o roraimense. Mas em Roraima, para cada dez mil habitantes, foram vendidos 11 carros. Ainda uma desigualdade, claro, mas não de dezenas de vezes, não é?

Em tempo: antes que os comentários enveredem por esse assunto, eu concordo que nossas cidades precisam de menos carros e mais bicicletas/metrôs/corredores de ônibus/trabalho remoto. Mas o fato de isso ser uma boa causa não nos dá o direito de fazer esses absurdos com os números, não é?

Pequena dica de Python: rot-13

A dica de hoje não é muito útil. Pelo menos eu nunca usei para nada realmente sério. Mas é bem divertida:

>>> t='All your base are belong to us.'
>>> t.encode('rot-13')
'Nyy lbhe onfr ner orybat gb hf.'

Rot-13 é um encoding comum do Python. Você pode escrever código em rot-13 também, se indicar o encoding do arquivo num cabeçalho:

# -*- encoding: rot-13 -*-
vzcbeg fgevat
sbe v va enatr(20):
    cevag fgevat.nfpvv_ybjrepnfr[:v]

Salve o conteúdo acima no arquivo rot13.py e você poderá executar:

$ python rot13.py

Divertido, não?

Pacote Ubuntu: cclive

O pacote cclive, para download de vídeos do YouTube na linha de comando, é uma reescrita do clive mais eficiente, com menor consumo de memória e menos dependências. Para instalar:

$ sudo apt-get install cclive

E para usar:

$ cclive http://www.youtube.com/watch?v=8fvTxv46ano

Isso vai baixar o vídeo na pasta atual. Simples e indolor. Mas qual a vantagem de usar a linha de comando em relação a uma extensão no navegador, onde você não precisa digitar comandos? Com a linha de comando é possível automatizar as tarefas. Criei um script que recebe um nome de usuário do YouTube e baixa os últimos 15 vídeos publicados. Chamei o arquivo de massclive. Veja o código fonte:

mkdir -p $1

lynx --dump http://www.youtube.com/user/$1/feed | \
  grep youtube.com/watch | \
  sed -e "s/.* //" | \
  sed -e "s/&.*//" | \
  sort -u | \
  while read url
  do
    cclive -c --output-dir $1 $url
  done

E você pode usar assim:

$ ./massclive maninthearenatv

Pequena dica de Python: mesclando listas

Essa é bem legal. Temos três listas:

>>> a=[1,2,3]
>>> b=[4,5,6]
>>> c=['a','b','c']

Veja:

>>> zip(a,b,c)
[(1, 4, 'a'), (2, 5, 'b'), (3, 6, 'c')]

Simples e útil, não? E se as listas tiverem tamanhos diferentes?

>>> c=['a','b']
>>> zip(a,b,c)
[(1, 4, 'a'), (2, 5, 'b')]

O resultado será truncado para o tamanho da menor lista. Se você quiser, pode obter um comportamento diferente com map, assim:

>>> map(None,a,b,c)
[(1, 4, 'a'), (2, 5, 'b'), (3, 6, None)]

Veja um truque que eu costumava usar bastante com zip:

>>> colors=['Azul','Vermelho','Amarelo','Verde','Branco']
>>> for i in zip(range(len(colors)),colors):
...   print '%i. %s' % i
... 
0. Azul
1. Vermelho
2. Amarelo
3. Verde
4. Branco

Até que eu descobri enumerate():

>>> for i in enumerate(colors):
...   print '%i. %s' % i
... 
0. Azul
1. Vermelho
2. Amarelo
3. Verde
4. Branco

Pacote Ubuntu: random faux Latin text generator

O pacote libtext-lorem-perl contém um gerador de Lorem Ipsum para o seu terminal. Eu tinha até feito um script para isso antes de saber da existência desse pacote. Para instalar:

$ sudo apt-get install libtext-lorem-perl

E para usar:

$ lorem

Para gerar vários parágrafos, use a opção -p informando quantos parágrafos você quer:

$ lorem -p12

Você também pode usar -w para indicar quantas palavras o lorem deve gerar, ou -s para indicar quantas sentenças. Olha o que dá para fazer:

echo "<section>
 <h1>`lorem -w 3`</h1>
 <h2>`lorem -s 1`</h2>
 <p>`lorem`</p>
 <p>`lorem`</p>
 <p>`lorem`</p>
</section>"

HTML5: Desenvolvendo agora as aplicações web de amanhã

Boa parte das APIs do HTML5 já estão disponíveis hoje para a maioria dos navegadores e, com um pouco de conhecimento e uma pitada de javascript, é possível desenvolver hoje aplicações com geoposicionamento, funcionamento offline, conexão em tempo real com o servidor, gráficos vetoriais e todo um novo conjunto de recursos de interface.

Por que esperar?

O HTML5 foi construído de maneira modular. Não é preciso esperar que toda a documentação esteja escrita para começar a trabalhar com ele. Você pode usar agora mesmo o que já está pronto.

Pensando nisso, preparamos este Workshop sobre as APIs do HTML5 e como construir a nova geração de aplicações web. Veja o programa.

Pequena dica de Python: any e all

Python tem duas funções muito interessantes: any e all. A função any recebe uma lista (ou outro objeto interável) e retorna True se algum dos elementos for avaliado como True. Já all só retorna True se todos os elementos forem avaliados como True. Veja:

>>> everybody=[1,2,3,4]
>>> anybody=[0,1,0,2]
>>> nobody=[0,0,0,0]
>>> any(everybody)
True
>>> any(nobody)
False
>>> any(anybody)
True
>>> all(everybody)
True
>>> all(nobody)
False
>>> all(anybody)
False

Sem segredos, certo? Mas essas duas funções junto com os generators permite uma sintaxe muito interessante:

>>> v=[10,12,25,14]
>>> any(n>20 for n in v)
True
>>> all(n>20 for n in v)
False

Veja um exemplo disso num código real:

if all(v<100 for v in values):
    msg='Para usar seu cupom de desconto, pelo menos '+
        'um dos produtos deve custar mais de R$ 100,00.'

E numa classe real:

class Form:
    # ...
    def validates(self):
        return not any(field.error for field in self.fields)

Módulo Python: gzip

O módulo gzip nos permite ler e escrever em arquivos .gz sem nenhum trabalho. Veja:

>>> import gzip
>>> f=gzip.open('teste.txt.gz','w')
>>> f.write('Hello!\n')
7
>>> f.close()
>>> 
$ gunzip teste.txt.gz 
$ cat teste.txt 
Hello!
$ gzip teste.txt 
$ python
Python 2.7.3 (default, Apr 20 2012, 22:39:59) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import gzip
>>> print gzip.open('teste.txt.gz').read()
Hello!

Pequena dica de Linux: CDPATH

Quando você executa o trivial comando cd o shell (seja o bash ou o zsh) procura pelo diretório informado nos caminhos indicados na variável de ambiente CDPATH. Se não houver uma variável CDPATH, o shell procurará no diretório atual. Veja:

elcio@vaio:~$ cd 5cms
bash: cd: 5cms: Arquivo ou diretório não encontrado
elcio@vaio:~$ export CDPATH=.:~/projetos
elcio@vaio:~$ cd 5cms
/home/elcio/projetos/5cms
elcio@vaio:~/projetos/5cms$ pwd
/home/elcio/projetos/5cms

Eu costumo editar meu .zshrc (edite o .bashrc se você usa bash) e incluir no final:

export CDPATH=.:~:~/projetos

Assim, sempre que eu executar um cd o shell vai procurar primeiro no diretório atual, em seguida no meu diretório home, por fim no meu diretório de projetos.

Qual é exatamente o problema com eval()?

Para iniciar este post, é preciso deixar algo claro: diferente da minha postura com os polêmicos ponto-e-vírgula, em que sei que sou “promíscuo e relaxado”, eu sou muito reticente quanto ao uso de eval() em javascript. O principal motivo é que eval() me cheira a gambiarra. Mas tenho muita dificuldade em dizer porquê. Na verdade, acho mesmo que é só uma questão de elegância.

Já li muita coisa sobre o assunto, mas nenhum argumento me convenceu. Os dois principais argumentos são performance e segurança. Em minha opinião nem um dos dois argumentos procede.

Performance

Em primeiro lugar, é preciso dizer que o argumento de que JSON tem pior performance raramente é verdade. Há alguns anos, código executado via eval não poderia ser cacheado ou pré-otimizado. Isso não é mais verdade hoje em dia. A V8 (Chrome), a Nitro (Safari) e a SpiderMonkey (Firefox) já trabalham com caching do código passado a eval em diversas circunstâncias. Além disso, pense nas situações em que eval seria útil. Não consigo imaginar uma em que performance seja um problema. Por exemplo, uso eval como um fallback para navegadores que não tem suporte nativo a JSON. Sinceramente, depois de um delay de dois segundos esperando por uma requisição Ajax, não faz absolutamente nenhuma diferença se interpretar esse retorno vai levar dez milissegundos a mais.

Alguém pode dizer que seria melhor nessa situação usar uma biblioteca JSON com validações, como a do Douglas Crockford. Mas isso acrescentaria 17Kb de código em troca de absolutamente nada. Alguém pode então argumentar que o que se ganha usando uma biblioteca dessas não é exatamente nada, mas pelo menos um validador do código antes da execução. Respondo a isso no final.

Segurança

O segundo argumento mais usado contra o uso de eval() é segurança. O fato de executar uma string, gerada dinamicamente, e não código escrito diretamente por você, pode dar calafrios. Puxa, mas não dá para ter a menor ideia do que será executado! Um agressor não poderia usar isso para executar código arbitrário? Isso não abre as portas para ataques XSS ou man-in-the-middle?

Aqui também, ninguém nunca conseguiu me demonstrar um único caso em que isso fosse uma preocupação real. Imagine o caso de uso que citei acima, por exemplo, de fazer parsing de dados JSON vindos via Ajax. Embora o código que vá passar por eval() não esteja no seu javascript, ele efetivamente foi escrito por você, no servidor. Se alguém consegue acesso a sua aplicação server afim de enviar dados maliciosos para suas requisições Ajax, por que ele se daria ao trabalho de fazer isso se ele poderia simplesmente gerar Javascript malicioso ou HTML malicioso? Se alguém teve esse nível de acesso a seu servidor, XSS é a menor de suas preocupações.

Outra variação do argumento da segurança diz que se você usa eval() a partir de uma entrada de dados do usuário, isso sim poderia abrir as portas para a execução de código malicioso. É preciso lembrar aqui que código javascript roda no client. Assim, o fato de eu poder digitar um script malicioso num campo de formulário, por exemplo, não significa nada exceto o fato de que posso “invadir minha própria máquina”.

Claro, se você recebe os dados gerados por esse eval() no servidor sem validá-los, isso pode causar problemas. Mas, nesse caso, o problema não está no eval() mas em sua validação porca no servidor. Se não houvesse eval() no código, a mesma coisa poderia ser feita na Firebug ou no console do Chrome.

Há ainda a preocupação com buscar dados de um servidor externo e executá-los, o que faria com que seu site possa executar código malicioso. Bom, se você inclui javascript em sua página gerado pelo Google Analytics, e pelo Twitter, Facebook, AddThis e outros geradores de widgets, porque não confiaria em executar código dessas mesmas fontes via eval()? Qual é exatamente a diferença?

Em suma, se as fontes de dados para o eval() não são confiáveis, não use-as de jeito nenhum. O problema não está no eval().

Qualidade de código

Um último argumento, menos usado mas em minha opinião mais relevante, tem a ver com a qualidade de código. O principal motivo que me faz evitar o uso de eval() é o fato de, se houver algum erro no código avaliado, será bem mais difícil debugar. O navegador vai acusar o número da linha do eval(). Esse é um forte argumento, mas não para todas as situações. Geralmente eu gero JSON no servidor com uma biblioteca ou módulo bastante confiáveis, tanto em PHP quanto em Python. Quais são sinceramente as chances de meu software falhar porque há um problema na biblioteca padrão de JSON do PHP?

Por isso, eu não costumo trocar um simples eval() pelo uso de uma biblioteca de JSON, por exemplo.

Fazendo errado

Não importa quão útil e boa seja uma ferramenta, sempre há uma infinidade de maneiras erradas de usá-la. Vi esses dias código assim:

eval('document.'+obj).className='selected'

Esse código é muito ruim, demonstrando um desconhecimento básico dos recursos da linguagem. Pode facilmente ser substituído por isso:

document[obj].className='selected'

Entenda que este artigo questionando os argumentos comuns contra o uso de eval() não é uma defesa de seu uso, principalmente de seu uso indiscrimado.

Seu argumento

Perdi alguma coisa? Há algo mais que precise ser dito? Por favor, fique à vontade para deixar seus comentários.

 

 

 

Pequena dica de Python: __missing__

A partir do Python 2.5, ao estender dicionários, você pode dar a suas classes um método __missing_, que será executado toda vez que você tentar acessar um índice inexistente. Veja:

class Counter(dict):
    def __missing__(self, key):
        self[key]=0
        return self[key]

Veja funcionando:

>>> votos=['john','paul','john','john','ringo',
...        'george','paul','ringo','ringo','john',
...        'paul','john','george','paul','paul',
...        'john','paul','john','ringo','paul']
>>> c=Counter()
>>> for v in votos:
...     c[v]+=1
... 
>>> c
{'ringo': 4, 'paul': 7, 'john': 7, 'george': 2}