Mostrando postagens com marcador python. Mostrar todas as postagens
Mostrando postagens com marcador python. Mostrar todas as postagens

sábado, 29 de setembro de 2007

Volta da PyConBrasil, Sandboard e Calabresa

Bom, eu finalmente reservei um tempinho para fazer um novo post e contar algumas das coisas que aconteceram durante o mês de Setembro, que para variar, passou mais rápido do que eu gostaria... :-/

A PyConBrasil, que reúne a fauna pythônica nacional (e agora também parte da internacional, com as presenças de Nate Aune do mundo Plone e Kenneth Rohde Christiansen do INdT com seu poliglotismo em 13 idiomas!), desse ano foi ótima! Quem não pode ir realmente perdeu um grande evento. A palestra inicial, O que Python faz quando você não está olhando, do Pedro Werneck (o que por si só já seria uma razão para não perdê-la), apresentou uma visão geral bem interessante dos aspectos técnicos da linguagem. Altamente recomendada.

Inicialmente estava programado para o Roberto Allende falar sobre o Plone 3, inclusive o Fábio Rizzo chegou a abrir mão do seu tempo, em função da grade apertada, mas o Roberto não pode vir e eu acabei tendo que sacrificar a minha palestra sobre o SQLAlchemy para dar uma pouco mais de atenção às novidades do Plone 3. Pena não termos tido tempo para perguntas, mas fique a vontade para comentar por aqui... :-)

O Grok também esteve bem representado no evento, contando com a participação dos ilustres Luciano Ramalho e Dirceu Tiegs. Um dos eventos noturnos, que estavam abertos para todos os estudantes da SOCIESC, foi justamente um comparativo entre os frameworks para desenvolvimento web. Eu fui incumbido de representar o Plone, o Ramalho o Grok e o Andrews Medina ficou com o Django. Cada um de nós falou um pouco de como chegou até o seu framework, apresentando as principais vantagens e as áreas de aplicação. Posso garantir que pelo menos nós três nos divertimos bastante naquele palco... :-D

Também tivemos a participação de outras figurinhas já conhecidas da comunidade Python, mas só para citar alguns dos feras presentes:

É obvio que eu vou esquecer de falar de muita gente, mas não dá para deixar de citar ainda o João Sebastião de Oliveira Bueno Calligaris, o João Chaves Júnior, o Júlio de Lima do Rêgo Monteiro, o Juracy Pereira de Santana Filho, o Leonardo Rochael Almeida, o Rodrigo Bernardo Pimentel, o Rudá Porto Filgueiras, o Sérgio Oliveira Campos, a Sulamita Garcia e os demais palestrantes do evento.

Em uma das noites eu apresentei a já consagrada palestra sobre Empreendedorismo, dessa vez de uma forma um pouco mais descontraída, praticamente cômica. O Andrews, prontamente, já adicionou um 'Climber' ao meu nome, afinal a vida é uma caixinha de surpresas... :-D

A cada edição da PyConBrasil acabamos conhecendo gente nova. Em 2005, na primeira edição em Campinas, a grande revelação foi o Frederico Gonzalez Colombo Arnoldi, ou simplesmente Fred, com o seu impressionante MPAlign, um programa de edição de seqüências e alinhamentos moleculares. No ano passado, em Brasília, tivemos o Sérgio de Oliveira Campos com o PyVersionWeb e o Ulysses Almeida com o sistema de monitoramento de cargas. Nesta terceira edição, eu diria que os maiores destaques foram o Flávio Codeço Coelho, apresentando Python na Ciência e o seu livro na Lulu.com, a Tatiana Al-Chueyr Pereira Martins falando a respeito do InVesalius, um software para reconstrução 3D de imagens médicas e o Roberto Antonio Ferreira De Almeida com o impronunciável e criativo Shrubbery, uma linguagem de templates.

Nesse ano deu trabalho para o Fred apresentar a sua palestra sobre o ensino de estatística com Python. Primeiro o seu notebook se recusou a exibir qualquer coisa no projetor da SOCIESC, em seguida tivemos um trabalhão para instalar todas as bibliotecas necessárias no meu notebook. A estratégia foi simples, executávamos os programas dos exemplos dele e quando dava algum erro, nós instalávamos os pacotes que faltavam. Tudo ia muito bem até chegarmos no python-rpy... que estava (e ainda esta!) com problemas no Ubuntu. Tentamos renomear a biblioteca _rpy2050.so para _rpy2051.so, na esperança da assinatura dos métodos não ter mudado, mas não funcionou. Depois tentamos recompilar o pacote, porém os mais de 300MB de download com as dependências inviabilizaram o processo. Por fim, a solução foi catar o arquivo _rpy2051.so em um pacote pré-compilado do Fedora! Quando tudo parecia bem, foi o meu notebook que se recusava a levantar o X! Com a ajuda do notebook do Andrews e o apoio do Senra, descobri que uma das atualizações do Gutsy naquela manhã tinha mudado as permissões do diretório /tmp, causando toda a confusão. Depois disso foi só alegria e transcorreu tudo bem com a palestra do Fred! :-)

Acabado o evento, combinamos de levar o Nate Aune até a ilha de Florianópolis, para ele conhecer um pouco do litoral brasileiro, afinal, três dias consecutivos de chuva em Joinville estavam distorcendo a imagem de sol, calor e praia, típica dos estrangeiros, sobre o Brasil... :-P

Na viagem com destino a Canasvieiras, acabamos passando por Camboriu (onde andamos no bondinho) e diversas outras praias, inclusive em Joaquina, onde deu tempo para brincar de sandboard! Confira o desempenho de um surfista de primeira viagem:

Mundando um pouco de assunto, no feriado estadual de 20 de Setembro (data máxima do Gaúcho), minha esposa levou as meninas para visitar os avós em Cachoeirinha e eu acabei ficando com o meu cunhado em casa. Como eu não pude contar com o repertório culinário aprimorado da minha esposa e muito menos com as opções locais, acabei tendo que me virar...

Santo Google foi a solução! Com o Google Base é possível encontrar um repositório completo, contendo eventos, atividades, hotéis, recomendações, produtos, serviços, entre uma série de diversos outros itens e, é claro, receitas! Eu acabei fazendo um mix entre diferentes receitas, aproveitando o que eu tinha em casa: massa (Farfalle, a do tipo gravatinha, da Barilla, claro!), lingüiça calabresa defumada, requeijão cremoso e queijo parmesão ralado. Modéstia a parte, ficou muito mais saboroso do que eu poderia imaginar... ;-)

