Firefox 3.5 webdev notes

30/6/2009 | Tags:, , , , , , | Escrito por: Dirceu Pauka Jr.

A nova versão do Firefox chega em um momento agitado na indústria dos navegadores. Para não fazer feio perto da forte concorrência a versão 3.5 é mais rápida na renderização e na execução de JavaScript.

Além disso a versão 3.5 trás ao Firefox suporte a novos padrões da W3C e isso é bem interessante uma vez que entre os “navegadores que prestam” o Firefox é o mais utilizado.

Novas funcionalidades para a tag canvas estão disponiveis.

Um novo modelo de se trabalhar com XMLHttpRequest foi desenvolvido e agora a função permite “Cross-site HTTP requests”.

Como sempre algumas novas funções foram implementadas ao JavaScript. Porém, são funções que deverão ser aproveitadas de melhor forma dentro de frameworks. Dessa forma é possivel utilizar melhor a capacidade do navegador sem “quebrar” a compatibilidade em navegadores que não suportam as novas funções.

Na parte do HTML 5 (draft) foi adicionado suporte a áudio e vídeo, cache de infomações (offline resources), uma API para uso do sqlite3, Workers, Geo location e o novo padrão de seletor (que suporta CSS3 nativo).

Na parte de CSS3 o Firefox implementa animações de forma parecida com o WebKit. Veja -moz-transform e -moz-transform-origin.

Se você ainda não baixou a versão 3.5 do Firefox baixe logo e saia por ai caçando exemplos que usem o potencial do canvas, animações de css3.

Ah!

Se você gerencia algum plugin de Firefox já deveria ter deixado uma versão pronta pro dia de hoje. De qualquer forma, a Mozilla explica o que deve ser feito para manter a compatibilidade dos plugins.

E

Finalmente um porn mode foi adicionado.



Widget do Submarino com YQL

4/6/2009 | Tags:, , , , , , | Escrito por: Dirceu Pauka Jr.

Meu último post foi uma tentativa de explicar o funcionamento da Yahoo Query Language. No final falei da possibilidade de se fazer um Widget do Submarino com a YQL e agora volto para implementar o prometido.

YQL

Como eu disse existe um post explicando a YQL, porém aqui vai uma explicação rápida:

A YQL pode ser usada para buscar dados nas APIs do Yahoo (Flickr, Delicious, Placemaker, Maps, …), nas APIs do DataTables (Twitter, Amazon, GeoLocation, …) ou em qualquer outro documento da web (página HTML).

Para mostrar como a busca em um documento qualquer da web é feita, escrevi o seguinte código:

Para testar use o console da YQL ou veja teste dessa busca. O YQL vai retornar o conteúdo pedido em XML ou JSON.

JSONP

“JSON with Padding” é uma técnica que permite o carregamento assíncrono de informações de um domínio externo.

