Sábado, Setembro 04, 2010

História para Inspirar

Pelos idos de 1998, eu e minha irmã assistíamos durante a tarde um bloco especial na programação do Cartoon Network, com alguns anime e outros programas bem interessantes.

Uma tarde, nós vimos uns teasers fantásticos sobre uma garota mágica e umas cartas. Os teasers eram, eles mesmos, muito bem produzidos, e a aura de mistério nos convenceu a agendar a estréia.

Nós assistimos a estréia e ficamos impressionados. CardCaptor Sakura era obviamente um desenho para público infantil mas alguma coisa na personagem principal, e na introdução da história, fez com que agendássemos o horário todos os dias.

E, realmente, todos os dias nós assistimos ao programa. E com o passar do tempo, a natureza da pesonagem principal e dos desafios que aumentavam progressivamente, e a trama que se revelava, nos prendeu ao programa.

Agora, ao contrário de maluquices como Lost, CardCaptor Sakura prometia convenvergência a um desafio final que realmente nos impressionava por dentro, seja pelo modo como a história era contada, seja pelo fato de que os excelentes estúdios da animação japonesa não são de enrolar. E alguma naquelas personagens inspirava você, as emoções simples representadas nas crianças, o otimismo marcante da própria Sakura.

Aconteceu que CardCaptor Sakura nos empolgava, a história que estavamos ouvindo era energizante; em parte por influencia nossa, praticamente todo o nosso grupo de amigos começou a assistir e eu percebi a mesma energia neles. Nós adorávamos acompanhar as aventuras da Sakura e o seu jeito de ser nos contagiava.

Sakura se tornou um modelo de comportamento, talvez. Nós sabemos que um programa para crianças é simplificado, mas exatamente por isso ele se torna um pouco... arquetípico.

Estou contanto essa história porque uma nova história alcançou o lugar ao lado de CardCaptor Sakura nas minhas lembranças.

Eu recomendo fortemente a todos vocês procurar Avatar: The Last Airbender e assistir às três temporadas.

Quarta-feira, Agosto 11, 2010

A Infinita Sabedoria do Entretenimento

O Danilo Gentili está indignado com a decisão do TSE entendendo que sátira política provoca desigualdade entre candidatos em uma eleição.

Eu acho impressionante que ele tenha escrito isso de forma tão clara logo no seu primeiro parágrafo e tenha ignorado por completo o foco da questão em sua longa reclamação.

Danilo, não interessa se o humor é saudável ou se Aristófanes fazia o que queria; por acaso você discorda do fato de que, em um período eleitoral, se nós satirizamos um candidato o outro candidato se beneficia?

Vou assumir que você, apesar de tudo, concorda que satirizar uma pessoa diminua a sua imagem e que, durante um processo eleitoral, este fato é relevante.

Então, Danilo, preciso perguntar a você se por acaso você acredita que sua condição de humorista lhe empresta uma sabedoria sobrenatural para injetar na rede de forças e poderes da sociedade a medida justa de sátira entre todos os candidatos.

Preciso saber se você e seus colegas humoristas são sábios o suficiente para satirizar apenas e tão somente o necessário de modo a evitar o efeito colateral que é a ridicularização de um candidato que está competindo com outros.

Será que você é iluminado o suficiente para não ter preferências durante uma eleição? Satirizar com mais intensidade candidatos em quem não pretende votar?

Entenda, Danilo, que eu acho muita graça na sátira política.

Mas eu não acho graça nenhuma nessa atitude de superioridade misteriosa de que se revestem pessoas cuja missão é entreter em matéria do governo da sociedade.

O TSE tem uma responsabilidade em um país cujo processo eleitoral está longe de funcionar razoavelmente -- sendo que apenas este ano estamos vendo vigorar uma lei tal qual a Lei da Ficha Limpa.

Faça-nos o favor de exercer a sua influência de forma madura no debate sobre o que é ou não é favorável à democracia durante esses poucos meses.

O macete é chamar de censura; daí você tem sempre razao.

Segunda-feira, Maio 24, 2010

Tumulto de casamento

O tumulto está quase no fim!

Fizemos neste fim de semana uma festa para a família e deu tudo certo, com um buffet de crepes e bastante cerveja.

Em Junho faremos a festa para os amigos, poderemos fechar a lista de presentes de casamento e preencher a sala com coisas que não sejam caixas de papelão.

Segunda-feira, Maio 10, 2010

o fim do software ... neste blog

A partir de hoje, escreverei artigos sobre software em outro blog. Este aqui voltará então à sua programação normal de pensamentos filosóficos esporádicos e comentários idiotas sobre o dia a dia.

Web Services infinitamente fáceis com JAX-WS

Isso provavelmente é notícia antiga para os praticantes do J2EE, mas hoje eu aprendi a notação mais básica do JAX-WS e estou impressionado com o esquema em geral.

Eu experimentei um pouco com o esquema do Apache Axis e, apesar de fácil, me fez um pouco perdido por não dominar ainda o macete dos arquivos de configuração e dos artefatos gerados.