Bom, ainda falta falar sobre outras coisas, mas deixo para um novo post durante essa semana...

Leia mais...

terça-feira, 28 de agosto de 2007

Rumo a Joinville: APyB & PyConBrasil

O mês de agosto passou tão rápido que quase não deu tempo de falar sobre alguma coisa por aqui... :-/

De qualquer forma, vou citar alguns acontecimentos das últimas semanas e outros que ainda estão por vir.

Primeiro uma rápida retrospectiva desse veloz Agosto:

  • A relação oficial das palestras da PloneConf foi anunciada.
  • O Plone 3 foi lançado em grande estilo, com direito a virar destaque no Digg.com.
  • Eu continuo progredindo no Rankk.org, aprendi meia dúzia de novas linguagens de programação e um sem número de técnicas de criptografia; agora rumo ao TOP3... ;-)
  • Aprendi a usar e a amar o zc.buildout, agora não saio mais de casa sem ele! ;-)
  • Atualizei meu Ubuntu Feisty para o Gutsy, sim eu adoro bleding-edge e já estava ficando deprimido com a falta de upgrades diários...

Agora o que está por vir:

  • Uma jornada de 568Km partindo às 7h da manhã dessa quarta, de Garibaldi com destino a Joinville, com direito a GPS, conexão EDGE/GPRS e carregador automotivo de bateria de notebook... ;-)
  • A Assembléia anual da Associação Python Brasil, às 19h desse mesmo dia, para a definição da próxima gestão.
  • A Conferência Brasileira de Python (a.k.a. PyConBrasil), que acontece de quinta à sábado; considerada como o evento nacional imperdível do ano! Gerenciar o processo de inscrição deu um trabalho do cão, mas acredito que vai valer cada segundo do tempo usado!
  • Algumas noites de muita descontração na presença dos amigos Pythonistas pelas ruas e points de Joinville.
  • Algumas horas em claro durante as madrugadas tentando chegar a Geb no Rankk.org e colocando o papo em dia com o grande amigo Rodrigo Dias Arruda Senra.

Nos vemos em Joinville, até breve! :-)

Leia mais...

terça-feira, 31 de julho de 2007

Documentação e rankk.org

Correria do cão, sumiço temporário, deadline de projetos se aproximando, mas o mundo não pára... então antes de continuar com dicas sobre o Plone 3.0 (que entrou em rc2 na sexta passada), vou falar sobre uma área importante do projeto: documentação.

Também aproveito a oportunidade para divulgar um novo site (novo para mim!) de desafios, num estilo semelhante ao já tradicional PythonChallenge, o Rankk!

Geralmente os desenvolvedores de software livre fazem aquilo que eles gostam, ou seja, programar, escrever código. Alguns abençoados vão mais longe e escrevem os testes antes do código. Mas são poucos os que se preocupam realmente com documentação... (só para constar: eu não sou um deles...)

Isso praticamente não gera problemas quando o projeto é pequeno, afinal basta ler o código... mas na medida em que o projeto vai ficando maior, mais complexo, é que os primeiros sinais ficam evidentes.

Agora imagine o caso de um projeto cujo núcleo possui cerca de 240 mil linhas de código, segundo as métricas do Ohloh (a propósito, o que você está esperando para criar a sua conta lá e relacionar os seus projetos?). Isso desconsiderando o resto da pilha, composta pelo Zope, CMF e dezenas de aplicações adicionais que estão disponíveis para uso através do Collective...

Durante muito tempo o Plone foi criticado exatamente pela sua falta de documentação. Com o tempo, num esforço conjunto de diversos desenvolvedores, capitaneados pelo Alexander Limi, foi desenvolvido o Plone Help Center (PHC) para ser utilizado na resolução dessa questão.

O PHC entou em operação no final de 2004 e rapidamente se tornou um grande sucesso. A quantidade de documentação do Plone cresceu em um ritmo quase que exponencial, abrangendo diversos tipos de audiências, desde aqueles que apenas procuram saber o que significa algo, passando por informações de como usar e até mesmo tutoriais passo-a-passo e completos manuais de referência.

Porém, como tudo o que existe em excesso, a área de documentação começou a apresentar problemas. Os usuários começaram a reclamar da enorme quantidade de documentação que estava sendo gerada! Isso acabava atrapalhando na hora de decidir o que era preciso ler a respeito de determinado assunto.

No mês passado, pela primeira vez na história do Plone, tivemos um sprint focado na questão da documentação (e também e-commerce): DocComm. Ele ocorreu nas dependências do Google, em Montain View, na California. A repercussão foi ótima, muitos posts a respeito das atividades que estavam sendo realizadas, entre elas a revisão da documentação existente e a classificação dela, através da técnica de card sorting , onde uma parede inteira acabou sendo preenchida... :-D

Com o sucesso obtido no sprint, onde o próprio PHC também foi atualizado, hoje podemos dizer que o Plone tem uma área de documentação da qual possa se orgulhar! Poucos projetos estão nessa condição, mas vale a pena citar também o SQLAlchemy pela freqüência de atualização e clareza da sua documentação.

Bom, mudando um pouco de assunto, ninguém é de ferro e como eu disse durante algumas entrevistas depois da Arena de Programação, nada melhor do que alguns desafios para desestressar depois de um dia (ou uma noite, ou de vários dias...) de trabalho! A propósito, atualizando o recorde de uptime: 44 horas (das 11:00 de domingo até às 07:00 de terça-feira)... ;-)

Uma das coisas mais interessantes do Rankk, fora a lenga-lenga sobre o Egito, pirâmides e tal..., é que ele não se resume a desafios envolvendo apenas uma única linguagem, ou foca diretamente em programação, e ainda nesse sentido, ele se quer está diretamente ligado a computação! Ter uma base sólida em matemática e lógica é muito mais importantes neste caso.

Obviamente existem problemas específicos de programação, ou melhor, de computação. Prepare seu repertório, pois pelo caminho você vai encarar Javascript, PHP, Perl, Prolog, SQL, Java, Lisp, Brainfuck, Python, código morse e mais alguma coisa que eu ainda não consegui identificar... :-D

Apesar de tudo, é diversão na certa, eu aguarantcho! ;-)

Atualizações:

Leia mais...

quinta-feira, 28 de junho de 2007

Python, Bauru e a Fonte Dançante

Fonte Dançante do Parque IbirapueraEste é um (não tão breve) relato sobre os acontecimentos dos últimos dias, para espantar as traças que já estavam começando a tomar conta deste blog...:-P