Toda biblioteca de JavaScript que se preze possui um método para esse procedimento.
jQuery: $.getJSON(url, function(data) { // callback });
MooTools: Request.JSON([options]);

A implementação desse tipo de requisição é bem simples.

Sabemos que o retorno de um arquivo chamado pela tag script é imediatamente executado pelo interpretador JavaScript.

Também sabemos que um objeto em JS pode ser representado por {} e pode conter pares de chave/valor. Ex: var Objeto = { chave: ‘valor’ };

Assim sendo, o que precisamos agora é que o conteúdo de um arquivo que vai ser requisitado utilizando a tag script seja uma chamada a nossa função previamente declarada.

Atente que ao contrario do xhttprequest o elemento HTML script não possui limitações quanto ao domínio que a requisição pode ser feita. Porém, para que a técnica funcione é necessário que o servidor requisitado retorne (em texto puro) uma chamada para nossa função.

Requisição:
http://pomoti.com/arquivo.php?callback=recebe_json
PHP simples para retorno:
echo $_GET['callback'] . ‘( {chave: “valor”} )’;
Retorno:
recebe_json( {chave: ‘valor’} );

Todos webservices que queiram trabalhar com JSON devem, então, aceitar um parâmetro para envio de callback.

Widget do Submarino

Fundamentadas as técnicas necessárias para a implementação vamos ao código.

// monta a requisição REST
var url = ‘http://query.yahooapis.com/v1/public/yql?q=’+
encodeURIComponent(query)+
‘&format=json’+
‘&callback=Submarino.recebe’;

// se tag head não existir, cria uma para evitar problemas
if (!document.getElementsByTagName(’head’)[0]) {
} else {
document.getElementsByTagName(’body’)[0].appendChild( document.createElement(’head’) );
}

// adiciona o elemento

Lembra? Isso é JavaScript, não Java. O código acima é tudo que você precisa para criar um plugin. Dentro da função, $this é a referencia ao objeto jQuery de onde o plugin foi chamado.

No exemplo, $this é um objeto com os elementos

e você pode fazer de tudo com eles. Como o plugin retorna $this, você pode continuar executando metodos do jQuery usando “Method Chaining”.

De volta a minha última questão. O que você possivelmente vai ganhar criando um plugin?

Alto nivel de reusabilidade
Muitos pedaços de JavaScript são geralmente reaproveitáveis, mas criando um plugin você passa ele para outro nível.

Configuração
Isso é ligado ao ponto anterior. O cenário sem plugin é ter um pedaço de código que você copia e cola modificando para seu proposito. Isso pode ficar muito mais fácil com plugins. Você pode escrever o seu para, por exemplo, aceitar algumas opções. Veja como fica agora:

Elegância
O código acima parece melhor que um script inteiro, não parece?

Agora é a hora de mostrar um exemplo real. Vamos fazer um script para tornar clicável cada linha da tabela.

Sempre que eu queria fazer as linhas clicáveis eu copiava esse código e mudava a URL ou o nome do parâmetro.

Com o plugin fica assim:

settings = $.extend(defaults, settings); // escreve em cima das opções default com as opções enviadas
$this = $(this);

$(”tr”, $this).click(function() {
location.href = settings.href + ‘?’ + settings.paramName + ‘=’ + $(”td:first”, $(this)).html();
});

return $this;
}

E então:

Ou quando eu quiser outra configuração:

Para saber mais sobre o desenvolvimento de plugins para jQuery, leia o guia oficial de desenvolvimento ou esse excelente artigo de Mike Alsup.
Espero ter inspirado você.



Greasemonkey com jQuery

7/4/2009 | Tags:, , , | Escrito por: Dirceu Pauka Jr.

Greasemonkey é um add-on para o Firefox que permite a instalação de scripts para modificar o funcionamento de páginas da web.

Semana passada eu escrevi um script de Greasemonkey para modificar as páginas da Wikipedia em uma tentativa de acelerar a leitura dos textos. O resultado visual é esse:
Klassic Wikipedia

É interessante para quem pretende fazer scripts de Greasemonkey utilizar a biblioteca jQuery para agilizar o desenvolvimento. Para isso o código comentado a seguir vai ajudar:

// Verifica se o jQuery pode ser usado
function GM_wait() {
if(typeof unsafeWindow.jQuery == ‘undefined’) { window.setTimeout(GM_wait,100); }
else { $ = unsafeWindow.jQuery; letsJQuery(); }
}
GM_wait();

function letsJQuery() {
// pode usar o $ aqui ;D
}

Obs: se você utiliza outro navegador existem outras opções para executar “user scripts”. Uma delas é o GreaseKit para WebKit (Safari).



ORC e Redes Neurais em JavaScript

7/4/2009 | Tags:, , , , , , | Escrito por: Dirceu Pauka Jr.

Esse texto é uma tradução do “OCR and Neural Nets in JavaScript” escrito por John Resig.


Um belo pedaço de JavaScript foi criado ontem. É um script para GreaseMonkey escrito por ‘Shaun Friedle‘ que resolve automaticamente o captcha do Megaupload. Existe uma demonstração online caso você queira dar uma olhada.

Atualmente os captchas usados no Megaupload não são muito “difíceis” de resolver (de fato eles são muito ruins – exemplos abaixo).

captchacaptchacaptcha

Existem porém pontos interessantes aqui:

  • A API getImageData do HTML 5 é usada para pegar informações sobre os pixels da imagem. No HTML 5 é permitido adicionar uma imagem no elemento canvas (de onde então pose-se extrair informações sobre cada pixel usando JavaScript).
  • O script implementa uma rede neural, escrita em puro JavaScript.
  • As informações do pixel, extraídas da imagem usando canvas, são jogadas dentro da rede neural em uma tentativa de adivinhar o caractere usado – algo parecido com Optical Character Recognition (OCR).

Se abrirmos o código fonte podemos perceber que o funcionamento recai em como o captcha é implementado. Como mencionado anteriormente esse não é um captcha muito bom. Ele tem 3 letras, cada uma em uma cor diferente, usando uma possibilidade de 26 caracteres e eles são todos do mesmo tipo gráfico.

O primeiro passo é fácil de entender: O captcha é copiado dentro do canvas e então convertido para escala de cinza.

image_data.data[i] = luma;
image_data.data[i+1] = luma;
image_data.data[i+2] = luma;
image_data.data[i+3] = 255;
}
}
}

