Stencil Shadows

November 22, 2007 by César Blum Silveira

Estou divulgando aqui uma pequena aplicação que desenvolvi como trabalho final da disciplina de Processamento Gráfico que estou cursando neste semestre. A aplicação demonstra o uso de stencil shadows [1], com o acréscimo da renderização de sombras sobrepostas.

O código, escrito em Python, está disponível sob a licença LGPL versão 2.1.

O download da aplicação pode ser feito aqui.

A exposição da fé

July 29, 2007 by César Blum Silveira

Comecei a ler um livro chamado Contra as Heresias, escrito por Ireneu de Lião. Ireneu, que foi bispo de Lião no final do século II, foi discíuplo de Policarpo de Esmirna, que foi discípulo de João, apóstolo do nosso Senhor. Esta sua obra, tida como uma das maiores obras da literatura cristã de todos os tempos, expõe toda a doutrina dos gnósticos da época e apresenta a refutação de tais doutrinas com base na razão e nas Escrituras. No entanto, também apresenta lindos discursos sobre a verdadeira fé cristã, sua doutrina e sua tradição.

É justamente um desses discursos que quero reproduzir aqui. Esta é uma obra de grande valor, e com certeza não existiriam tantas infelizes divisões na Igreja de hoje se todos os ministros da Palavra a lessem, dada a grande quantidade de esclarecimentos contida nela.

Segue o texto que desejo reproduzir. É a seção 10,3 do livro I (Contra as Heresias é, na verdade, uma compilação de cinco livros escritos por Ireneu):

A exposição [das Escrituras] feita com sabedoria maior ou menor, não quer dizer que se muda a doutrina ou que se pense noutro Deus além daquele que é o Criador, Autor e Nutrício deste universo, como se ele não bastasse, ou noutro Cristo, ou noutro Filho único. Trata-se simplesmente: de indicar a maneira com que cada um procura explicar a doutrina contida nas parábolas, mostrando a sua concordância com a doutrina da verdade e de expor a maneira com que se realizou o desígnio salvífico de Deus; de mostrar que Deus usou de longanimidade, quer diante da apostasia dos anjos, quer diante da desobediência dos homens; de dar a conhecer por que o mesmo e único Deus fez algumas coisas temporais e outras eternas, por que fez os seres celestes e terrestres. A razão pela qual, sendo invisível, se manifestou aos profetas, não de uma só forma, mas de diversas; de indicar por que fez várias Alianças com a humanidade e as características de cada uma; “por que Deus incluiu todos na incredulidade para ter misericórdia de todos” [Romanos 11:32]; trata-se de publicar numa ação de graças que o Verbo de Deus se fez homem e sofreu e anunciar que a vinda do Filho de Deus se deu nos últimos tempos e não no início; de mostrar o que está nas Escrituras a respeito do fim e das realidades futuras e de não calar que Deus fez das “nações que não tinha esperança, co-herdeiras, concorporais e co-participantes dos santos” [Efésios 3:6]; de proclamar que “esta carne mortal se revestirá de imortalidade e esta carne corruptível, de incorruptibilidade” [1 Coríntios 15:54]; de proclamar como “este que não era povo se tornou povo, e a que não era amada se tornou amada” [Oséias 2:23; Romanos 9:25]; e como “os filhos da que era estéril se tornaram mais numerosos que os da casada” [Isaías 54:1; Gálatas 4:27]. É em casos como estes e semelhantes que o Apóstolo exclama: “Ó abismo da riqueza, da sabedoria e da ciência de Deus! Como são imperscrutáveis seus juízos e impenetráveis os seus caminhos!” [Romanos 11:33].

(Referências bíblicas acrescentadas segundo a indicação das notas de rodapé do livro.)

Quão geek és tu?

July 26, 2007 by César Blum Silveira

Ao contrário do que muitos acham, eu nem sou tanto assim:

49% GeekMingle2Free Online Dating

Já é o segundo teste que eu faço que atesta tal fato.