A semana passada foi um correria do cão. Tudo começou com a definição das tarefas a serem implementadas para a Plone Solutions, nada muito complexo, apenas algumas melhorias em um produto chamado Dashboard, que pemite a seleção e a ordenação de quais portlets estarão disponíveis na sua página inicial, assim que o login em um Plone site é realizado.

Aliás, essa funcionalidade já foi incorporada no Plone 3.0, que deve ter o primeiro release candidate liberado em duas semanas, já que finalmente os problemas do five.lsm e a questão das tools X utilities foram resolvidas.

Quarta-feira pela manhã eu tive uma reunião com o pessoal da Recria, em Caxias do Sul, para definir alguns pontos que ficaram em aberto desde o lançamento do portal em 2004. Em seguida o almoço, um já tradicional prato italiano, na Pasta & Cia, no Shopping Prataviera, onde pude contar com a agradável presença de ex-colegas do curso de graduação na UCS. Logo mais à noite, tivemos a final da Copa Libertadores da América onde o Inter, digo, o Boca Juniors sagrou-se hexa-campeão, após uma ótima atuação em cima do Grêmio, em pleno Estádio Olímpico. Meu palpite de 3x0 só não foi concretizado pois o Palermo conseguiu a façanha de perder mais um pênalti na sua carreira... Provavelmente ele conste no Guinness Book como o jogador que mais errou pênalties na história! :-D

Chega quinta-feira e é hora de embarcar para São Paulo para participar da asssembléia de fundação da Associação Python Brasil. Por uma tremenda coincidência, acabei encontrado outro colega da UCS, o Samuel Fisch, que estava fazendo a viagem de volta à Angola, depois de passar duas semanas de férias no Brasil. Nosso vôo para Congonhas saiu com atraso de 20 minutos, mas passou tão rápido que nem tivemos tempo de botar todo o papo em dia. Ontem fiquei sabendo que a conexão dele para o Rio de Janeiro atrasou e ele acabou perdendo o vôo para Angola, tendo que retornar a Caxias e indo viajar novamente no domingo... :-(

Eu optei por viajar a São Paulo um dia antes justamente tentando evitar que qualquer atraso causado pelo sistema áereo brasileiro interferisse nas minhas atividades. A estratégia deu certo, mas ao invés de eu finalizar as tarefas da Plone Solutions eu acabei usando o tempo em outras atividades. Buscamos o Osvando Santana em Guarulhos e mais tarde fomos comer uma boa pizza paulistana (mas não melhor do que as Caxienses, claro!) junto com o Luciano Ramalho e mais alguns amigos.

Fiquei hospedado no apartamento do Érico Andrei, da Simples Consultoria, que me acolheu com uma grande hospitalidade. Ao invés de dormir (sleep is for the weak, no sleep for you!) acabei usando a noite para deixar tudo o que estava pendente da Plone Solutions concluído para o dia seguinte. Na verdade acabei usando a manhã também e quando finalmente pensei em dormir já era meio-dia de quinta-feira e o Érico me ligou avisando que estava indo me buscar...

Almoçamos e fomos direto para a sede do IPSO. Lá iniciamos os preparativos para a assembléia de logo mais. O pessoal já estava em um bom número quando nós paramos de falar a respeito dos episódios dos MythBusters e partimos para uma seção de piadas. Acho que acabei me empolgando um pouco nas melhores do Joãozinho, pois todo mundo parou para escutar... :-)

A assembléia de fundação da Associação Python Brasil (APyB) acabou transcorrendo tranqüilamente, com todos os artigos sendo cuidadosamente debatidos e analisados por todos os presentes, especialmente o Sérgio! O Jean Ferri foi o último a chegar, já que o seu vôo de Brasília teve um pequeno atraso de 7 horas...

O resultado das eleições pode ser consultado diretamente no site da APyB. O mesmo vale para o estatuto deliberado. Depois ainda saímos para um Happy Hour com a galera e visitamos alguns bares para conhecer os agitos da noite paulistana...

De volta ao apartamento do Érico, ainda fiquei um bom tempo no computador antes de ir tomar um banho e dormir às 02:45. Detalhe, como eu havia acordado às 08:00 de quarta-feira, acabei batendo meu recorde pessoal de uptime em 45 minutos. A nova marca a ser atingida agora é de 42h45m! ;-)

Sábado, 06:00 da madrugada e o Érico já foi acordando eu e o Marco André, que também estava hospedado lá. Partimos para buscar o Osvaldo e ir em direção a (mais de uma hora de estrada!) UNICSUL onde o Osvaldo apresentaria um palestra introdutória sobre Python e eu sobre Empreendedorismo. Aliás, o próprio Érico me avisou que um artigo do ComputerWorld sobre a X3ng havia sido publicado recentemente.

Após as palestras na UNICSUL (e de mais uma hora de viagem na estrada) estávamos novamente na sede da Simples Consultoria, onde estava sendo preparado um churrasco em comemoração aos quatro anos da empresa. Uma tarde inteira de conversa depois, acompanhamos o pessoal até o aeroporto de Congonhas e retornamos para o apartamento do Érico para um merecido descanso.

Havia planos para uma partida de golfe no domingo pela manhã, mas eu e o Érico acabamos dormindo quase até o meio-dia... Fui convidado então para conhecer o legítimo Bauru paulista. Antes ainda passamos um bom tempo na Livraria Cultura, uma loja colossal com 3 andares e milhares de itens a disposição do público. Pois bem, o tal Bauru realmente era saboroso, porém um tanto quanto nanico para os padrões gaúchos! A melhor parte é o recheio com os diversos tipos de queijos derretidos, mas a carne em micro-fatias bem que poderia ser substituída por aqueles (agora famosos) bifes que a comunidade saboreou no restaurante Tudo Pelo Social, em Porto Alegre, durante o FISL desse ano... :-)

No restante do domingo, fizemos um passeio de carro por alguns pontos turísticos e históricos da capital paulista. Eu acabei esquecendo a minha câmera digital no bolso da jaqueta, lá no apartamento e passei em branco sem registrar absolutamente nada! Felizmente ainda fizemos um pit-stop em casa para pegar agasalhos e então partimos em direção ao Monumento às Bandeiras, no Parque Ibirapuera, onde a prefeitura recentemente instalou uma fonte dançante em comemoração aos 450 anos da cidade.