O canvas é então quebrado em três matrizes de pixels - cada uma contendo um caractere (isso é bem fácil de fazer - uma vez que cada caractere é de uma cor diferente, eles são separados pela diferença de cores usadas).

// Muda todos pixels de tal cor para a cor branca
if (image_data.data[i] == colour) {
image_data.data[i] = 255;
image_data.data[i+1] = 255;
image_data.data[i+2] = 255;
} else { // Todo o resto vira preto
image_data.data[i] = 0;
image_data.data[i+1] = 0;
image_data.data[i+2] = 0;
}
}
}
}

Finalmente qualquer pixel solto é removido da imagem (retornando um caractere limpo). Isso é feito procurando por pixels brancos (que eram da cor da letra) que são cercados de preto (que não bateram com nenhuma cor de letra). Se esse for o caso o pixel é simplesmente removido.

if (image_data.data[i] == 255 &&
image_data.data[above] == 0 &&
image_data.data[below] == 0) {
image_data.data[i] = 0;
image_data.data[i+1] = 0;
image_data.data[i+2] = 0;
}

Estamos bem próximos de ter uma forma que pode alimentar uma rede neural, mas não estamos lá ainda. O script agora vai fazer uma forma bem crua de detecção de borda na forma, procurando pelos pixels que cercam o caractere e então o transformando em um retângulo. Nesse trecho a matriz também é reduzida para 20 por 25 pixels.

image_data[i] = cropped_canvas.getContext("2d").getImageData(0, 0,
cropped_canvas.width, cropped_canvas.height);

Então, após todo esse trabalho, o que nós temos? Uma matriz de 20 por 25 pixels contendo um único retângulo preenchido com preto e branco. Terrivelmente excitante.

Agora alguns pontos estratégicos são extraído da matriz para serem usado como "receptores" (eles que alimentarão a rede neural). Como exemplo, o receptor deve olhar para o pixel da posição 9x6 e verificar se ele está "ligado" ou não. Somente 64 estados (muito menos do que a matriz de 20 por 25 inteira) são então jogados para dentro da rede neural.

A questão que você deve estar se perguntando agora é: Por que não fazer somente uma simples comparação de pixels? Por que "isso de" redes neurais? Bom, o problema é que com toda essa redução da informação um monte de ambiguidade existe. Se você rodar a demonstração do script vai perceber que a comparação simples de pixels vai falhar mais que a nossa rede.

A próxima etapa é tentar adivinhar a letra. A rede é então alimentada com 64 valores boleanos (coletados das letras) juntamente com uma serie de valores pre-computados. Um dos conceitos por trás do funcionamento de redes neurais é que você reutiliza valores de execuções anteriores. É como se o autor do script rodasse ele várias vezes e coletasse uma serie de resultados para conseguir um valor ótimo. O resultado em si não tem nenhuma funcionalidade por si só mas ele ajuda a derivar o valor final.

A rede neural utiliza os 64 valores extraídos dos caracteres do captcha para comparar com valores pré-computados de cada letra do alfabeto. O resultado retornado dessas comparações é parecido com ‘98% de chances para A’, ‘36% de chances para B’, etc..

Repetindo com todas letras do captcha o objetivo é atingido. Ele não é 100% perfeito (imagino que resultados melhores seriam alcançados se a letra não fosse transformada em um simples retângulo antes da execução do algoritmo) mas é bom pelo que é – e impressionante considerando que tudo acontece 100% no navegador usando padrões emergentes.

Como nota – o que acontece aqui é bem especifico para esse captcha. Essa técnica deve funcionar em mais alguns captchas mal implementados, mas além disso a complexidade da maioria dos captchas é muito avançada (principalmente para qualquer analise no lado do cliente).

Eu estou esperando trabalhos interessantes derivados desse projeto – isso carrega bastante potencial.