Achei o teste bem tri, ao contrário de alguns outros que existem por aí.

Em português mesmo

July 16, 2007 by César Blum Silveira

Esqueçam o último post (que eu já deletei). Vou blogar em português mesmo.

Essa semana devo voltar a blogar.

Piada nerd

April 20, 2007 by César Blum Silveira

Como se baixa a Internet?

$ wget *

:P

Mais de mês

March 12, 2007 by César Blum Silveira

Pois é, 1 mês e 2 dias de blog :-)

Problemas com teclado ABNT2 no Ubuntu Edgy

March 5, 2007 by César Blum Silveira

Ontem, depois de uma tentativa frustrada de instalar e configurar o Gentoo aqui em casa, voltei a instalar o Ubuntu.

Depois de uma instalação a partir do CD do Ubuntu Dapper, logo atualizei-o para o Edgy. No entanto, diferente de outras vezes que eu havia atualizado, dessa vez o meu teclado parou de funcionar corretamente. Mesmo após um dpkg-reconfigure xserver-xorg, a tecla correspondente à ‘/’, o Caps Lock, e as combinações Ctrl+Alt+F* de dentro do X para ir para o console não funcionavam. Depois de muito fuçar a nada resolver, decidi tentar mudar o xorg.conf na mão. No fim das contas, foi bem fácil resolver o problema. Basta configurar o teclado como está escrito a seguir:

Section "InputDevice"
       Identifier      "Generic Keyboard"
       Driver          "kbd"
       Option          "CoreKeyboard"
       Option          "XkbRules"      "xorg"
       Option          "XkbModel"      "abnt2"
       Option          "XkbLayout"     "br"
       Option          "XkbVariant"    "abnt2"
EndSection

Decidi postar aqui pra caso alguém mais tenha o mesmo problema e não goste (como eu) de fazer gambiarras com xmodmap.

Listas de opções interativas em bash

February 24, 2007 by César Blum Silveira

Durante o feriado do carnaval, decidi brincar um pouco mais com o bash. Desta vez, descobri como detectar se as teclas direcionais do teclado foram pressionadas pelo usuário, o que, combinado às técnicas apresentadas no meu post anterior, me permitiu desenvolver um script que apresenta um menu com diversas opções sobre as quais o usuário pode navegar.

Seqüências de escape são “o ouro”, como dizem! Elas permitem realizar uma série de coisinhas legais, como mudar a posição do cursor (o clássico gotoxy) ou limpar a linha atual do terminal. Para quem não sabe, uma seqüência de escape é uma série de caracteres normalmente iniciada após pressionar a tecla ESC que permite que uma máquina ou aplicação execute um comando [1]. No escopo deste post, estamos falando das seqüências de escape ANSI X3.64 [2], usadas pela maioria dos terminais presentes nas distribuições Linux.

Para fazer um pequeno teste, experimente o seguinte: abra um terminal e pressione ENTER algumas vezes. Agora, digite o seguinte:

echo -e "\\e[2;1H\e[2Khello, world"

O cursor moveu-se para o início da segunda linha do terminal, e foi impressa a mensagem "hello, world". Explicando o comando:

echo - comando para imprimir mensagens no terminal. A opção -e permite que sejam usadas seqüências de escape.