Segunda-feira, hora de voltar para casa, mas desta vez por Guarulhos. Chegamos em cima do laço no aeroporto, o suficiente para encontrar um funcionário da companhia aérea equipado com um PDA e uma mini-impressora para emitir a minha passagem. Em seguida nada de pressa, apenas uma hora de espera na interminável fila de embarque. Duas barrinhas de cereal depois, eu pousei tranqüilamente em Caxias, com temperatura ambiente de 5°C! :-/

E assim, após voltar a Garibadi, teve-se início mais um ciclo semanal...

Leia mais...

quinta-feira, 24 de maio de 2007

Comandos mais usados e algumas dicas

Ok, eu admito... eu não resisto a um meme... :-D

Desta vez o assunto[1, 2, 3] é referente aos comandos mais executados na sua máquina...

Porém eu acabei sendo um pouco mais abrangente, falando de coisas que podem ser úteis no seu dia a dia.

Originalmente a idéia seria apenas postar o resultado desta seqüência de comandos (a contra-barra foi usada apenas para não quebrar o layout do blog, que tem uma largura fixa limitada):

history|awk '{print $2}'|awk 'BEGIN {FS="|"} {print $1}'|\
        sort|uniq -c|sort -rn|head -10

Eu até tenho uma simpatia muito grande pelo bash (apesar de querer muito aprender o zsh) e pelo demais comandos utilizados, mas tenho algum tipo de aversão ao awk (e, diga-se de passagem, não tem nada a ver com o Aho, o livro do dragão continua na minha relação dos favoritos). Desculpe-me, mas eu realmente não gosto dele. Deve ser alguma influência do Verde, mas eu prefiro o sed. É um direito meu... ;-)

Buenas, com o amado sed, o comando simplifica um pouco (isso se você, como eu, gosta de comer expressões regulares com farinha...):

history|sed -r 's/[ 0-9]+ ([^ |]+).*/\1/'|\
        sort|uniq -c|sort -rn|head -10

Explicando um pouco a regexp: ela ignora todos os espaços ou números seguido de um espaço, casa com uma seqüência de caracteres até encontrar o próximo espaço ou uma barra vertical (vulgo pipe), ignorando todo o resto.

Para eu não ser crucificado por aí, esta é uma versão pythônica da coisa:

from os.path import expanduser

history = open(expanduser('~/.bash_history'))
commands = [line.split()[0].split('|')[0] for line in history]
counter = {}
for command in commands:
    if command in counter:
        counter[command] += 1
    else:
        counter[command] = 1

topten = sorted(counter.items(), key=lambda x:x[1], reverse=True)
for command, total in topten[:10]:
    print total, command

Não usei nada de extraordinário para resolver o problema, apenas limpei os comandos que estavam armazenados no histórico e salvei numa lista. Depois criei um dicionário cuja chave era o comando e o valor era o número de vezes que o comando ocorreu. Em seguida, ordenei de forma reversa a lista de tuplas de itens do dicionário, considerando a segunda posição (o total de ocorrências) como chave de ordenação. Por fim, imprimi os comandos com os respectivos totais.

Certo, agora para acabar a enrolação aqui vai a minha relação atual:

1378 vi
 713 sudo
 372 ls
 327 svn
 267 cd
 214 python
 133 mv
  88 ssh
  68 rgrep
  64 less

Com base nela você fica sabendo qual o meu editor, paginador e linguagem de programação preferidos, que eu evito ficar logado como root, que eu uso um sistema de controle de versões, que eu acesso outras máquinas de forma segura, que eu procuro em arquivos de forma recursiva, além de verificar a listagem e mudar de diretório de vez em quando. A última coisa a ser dita é que o mv só faz parte da lista porque toda semana tem episódios novos das séries[1, 2] que eu acompanho (que por sinal acabaram juntas nessa semana...) e eu movo os arquivos para o pendrive para poder assistir no DVD player da sala, com som 5.1... ;-)

Para quem estranhou a quantidade de comandos armazenados no meu histórico, basta dizer que o meu ~/.bashrc está configurado para armazenar os 5000 últimos comandos, sem repetição seqüencial e sem salvar os que iniciam com um espaço em branco (útil para aqueles que não devem ficar armazenados):

export HISTCONTROL=ignoreboth
export HISTSIZE=5000

Por fim, ainda utilizo o seguinte ~/.inputrc, de forma a ignorar maiúsculas/minúsculas quando usar a tecla tab para completar nomes de arquivos/diretórios e também para poder digitar as primeiras letras de um comando e navegar apenas entre os usos anteriores deste comando em particular com as setas para cima/para baixo:

set completion-ignore-case On
"\e[B": history-search-forward
"\e[A": history-search-backward

Leia mais...

domingo, 6 de maio de 2007

Binary People

You are Binary.  You are not human and go to great lengths to prove it. You always know where you are and how you got there, but no one else does, ever.Seguindo a tendência que pudemos acompanhar nos últimos dias, onde o Érico, o Osvaldo e o Sidnei já postaram e aproveitando para dar uma força ainda maior a este meme, acabo de fazer o teste e, literalmente, deu binário... :-P

Esse era o motivo que faltava para eu encomendar a minha camiseta do ThinkGeek... :-D

O fato acabou trazendo algumas recordações... como quando aprendi a manipular estruturas de campos de bits em C e mais recentemente (ok, já fazem mais de dois anos...) quando tive que fazer algo semelhante em Python. Aliás, quando implementei isso em Python, acabei chutando um pouco o balde... foi meio overkill para o que eu estava precisando resolver, mas acabou se tornando uma solução genérica para converter números entre qualquer base numérica (com testes!), mesmo entre as bases que nem existem... ;-)

Obviamente, dois anos depois, eu posso dizer que faria aquela classe Number bem diferente, mas isso é assunto para outro post...

Leia mais...

quarta-feira, 2 de maio de 2007

Insanifying, Parte II

Terceiro e último dia da competição e do FISL. No dia anterior, os problemas exigiam que se conhecesse o mínimo da estrutura do projeto Debian. Quem não soubesse como fazer algo, poderia pedir ao Felipe ou ao Otávio e eles informariam. Poderia ainda pedir a qualquer um dos presentes no FISL ou mesmo a quem estivesse on-line. Porém, isso acabaria consumindo parte do tempo das equipes.

Eu uso o Debian nos meus servidores desde o lançamento do Potato 2.2r5 no início de 2002. Naquela época um dos meus hobbies era testar diferentes sistemas operacionais. No meu computador eu tinha cinco sistemas instalados ao mesmo tempo (Conectiva & Mandrake (agora Mandriva), NetBSD, OpenBSD, Windows e mais uma partição vazia para ficar testando outros...) quando resolvi instalar o Debian e, gradualmente, ir desinstalando os que estavam instalados... :-)

