tag:blogger.com,1999:blog-10531175349820928582024-02-20T12:05:36.077-08:00A Developer DiaryWilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-1053117534982092858.post-9423440017137575422010-03-05T04:13:00.000-08:002010-03-05T04:17:26.111-08:00wilker-dev migrando para o PosterousOlá galera, gostaria de dizer que esse blog está migrando para o Posterous, não haverão novos aqui, e os posts antigos já foram migrados, para continuar acompanhando o site continue em <a href="http://wilker-dev.posterous.com">http://wilker-dev.posterous.com</a>Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com0tag:blogger.com,1999:blog-1053117534982092858.post-38845716932515929512009-11-05T18:44:00.000-08:002009-11-05T18:47:08.902-08:00Template para RailsBom, como eu comecei a desenvolver mais com rails ultimamente eu decidi criar um template de inicialização para minhas apps.<br /><br />Os templates do Rails podem fazer para você várias configurações iniciais para sua aplicação (configurar gems, iniciar repositório git...).<br /><br />Abaixo segue o template que eu criei:<br /><br /><script src="http://gist.github.com/227656.js"></script><br /><br />Para quem quizer utilizar para testar basta executar o seguinte comando:<br /><br /><code>rails NOME_APP -m http://gist.github.com/raw/227656/f64ca46032c6e83f92000c9c33ce078b65beafdd/rails_template.rb</code>Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com0tag:blogger.com,1999:blog-1053117534982092858.post-41015443961603664352009-11-03T06:47:00.000-08:002009-11-05T06:22:51.731-08:00Rails no Ubuntu 9.10 (usando o mysql do xampp)Bom, estive tendo alguns problemas para instalar as coisas aqui no Ubuntu, mas consegui resolver, segue o passo a passo de comandos para ter tudo instalado e pegando:<br /><br />1. Instalar o XAMPP e o XAMPP development package (instrucoes no site do <a href="http://www.apachefriends.org/en/xampp-linux.html">xampp</a>)<br />2. Instalar o Ruby com Development Package:<br /><code>sudo apt-get install ruby1.8 ruby1.8-dev rubygems1.8 irb rake libopenssl-ruby1.8<br /></code><br />3. instalar o rails<br /><code>sudo gem install rails<br /></code><br />4. rodar o xampp<br /><code>sudo /opt/lampp/lampp start<br /></code><br />5. instalar o mysql<br /><code>sudo gem install mysql -- --with-mysql-dir=/opt/lampp/ --with-mysql-lib=/opt/lampp/lib/mysql --with-mysql-include=/opt/lampp/include/mysql<br /></code><br />6. configurar link para socket<br /><code>sudo mkdir /var/run/mysqld<br />sudo ln -s /opt/lampp/var/mysql/mysql.sock /var/run/mysqld/mysqld.sock<br /></code><br /><br />É isso, com isso rolo tudo certo aqui :)<br /><br /><span class="Apple-style-span" style="color:#FF0000;">UPDATE:</span><br /><br />Eu percebi que o link do mysqlsock é perdido sempre que o sistema é reiniciado.<br />Então eu criei um script para iniciar o xampp e criar o link automaticamente na inicialização:<br /><br />crie o arquivo abaixo:<br /><br /><span style="font-style:italic;">/usr/bin/lamppstart</span><br /><code>#! /bin/bash<br /><br />/opt/lampp/lampp start<br />mkdir /var/run/mysqld<br />ln -s /opt/lampp/var/mysql/mysql.sock /var/run/mysqld/mysqld.sock</code><br /><br />após criar o script é nescessário incluí-lo na inicialização do sistema, para isso adicione a linha para executa-lo dentro do arquivo /etc/rc.local, o meu arquivo ficou assim:<br /><br /><span style="font-style:italic;">/etc/rc.local</span><br /><code>#!/bin/sh -e<br />#<br /># rc.local<br />#<br /># This script is executed at the end of each multiuser runlevel.<br /># Make sure that the script will "exit 0" on success or any other<br /># value on error.<br />#<br /># In order to enable or disable this script just change the execution<br /># bits.<br />#<br /># By default this script does nothing.<br /><br />/usr/bin/lamppstart<br /><br />exit 0</code>Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com5tag:blogger.com,1999:blog-1053117534982092858.post-66876513065169065072009-10-22T18:57:00.000-07:002009-10-22T19:25:19.469-07:00Como ter um host privado de Git gratuitamenteHoje vim aqui pra contar meio que um "truque" para repositórios online privados grátis com Git.<br /><br />Pra quem não conhece, o Git é um DVCS (Distributed Version Control System), está fora do escopo desse post falar muito sobre ele, mas pra quem não conhece é uma ótima pedida ;)<br /><br />Pra quem já conhece o git, é bem provavel que também conheça o github, que é uma rede social de código para git, se faz muito útil para projetos open-source, e você pode pagar por planos para ter repositórios privados. Mas também é fato que com o tempo você vai querer repositórios privados para alguns projetos (fazendo freelas por exemplo), e você não tem verba para arcar com os custos do repositório privado.<br /><br />Bom, hoje eu venho apresentar uma solução meio gambiarral, mas que tem funcionado muito bem para mim :)<br /><br />Para isso você vai precisar criar uma conta no <a href="http://www.getdropbox.com/">dropbox</a>, e instalar o mesmo na sua máquina. O Dropbox é um serviço de disco virtual muito legal, com conta free você começa com 2GB de espaço no servidor deles, que podem ser gratuitamente espandidos para 5GB (é só ir convidando seus amigos, a cada um que se registrar você ganha 250mb adicionais). O programa instala na sua maquina, e ele cria uma pasta especial, onde tudo que é jogado nessa pasta é automaticamente enviado para o servidor deles.<br /><br />Então vamos começar, crie uma conta no Dropbox e instale o mesmo na sua máquina. Com ele instalado, apenas por questão de organização, crie uma pasta chamada git dentro do dropbox (esse passo é opcional), dentro dessa pasta iremos gravar nossos repositórios.<br /><br />Vamos iniciar agora um novo repositório no seu pc, apenas para fins demonstrativos (faça isso fora da pasta do dropbox, em qualquer outro lugar do seu pc):<br /><br /><code><br />mkdir git_privado<br />cd git_privado<br />git init<br />touch README<br />git add README<br />git commit -m 'initial commit'<br /></code><br /><br />com isso temos um repositório bem simples iniciado na sua maquina, agora vamos para a pasta do dropbox dentro do seu pc, siga os seguintes passos:<br /><br /><code><br />cd git<br />mkdir git_privado.git<br />cd git_privado.git<br />git init --bare<br /></code><br /><br />Oque nós fizemos agora foi criar um repositório vazio dentro do dropbox, assim como qualquer outra coisa, o dropbox vai enviar automaticamente os arquivos para o seu servidor, também notem que o repositório foi criado com a opção "--bare", dessa forma ele inicia apenas os arquivos do repositório em si, sem a árvore de arquivos do projeto (é como ter apenas a pasta .git do repositório).<br /><br />Estamos quase prontos, agora vamos configurar nosso repositório inicial para enviar as alterações para o Dropbox (navegue pelo command até a pasta do projeto criado na primeira etapa):<br /><br /><code><br />git remote add origin ~/Dropbox/git/git_privado.git<br />git push origin master<br /></code><br /><br />nota: onde eu coloquei "~/Dropbox/git/git_privado.git", mude para a pasta correta do dropbox de acordo com o seu sistema operacional.<br /><br />Na primeira linha nós apontamos para o repositório remoto (que nesse caso está na pasta do dropbox), e depois nós enviamos as alterações para o mesmo. Com isso o dropbox já vai enviar as alterações automaticamente :)<br /><br />Quando você estiver em outro PC, basta instalar o dropbox novamente, e dar um clone na pasta do repositório, assim você pode manter tudo sincronizado. E o mais legal é que no dropbox você pode compartilhar pastas, então quando você quizer autorizar alguem a mexer no repositório, basta pedir ao mesmo para criar uma conta no dropbox, e então você compartilha a pasta do repositório com ele, assim os dois (ou quantas pessoas você quizer) podem estar dando push para o repositório :)<br /><br />É meio gambiarra, mas tem funcionado muito bem para os meus projetos, espero que sirva para alguns de vocês também ;)<br /><br />FuiiiWilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com7tag:blogger.com,1999:blog-1053117534982092858.post-90206351387625968552009-10-09T13:11:00.000-07:002009-10-22T20:09:23.367-07:00Calendar Iterator, criando calendários para RailsEu estava aqui trabalhando num projeto em Rails, e surgiu a nescessidade de usar um calendário no site. Bom, como tudo no Rails eu decidi procurar algum plugin para isso, e encontrei o <a href="http://github.com/topfunky/calendar_helper">Calendar Helper</a>, foi uma surpresa pois esse foi o único que eu encontrei, tentei utiliza-lo, precisei fazer algumas modificações no mesmo, mas fui precisando de mais e mais modificações, até eu decidir que esse plugin não era o correto pra mim, eu precisava de algo mais customizavel e simples. Então decidi criar o meu próprio, o <a href="http://github.com/wilkerlucio/calendar_iterator">Calendar Iterator</a>.<br /><br />A idéia é bastante simples, no lugar gerar o calendário inteiro (tabela, headers...) eu decidi simplesmente gerar os dias pertinentes ao calendário do mês atual, dessa forma o resto é facilmente customizável.<br /><br />Veja alguns exemplos de uso:<br /><br /><pre class="sh_html code"># criando um calendário simples<br /><table><br /> <tbody><br /> <% calendar_iterate do |d| %><br /> <%= d %><br /> <% end %><br /> </tbody><br /></table><br /><br /># usando links nos dias do calendário<br /><table><br /> <tbody><br /> <% calendar_iterate do |d| %><br /> <%= link_to d, events_path(:day => d.mday) %><br /> <% end %><br /> </tbody><br /></table><br /><br /># trocando a data do calendário (se você não preencher algum parâmetro, o ano/mês atual serão utilizados)<br /><table><br /> <tbody><br /> <% calendar_iterate :month => 6, :year => 2009 do |d| %><br /> <%= d %><br /> <% end %><br /> </tbody><br /></table><br /><br /># usando uma versão totalmente customizada das tags <tr> e <td><br /><table><br /> <tbody><br /> <% calendar_iterate.each_week do |w| %><br /> <tr class="some_class"><br /> <% w.each do |d| %><br /> <td class="cell_class"><%= d %></td><br /> <% end %><br /> </tr><br /> <% end %><br /> </tbody><br /></table><br /></pre><br /><br />Então é isso, o código do projeto está no <a href="http://www.github.com">Github</a>, e pode ser visto <a href="http://github.com/wilkerlucio/calendar_iterator">aqui</a>.<br /><br />Para instalar o Calendar Iterator na sua aplicação execute o seguinte comando:<br /><br /><code>script/plugin install git://github.com/wilkerlucio/calendar_iterator.git</code>Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com0tag:blogger.com,1999:blog-1053117534982092858.post-47285775142009005782009-04-16T05:23:00.000-07:002009-04-16T05:25:27.328-07:00Dica rápida, tiny-url apiSó uma postagem rapidinha some como criar tiny-urls facilmente (para usar com programação).<br /><br />Apenas faça um acesso http na url:<br /><br /><code>http://tinyurl.com/api-create.php?url=http://URL_PARA_REDUZIR</code><br /><br />Ele retorna apenas a tiny-url gerada, sem html nem nada, mais simples impossível ;)Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com1tag:blogger.com,1999:blog-1053117534982092858.post-90374521374107167062009-04-08T23:17:00.000-07:002009-04-08T23:32:12.784-07:00Cores no console do windowsOlá galera,<br /><br />Atualmente eu estou criando uma biblioteca para Specs em PHP.<br /><br />Como toda boa biblioteca do gênero, eu decidi que os testes iriam rodar atravéz da tela de comando.<br /><br />Para o caso de testes, eu considero bastante importante que se tenha uma saída colorida para identificar de forma mais rápida os resultados. Pesquisando na net achei muita coisa sobre comandos ANSI que permitem fazer várias coisas legais, como por exemplo mover cursor, mudar a cor... Tudo muito bonito, até chegar no console do windows...<br /><br />A desgraça não queria pegar cores de jeito nenhum, até achei em vários tutoriais na net para abilitar o ANSI no windows, mas no meu Vista (eca...) não funcionou... Então fui pro lado prático da coisa, fui ver onde funcionava. Eu utilizo o Cucumber para testes do Ruby aqui, e ele consegue fazer a saída colorida, então decidi ir por esse ponto. Depois de alguns testes eu vi que incluindo certas bibliotecas na hora de rodar o ruby, ele consegue automaticamente converter os ANSI para o console do windows, oque foi lindo, então eu meio que usei o ruby de proxy para a execução do programa em PHP, assim ele iria ler a saída, converter e exibir. Funcionou :D<br /><br />Resultado:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_0JOQPTr_DS4/Sd2UuiSifXI/AAAAAAAAALQ/yc4QxUmX8cI/s1600-h/colored_output.gif" target="_blank"><img style="cursor:pointer; cursor:hand;width: 320px; height: 194px;" src="http://4.bp.blogspot.com/_0JOQPTr_DS4/Sd2UuiSifXI/AAAAAAAAALQ/yc4QxUmX8cI/s320/colored_output.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5322573861821250930" /></a><br /><br />Como podem ver, bastante colorido e legal :)<br /><br />O código Ruby que eu usei para o proxy está aqui:<br /><br /><pre class="sh_ruby code"><br />#!ruby<br /><br />require 'rubygems'<br /><br />gem 'win32console', '>= 1.2.0'<br />require 'Win32/Console/ANSI'<br /><br />puts `/xampp/php/php5.3.0beta2/php.exe #{$*.join ' '}`<br /></pre><br /><br />Claro que para uma futura versão de release isso ai vai mudar muito (adaptar pra verificar se está em windows, tratamento de erros e etc...)<br /><br />Enquanto isso a Limber Spec já está dando os primeiros passos e deve ter algo funcionando de verdade em breve :)<br /><br />Só pra finalizar, uma referência esperta pra quem quizer dar uma olhada sobre comandos ANSI: <a href="http://academic.evergreen.edu/projects/biophysics/technotes/program/ansi_esc.htm">http://academic.evergreen.edu/projects/biophysics/technotes/program/ansi_esc.htm</a>Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com0tag:blogger.com,1999:blog-1053117534982092858.post-51325004995037781762009-03-17T12:28:00.000-07:002009-03-18T06:55:05.846-07:00Brincando com o PHP 5.3 beta 2Bom, pensando um pouco sobre a arquitetura da Framework que eu pretendo criar, eu decidi dar uma pesquisada sobre as novas versões do PHP para ver oque vem por ai. Fiquei feliz em saber que o PHP 5.3 deve ter um release oficial dentro dos próximos 3 mêses.<br /><br />Como minha Framework deve demorar muito mais que isso para ter um release oficial, então eu resolvi instalar o PHP 5.3 Beta aqui na minha máquina para ver como está ficando. Para quem quizer instalar, eu encontrei um <a href="http://forge.typo3.org/wiki/45/PHP_53alpha_installation_on_Windows_%28xampp%29">tutorial muito legal</a> de como instalar ele na porta 81 a partir de uma instalação XAMPP padrão (não se preocupe, ele é igualmente útil mesmo que você não utilize o XAMPP).<br /><br />Depois de instalado, vamos aos testes :)<br /><br /><h3>Late Static Binding</h3><br />Esse é um recurso que já me fez perder bastante a paciência (na verdade a ausência dele...). O problema do que o Late Static Binding resolve é mais fácil de ser descrito com exemplos, então vamos a um exemplo:<br /><br /><pre class="sh_php code">class A<br />{<br /> public static function metodo()<br /> {<br /> return self::outro_metodo();<br /> }<br /><br /> public static function outro_metodo()<br /> {<br /> return "classe A chamando";<br /> }<br />}<br /><br />class B<br />{<br /> public static function outro_metodo()<br /> {<br /> return "classe B sobreescreveu";<br /> }<br />}<br /><br />echo B::metodo();<br /></pre><br /><br />Dado o código acima, o natural (na minha opinião) seria que a saída fosse: "classe B sobreescreveu"<br /><br />Mas esse não é o comportamento que o PHP adota, para esse caso o retorno seria: "classe A chamando"<br /><br />Isso ocorre pelo local da chamada no PHP, ele sabe que o método "metodo" foi definido na classe A, então mesmo chamando a partir de B, ele vai ser executado como um membro de A.<br /><br />Isso pode gerar grandes problemas quando se quer fazer com métodos estáticos com um certo nível de complexidade, no meu caso a classe do ActiveRecord.<br /><br />Com o Late Static Binding esse problema é resolvido da seguinte forma:<br /><br /><pre class="sh_php code">class A<br />{<br /> public static function metodo()<br /> {<br /> return static::outro_metodo();<br /> }<br /><br /> public static function outro_metodo()<br /> {<br /> return "classe A chamando";<br /> }<br />}<br /><br />class B<br />{<br /> public static function outro_metodo()<br /> {<br /> return "classe B sobreescreveu";<br /> }<br />}<br /><br />echo B::metodo();<br /></pre><br /><br />O código está quase totalmente igual, a diferença é na hora da chamada do "outro_metodo" que antes era "self::outro_metodo()" e agora é "static::outro_metodo()". Com isso o PHP consegue manter a compatibilidade com códigos antigos.<br /><br />Essa é uma grande adição e vai fazer com que possamos criar classes como o ActiveRecord com uma interface mais limpa :)<br /><br />So pra finalizar, uma dica que também veio junto com esse recurso, que é o novo método: get_called_class()<br /><br />esse método retorna a classe atual usando o mesmo esquema do static no exemplo anterior.<br /><br /><h3>Namespaces</h3><br />Esse aqui, não sei como o PHP passou tanto tempo sem ter... De qualquer forma, para os "Javistas" agora temos pacotes, para "Rubistas" temos módulos, e por ai vai.<br /><br />Os namespaces não são nada além de uma forma para organizar suas classes (e como consequência, ajudando a evitar conflito de nomes).<br /><br />A verdade é que não fiquei muito satisfeito como o PHP está usando isso no momento (pode mudar, espero que mudem...).<br /><br />Vou citar alguns pontos, a começar pela definição/uso:<br /><br />namespace MeuNamespace\SubNamespace\Aninhando;<br /><br />sinceramente... quem foi que teve a idéia de usar a barra invertida para separar os namespaces? achei feio... mas dos males esse é o menor (para o uso as barras são usadas da mesma forma)<br /><br />Quem conhece Java/.NET (ou outros, vocês entenderam...), sabe que ao importarmos um pacote, as classes ficam diretamente acessiveis; o PHP comeca falhando nesse ponto... não é possível importar um pacote e ter as classes diretamente acessiveis... se você quizer ter acesso direto a classe (como se ela estivesse no pacote atual) você deve importar as classes uma a uma, exemplo:<br /><br /><pre class="sh_php code">use MeuNamespace\A;<br />use MeuNamespace\B;<br /><br />$a = new A();<br />$b = new B();<br /></pre><br /><br />tendo em mente o mesmo caso, o código abaixo NÃO funciona:<br /><br /><pre class="sh_php code">use MeuNamespace;<br /><br />$a = new A();<br />$b = new B();<br /></pre><br /><br />Além de receber um erro de ClassNotFound você ainda ganha de presente um Warning: The use statement with non-compound name 'MeuNamespace' has no effect<br /><br />Para resumir um pouco o resto dos recursos de use (para importar) vou citar alguns exemplos (esses funcionam):<br /><br /><pre class="sh_php code">use MeuNamespace\SubNamespace;<br />use MeuNamespace as MN;<br /><br />$a = new MN\A();<br />$b = new MN\B();<br />$c = SubNamespace\C();<br /></pre><br /><br />Outra coisa que imcomoda é quando se está desenvolvendo dentro de um namespace... Entendam que o PHP considera os namespaces como pastas do seu HD, então, se você estiver trabalhando em um namespace, e precisar acessar o namespace global, você precisa avisar isso, exemplo:<br /><br /><pre class="sh_php code">namespace MeuNamespace; //informa o namespace do arquivo<br /><br />class A<br />{<br /> public function __construct($a)<br /> {<br /> $a = \trim($a);<br /> }<br />}<br /></pre><br /><br />Ou seja, nada limpo pra se programar... espero que a turma do PHP também ache isso... senão vamos ter códigos PHP entupidos com essas barras invertidas no meio...<br /><br /><a href="http://wiki.php.net/rfc/namespaceseparator">RFC: Namespace Separator</a><br /><a href="http://wiki.php.net/rfc/namespaceresolution">RFC: Namespace Resolution</a><br /><br /><h3>Traits</h3><br />Os traits no PHP, vamos resumir isso de forma simples, sabe aquelas interfaces que você implementa no objeto, você diz que o objeto vai usar a interface, e então você cria a implementação para os respectivos métodos. Os traits são como interfaces, mas com uma grande diferença: eles vem com implementação.<br /><br />Isso resolve o problema de herança múltipla, para quem é do mundo Ruby, os Traits são os Mixins do PHP :P<br /><br />Isso é legal para várias coisas, quem programa em Ruby sabe o poder que podemos ter com isso (falo da turma do Ruby porque para eles isso já é muito comum), um exemplo simples seria para quebrar a implementação de uma classe em várias partes (pretendo usar isso no ActiveRecord visto o tamanho da mesma...).<br /><br />Eu achei estranho pois não consegui utilizar os traits, embora no RFC do PHP esteja dizendo que eles foram inclusos no PHP 5.3, quem sabe no proximo beta release?<br /><br /><a href="http://wiki.php.net/rfc/traits">RFC: Traits</a><br /><br /><h3>Lambda e Closures</h3><br />Com certeza esse é um dos recursos mais esperados por mim. Com isso será possível executar uma programação de high-order no PHP.<br /><br />Nas versões atuais já é possível algo semelhante utilizando o método <a href="http://br.php.net/manual/pt_BR/function.create-function.php">create_function()</a> do PHP, mas além de acabar com a organização do código, não suporte sintaxe highlight, ainda é algo bastante limitado.<br /><br />Agora com funções lambda e closures é bem mais prático criar uma programação high-order utilizando funções como blocos.<br /><br />Eu fiz alguns testes aqui para uma criação de enumeraveis como em Javascript e Ruby:<br /><br /><pre class="sh_php code">class ArrayData implements IteratorAggregate<br />{<br /> private $data;<br /> <br /> public function __construct($data = array())<br /> {<br /> $this->data = $data;<br /> }<br /> <br /> public function getIterator()<br /> {<br /> return new ArrayIterator($this->data);<br /> }<br /> <br /> public function push()<br /> {<br /> $args = func_get_args();<br /> <br /> foreach ($args as $arg) {<br /> array_push($this->data, $arg);<br /> }<br /> }<br /> <br /> public function each($block)<br /> {<br /> foreach ($this as $value) {<br /> $block($value);<br /> }<br /> }<br /> <br /> public function map($block)<br /> {<br /> return new static(array_map($block, $this->data));<br /> }<br /> <br /> public function inject($base, $block)<br /> {<br /> $this->each(function($value) use (&$base, $block) {<br /> $base = $block($base, $value);<br /> });<br /> <br /> return $base;<br /> }<br /> <br /> public function reject($block)<br /> {<br /> $new_data = new static;<br /> <br /> $this->each(function($value) use ($block, $new_data) {<br /> if (!$block($value)) $new_data->push($value);<br /> });<br /> <br /> return $new_data;<br /> }<br />}<br /></pre><br /><br />Esse foi apenas um exemplo básico para fins de teste, com o código acima foi possível criar algo assim:<br /><br /><pre class="sh_php code">$data = new ArrayData(array(1, 2, 3));<br />$data->push(4, 5);<br /><br />$data->map(function($value) {<br /> return $value * 2;<br />})->reject(function($value) {<br /> return $value > 5;<br />})->each(function($value) {<br /> echo "$value <br />";<br />});<br /><br />echo $data->inject(0, function($sum, $value) {<br /> return $sum + $value;<br />});<br /></pre><br /><br />Apesar de bastante legal, a performance não foi essas coisas, fiz o seguinte teste de beenchmark:<br /><br /><pre class="sh_php code">function beenchmark($block)<br />{<br /> $start = microtime(true);<br /> $block();<br /> echo "<br />Executed in " . (microtime(true) - $start);<br />}<br /><br />$a = range(0, 100000);<br />$b = new ArrayData($a);<br /><br />beenchmark(function() use ($a) {<br /> $s = 0;<br /> <br /> foreach ($a as $value) {<br /> $s += $value;<br /> }<br />});<br /><br />beenchmark(function() use ($b) {<br /> $s = 0;<br /> <br /> $b->each(function($value) use (&$s) {<br /> $s += $value;<br /> });<br />});<br /><br />beenchmark(function() use ($b) {<br /> $b->inject(0, function($s, $value) {<br /> return $s + $value;<br /> });<br />});<br /></pre><br /><br />Que resultou respectivamente em:<br /><br /><code>Executed in 0.0579040050507<br />Executed in 0.131916046143<br />Executed in 0.254753112793<br /></code><br />Como pode-se ver, uma operação de inject teve um desempenho 5 vezes pior que uma versão linear simples com arrays.<br /><br />Obviamente a classe pode ter algumas coisas mais "raw" na implementação para melhorar esse cenário, estou apenas demostrando oque acontece no caso de uso excessivo de lambda, então devemos utilizar com cautela.<br /><br />Fiz um teste onde o resultado saiu em desacordo com o RFC do PHP, usando o seguinte código:<br /><br /><pre class="sh_php code">class A<br />{<br /> public function my_method()<br /> {<br /> return "ok, reach here";<br /> }<br /> <br /> public function inner_lambda()<br /> {<br /> $proc = function() {<br /> return $this->my_method();<br /> };<br /> <br /> return $proc();<br /> }<br />}<br /><br />$a = new A();<br /><br />echo $a->inner_lambda();<br /></pre><br />Isso me resultou em: Fatal error: Using $this when not in object context<br /><br />Mas de acordo com o RFC do PHP (link abaixo) o uso de $this deveria ser possível para funções lambda criadas dentro de objetos, isso deve ser corrigido nos próximos releases.<br /><br /><a href="http://wiki.php.net/rfc/closures">RFC: closures</a><br /><br /><h3>Conclusão</h3><br />O PHP está melhorando bastante, isso vai suprir muitas coisas para poder criar uma framework mais ágil e prática de se usar, espero melhoras até o release final do PHP 5.3, mas acho que o PHP está indo no caminho certo.Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com0tag:blogger.com,1999:blog-1053117534982092858.post-58477200560452602452009-03-09T10:10:00.000-07:002009-03-17T22:14:03.501-07:00Bow and Arrow em Ruby com ShoesQuando o professor da faculdade pediu um projeto para ser apresentado na cadeira de Linguagem de Programação 2 (que na minha faculdade é considerado orientação a objetos, ensinado com Java), eu perguntei se poderia fazer o projeto em outra linguagem que não fosse Java, e felizmente o professor aceitou.<br /><br />Decidi então programar em Ruby, sobre o projeto, eu não tenho muita criatividade para softwares esporádicos, então minha decisão foi fazer um remake de um antigo jogo para windows 95, o "Bow and Arrow" (ou barrow para os mais chegados =P). Decidi que seria um bom desafio e me ajudaria a entender melhor o Ruby (já estudo Ruby a cerca e 1 ano, mas nunca fiz mais do que pequenos scripts e testes).<br /><br />Depois de roubar todos os sprites do jogo original, eu comecei a programar, para criar a camada visual eu decidi utilizar o Shoes, porque eu ja tinha algum conhecimento sobre o mesmo, e também porque tem muito jogo feito com ele, então a comodidade me fez ficar nele.<br /><br />Antes de começar eu decidi ler algums fontes de jogos feitos com Shoes, baixei vários jogos no shoesbox para ver como as pessoas estavam lhe dando com frame-rate, sprites animados... Infelizmente essa parte da missão não teve muito resultado, pouquissimas aplicações utilizavam algum tipo de engine para seus jogos e as soluções não tinham nada de muito sofisticado, a única conclusão foi que todo mundo usada o metodo "animate" para o main loop do jogo.<br /><br />No começo do desenvolvimento eu fiz tudo em apenas um arquivo Ruby, apenas para fazer alguns testes, nesse ponto era possível controlar o arqueiro com o mouse, e atirar as flechas (que eram imediatamente repostas após atiradas). Depois de vários testes feitos eu vi que era hora de organizar aquela bagunça, então comecei a criar uma engine própria para o jogo.<br /><br />A primeira parte era deixar o arquivo principal o mais enxuto possível, então deixei ele apenas iniciando a aplicação em Shoes, criando uma instância da classe do jogo, iniciando o "animate" e chamando o loop do jogo a cada iteração do animate. Eu sabia que eu precisaria separar as fases do jogo, mas eu decidi começar o desenvolvimento pelos elementos do jogo, então comecei pela classe básica dos elementos, essa classe não tinha muita coisa, apenas definição de variáveis básicos do elemento (x, y, largura, altura), teste de colisão (que também fiz a sobrecarga do operador & para testar colisão entre objetos, hehehe), e um método draw vazio. Sem muitas delongas, a partir dessa classe eu fiz a classe do herói, das flechas e dos balões.<br /><br />Para o herói de inicio a coisa foi um pouco mais complicada, a inicar pelo problema de "estados", afinal o herói deveria poder ter vários "estágios":<br /><ul><li>stand -> estágio padrao, onde ele pode puxar a flecha para atirar</li><li>armed -> estágio armado, onde ele está preparado para atirar uma flecha</li><li>waiting -> estágio de aguardo, onde ele tem que aguardar um tempo para poder voltar ao stand para poder atirar novamente</li></ul>Se eu estivesse em outra linguagem eu provavelmente teria feito um "switch/case" (ou case/when para ruby =P) dentro do método draw que iria fazer um teste para cada estado. Mas, eu to no mundo do Ruby, e eu já sabia que eu precisaria controlar estados em vários objetos diferentes. Então eu fui a lugar para criar uma StateMachine.<br /><br />A idéia básica era simples, seria um módulo, onde teria métodos de classe para adicionar estados (onde os parâmetros seriam o nome do estado e um bloco para a execução do estado), e também o módulo já deveria sobrever o método draw para acionar o estado correto, e por final, métodos para ler/modificar o estado atual.<br /><br />A idéia não teve problemas... já para implementar... Eu gastei umas 3 horas para fazer essa classe, não por ser difícil ou trabalhosa, mas por não conhecer direito essa parte do Ruby. Depois de alguns estudos eu vi que o correto seria usar algo do tipo:<br /><br /><pre class="sh_ruby code">module StateMachine<br /> def self.included(base)<br /> base.extend ClassMethods<br /> end<br /><br /> module ClassMethods<br /> # aqui vem os métodos da classe<br /> end<br />end<br /></pre><br /><br />Até ai tudo bem, mas meu primeiro erro foi conceitual, em não pensar na classe como uma instância, isso me "comeu" algum tempo, quando eu me dei conta disso, então eu sabia que deveria salvar os estados no "objeto da classe" e depois acessa-los a partir das instâncias. Depois de várias e várias tentativas, eu descobri que poderia fazer isso usando variáveis de instância dentro do ClassMethods, e acessando elas atravez de self.class dentro da instância (até agora não sei se foi o caminho mais correto, mas funcionou).<br /><br />detalhe traumatizante: o Shoes não existe mensagens no console padrão, e quando tinha algum erro de execução ele simplesmente deixava a tela branca ou travava o jogo, sem dar nenhuma mensagem de erro... so depois de desenvolver cerca de 70% do projeto eu descobri que apertando "alt+/" o Shoes abre um console onde apareciam as mensagens de erro... agora imagina testar recursos de linguagem que você não conhece sem conseguir ver mensagens de erro (é algo parecido como depurar JavaScript em IE 6)<br /><br />Depois disso a StateMachine ficou ok, e usei ela para implementar os estados no herói. Outro detalhe legal nesse ponto foi o uso de um hook, pois existiam ações do herói que eram comuns a todos os estados, então para resolver isso fiz um alias para o método draw da StateMachine, e redefini o método draw executando as ações padrão e depois chamando o draw do StateMachine (agora chamado de old_draw). Com isso eu já tinha feito várias coisas do jogo, tava indo tudo bem, então eu fui desenvolver usando o "Hackintosh" do meu notebook (tenho windows e leopard no meu HP), então me dei conta de um problema, no Mac o jogo estava rodando mais rápido... Isso significava que o "animate" do Shoes não garantia o frame-rate (oque pra mim até o momento era verdade...). Com isso foi nescessário a criação de calculos sobre tempo, eu fiz isso dentro do loop principal do jogo, calculanto o tempo passado entre o atual momento e a ultima iteração, tive que mudar muita coisa no jogo inteiro para sair passando esse "tempo passado" por entre todas as classes (em verdade... ontem depois de ter o jogo pronto eu pensei seriamente se não deveria ter deixado isso numa variável global ou em um ponto de acesso geral, para não ficar repassando isso por todo mundo, mas agora ja foi, que sabe num próximo refactoring?), e fora isso também foi nescessário mudar os cálculos de velocidade (que já estavam sendo usados nas flechas e nos balões) para trabalharem de acordo com o tempo.<br /><br />Timing ok agora, o jogo no windows rodava com um FPS menor que no Mac, mas a velocidade do jogo era a mesma :)<br /><br />Outro detalhe no herói, eu decidi que nessa versão não seria nescessário clicar com o botão direito do mouse para recarregar a flecha (nunca gostei desse detalhe no jogo original), mas para também não ser uma "metralhadora ambulante" eu coloquei um pequeno delay para ele poder atirar uma nova flecha (a troca entre os estados). Oque estava me incomodando era a implementação desse delay... no momento salvava o tempo ao entrar no estado de waiting, e no estado de waiting verificava o tempo passado a cara iteração até passar o tempo nescessário para então voltar ao estado stand. Me lembrei então do método setTimeout do Javascript, que me seria extremamente conveniente nesse caso, mas que não existe no Ruby. Então foi a hora de criar uma TimerMachine!<br /><br />Como eu já tinha o dado do tempo passado a cada ciclo isso não seria difícil de implementar, e de fato não foi. Quando pronto, era apenas incluir o módulo TimerMachine, e dentro do ciclo do objeto deveria ser chamado o método update_timers(elapsed) para atualizar o tempo dos timers. Para utilizar era apenas fazer "add_timer(time, repeats, &block)", e o bloco seria executado após o tempo (em segundos). O repeats por padrão era 1 (executar apenas 1 vez) e em caso de 0 seria repetido indefinidamente. Essa implementação já estava adequada, mas me liguei que poderia ir mais longe :)<br /><br />Como por padrão o método de update de todos os objetos era draw (de fato essa era a interface para o acesso externo), então eu criei um hook automático no módulo do TimerMachine, que verificava se a classe onde o mesmo foi incluido tinha o método draw definido, e em caso de sua existência, ele mesmo ja criava o hook chamando o update_timers automaticamente (Ruby's Magic!!)<br /><br />Acho que posso dizer que depois desse ponto o desenvolvimento ficou mais fácil, basicamente eu criei a abstração para as fases e separei a parte básica do jogos dos níveis, fui criando as fases 1 a 1, sempre fazendo refactoring quando nescessário até o projeto sair.<br /><br />Para quem quizer ver "mais de perto" os problemas que falei, por favor veja o histórico de código do projeto: <a href="http://github.com/wilkerlucio/bow_and_arrow/tree/master" target="_blank">http://github.com/wilkerlucio/<wbr>bow_and_arrow/tree/master</a><br /><br />O projeto também foi enviado para o ShoesBox (coleção de aplicações feitas em Shoes): <a href="http://the-shoebox.org/apps/139" target="_blank">http://the-shoebox.org/apps/<wbr>139</a><br /><br />Quem quizer dar uma olhada no gameplay do jogo eu enviei um vídeo para o youtube:<br /><br /><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/7eQzoe-_xl8&hl=pt-br&fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/7eQzoe-_xl8&hl=pt-br&fs=1" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object><br /><br />Para rodar o jogo é preciso ter o Shoes instalado na maquina, você pode baixar o Shoes em: <a href="http://www.shoooes.net/" target="_blank">http://www.shoooes.net/</a><br /><br />Com o shoes instalado, apenas faça um clone do projeto na sua maquina, e rode com: shoes bow_and_arrow.rb<br /><br />Como ainda me considero iniciante em Ruby, programadores mais experientes podem encontrar várias coisas no código que poderiam ter sido melhor implementadas com Ruby (tenho certeza que existem muitos pontos assim no codigo...), mas mesmo assim acho que pode ser útil para quem quizer dar uma estudada ;)<br /><br />Quem quizer dar mais algum progresso para o jogo (eu ainda não implementei todas as fases do jogo original, como por exemplo a fase do Bull's Eye onde você tem que acertar o meio do alvo) por favor usem o GitHub como várias de vocês já devem conhecer ;)<br /><br />Espero ter conseguido contribuir com algo para a comunidade, qualquer dúvida sobre o jogo podem perguntar pelos comentários ;)Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com10tag:blogger.com,1999:blog-1053117534982092858.post-34375388700865402012009-01-18T12:21:00.001-08:002009-03-17T13:21:39.693-07:00Dando uma investida em 3DOlá galera, decidi que vo passar a reportar aqui meus estudos nas áreas diversas do mundo do desenvolvimento, assim posso postar com maior frequência :)<br /><br />Bom, últimamente tenho estudado bastante sobre 3D, modelagem, materiais, luz... ainda no básico sobre modelagem, estou estudando 2 programas simultaneamente:<br /><br />1. <a href="http://sketchup.google.com/">Google Sketchup</a><br />2. <a href="http://www.blender.org">Blender</a><br /><br />Os 2 são ótimos programas, mas o Sketchup é melhor (mais fácil) na hora de criar edificações, e o Blender já é mais generico e também mais poderoso de uma forma geral.<br /><br />Até agora estou criando o projeto do meu quarto no Sketchup e seguindo alguns tutoriais pelo Blender<br /><br /><a href="http://img80.imageshack.us/my.php?image=myroomjh3.png" target="_blank"><img src="http://img80.imageshack.us/img80/1948/myroomjh3.th.png" border="0" alt="Free Image Hosting at www.ImageShack.us" /></a><br /><br /><i>Meu quarto</i><br /><br /><br /><br />Por hoje é só, pretendo postar mais mesmo sendo posts menores, vamos ver se consigo mexer isso aqui :)Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com0tag:blogger.com,1999:blog-1053117534982092858.post-68465045731574499012008-10-21T06:51:00.000-07:002009-03-17T22:17:02.338-07:00Porque usar UTF-8 - Codificando/DecodificandoBom galera, como prometido venho hoje aqui demonstrar como o UTF-8 realmente funciona por debaixo dos panos, e vamos criar uma implementação do mesmo utilizando JavaScript.<br /><br />Como eu já havia dito antes, o UTF-8 usa uma codificação de tamanho variável, onde cada caractere pode ocupar entre 1 e 4 bytes, para que isso seja possível, existem bits que são usados para verificar isso, vamos ver o primeiro caso:<br /><br />Eu falei para vocês anteriormente que para os valores ASCII padrão o UTF-8 mantém a compatibilidade, ou seja, não existe nenhum transformação para os caracteres entre 0 e 127, se você olhar o binário disso, vai perceber que isso varia entre:<br /><code>00000000<br />01111111<br /></code><br />É importante notar que o primeiro bit do byte não é modificado, isso é importante porque ele é <span style="font-weight: bold;">flag</span> que indica se vamos precisar de mais bytes no caractere, então, a partir do valor 128 temos que utilizar algum tipo de transformação.<br /><br />Antes de proseguirmos com os detalhes vamos iniciar nosso script, comecem ele da seguinte forma:<br /><pre class="sh_html code"><br /><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"<br />"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><br /><html><br /><head><br /> <title>Conversor de UTF-8</title><br /> <script type="text/javascript" charset="utf-8"><br /><br /> get = function(id) {<br /> return document.getElementById(id);<br /> };<br /><br /> UTF8 = {<br /> encode: function(content) {<br /> return content;<br /> },<br /> <br /> decode: function(content) {<br /> return content;<br /> }<br /> }<br /><br /> encodeFromTo = function(source, destiny, method) {<br /> var value = get(source).value;<br /> <br /> get(destiny).value = method(value);<br /> };<br /><br /> window.onload = function() {<br /> get('encode_button').onclick = function() {<br /> encodeFromTo('original_area', 'encoded_area', UTF8.encode);<br /> };<br /> <br /> get('decode_button').onclick = function() {<br /> encodeFromTo('encoded_area', 'original_area', UTF8.decode);<br /> };<br /> };<br /><br /> </script><br /> <style type="text/css" media="screen"><br /><br /> textarea {<br /> width: 300px;<br /> height: 200px;<br /> }<br /><br /> </style><br /></head><br /><body><br /> <textarea id="original_area"></textarea><br /><br /> <button type="button" id="encode_button">Codificar para UTF-8</button><br /> <button type="button" id="decode_button">Decodificar de UTF-8</button><br /><br /> <textarea id="encoded_area"></textarea><br /></body><br /></html><br /></pre><br />Esse é um simples script que por hora não faz nada :P<br /><br />Mas ele pega o valor do campo de cima e mostra esse valor codificado no campo de baixo, assim como pega o campo de baixo e joga decoficidado no campo de cima. A partir de agora só iremos trabalhar nos métodos <span style="font-weight: bold;">encode</span> e <span style="font-weight: bold;">decode</span> do objeto <span style="font-weight: bold;">UTF8</span> que criamos acima.<br /><br />Voltando ao UTF-8, vamos criar primeiro o codificador, então vamos continuar o entendimento dos bytes.<br /><br />A partir do momento que o primeiro bit deveria ser usado, então a coisa muda, imaginando um caso simples, o caractere de numero 128, se continuassemos usando a maneira simples de somar bits teriamos a seguinte sequencia de bits:<br /><code>10000000</code><br />Mas para o UTF-8 a sequencia correta seria:<br /><code>11000010 10000000</code><br />Parece complicado, mas não é para tanto, quando passamos dos 128 caracteres iniciais temos alguns "moldes" onde devemos encaixar nossos bits, que no caso são os seguintes (por uso de bytes):<br /><code>1 byte - 0xxxxxxx<br />2 bytes - 110xxxxx 10xxxxxx<br />3 bytes - 1110xxxx 10xxxxxx 10xxxxxx<br />4 bytes - 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx<br /></code><br />Esses moldes não são ao acaso, e como pode-se ver eles seguem um padrão, esses moldes são importantes para que o precesso de decodificação, notem que a partir dos primeiros bits do primeiro byte é possivel saber exatamente quantos bytes tem o caractere atual.<br /><br />Para criamos o processo de encoding, o primeiro passo é descobrir quantos bytes serão nescessários para criar nosso caractere no formato UTF-8, para saber isso é só contar os limites a partir do número de bits que podem ser alocados em cada nível. Mas como eu sou muito legal eu já vou disponibilar esses números para você, e são eles: 128, 2048, 65536<br /><br />Pra quem nunca executou operações bit a bit pode parecer um pouco complicado sair mexendo eles por ai, mas é facil, primeiro mantenha a calculadora do windows aberta (em modo científico, assim você pode converter entre decimal, hexadecimal e binario sempre que precisar, e você vai precisar), então vamos criar a função de encode:<br /><pre class="sh_javascript code">var encoded = ''; //iniciamos com uma string vazia<br /><br />for (var i = 0; i < content.length; i++) { //iniciando uma iteracao sobre cada caractere da string<br />var c = content.charCodeAt(i); //pegando o codigo do caractere na posicao atual<br /><br />//verificando numero de bytes<br />if (c < 128) { //1 byte<br /> encoded += String.fromCharCode(c); //simplesmente recolocamos o caractere sem modificações<br />} else if (c < 2048) { //2 bytes<br /> encoded += String.fromCharCode((c >> 6) | 0xC0); //primeiro caractere<br /> encoded += String.fromCharCode((c & 0x3F) | 0x80); //segundo caractere<br />} else if (c < 65536) { //3 bytes<br /> encoded += String.fromCharCode((c >> 12) | 0xE0); //primeiro caractere<br /> encoded += String.fromCharCode(((c >> 6) & 0x3F) | 0x80); //segundo caractere<br /> encoded += String.fromCharCode((c & 0x3F) | 0x80); //terceiro caractere<br />} else { //4 bytes<br /> encoded += String.fromCharCode((c >> 18) | 0xF0); //primeiro caractere<br /> encoded += String.fromCharCode(((c >> 12) & 0x3F) | 0x80); //segundo caractere<br /> encoded += String.fromCharCode(((c >> 6) & 0x3F) | 0x80); //terceiro caractere<br /> encoded += String.fromCharCode((c & 0x3F) | 0x80); //quarto caractere<br />}<br />}<br /><br />return encoded;<br /></pre><br />Pra quem não está acostumado com manipulação de bits isso pode parecer coisa de louco, mas é simples, vou ilustrar como funcionam os operadores bit a bit utilizados nas operações:<br /><br />right shift (>>): esse operador simplesmente move bits a direita, caso o bit ultrapasse o primeiro ele é descartado, exemplos:<br /><code>00011000 >> 2<br />resulta em: 00000110<br />01101110 >> 3<br />resulta em: 00001101<br /></code><br />ou seja, eh simplesmente mover bits a direita (se lembre, tudo isso é forma de representação, tudo são bits, desde numeros a caracteres, vc não vai digitar em formato binário nunca, pelo menos não em javascript)<br /><br />E binário (&): executa uma operação E entre binários, a idéia é simples, você coloca os bits que são comparados em uma listagem de 1 para 1, caso o valor seja 1 nos 2, o resultádo será 1, caso contrário será 0, exemplos:<br /><code> 00110111<br />& 01100010<br />----------<br /> 00100010<br /><br /> 01111000<br />& 00111110<br />----------<br /> 00111000<br /></code><br />esse operador é muito usado para mascarar bits, por exemplo, você quer apenas os 4 últimos bits de um dado binário, então você opera um E contendo 00001111 sobre esse binário, dessa forma você terá o resultado com os 4 últimos valores.<br /><br />OU binário (|): esse é parecido com o anterior, mas com uma diferença básica, esse retorn 1 exceto se os 2 operadores forem 0, exemplo:<br /><code> 00110101<br />| 11100001<br />----------<br /> 11110101<br /></code><br />Isso são alguns operadores binários, caso não tenha ficado muito claro podem tirar suas dúvidas comigo por comentários ou e-mail.<br /><br />Dever de casa: pegue os números utilizados no algoritmo anterior em formato hexadecimal (que comecam com 0x) e veja suas formas em binário (use a calculadora do windows ou similar), e va executando o algoritmo como se fosse o computador, dessa forma você terá um melhor entendimento do algoritmo.<br /><br />O encode está pronto, agora precisamos pegar os códigos Unicode a partir disso que geramos, então vamos criar o decode:<br /><pre class="sh_javascript code">var decoded = ''; //string vazia<br />var i = 0; //iterador<br />var n = c1 = c2 = c3 = c4 = 0; //buffers<br /><br />while (i < content.length) {<br />c1 = content.charCodeAt(i);<br /><br />if (c1 < 128) { //1 byte<br /> decoded += String.fromCharCode(c1); //sem conversão, padrão ASCII<br /> i++; //proximo byte<br />} else if (!(c1 & 0x20)) { //2 bytes<br /> c2 = content.charCodeAt(i + 1);<br /> decoded += String.fromCharCode(((c1 & 0x1F) << 6) | (c2 & 0x3F));<br /> i += 2; //pular 2 bytes<br />} else if (!(c1 & 0x10)) { //3 bytes<br /> c2 = content.charCodeAt(i + 1);<br /> c3 = content.charCodeAt(i + 2);<br /> decoded += String.fromCharCode(((c1 & 0xF) << 12) | ((c2 & 0x3F) << 6) | (c3 & 0x3F));<br /> i += 3; //pular 3 bytes<br />} else if (!(c1 & 0x8)) { //4 bytes<br /> c2 = content.charCodeAt(i + 1);<br /> c3 = content.charCodeAt(i + 2);<br /> c4 = content.charCodeAt(i + 3);<br /> decoded += String.fromCharCode(((c1 & 0x7) << 18) | ((c2 & 0x3F) << 12) | ((c3 & 0x3F) << 6) | (c4 & 0x3F));<br /> i += 4; //pular 4 bytes<br />}<br />}<br /><br />return decoded;<br /></pre><br /><br />O processo inverso é exatamente a mesma coisa, é só pegar os bits que você jogou no formato e junta-los novamente. Para descobrir quantos bytes são usados eu utilizei a seguinte idéia:<br /><br />1 - se for menor que 128, então é padrão ASCII, jogar direto<br />2 - verificar bit zero dentro do primeiro byte, a partir disso é possível descobrir o número (se baseando nos formatos possíveis).<br /><br />O único operador novo é o <span style="font-weight: bold;">left shift (<<)</span> que simplesmente move os bits para esquerda ;)<br /><br />Bom galera, termino por aqui, qualquer dúvida entrem em contato comigo por e-mail ou comentários.<br /><br />Mudarei de assunto no próximo post (assunto indefinido até o momento ;).<br /><br />See yah!Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com0tag:blogger.com,1999:blog-1053117534982092858.post-55806853190074445692008-09-10T21:24:00.000-07:002008-10-14T07:25:27.383-07:00Porque usar UTF-8Olá, estou inaugurando esse meu novo blog hoje, esse blog será dedicado a desenvolvimento em geral, irei postar aqui coisas que já aprendi ao longo da minha vida de desenvolvedor e coisas que ainda aprendo (afinal, nesse mundo nós nunca paramos de aprender).<br /><br />Hoje eu quero falar sobre um assunto do qual acredito que a maioria já deva ter passado, que é o clássico problema de <span style="font-weight: bold;">encoding</span>. Muitas pessoas apenas saem usando o encoding que funcionar na hora, mas na verdade não fazem a menor ideia do que os encodings são e muito menos porque eles existem (e pensam, por que simplesmente não adoptam apenas um encoding para acabar com essa pu*****), nesse artigo pretendo explicar o que são os encodings, porque existem, como funcionam, e como diz o título do artigo, porque devemos utilizar UTF-8. Agora chega de enrrolação e vamos ao que interessa :)<br /><br /><span class="Apple-style-span" style="font-weight: bold;font-size:large;" >Como tudo começou</span><br /><br />Para entendermos esse assunto que pode ser um tanto complicado, vamos começar do começo realmente, por que existem tantos formatos de encoding (que diga-se de passagem, normalmente nós brasileiros só lidamos com dois...).<br /><br />Vamos voltar no tempo e lembrar dos computadores primórdios, naqueles tempos os computadores nem se imaginavam com letras, eles eram utilizados apenas para operações numéricas, então nem existiam caracteres, oque dizer então de processos de encoding.<br /><br /><span style="font-weight: bold;">O padrão ASCII</span><br /><br />Muitos já devem no mínimo ter lido em algum lugar a sigla ASCII (American Standard Code for Information Interchange), pois é, o ASCII é um padrão americano para troca de mensagens (para textos) e esse padrão utiliza 7 bits para armazenar cada caractere, então, isso significa que ele suporta até 128 caracteres (que é o máximo número possível de se armazenar em 7 bits). Então essa é uma forma antiga de se conseguir reproduzir textos no computador, pois assim nós temos um mapeamento dos números com os caracteres. Dentro desses 128 caracteres do padrão ASCII, 33 não <span style="font-style: italic;">não imprimíveis</span>, ou seja, caracteres de comando, e os outros 94 são imprimíveis (excepto o espaço), ou seja, são realmente coisas para aparecer na tela.<br /><br />Para os americanos esse padrão da conta, mas como sabemos a informática cresceu, e esse padrão não dava conta de caracteres de outros locais como nossos acentos latinos por exemplo... Várias soluções devem ter sido tentadas para solucionar esse problema, mas eu sinceramente não tenho tanto conhecimento sobre esse meio tempo, então já irei pular para algo concreto que aconteceu.<br /><br /><span style="font-weight: bold;">Padrões ISO</span><br /><br />Os mais entendidos já devem ter percebido algo estranho, o padrão ASCII usa 7 bits para representar os caracteres, mas a menor unidade que o computador trabalha é 1 byte (ou seja, 8 bits), então temos ai um bit sobrando em cada caractere que usamos, e se fizermos uso desse bit podemos duplicar a capacidade de 128 para 256 caracteres por byte, e é nesse ponto que entram os padrões ISO.<br /><br />De certa forma todos os lugares do mundo usam os caracteres americanos, então eles se mantiveram estáticos nos seus 128 bits como já estavam antes, mas agora vinha o problema do que fazer com os outros 128 que agora seriam utilizados, é lógico que 128 caracteres a mais não são suficientes para comparar todos os caracteres do mundo, então foram criadas várias tabelas ISO, onde cada uma mapeava os 128 bits restantes para certa localidade, nós pode exemplo utilizamos muito o padrão ISO-8859-1 (caracteres latinos). Dessa forma temos um padrões para representar quaisquer caracteres do mundo, mantendo o padrão de 1 byte por caractere.<br /><br />Então parece que as coisas estão ficando boas, mas resta um problema...<br /><br /><span style="font-weight: bold;">Caracteres de várias localidades juntos</span><br /><br />Bom, como vimos ate o momento, e possível usar qualquer tipo de caractere se você estiver com o encoding correto, mas e se você tiver um site internacional, onde você precisa utilizar mais de um idioma ao mesmo tempo?<br /><br />Para nos salvar então existem as codificações UTF (Unicode Transformation Format) onde e possível utilizar os caracteres diretamente a partir do seu código Unicode. Mas espera ai, o escopo dos códigos Unicode e imenso, seria um abuso gastar tantos bytes com cada caractere para podermos comportar os maiores... E por isso que o UTF existe, ele na verdade e um padrão de codificação de caracteres, existem vários algoritmos diferentes de UTF (UTF-1, UTF-7, UTF-8, UTF-16 e UTF-32), vou me reter nesse artigo ao mais utilizado, o UTF-8.<br /><br /><span style="font-weight: bold;">UTF-8</span><br /><br />O UTF-8 utiliza um modo de codificação onde os caracteres tem tamanho variável (podem variar entre 1 e 4 bytes), ele usa um modelo nos bytes para que seja possível descobrir quantos bytes o caractere atual estará utilizando. Com a codificação UTF-8 temos acesso a um alcance da tabela unicode entre os caracteres de código U+0000 ate U+10FFFF, que são todos os caracteres formais da tabela Unicode, e garanto a vocês, é tudo que precisam, heheh.<br /><br />Outro detalhe interessante do padrão UTF-8 e que ele é compatível com o padrão ASCII, então os caracteres entre 0 e 127 são escritos em UTF-8 de forma exatamente igual ao formato ASCII, dessa forma eles são compatíveis.<br /><br />No próximo artigo estarei postando em detalhes como funciona a codificação do UTF-8, assim como criaremos um script conversor utilizando Javascript (ninguém tem desculpa pra dizer que não tem como usar, hehehe).<br /><br /><span style="font-weight: bold;">Resumo</span><br /><br />Como pudemos ver o UTF-8 e uma evolução, e com a banda que temos hoje em dia o que ele aumenta no tamanho do texto e insignificante, sinceramente não existe motivo para utilizar os velhos padrões ISO, porque mesmo que hoje você não use caracteres fora do latino (e olha que usa, um bom exemplo são aquelas aspas que o word adora colocar, que não são aspas comuns e não estão disponíveis nos caracteres latinos, e pior, seus clientes adoram copiar texto do word) você ira poupar muitas dores de cabeça.<br /><br />Esperam que tenham gostado do meu primeiro artigo nesse blog, estarei postando muitas coisas dos mais variados assuntos no ramo do desenvolvimento daqui para frente.<br /><br />Grato a sua atenção, e até a próxima.Wilker Lúciohttp://www.blogger.com/profile/08197133298620910758noreply@blogger.com3