\e[2;1H - esta sequencia de escape (\e representa o ESC) move o cursor para a primeira linha da segunda coluna.

\e[2K - seqüência de escape que limpa a linha atual.

hello, world - a mensagem a ser impressa

As seqüências de escape também permitem alterar a cor da fonte de do fundo do terminal. O comando abaixo, por exemplo, imprime a mensagem "hello, world" com fundo azul e letra branca:

echo -e "\\e[44;37mhello, world"

Além de brincar com as seqüências de escape, para escrever o script abaixo tive que descobrir como ler as tecla direcionais. Para isso, basta executar o comando read e pressionar alguma das teclas e ver o que é impresso. No caso da tecla direcional para cima, por exemplo, podemos ver que a string ^[[A é impressa no terminal. Seguindo esta dica, aprendi que, na verdade, ^[ também é o mesmo que a tecla ESC. Portanto, se quisermos "imprimir" uma tecla direcional para cima, podemos executar o comando

echo -e '\\e[A'

Não há muita utilidade em "imprimir" uma tecla direcional (normalmente é impresso um retangulo), mas é possível usar o comando acima para armazenar o valor da tecla em uma variável, para posteriores comparações:

UP_KEY=$(echo -n -e '\\e[A')

Abaixo está o script sobre o qual eu falei. Vale ressaltar que os echo's usam a opção -n para evitar que seja emitido um caractere de nova linha, o que o comando echo faz por padrão. As técnicas do post anterior foram utilizadas por apenas um motivo: o comando read é usado sem a opção -n. Fiz isso porque as teclas direcionais emitem 3 caracteres por vez, enquanto caracteres normais emitem apenas 1. Portanto, o comando read -n1 não funcionaria para detectar teclas direcionais, porém read -n3 obrigaria o usuário a teclar caso eu quisesse detectar outras teclas. Não é o caso deste script, mas pode ser que alguém queira permitir esse tipo de interação. Se a preocupação for apenas ler teclas direcionais, é possível usar o comando stty apenas com a opção -echo (para que não sejam impressas coisas estranhas na tela quanto o usuário tenta navegar além das opções apresentadas) e o comando read pode ser usado com a opção -n3.

Use as teclas direcionais para cima e para baixo para navegar entre as opções. Use a tecla direcional para a direita para escolher uma opção (apenas "Quit" faz alguma coisa neste script). Meu próximo passo será tentar descobrir como ler a barra de espaço e/ou a tecla ENTER (é preciso descobrir como determinar se uma dessas teclas foi pressionadas ou se nada foi pressionado).

Finalmente, eis o script:

#!/bin/bash

# armazena os valores das setas direcionais
UP_KEY=$(echo -n -e '\\e[A')
DOWN_KEY=$(echo -n -e '\\e[B')
RIGHT_KEY=$(echo -n -e '\\e[C')

# configurações do menu
OPTION=( "Option 1" "Option 2" "Option 3" "Quit" )
NUM_OPTIONS=${#OPTION[*]}
CURRENT=0

# vai para o início da linha atual. como não há uma seqüência de escape única
# para isso, o cursor é movido para o início da linha anterior e a seguir
# para o início da linha seguinte, retornando à linha atual
function startline () {
    echo -n -e "\\e[1F"
    echo -n -e "\\e[1E"
}

# limpa a linha atual
function clearline () {
    echo -n -e "\\e[2K"
    startline
}

# imprime uma opção do menu. se o segunto argumento for um valor verdadeiro
# (1, por exemplo), a opção é impressa como selecionada
function print_option () {
    if [ $2 ]; then
        echo -n -e "\\e[7m"
    fi

    clearline

    echo -n -e ${OPTION[$1]}
    echo -n -e "\\e[0m"
}

# move a seleção para cima. a sequencia de escape \\e[1F move o cursor para
# o início da linha anterior
function move_up () {
    if [ $CURRENT -gt 0 ]; then
        print_option $CURRENT
        CURRENT=$((CURRENT - 1))
        echo -n -e "\\e[1F"
        print_option $CURRENT 1
    fi
}

# move a seleção para baixo. a sequencia de escape \\e[1E move o cursor para
# o início da linha seguinte
function move_down () {
    if [ $CURRENT -lt $((NUM_OPTIONS-1)) ]; then
        print_option $CURRENT
        CURRENT=$((CURRENT + 1))
        echo -n -e "\\e[1E"
        print_option $CURRENT 1
    fi
}

# detecta se uma tecla foi pressionada
function keypressed () {
    read KEY
    [ $KEY ]
}

# armazena as configurações de linha do terminal
STTY_SETTINGS=$(stty -g)

# imprime as opções do menu
for i in $(seq 0 $((${#OPTION[*]}-1))); do
    echo ${OPTION[i]}
done

# vai para a primeira opção e a imprime como selecionada
echo -n -e "\\e[${NUM_OPTIONS}F"
print_option $CURRENT 1

# altera as configurações de linha do terminal
stty -icanon min 0 time 0 -echo

# loop do menu
while [ 1 ]; do
    if keypressed; then
        if [ $KEY = $UP_KEY ]; then
            move_up
        elif [ $KEY = $DOWN_KEY ]; then
            move_down
        elif [ $KEY = $RIGHT_KEY ]; then
            if [ $CURRENT = 3 ]; then
                break
            fi
        fi
    fi
done

# restaura a cor padrão do terminal
echo -e '\\e[0m'

# restaura as configurações de linha do terminal
stty $STTY_SETTINGS

Referências:

[1] http://en.wikipedia.org/wiki/Escape_sequence
[2] http://www.dicas-l.com.br/artigos/linux-modotexto/coluna11.html

Keypressed e Readkey em Bash

February 11, 2007 by César Blum Silveira

Quem já programou em Pascal provavelmente já usou a dupla de funções keypressed/readkey. A função keypressed serve para detectar se alguma tecla foi pressionada durante a execução do programa. Já a função readkey é usada para descobrir qual tecla foi pressionada.

Esse recurso poderia ser útil no Bash em algumas situações. No Bash, temos o comando read, que lê uma entrada do usuário. Apesar de ser possível utilizar o comando da seguinte maneira,

$ read -n1 KEY

para que o comando retorne assim que o usuário pressionar um tecla, não é possível fazer com que o comando aguarde pela entrada apenas por um período de tempo.

No entanto, é possível alterar as configurações do terminal para alcançarmos este objetivo. O comando stty serve para alterar as configurações de linha do terminal. Assim, podemos utilizá-lo da seguinte maneira para fazer com que o comando read não espere indefinidamente pela entrada do usuário:

stty -icanon min 0 time 0

Ou ainda:

stty -icanon min 0 time 0 -echo

caso não queiramos que a entrada digitada seja também impressa no terminal.

A opção -icanon permite que alguns parâmetros sejam configurados. Dois destes parâmetros são min e time. min determina qual deve ser o tamanho mínimo da entrada. Assim, configurando essa opção como 0, é possível fazer com que nenhum caractere seja lido da entrada. A opção time determina o timeout da leitura em décimos de segundo. Com o valor 0, este tempo será o mínimo possível.

Para ilustrar o uso desses comandos, escrevi o shell script abaixo. Vale ressaltar que a lógicado script é um pouco diferente daquela normalmente utilizada em Pascal. Em Pascal, chama-se keypressed, e, caso a função retorne true, chama-se readkey para descobrir qual tecla foi pressionada. No script abaixo, a ordem é contrária: chama-se readkey, e então keypressed. Se o usuário pressionou alguma tecla quando readkey foi chamada, keypressed retornará 1 (true). A tecla digitada fica armazenada na variável $KEY.

#!/bin/bash

# salva as configurações atuais do terminal
STTY=$(stty -g)

stty -icanon min 0 time 0 -echo

while [ 1 ] ; do
    read -n1 key

    if [ $key ]; then
        echo "Pressed $key."

        if [[ $key = "q" ]]; then
            break
        fi
    fi
done

# restaura as configurações do terminal
stty $STTY

É possível definir funções semelhantes aquelas que encontramos no Pascal:

#!/bin/bash

function readkey() {
    read -n1 KEY
}

function keypressed() {
    [ $KEY ]
}

# salva as configurações atuais do terminal
STTY=$(stty -g)

stty -icanon min 0 time 0 -echo

while [ 1 ]; do
    readkey

    if keypressed; then
        echo "Pressed $KEY."

        if [[ $KEY = "q" ]]; then
            break
        fi
    fi
done

# restaura as configurações do terminal
stty $STTY

Apesar de a lógica ser um pouco diferente, creio que isso não é um problema para a implementação em Bash das mesmas coisas que poderiam ser feitas em Pascal.

Edit: a mesma lógica utilizada em Pascal pode ser implementada em Bash como no script abaixo:

#!/bin/bash

function keypressed() {
    read -n1 KEY
    [ $KEY ]
}

# salva as configurações atuais do terminal
STTY=$(stty -g)

stty -icanon min 0 time 0 -echo

while [ 1 ]; do
    if keypressed; then
        echo "Pressed $KEY."

        if [[ $KEY = "q" ]]; then
            break
        fi
    fi
done

# restaura as configurações do terminal
stty $STTY

Closures

February 11, 2007 by César Blum Silveira

Pois é, meu último post foi sobre alguns desapontamentos com o Common Lisp, mas agora vou escrever sobre uma coisa que achei legal nele. Vai entender…

Uma coisa interessante de se fazer em Common Lisp são os chamados closures (em português acho que seria “fechamento”). Um closure se trata de um encapsulamento de uma variável léxica (em outra linguagens conhecidas como variáveis locais), tornando a sua referência acessível fora do escopo em que foi declarada. Para ilustrar, é melhor mostrar logo algum código.

Primeiro, um pouco de Common Lisp. Assim como em C declaramos variáveis locais, também é possível fazê-lo em CL, da seguinte maneira:

(defun func (arg1 arg2)
  (let ((a 0))
    ...

O Common Lisp também permite a declaração de funções anônimas (lambda). A expressão

(lambda (x) (+ x 1))

declara uma função que recebe um número e retorna o mesmo número somado a 1. Esse tipo de coisa é usado, por exemplo, em mapeamentos de listas, como no exemplo a seguir:

(map #'(lambda (x) (+ x 1)) '(1 2 3))

Esta expressão retorna a lista (2 3 4). Note que a facilidade oferecida pelo operador lambda é o fato de não ser necessário declarar uma nova função (quero dizer, com defun) para ser usada apenas naquele momento.

Agora, sabemos que, em C, algo parecido com isso

void *foo() {
    int a;
    return &a;
}

não funciona, pois a variável é perdida quando a pilha volta ao seu estado anterior. Porém, em Common Lisp, é perfeitamente legal fazer o seguinte:

(defun make-closure ()
  (let ((i 0))
    #'(lambda () (incf i))))

A princípio, pode parecer errado, pois estamos retornando uma função (o operador #’ faz com que seja retornado o objeto que representa a função, evitando que a expressão lambda seja avaliada) que incrementa uma variável local. No entanto, basta testarmos em algum ambiente Common Lisp para vermos que isso de fato funciona:

[1]> (defun make-closure () (let ((i 0)) #'(lambda () (incf i))))
MAKE-CLOSURE
[2]> (defparameter foo (make-closure))
FOO
[3]> (funcall foo)
1
[4]> (funcall foo)
2
[5]> (funcall foo)
3

Note que se chamarmos make-closure outra vez, receberemos um novo closure:

[6]> (defparameter bar (make-closure))
BAR
[7]> (funcall bar)
1
[8]> (funcall bar)
2
[9]> (funcall foo)
4

Uma idéia que tive para o uso de closures é justamente usá-los para definir contadores globais, sem a necessidade de declarar variáveis globais, aumentando o potencial de perda do controle das coisas.

(defun make-closure ()
  (let ((i 0))
    #'(lambda () (incf i))))

(defmacro defcounter (name)
  (let ((counter (make-closure)))
    `(defun ,name () (funcall ,counter))))

Note que defcounter cria ainda mais um closure! Testando:

[3]> (defcounter counter1)
COUNTER1
[4]> (counter1)
1
[5]> (counter1)
2
[6]> (counter1)
3
[7]> (counter1)
4
[8]> (defcounter counter2)
COUNTER2
[9]> (counter2)
1
[10]> (counter2)
2

Funciona :-)