Com o lançamento do Ubuntu Warty Warthog em 2004, eu acabei deixando o Debian para ficar com o Ubuntu, que como todos devem saber, é baseada no próprio Debian. Pois bem, posso dizer que durante estes cinco anos fiquei bem familiarizado com o Debian/Ubuntu. Isso acabou ajudando a nossa equipe, pois praticamente todas as dúvidas do Guilherme e do Kalecser estavam na ponta da minha língua e acabei por me tornar uma espécie de líder para a equipe... :-)

Voltando ao terceiro dia. Novamente fizemos um círculo para receber as instruções. Dessa vez o desafio consistia em torno de um único problema, mais uma vez envolvendo o tema da fase anterior. O Debian é composto por mais de 18 mil pacotes, dos quais uma grande maioria possui suporte a internacionalização (i18n, para ser mais conciso).

A questão é que uma quantidade razoável das mensagens que precisam ser traduzidas se repetem, ou no mínimo são bastante semelhantes. Isso gera a necessidade da utilização de alguma ferramenta que implemente o conceito de Translation Memory, de forma a agilizar o processo de tradução, bem como manter a consistência quando forem utilizados termos semelhantes.

Só para dar um exemplo: o termo 'Save' está presente no menu de praticamente qualquer aplicativo gráfico. A idéia é que a tradução de todas as mensagens de todos os pacotes que utilizem esse termo fiquem iguais, no caso 'Salvar'. Isso evita a ocorrência de discrepâncias nas traduções, muito comuns em casos onde diferentes pessoas colaboram no processo de tradução. Também é importante que quando o termo for usado em outras mensagens (Save as/Save all/...) a tradução seja sugerida, agilizando o processo e reduzindo possíveis erros de consistência.

Nós recebemos um arquivo de 70MB, com uma amostra das traduções utilizadas por alguns pacotes, totalizando cerca de 300MB depois de descompactado. Cabe lembrar que essa amostra representa apenas um percentual do volume de mensagens presentes nos pacotes do Debian. Segundo o Felipe e o Otávio, atualmente nenhum dos softwares existentes (livres ou não) consegue carregar toda a base de traduções dos idiomas presentes no Debian:

>>> import re, urllib
>>> url = 'http://www.debian.org/international/l10n/po'
>>> page = urllib.urlopen(url).read()
>>> uls = re.findall('<ul>.*<ul>(.*)</ul>', page, re.DOTALL)[0]
>>> len(re.findall('<li>(.*)</li>', uls))
226

(Para os mais desavisados, o programinha acima acessa o site do Debian e salva uma cópia da página com a relação dos idiomas existentes, filtrando para ficar apenas com o segundo bloco de itens, já que o primeiro contém o menu de navegação e imprime o número de itens encontrados.)

Sim... existem 226 idiomas (ou variações de idiomas) no Debian! Impressionante!

A tarefa consistia em escrever uma especificação e realizar a implementação de um software para auxiliar no processo de tradução, permitindo que:

  • administradores possam adicionar novos pacotes no sistema;
  • tradutores possam efetuar as traduções fazendo uso do recurso de Memory Translation;
  • revisores possam acessar o sistema e sugerir alterações nas traduções já existentes.

A propósito, o nosso programa acabou sendo chamado de ATR, em função de ter que atender às necessidades das 3 classes: Administradores, Tradutores e Revisores... :-)

A primeira coisa que fizemos foi definir a estratégia. Mais uma vez sabíamos que não seria possível concluir totalmente a tarefa em tempo. Então decidimos que seria melhor fazer pelo menos um pouco de cada uma das coisas, ao invés de fazer uma das coisas bem-feita e ignorar as outras.

Precisaríamos de algo que fizesse a indexação de texto de forma rápida e sem consumir recursos demasiados do sistema. Depois de um rápido brainstorming, optamos pelo uso do Lucene, devido ao conjunto das suas características, que já contempla diferentes funções para a busca de texto. Também decidimos que a aplicação teria interface gráfica, ao invés de rodar em modo texto no console.

Como o Guilherme e o Kalecser tinham experiência na mesma linguagem de programação (Java), optamos pela seguinte divisão de tarefas:

Dorneles
especificação do sistema e desenvolvimento de qualquer coisa que levasse muito tempo em Java
Guilherme
parser dos arquivos de tradução e integração com o Lucene
Kalecser
implementação da interface gráfica

Mais uma vez o trabalho colaborativo seria fundamental. Continuamos usando o Google Docs para a especificação, mas iríamos precisar de um sistema de controle de versão para o código. Então instalei e configurei um servidor de Subversion na minha máquina. Aprendi que no mundo Java praticamente ninguém vive sem o Eclipse... e aprendi como instalar o plugin de Subversion nele também... :-)

Para termos uma noção de como era a interface gráfica do softwares já existentes, usamos o valioso serviço do Google Images. Com isso, o Kalecser e eu rascunhamos o que nós consideramos ser a melhor solução para o nosso programa.

Em seguida o Kalercer precisou extrair a relação dos idiomas disponíveis para popular um combo na tela e isso iria levar um certo tempinho em Java. Então ele pediu e eu escrevi rapidamente um programinha (4 linhas, se não me falha a memória) em Python e devolvi a saída no formato que ele havia solicitado.

Enquanto isso o Guilherme quebrava a cabeça para ver se o Java tinha algum recurso nativo para ser usado na manipulação de arquivos de catálogo de mensagens do gettext (PO e POT). Se não me engano, acabamos desenvolvendo um parser temporário e implementando nosso próprio algoritmo de busca de texto por similaridade.

Por fim, acabamos fazendo mais algumas pseudo-implementações de características que achávamos importante constar no sistema e nos preparamos para empacotar e documentar o que havíamos desenvolvido até então. O empacotamento acabou virando POG (esquecemos até a licença!), pois já tínhamos esgotado o tempo e não pudemos gerar um pacotinho Debian nos conformes... Nossa solução ficou longe do que constava na especificação, mas acredito que fizemos um bom trabalho durante o tempo determinado.

É claro que seria melhor se recebêssemos uma especificação já pronta e tivéssemos apenas que programar. O problema é que o pessoal do Debian ainda não tem uma solução para isso. Dessa forma, usaram a oportunidade de ter 12 cérebros a disposição para colher algumas idéias que poderão vir a se tornar a futura ferramenta.