Fora isso, eu não vi, no tanto que estudei, o meio de trocar argumentos de um tipo não primitivo com o Axis, o que me deixou um pouco ressabiado -- ou é difícil, ou é impossível.

Agora, com o Metro no GlassFish?

@WebService
public class Echo {
    public String echo (String value) { return value; }
}

Está pronto o EchoService.

Empacotando este negócio em um "Dynamic Web Project" e implantando no GlassFish, o Metro descobre sozinho a existência da classe Echo e configura automaticamente um EchoService muito razoável.

Eu achei, originalmente, que era preciso instalar a ferramenta Apache CXF na incubadora do projeto Eclipse Web Tools mas é desnecessário.

Aparentemente, a engenharia da norma JAX-WS foi muito boa, e existe também uma JAX-B que especifica a tradução de "java" para "xsd" de um modo que o seguinte também funciona como esperado:

public class Bar {
    public String data;
    Bar (String data) { this.data = data; }
}

@WebService
public class Echo {
    public Bar echo (String value) { return new Bar(value); }
}

É tudo o que eu preciso pra passar de fase.

Sábado, Abril 24, 2010

GlassFish em servidor Fedora 11

Consegui, afinal, configurar um servidor Fedora 11 com o GlassFish instalado.

Estou usando o seguinte script em /etc/init.d para gerenciar o serviço no sistema.

#!/bin/sh
#
# glassfish Sun GlassFish v3
#
# chkconfig:   - 99 1
# description: Sun's modern J2EE implementation based on OSGi

### BEGIN INIT INFO
# Provides: glassfish
# Required-Start: $network
# Required-Stop: $network
# Short-Description: J2EE implementation
# Description: Sun's modern J2EE implementation based on OSGi    
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions

exec="/opt/glassfishv3/glassfish/bin/asadmin"
prog="glassfish"
config="/opt/glassfishv3/glassfish/domains/domain1/config/domain.xml"

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

lockfile=/var/lock/subsys/$prog

start() {
    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    echo -n $"Starting $prog: "
    ${exec} start-domain domain1 >/dev/null 2>&1
    retval=$?
    [ $retval -eq 0 ] && success $"$prog startup" || failure $"$prog startup"
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    ${exec} stop-domain >/dev/null 2>&1
    retval=$?
    [ $retval -eq 0 ] && success $"$prog shutdown" || failure $"$prog shutdown"
    echo
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    start
}

reload() {
    restart
}

force_reload() {
    restart
}

rh_status() {
    ${exec} uptime
    uptime_retval=$?
    if [ $uptime_retval -eq 0 ]; then
        return 0
    fi
    if [ -z $lockfile ]; then
        return 2
    fi
    return 3
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}


case "$1" in
    start)
        rh_status_q && exit 0
        $1
        ;;
    stop)
        rh_status_q || exit 0
        $1
        ;;
    restart)
        $1
        ;;
    reload)
        rh_status_q || exit 7
        $1
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?

Quarta-feira, Abril 07, 2010

Algoritmos da Amazon

"As someone who has purchased or rated books by Erich Gamma, you might like to know that How You Could Be A Better Friend is now available."

(...)

Amazon, Erich Gamma é autor de um livro sobre engenharia de software. Que porra é essa?

Quarta-feira, Março 31, 2010

O estilo funcional em C++

Estava de mau humor e resolvi ironizar a vida estudando numa aula de Java o artigo "Why Functional Programming Matters", que eu copiei do site do Haskell.

Acabei finalmente entendendo (eu acho!) as primeiras implicações importantes de lazy evaluation. O exemplo mais simples dessas implicações no artigo, na minha opinião, está no programa que computa aproximações da raiz quadrada pelo método de Newton-Raphson.

Esse método é basicamente uma expressão matemática que começa com um resultado anterior e usa esse resultado para computar um próximo, garantindo que o próximo é melhor que o anterior.