Obviamente que tratava-se de um evento de programação, então entendo o fato de termos que ter programado algo para mostrar no final do dia. Caso os doze participantes tivessem trabalhado juntos, certamente o Debian teria se beneficiado mais, porém isso não seria possível nesse tipo de evento.

Encerramos a competição sem ter a menor idéia de como havia sido o nosso desempenho em comparação com as outras três equipes. Esse suspense durou mais algumas horas até o anúncio do resultado final. Mas isso é assunto para o próximo post, que só vai sair depois que o Felipe e o Otávio me enviarem o material que eles haviam prometido... ;-)

Leia mais...

quinta-feira, 19 de abril de 2007

Qualifying

É nessa hora que o bicho pega para valer! As regras dessa fase são as mesmas da já tradicional Maratona de Programação da ACM. Os competidores deveriam resolver a maior número de problemas, no menor tempo possível, cometendo o mínimo de erros.

Apenas 12 dos 29 participantes seriam classificados para a próxima etapa (lembrem-se, 11 desistiram antes mesmo de iniciar). A prova era composta por um conjunto de 6 problemas: 2 fáceis, 3 intermediários e 1 difícil. A cada problema resolvido corretamente, um balão com a cor do problema era preso ao monitor do competidor.

Alguns fatos merecem destaque. O problema A era muito fácil de ser resolvido, bastava ler doze números e imprimir a média, com arredondamento em duas casas e um caractere de fim de linha (que eu não vi que era preciso na primeira lida à jato no problema e me custou um submissão extra mais tarde...) mas o problema C era exatamente o mesmo do cara-e-coroa do warm up, com uma pequena alteração no nome das pessoas. Com isso eu consegui a façanha de ter o primeiro balão com ZERO minutos! Entretanto, acredito que isso acabou me desconcentrando e ao invés de eu partir para o próximo problema eu fiquei cuidando quanto tempo o pessoal iria levar para notar que o problema era o mesmo... :-)

Na seqüência eu parti para o A, mas deixei passar o maldito fim de linha, o que resultou em uma penalidade de dez minutos numa coisa boba. Com isso acabei caindo da primeira para a quinta posição em apenas oito minutos! :-/

O próximo escolhido foi o problema E, do jogo do bicho. Que raiva! Não posso nem lembrar! Cada linha de entrada tinha o valor da aposta, o número apostado e o número sorteado. Bastava imprimir quanto o apostador tinha ganho. Simples, muito simples. O mais demorado foi determinar a fórmula para ver se dois números pertenciam ao mesmo grupo de animais, pois tinha a pegadinha do zero fazer parte do mesmo grupo do 97-98-99 e não do 01-02-03.

Depois de queimar um pouco a mufa (e graças ao poderio do interpretador Python, que realmente me ajudou nessa hora), saiu a fórmula ótima: ((n+3) % 100)/4 ou ainda ((n-1) % 100)/4, se preferirem. As outras possibilidades de acerto foram resolvidas na base do módulo de 10, 100, 1000 e 10000, conforme o caso. Me permitam uma observação: alguns competidores resolveram o desafio acima não pela programação arte, mas sim pela programação de resultado, ou seja, adicionaram um if a mais para tratar o caso do zero e era isso, mesmo não sendo a melhor coisa a ser feita, já resolvia também. Alguns foram além, usando o método de programação ogro, muito perto do que hoje é conhecido como programação orientada a gambiarra! Onde, acreditem ou não, a solução consistia em 100 (sim, cem!) ifs, um para cada posição possível no jogo do bicho! :-D

Voltando ao meu caso, ajustadas as condições, salvo o programa, compilo, executo com a minha entrada de testes. Tudo funcionando localmente, envio e... incorrect output! Reviso todo o programa, verifico o balanceamento dos parênteses, adicionando alguns pares a mais só para garantir. Envio de novo. A resposta demora e começo a voltar minhas atenções para um novo problema.

O escolhido foi o D, que basicamente era um problema de análise das submissões de soluções para problemas de maratona (qualquer semelhança recursiva, à la GNU, não é mera coincidência!). A entrada era um inteiro com o número de submissões, seguida pela letra do problema, o tempo em questão e o resultado: correto ou incorreto. A saída deveria dizer quantos problemas foram resolvidos e o tempo total. O tempo dos problemas não resolvidos não conta e para cada erro em um problema resolvido, temos 20 minutos de penalidade.

Estou terminando a estrutura de dados do D quando chega a resposta do C. Mais um incorrect output... Largo o D de mão e dou mais uma revisada geral no código do problema C e lá se vão preciosos minutos. Cheguei a pensar que tinha enviado a última submissão sem salvar as últimas modificações. Envio ele mais uma vez e volto ao D. Estrutura do programa pronta, testo a leitura da entrada de dados. Por algum motivo escroto, não teve cristo de conseguir ler um char, um inteiro e uma string com o scanf, dava segmentation fault direto...

Saudades de Python! Saquei fora a leitura da string e substitui por um tosco gets. Agora sim, mesmo com warning do compilador, leitura dos dados com sucesso. A lógica para gerar o resultado final também não tinha nada de mais, bastava ir somando 20 quando o resultado era incorreto ou o tempo informado caso era correto, além de marcar quais problemas tinham sido respondidos. Depois era só imprimir o total de problemas corretos e a soma do tempo deles. Enviei e passou de primeira...

Olho no relógio e levo um susto, já haviam passados 2h18m! Maldito segfault e mais maldito ainda daquele problema C. Dou uma levantada, para esticar as canelas, olho para os lados e vejo pelo menos oito pessoas já com três problemas, algumas delas com quatro e outras já com cinco! A Arena havia se transformado num verdadeiro arco-íris, era balão colorido por todos os lados! Olho mais um pouco ao redor e nada de comida e muito menos de bebida. O restante da jornada se desenhava como algo trágico... :-)

Mais uma vez eu volto ao problema C. Dessa vez lendo linha a linha a descrição do problema e adicionando todos os casos limites na minha entrada de testes. Algo me chamou a atenção. O exemplo de entrada tinha um valor acima do valor máximo permitido. Mando uma clarificação (que nada mais é do que um pedido de esclarecimento feito pelo BOCA, onde a resposta fica disponível a todos os participantes). Vem a resposta, mas ela não gera a necessidade de alterar o meu código.

Troco algumas linhas e lugar, o nome das variáveis e uma e outra coisa, na esperança de eu ter encontrado algum bug no compilador ou qualquer outra coisa externa ao problema. O código resolve com exatidão todos os casos limites que eu havia especificado. Envio o problema novamente e volto minha atenção para o B. Escolhi ele pois estava na cara que o problema classificado como difícil era o E, com três páginas de especificação. Além disso, no placar daquele momento nenhum dos competidores que já haviam resolvido cinco problemas tinha feito o tal do problema E. Eu obviamente não seria o primeiro... ;-)

Começei a procurar nos meus problemas impressos algo que manipulasse strings. Achei alguns e lembrei dos famigerados strcmp e strcopy. Também encontrei exemplos de definição e uso de struts. Olho para o interpretador Python que ainda estava aberto e começo a agradecer ao Guido pelo simples fato de existir um operador de slice e de que listas e dicionários fazem parte da biblioteca padrão... :-)

Chega a resposta do C e... adivinhem? Não passou mais uma vez. O pior é que eu tinha certeza que nada poderia estar errado, afinal todos os casos limites passavam nos meus testes. Olho para a classificação e vejo que não era apenas eu quem estava com problemas naquele problema. Decidi largar de mão de vez e me dedicar ao B, afinal eu precisava de uma quarta questão resolvida, pois naquele momento eu já estava com a última ou a penúltima vaga entre as 12 disponíveis e muito possivelmente mais alguns competidores resolveriam quatro problemas.

Eis que então o fantasma do segfault voltou a me assolar... Eu lembro que na época que eu programava em C/C++ diariamente eu conseguia identificar a causa desses erros apenas passando o olho no código. Infelizmente, eu não iria readquirir esse dom durante as 5 horas de competição naquele dia... Gastei o resto do meu tempo tentando resolver isso, mas sem sucesso e já estava me conformando em ficar de fora do segundo e terceiro dias da Arena. Isso porque eu estava na posição limite de classificação e o placar congela na meia hora final. Dessa forma, apenas o próprio competidor sabe se ele acertou ou não as submissões feitas naquele período, o que acaba tornando a competição mais emocionante.

Resolvi dar mais uma arejada no cérebro e discutir com outros competidores, que estavam na mesma situação que eu, sobre o problema C. Foi quando surgiu a hipótese de ter algo a ver com a questão da precisão no valor da aposta e/ou no resultado. Eu inicialmente tinha descartado isso, afinal a aposta teria apenas duas casas decimais e o multiplicador, em caso de acerto, era sempre inteiro. Porém, contrariando o meu raciocínio, bastou mudar a variável de float para double e fazer os respectivos ajustes na leitura e escrita que o diacho do problema passou. Isso eu fiquei sabendo mais tarde, pois eram os dez minutos finais de competição e nesse período nem o próprio competidor é informado sobre o resultado da sua submissão, o que torna tudo absurdamente mais emocionante ainda! Aliás, cinco competidores tiveram o problema C resolvido nos minutos finais, depois da discussão coletiva sobre o possível problema de precisão.

Cinco horas de competição haviam passado. A organização fez um pequeno suspense, mas logo divulgou o resultado. Chegava a vez do anúncio da classificação final do qualifying. Eu tive a nítida impressão de ter gasto mais tempo brigando com a linguagem do que resolvendo os problemas propostos, mas consegui terminar essa fase em uma digna nona posição. Isso após quase ficar de fora dos doze classificados, salvo em cima da hora pelo ingrato problema C... :-)

Posteriormente também foram divulgados os arquivos de entrada/saída usados pela organização na avaliação dos problemas.

Leia mais...

quarta-feira, 18 de abril de 2007

Warm up

Finalmente chegou a hora do aquecimento. Cada participante foi convidado a sortear um número, que representaria o seu identificador no sistema. Após isso, o competidor era encaminhado a um computador e informado dos dados de login provisório e como proceder para alterar sua senha.

Em seguida a organização explicou todas as regras e como usar o sistema controle da Arena, o BOCA. Dois problemas (cujos PDFs serão enviados assim que os organizadores lerem isso...) foram disponibilizados e os participantes foram incentivados a testar todas as opções existentes, desde a submissão de respostas, acompanhamento do placar, até a solicitação de clarificação das questões.

Antes de confirmar a minha inscrição, algo me fez pensar se eu realmente gostaria de participar. O problema era que a minha linguagem preferida não estava na relação das que poderiam ser usadas para resolver os problemas. Isso me deixou preocupado, afinal eu teria que escolher entre C/C++ (que eu havia tocado pela última vez em 2000, nas competições da maratona da ACM), Pascal (que eu havia usado apenas durante as primeiras cadeiras da faculdade, em 1997/1998) e Java (que eu conheci em 1999 numa cadeira eletiva, mas odiei desde o primeiro dia que tive contato). Acabei sendo forçado a usar C/C++ mesmo, já que depois de Python é a linguagem que eu mais tive contato, mesmo fazendo anos que eu não desenvolvia nada com elas...

Pensando nisso, no dia anterior ao início do FISL eu saí para procurar uma gráfica expressa. Encontrei uma milagrosamente aberta às 21:00 ao lado do Rua da Praia Shopping. Isso claro, depois de caminhar uns 2km do hotel onde eu estava hospedado. Lá eu conheci o Marcos Backes, com o qual fiquei conversando a respeito de Lost, informática, empreendedorismo e mais uma porção de coisas, enquanto o material era processado. No total, foi impresso cerca de 50 problemas que eu resolvi na minha época de maratonista da ACM, para pelo menos ter uma base de como proceder. Foi o que me salvou, uma vez que a referência da linguagem não estava instalada nos computadores e eu não vi nenhum livro dando sopa no local. Optei por usar a IDE Anjuta, já que o meu .vimrc turbinado não pode ser usado...