Seja N o número cuja raiz quadrada você deseja aproximar, e uma aproximação anterior x. O procedimento começa chutando x, por exemplo 1. O método afirma que o próximo x deve ser ( x + ( N / x ) / 2 .

O artigo descreve um programa para resolver o método. O programa segue abaixo; para entendê-lo completamente, estude o artigo.


repeat f a = cons a ( repeat f ( f a ) )

within e ( cons a ( cons b rest ) ) =
  = b , if abs(a - b) <= eps
  = within e ( cons b rest), otherwise

next N x = ( x + N / x ) / 2

sqrt a0 e N = within e ( repeat ( next N ) a0 )

O espírito geral do programa é assim:

repeat é uma função que gera uma lista contendo um elemento inicial seguido do resultado da função f com argumento elemento-anterior. Observe que repeat gera uma lista infinita, assumindo que f está definida para todo a.

within é uma função que percorre uma lista procurando um par de elementos cuja diferença seja menor que um epsilon.

A notação de parâmetros em within faz o que eu chamo de "desempacotar a lista". O segundo argumento é uma lista; a definição de within desempacota os dois primeiros, chamando-os de a e b.

next computa a próxima aproximação da raiz quadrada de N com aproximação anterior x segundo o método de Newton-Raphson.

sqrt computa a raiz quadrada de um número conforme uma tolerância e e um chute inicial a0; sua definição aplica within a repeat, e repeat a next.

sqrt basicamente avalia within à lista gerada por repeat , e repeat gera a lista de resultados de next.

Este programa, segundo a intuição de um programador acostumado a linguagens imperativas, nunca termina, porque repeat nunca termina de gerar a lista infinita.

Porém, lazy evaluation garante que esse programa termina -- garante que repeat será avaliado apenas o número de vezes necessária para que within se satisfaça. Eu entendo que o segredo disso está no momento em que o interpretador avalia o "desempacotamento" de uma lista, porque este é o momento em que o processamento exige a geração de mais um elemento.

Isso é mesmo sensacional. Como seriam esses pequenos componentes em C++0x?

Vamos começar brincando com uma versão muito eficiente de abs, o que não tem nada a ver com o problema em questão.

template
auto abs (Number x) -> typename std::enable_if< std::is_signed::value, Number>::type
{
  return x < 0 ? -x : x ;
}

template
auto abs (Number x) -> typename std::enable_if< ! std::is_signed::value, Number>::type
{
  return x;
}

A notação acima é a nova notação para funções em C++0x, onde a especificação do retorno fica depois da lista de argumentos.

A definição de abs faz uso de SFINAE para sobrecarregar dois templates, de outro modo indistinguíveis, usando std::enable_if.

Assim, abs pode se reduzir a nada quando nem mesmo faz sentido que o número possua um sinal.

Em seguida, vamos chamar as listas de Range e declarar a forma geral de uma função unpack.

template
auto unpack (Range& r) -> Value;

template
auto unpack (Sequence& s) -> decltype(s.front())
{
  typename Sequence::value_type v = s.front();
  s.pop_front();
  return v;
}

Definimos o significado de unpack providenciando uma sobrecarga, exclusiva para Containers da STL, que faz o que deve fazer. Em português, unpack resulta o elemento à esquerda e modifica a lista para conter o resto.

Assim, definimos within:

namespace detail
{

  template
  auto within (Number eps, Number a, Number b, Range rest) -> Number
  {
    if (abs(a - b) <= eps) return b;
    else {
      const Number c = unpack(rest);
      return within(eps, b, c, rest);
    }
  }

}

template
// requires(ValueType(Range) == Number)
auto within (Number eps, Range list) -> Number
{
  const Number a = unpack(list);
  const Number b = unpack(list);
  return detail::within(eps, a, b, list);
}

within desempacota a e b e delega para uma subrotina; a subrotina faz o que se espera. Observe que a lista a processar é um desses tais Ranges.

O componente equivalente a repeat deve gerar esse Range.

namespace detail
{
  template
  struct repeat_range
  {
    Function f;
    Value x;

    auto operator() () -> decltype(f(x))
    {
      return x = f(x);
    }
  };

  template
  auto unpack (repeat_range& r) -> decltype(r())
  {
    return r();
  }
}

template
// requires(UnaryFunction(Function) && Domain(Function) == Value)
auto repeat (Function f, Value a) -> detail::repeat_range
{
  return detail::repeat_range { f, a };
}

Um Range é um objeto especial, que representa a lista; definimos um repeat_range que continuamente aplica uma função, e definimos unpack para este Range. (Observe como repeat_range usa o último valor gerado na geração do próximo.)
A função repeat é utilitária e constrói o Range com os argumentos certos.

A notação de construção usada na definição de repeat também é nova, e generaliza a inicialização entre structs C e objetos C++.

Por último, implementamos a função importante para a aplicação, sqrt. Escolhi ocultar o equivalente a next porque a mim não interessa muito.

namespace detail
{
  template
  auto sqrt (Number N, Number x) -> Number
  {
    return (x + (N / x)) / 2;
  }
}

template
auto sqrt (Number N, Number x, Number eps) -> Number
{
  return
    within(eps,
      repeat(
        [=] (Number x) { return detail::sqrt(N, x); },
        x
      )
    );
}

Agora, isso é punk. A função no detail computa a próxima aproximação é trivial. O driver principal, por outro lado, é complexo.

Em primeiro lugar, aquela notação esquisita ali é uma expressão lambda. Para todos os efeitos, a avaliação desta expressão produz uma função, que vira argumento para repeat.

repeat, portanto, aplicará uma função lambda -- que por sua vez computa a próxima aproximação da raiz de N com chute x -- ao valor inicial x. O símbolo [=] significa que os nomes dentro do lambda se tornam cópias por valor dos objetos de mesmo nome no escopo maior.

repeat, como vimos antes, produz um Range, sobre o qual within opera. E within procura um par de valores neste Range -- aplicando unpack quando necessário -- em busca de um par cuja diferença seja menor que eps.

Assim, nesmo programa C++, simulamos com significativo esforço a lazy evaluation funcional, para computar a raiz quadrada. Usando __attribute__((const)) esse programa deve otimizar até o Nirvana, mas eu não verifiquei.

O programa esparramado no texto acima funciona de verdade com o GCC 4.5 e provavelmente funciona também com o ICC 11.1.