Durante a manhã do primeiro dia tivemos o V Encontro da Comunidade Python/Zope/Plone, então já cheguei atrasado na Arena. Para piorar a situação, levei mais de uma hora para me reeducar e familiarizar com o processo de edição/compilação/depuração/execução dos programas em C. Para resolver o primeiro problema (um banal cara-e-coroa onde na primeira linha tínhamos um inteiro N e na linha seguinte N resultados, que poderiam ser 0, representando cara ou 1, para coroa e bastava imprimir o número de caras e de coroas) foram, desde o início do warm up, exatos 72 minutos... :-(

Confesso que nem cheguei a ler o segundo problema, pois o tempo já estava se esgotando e eu queria testar outras coisas ainda. Cheguei a pensar em deixar o desafio de lado e curtir o FISL, mas eu não iria desistir depois de ter começado...

Depois do warm up, uma pequena pausa para o almoço (um taco-burger, na correria!). Encontrei ainda o Heitor Strogulski, um mestre da minha época de graduação na UCS, que foi fundamental para o surgimento da minha empresa. Porém, naquele momento, ele aproveitou para tirar um sarro a respeito da minha performance bizonha durante o aquecimento... :-D

Atualização: atendendo a pedidos, adicionado link para o meu .vimrc.

Leia mais...

O processo de inscrição

Ao contrário do que muita gente pensa, a inscrição para poder participar da Arena não foi uma tarefa muito complicada. Curiosidade e um senso investigativo apurado já seriam suficientes para garantir uma vaga, como de fato foi. Das 40 vagas inicialmente alocadas, todas foram preenchidas (confira a ordem de inscrição dos participantes), mas apenas 29 inscritos se apresentaram na Arena no primeiro dia, o que me leva a crer que muitos (ok, talvez não muitos... mas pelo menos alguns...) dos 11 que conseguiram resolver o desafio da inscrição e se ausentaram, não eram programadores.

Voltando ao processo em si: no dia 31/03 a organização do FISL divulgou no endereço da Arena que as inscrições estavam abertas. Nenhuma outra informação foi divulgada até o dia 04/04, quando a primeira dica foi revelada. A partir de então, uma nova dica foi adicionada diariamente e chegamos em 11/04 com o seguinte conjunto:

  • 2007-04-04: Dica 1: "O processo de inscrição começa aqui..."
  • 2007-04-05: Dica 2: "Existe um código embutido nesta página HTML..."
  • 2007-04-06: Dica 3: "As salas do fisl importam..."
  • 2007-04-07: Dica 4: "O CMS usado no site do fisl importa..."
  • 2007-04-08: Dica 5: "Se você já sabe o que faz o código embutido e porque as salas do fisl importam então você já sabe o caminho..."
  • 2007-04-09: Dica 6: "A inicial do nome von Neumann é a letra "V"..."
  • 2007-04-10: Dica 7: "A URL desta página importa ..."
  • 2007-04-11: Dica fisl8.0: "As informações finais (último passo) para você conseguir fazer a inscrição estão em Português."

A primeira dica já dizia algo óbvio para quem participou de desafios semelhantes, como o fantástico Python Challenge: algo oculto na página daria uma pista da próxima coisa a ser feita.

A segunda dica confirmou a primeira: no fonte HTML da página haviam dois trechos codificados, no primeiro um código JavaScript e logo abaixo as cinco dicas iniciais. Ambos os trechos estavam cifrados com o famigerado ROT13 e três das cinco dicas ainda não haviam sido liberadas. O próprio trecho JavaScript era uma implementação do algoritmo ROT13 cifrado em ROT13. Isso já havia sido mencionado anteriormente pelo Hélio Castro. Durante o evento, a organização confirmou que as dicas haviam sido deixadas propositalmente no código HTML. O fato é que desde o dia 04/04 as cinco primeiras dicas já seriam conhecidas por quem decodificasse o fonte em ROT13, mas isso não resolvia o mistério.

A terceira dica foi fundamental para decifrar a charada. O fato das "salas importarem" e que logo abaixo tínhamos um link para a página com o nome dos homenageados das salas era muito suspeito. No referido link havia mais uma dica escondida no fonte HTML, antecedendo o nome das salas:

the names! THE NAMES! What are important in them?
Did you clicked on the url up above?
Get the important words and their first letters.
And hack the url, baby. Hack. 

Era uma dica direta: bastava clicar na URL acima (que remetia para a grade de programação, com as salas em uma determinada ordem) e para o nome de cada sala, na ordem apresentada, pegar a primeira letra, ou seja: bbtcdcvhh. Além disso, seria preciso hackear a URL do site (confirmado pela quarta dica). Era uma pista para juntar o fato de que o ROT13 havia sido mencionado com o fato de termos algo onde aplicá-lo. A quinta dica confirmou isso. Dessa forma, obtemos: oogpqpiuu e acessando http://fisl.softwarelivre.org/8.0/www/?q=pt-BR/oogpqpiuu é exibido as instruções para efetivar a inscrição.

Neste ponto aconteceu algo interessante: a grande maioria dos que tentaram resolver a charada estavam usando a letra N para a sala de John von Neumann, o que faz um grande sentido, afinal em português costumamos ignorar as preposições "da/de/dos" quando usamos as iniciais de nomes próprios. Porém, quem tivesse prestado atenção na grade de programação saberia que a organização deu o nome de "von Neumann" para a sala. Assim, a letra correta passa a ser o V. Isso foi enfatizado mais tarde pela sexta dica, que não estava inicialmente prevista, mas foi necessária em função do grande número de pessoas que estavam acessando a URL com o N no lugar do V, segundo a organização.

Outra dúvida recorrente foi: em qual URL deveria ser tentado o acesso? Afinal, as URLs do site e da grade de programação eram diferentes e havia ainda a possibilidade de que existissem outras URLs. A sétima dica veio para acabar com esse dilema, afirmando que a URL do site era a importante.

Uma observação importante a respeito da quarta dica, que era ambígua: ela falava sobre o Drupal, o CMS do site. Mas afinal, o que a respeito do CMS? Num primeiro momento ficou parecendo que se tratava da URL do site, onde deveria ser aplicado as iniciais com os nomes das salas. Porém, durante o período de julgamento das soluções para os problemas do segundo e terceiro dias, enquanto os finalistas aguardavam numa sala, um dos competidores comentou que o Drupal armazena internamente todos os conteúdos de forma sequencial e que ele havia baixado todos os items do site com um script, mas em função da grande quantidade de conteúdo, após uma rápida conferida, ele não havia encontrado nada de interessante. Então, enquanto eu estava escrevendo esse relato, fiz o seguinte script Python:

from urllib import urlopen
url = 'http://fisl.softwarelivre.org/8.0/www/?q=node/%s'
for n in xrange(1000):
    if 'Parab' in urlopen(url % n).read():
        print n

Surpreendentemente, entre as primeiras 1000 páginas do site, a única que possui a string 'Parab' (de 'Parabéns', que é o título da página com as instruções de inscrição) é a de número 192, então quem acessasse http://fisl.softwarelivre.org/8.0/www/?q=node/192 teria encontrado a URL para se inscrever. De qualquer forma, o mistério envolvia mesmo a questão de pegar as iniciais de cada sala e aplicar o ROT13, afinal mesmo que alguém tivesse entrado naquela página por acaso, ainda seria necessário informar ao menos 5 passos para chegar até aquele ponto.

Leia mais...