Avançar para a área de conteúdo

ir para o conteúdo principal

developerWorks Brasil  >  Linux  >

Perl Elaborado: Perl e a Nuvem Amazon, Parte 4

Mergulhe no código base integral do site mod_perl

developerWorks
Opções de documento

Opções de documento que necessitam de JavaScript não são exibidas

Código de amostra


Classificar esta página

Ajude-nos a melhorar este conteúdo


Nível: Intermediário

Teodor ZlatanovGold Software Systems

14/Jun/2009

Esta série em cinco partes percorre a construção de um Web site simples de compartilhamento de fotos usando Perl e Apache para acessar Simple Storage Service (S3) e SimpleDB da Amazon. Nesta parte, examine o código base integral do site mod_perl , incluindo como configurar o nível superior, o que fazer com os manipuladores e como configurar dependências externas.

Nesta parte, prepare-se para testemunhar um site mod_perl integral (somente código; os modelos estão na próxima parte). Agora, nosso ritmo anteriormente relaxado (um passeio ou meio galope, se preferir) se tornará um galope completo à medida que cavalgamos com nosso cavalo mod_perl pelas Planícies de Metáforas Filtradas.

Para Obter o Máximo desta Série

Esta série requer conhecimento de nível principiante de HTTP e HTML, assim como conhecimento de nível intermediário de JavaScript e Perl (em um processo mod_perl Apache). Algum conhecimento de bancos de dados relacionais, armazenamento em disco e redes será útil. A série fica cada vez mais técnica, portanto, consulte a seção Recursos se precisar de ajuda com qualquer um desses tópicos.

Incentivo muito a leitura do código de origem. O site é funcional, mas muitos detalhes não estão integralmente explicados nesta série, pois espero que você os entenda ou possa aprender o que não entendeu. Sua livraria local ou remota e mecanismos de procura são seus amigos.

Especificamente, configurar um site mod_perl integral e usar o Template Toolkit são tópicos amplos que foram cobertos muitas vezes e, portanto, não são explicados aqui de forma alguma. A melhor maneira de aprender é trabalhar cada questão e obstáculo até o site estar em execução. Esta série apresenta o motor, as rodas, o chassi, etc.—fica por sua conta por gasolina e colocar o carro na estrada.

Como antes, uso share.lifelogs.com nesta série como o nome de domínio. Lembre-se de alterá-lo conforme necessário para seu próprio ambiente.

Configuração de Nível Superior

É necessário ter um servidor Apache funcional com suporte a mod_perl (para configurar um). Insira a seção a seguir em seu arquivo Apache httpd.conf, conforme mostrado na Lista 1:


Lista 1. Fornecendo suporte mod_perl para arquivo de configuração do Apache share.httpd.conf

<VirtualHost 1.2.3.4:80>
        ServerName      share.lifelogs.com
        DocumentRoot    /var/www/html
        ErrorLog        /var/log/apache/error-share.log
        PerlRequire     /home/tzz/mod_perl_require_share.pl
        <Location />
                SetHandler      perl-script
                PerlHandler     SharePerlHandler
        </Location>
        SetEnv AWS_KEY 'my-AWS-key'
        SetEnv AWS_SECRET_KEY 'my-secret-AWS-key'
</VirtualHost>

Tudo vive sob /home/tzz, como pode ver.

Coisas importantes aqui:

  • Há um log de erros específico (de forma que é possível observar erros com este site em isolamento).
  • As chaves de desenvolvedor da Amazon são passadas no ambiente de processo. Dessa forma, o código de origem Perl não terá as mesmas, caso o código de origem vaze de alguma forma. (A configuração do servidor da Web geralmente é mais segura do que o código de origem.)

Observe que tudo é tratado através do SharePerlHandler, todo pedido em share.lifelogs.com! Provavelmente, isso não é o desejado em um ambiente de produção.

A diretiva PerlRequire simplesmente configurou um ambiente, sem fazer nada de especial. Novamente, tudo está sob /home/tzz.

A Lista 2 mostra o arquivo Perl mod_perl_require_share.


Lista 2. O arquivo mod_perl_require_share.pl

#!/usr/bin/perl -w

use strict;

use lib '/home/tzz';

use SharePerlHandler;

1;



Voltar para parte superior


O Manipulador mod_perl

O manipulador mod_perl está inteiramente no arquivo SharePerlHandler.pm. Possui diversas seções, de forma geral: configuração, manipulador principal, manipuladores de comentários e fotos, utilitários gerais e utilitários SimpleDB.

Os utilitários gerais e SimpleDB poderiam viver em seus próprios módulos, mas, por questão de simplicidade, deixei tudo em um local. Os manipuladores de comentários e fotos e as funções de utilitário SimpleDB são principalmente do script simple_go.pl (consulte Downloads) com algumas pequenas mudanças.

Vamos iniciar com a configuração. À medida que percorro cada seção, explicarei minhas decisões; com muita frequência, "simplicidade" será a razão por eu ter feito as coisas de determinada maneira. Criar um bom Web site é difícil, portanto, considere tudo que encontrar aqui como um modelo geral a ser moldado de acordo com suas necessidades e orçamento, em vez de ser um projeto final que pode ser colocado em produção. O fato de funcionar pode, na verdade, ser uma distração, mas não resisti à tentação de torná-lo funcional.



Voltar para parte superior


Configurando Dependências Externas

A Lista 3 mostra a configuração geral para o arquivo SharePerlHandler.pm:


Lista 3. Configuração geral para SharePerlHandler.pm

package SharePerlHandler;
use Apache::Constants qw(:common REDIRECT);
use strict;
use Carp qw/verbose cluck carp croak confess/;
use Data::Dumper;
use Apache::Request;
use Template;
use POSIX;
use Digest::HMAC_SHA1 qw(hmac_sha1 hmac_sha1_hex);
use MIME::Base64;
use Data::UUID;				# generates unique IDs
use lib '/home/tzz/amazon-simpledb-2007-11-07-perl-library/src/';
use Amazon::SimpleDB::Client;

SharePerlHandler.pm depende de muito módulos. Primeiro, usa o módulo strict , que é essencial para boa programação Perl. Eu não colocaria algo em produção que não executasse sob use strict. Além disso:

  • Os módulos Carp fornecem melhores erros.
  • Data::Dumper é para depuração geral.
  • POSIX é para muitas funções que descobri que preciso frequentemente.
  • Digest::HMAC_SHA1 e MIME::Base64 são para a política de upload do Amazon S3.
  • O módulo Template é o Template Toolkit, que permitirá criar páginas HTML com algum conteúdo dinâmico rapidamente.
  • Data::UUID é para gerar IDs exclusivos.
  • Apache::Request e Apache::Constants são para interação de mod_perl com o servidor Apache.
  • Por fim, Amazon::SimpleDB::Client é da Amazon e permite interagir com SimpleDB.

Se não souber como instalar esses módulos a partir de CPAN, isso é feito com cpan -e 'install MODULE' (se não souber disso, provavelmente, é possível que esteja bem confuso agora...) .

Não usamos os módulos Net::Amazon::S3 apesar de podermos (na Parte 2 eu disse que iríamos). Eles simplesmente não foram necessários devido a diversas decisões de arquitetura por questão de simplicidade; saiba mais sobre isso quando eu falar sobre uploads.

A Lista 4 mostra a configuração global para SharePerlHandler.pm.


Lista 4. A configuração global para SharePerlHandler.pm

use constant IMAGE_MODE   => 0;
use constant COMMENT_MODE => 1;

use constant VERBOSE => 1; # can also be done through the environment or some other way

my $template = Template->new( {
			       INCLUDE_PATH => '/home/tzz/templates/share',
			       RECURSION => 1,
			      }
			    );

my $uuid = Data::UUID->new();

Constantes serão necessárias para representar o modo de imagem versus o modo de comentário para as operações SimpleDB básicas, portanto, defina-as aqui. A constante VERBOSE pode ser substituída por qualquer outro método para controlar detalhamento em seu servidor. Lembre-se, quanto mais dinâmico o controle sobre detalhamento, mais caro é (pois o servidor precisa verificar toda vez).

Em seguida, você obtém um objeto $templates totalmente novo (que irá carregar modelos de /home/tzz/templates/share e fará recursão). Por fim, um gerado de UUID é obtido para ser usado em toda parte.



Voltar para parte superior


O Manipulador Principal

Tudo bem, este é principal, o local onde a magia acontece. PRESTE ATENÇÃO! (Acordado? Bom!) Dê uma boa olhada na Lista 5.


Lista 5. Mais configuração global

sub handler
{
 my $r = shift @_;
 my $q = Apache::Request->new($r,
                        POST_MAX => 4096,
                        DISABLE_UPLOADS => 1);

 my $user = (rand 2 > 1) ? 'bob' : 'ted';
                              # pick a user randomly between bob and ted
                              # (50% chance each)

 handle_photo($q);
                              # always try to delete, add, or edit a URL
                              # if it's passed as a parameter
 handle_comment($q);
                              # always try to delete, add, or edit a comment
                              # if it's passed as a parameter

 my $uri = $q->uri();
 my $tfile = $uri;
 $tfile =~ s,^/,,;            # remove the starting "/" in the name if it exists
 $tfile =~ s,/$,,;            # remove the ending "/" in the name if it exists
 $tfile =~ s,/,_,g;           # "/" in the file name becomes "_" so all the
                              # templates can be in one directory

 $tfile = 'index' unless length $tfile;	
                              # make the URI "index" if it's
                              # empty (e.g. someone hit the / URI)

 if ($tfile =~ m/\.html$/)
 {
  $tfile =~ s/html$/tmpl/;    # map ANYTHING.html to ANYTHING.tmpl
 }
 else
 {
  $tfile .= '.tmpl';          # map ANYTHING to ANYTHING.tmpl
 }

 my $policy = '';
 my $signature = '';

 if ($tfile eq 'upload.tmpl')
 {
  $template->process('policy.tmpl',
                 {
                  username => $user,
                 },
                 \$policy) || croak($template->error());

  my $key = $ENV{AWS_SECRET_KEY};
  $policy = encode_base64($policy);
  $policy =~ s/\n//g;
  $signature = encode_base64(hmac_sha1($policy, $key));
  $signature =~ s/\n//g;
 }

 $q->send_http_header('text/html; charset=utf-8');
 my $output = '';

 $template->process($tfile,
     {
      request   => $q,
      username  => $user,
      policy    => $policy,
      signature => $signature,
      env       => \%ENV,
      params    => \%{$q->param()},
      fimages   => sub { return list_simpledb(sprintf('SELECT * from `%s`',
                   simpledb_image_domain_name())) },
      fcomments => \&get_comments,
     },
     \$output) || croak($template->error());
	
 print $output;
 return OK;
}

Nossa, é uma função longa. É quase longa demais; provavelmente, eu extrairia as partes que podem ser independentes ("refatore-a", como os jovens legais falam hoje em dia) se precisasse incluir até mesmo um pouco mais de lógica. Funciona bem para mostrar como pode ser a aparência do manipulador principal, no entanto.

Primeiro a função obtém o objeto do pedido. Configura então um nome de usuário aleatório ("bob" ou "ted"); geralmente, você teria seu próprio modo de obter isso, possivelmente através de cookies ou pode permitir que o Apache trate da autenticação e autorização.

Eu disse na Parte 1 que haveria uma tabela de usuários em SimpleDB, mas isso complicou muito o site, então, a eliminei. Consultar usuários em SimpleDB não é simples, pois era necessário fornecer uma maneira para inscrever e gerenciar informações sobre usuários. Tornou o código muito grande, portanto, perdoe essa omissão —é definitivamente possível manter a tabela de usuários em SimpleDB.

Tudo bem, em seguida, você irá querer tratar de parâmetros de fotos ou de comentários. Por exemplo, caso veja o parâmetro deletecommentid , você tenta excluir esse ID de comentário. Vamos detalhar os manipuladores de parâmetros de fotos e comentários posteriormente.

Em seguida, é necessário gerenciar o pedido em si. Isso é feito com um mapeamento simples que transforma "any/request/here.html" em "any_request_here.tmpl" e solicita então esse modelo. Asseguramos que index.tmpl seja fornecido para o pedido "/".

Quaisquer URIs que não tenham um modelo correspondente não produzirá nenhum dado e, na verdade, emitirá um erro. Essa não é uma técnica de produção , vamos deixar claro, mas configura um Web site em poucas linhas, portanto, é bastante útil quando o objetivo é brevidade e simplicidade em um demo.

Em seguida, se o arquivo de modelo for "upload.tmpl", você sabe que precisará gerar uma política de upload para S3 e, portanto, faz isso usando o arquivo policy.tmpl. O nome de usuário é passado para esse modelo, que é muito semelhante àquele na Parte 2 desta série. A Lista 6 mostra um modelo de política.


Lista 6. Lista de código de amostra em largura máxima

{"expiration": "3000-01-01T00:00:00Z",
  "conditions": [
    {"bucket": "images.share.lifelogs.com"},
    {"acl": "public-read"},
    ["starts-with", "$key", ""],
    ["starts-with", "$Content-Type", ""],
    ["starts-with", "$success_action_redirect",
     "http://share.lifelogs.com/s3uploaded?user=[% username %]"],
    ["content-length-range", 0, 1048576]
  ]
}

A principal diferença aqui é que em vez de tornar o nome do usuário parte da URL de sucesso, ele é transformado em um parâmetro, pois torna o manipulador de parâmetro de imagem muito mais simples. Mais sobre isso adiante.

Agora, você assina a política e segue para enviar os cabeçalhos HTTP (bom trabalho aí, Apache!). Em seguida, gere a saída necessária com muitos parâmetros, da seguinte forma:

  • request, o pedido Apache
  • username, o nome de usuário aleatório
  • policy, a política de upload do S3 (poderia estar em branco).
  • signature, a assinatura da política do S3 (poderia estar em branco)
  • env, o ambiente de processo (não faça isso na produção!)
  • params, os parâmetros, por exemplo, a partir de um pedido POST ouGET
  • fimages, uma função para retornar todas as imagens
  • fcomments, uma função para retornar todos os comentários, apontados por ID de imagem

Isso é tudo para o manipulador geral. Toda a magia restante ocorre nos manipuladores de parâmetros de comentários e imagens e nos próprios modelos. Vamos continuar nossa jornada descendente.

Os manipuladores de imagens e comentários são chamados para cada pedido. Se localizarem parâmetros que parecem aplicáveis, executarão uma operação: incluir, modificar ou excluir uma imagem ou um comentário. Os modelos, que vamos estudar após SharePerlHandler.pm, contêm estes parâmetros em formulários POST .

Não pule adiante, há muito aqui para mantê-lo entretido —código de má qualidade, arquitetura instável e a esperança de você encontrar um erro que valha a pena postar no Twitter ("haha o @tzlatanov é mto ruim o pior olha esse mapa usado em contexto vazio e ai meu Deus modelos kebrados é claro que ele não é um h4ck3r de vdd mod_perl é tão ultrapassado.").



Voltar para parte superior


O Manipulador de Parâmetro de Comentário

A Lista 7 mostra o manipulador de parâmetro de comentário.


Lista 7. O manipulador de parâmetro de comentário

sub handle_comment
{
 my $q = shift @_;

 my $user           = $q->param('user');
 my $imageid   	  = $q->param('refimageid');
 my $comment   	  = $q->param('comment');
 my $refcommentid   = $q->param('refcommentid');
 my $commentid 	  = $q->param('commentid');
 my $deleteid 	  = $q->param('deletecommentid');

 my $result;

 if (defined $deleteid) # delete
 {
  $result = delete_simpledb($deleteid, COMMENT_MODE);
 }
 elsif (defined $commentid && defined $comment) # edit
 {
  my %q = (
         comment => $comment,
        );

  put_simpledb($commentid, COMMENT_MODE, %q);
  $result = get_simpledb($commentid, COMMENT_MODE);
 }
 elsif (defined $imageid && defined $comment) # new comment
 {
  my %q = (
         image_id => $imageid,
         comment => $comment,
        );

  $q{reply_to} = $refcommentid if defined $refcommentid;
  $q{user} = $user if defined $user;

  my $id = new_uuid();
  put_simpledb($id, COMMENT_MODE, %q);
  $result = get_simpledb($id, COMMENT_MODE);
 }

 $q->param()->{'result'} = $result;
}

O manipulador de parâmetro de comentário possui três modos possíveis, dependendo dos parâmetros passados a ele. Os modos são mutuamente exclusivos. Em cada caso, o parâmetro de consulta result é configurado de forma apropriada para indicar o êxito se estiver definido. Assim, os modelos podem verificar posteriormente se está configurado e agir conforme necessário. À medida que o site cresce, você provavelmente irá querer incluir outros parâmetros, como last_operation ou error_message.

Se o parâmetro deletecommentid estiver configurado, o manipulador chama delete_simpledb com os valores apropriados. Esse é o modo mais simples incondicional.

O próximo modo modifica um comentário. Não verifica se o comentário existe no momento, portanto, um ID incorreto aqui criaria um novo comentário. Verificar é fácil, mas caro (é necessário fazer uma chamada extra a SimpleDB, o que é lento, já que é uma roundtrip HTTP completa mais o tempo de processamento do lado da Amazon).

Observe que, como cada comentário possui seu próprio ID, editar é fácil. Sem registros de comentários individuais, você poderia ter agrupado comentários como um atributo de imagem (uma array de cadeias de caracteres, cada uma um comentário), mas teria sido então muito mais difícil editar ou excluir um comentário individual. Essencialmente, teria sido necessário implementar sua própria estrutura re registro em um comentário para representar um ID, um usuário de postagem, etc.

O modo de edição é acionado pela presença dos parâmetros de consulta commentid e comment , que determinam o UUID de destino de edição e o novo conteúdo do comentário, respectivamente. O resultado é a recuperação do mesmo UUID novamente de SimpleDB, portanto, você poderia verificar aqui se o campo de comentário resultante é o desejado (caso contrário, algo saiu errado). Não verifico tudo isso aqui por questão de simplicidade.

O modo final, criando um novo comentário, é acionado pelos parâmetros imageid e comment . Como opção, aceitará um UUID de referência (quando o comentário é uma resposta a outro) e um nome de usuário (quando o comentário não for anônimo). Exatamente como o modo de edição, você simplesmente efetua put_simpledb dos atributos e obtém então os mesmos de volta sem verificar se os campos foram modificados corretamente.



Voltar para parte superior


O Manipulador de Parâmetro de Imagem

Esse manipulador é muito semelhante ao manipulador de comentário, portanto, se tiver dormido na seção anterior, volte e preste atenção.

A URL da imagem, se não for passada, é construída a partir da chave e do depósito do S3. Dessa forma, há uma interface consistente para manipular redirecionamentos com êxito após uploads do S3. A Lista 8 mostra o manipulador de parâmetro de imagem.


Lista 8. O manipulador de parâmetro de imagem

sub handle_photo
{
 my $q = shift @_;

 my $user     = $q->param('user');
 my $name     = $q->param('name');
 my $bucket   = $q->param('bucket');
 my $key      = $q->param('key');
 my $url      = $q->param('url');
 my $editid   = $q->param('imageid');
 my $deleteid = $q->param('deleteimageid');

 # set the URL from the S3 key and bucket if necessary
 if (!defined $url && defined $key && defined $bucket)
 {
  $url = sprintf("http://%s.s3.amazonaws.com/%s", $bucket, $key)
 }

 my $result;

 if (defined $deleteid) # delete
 {
  $result = delete_simpledb($deleteid, IMAGE_MODE);
 }
 elsif (defined $name && defined $editid) # editing an image name
 {
  my %q = (
         name => $name,
        );

  put_simpledb($editid, IMAGE_MODE, %q);
  $result = get_simpledb($editid, IMAGE_MODE);
 }
 elsif (defined $url && defined $name && defined $user) # adding a new one
 {
  my %q = (
         url => $url,
         name => $name,
         user => $user,
        );

  $q{bucket} = $bucket if defined $bucket;

  my $id = new_uuid();
  put_simpledb($id, IMAGE_MODE, %q);
  $result = get_simpledb($id, IMAGE_MODE);
 }

 $q->param()->{'result'} = $result;
}

A exclusão da imagem é acionada pelo parâmetro deleteimageid . A edição do nome de uma imagem é feita com os parâmetros name e imageid . A criação de uma nova imagem é realizada com uma URL, um nome de usuário e um nome de imagem. O depósito de imagens é opcional e deve aparecer somente se esse manipulador for chamado após um upload bem-sucedido do S3 ser redirecionado para nosso site.

Lembre-se da política, o redirecionamento bem-sucedido do S3 possui o nome de usuário como parte da URL como um parâmetro. Também terá a chave e o depósito, de forma que tudo que se precisa fazer é criar uma imagem a partir deles.



Voltar para parte superior


Funções de Utilitário

Vamos dar uma olhada nas funções realmente diversas.


Lista 9. Funções realmente diversas

sub qlog
{
 printf STDERR @_;
 print STDERR "\n";
}

sub new_uuid
{
 return $uuid->to_string($uuid->create());
}

sub simpledb_image_domain_name
{
 return simpledb_domain_name(IMAGE_MODE);
}

sub simpledb_comment_domain_name
{
 return simpledb_domain_name(COMMENT_MODE);
}

sub simpledb_domain_name
{
 return sprintf "%s.share.lifelogs.com",
  (shift == IMAGE_MODE) ? 'share_photos' : 'share_comments';
}

qlog é interessante quando você não quer gravar printf STDERR toda vez. Também grava um término de linha. Se saída variada tem que ir para o log de erros do Apache é você quem decide. Além disso:

  • new_uuid é para gerar um novo UUID.
  • simpledb_domain_name, simpledb_image_domain_name e simpledb_comment_domain_name usam o parâmetro mode (que pode ser IMAGE_MODE ou COMMENT_MODE) para fornecer um domínio SimpleDB.


Voltar para parte superior


Funções de Utilitário SimpleDB

As funções de utilitário SimpleDB são praticamente iguais àquelas na Parte 3 (simple_go.pl). Faça download das mesmas a partir da seção Downloads abaixo. Vou listar as mudanças:

  • get_comments é uma nova função para obter todos os comentários, chaveados pelo ID da imagem e, então, pelo ID do comentário pai ou pela palavra noparent.
  • qlog é usada em vez de print e a constante VERBOSE é usada em vez de $verbose.
  • O serviço é inicializado para cada pedido usando as chaves de ambiente AWS_KEY e AWS_SECRET_KEY .
  • O modo, como $mode, é passado em vez de ser global.
  • Nos erros, em vez de usar die(), deve tratá-los da melhor maneira possível.
  • O nome de domínio é obtido com simpledb_domain_name em vez de uma variável global.
  • As funções forem renomeadas, pois "get" e "put" não são bons nomes em uma espaço de nomes que não atende a um único propósito, como o antigo script simple_go.pl fez.

Devo mencionar novamente que esse código aceitará somente valores únicos por atributo. Se qualquer atributo tiver uma array de cadeias de caracteres, somente uma delas será retornada. Quando atributos são gravados, somente um valor permanecerá mesmo se houver uma array de valores antes. O código é significativamente mais simples por causa disso, mas também não é adequado para o uso geral de SimpleDB.



Voltar para parte superior


Conclusão

Agora, você realizou um tour do código de um site mod_perl integral, usando o que gravamos nas Partes 2 e 3 desta série (os arquivos para download dessas partes estão disponíveis abaixo também). O site resultante usa o Template Toolkit, S3 e SimpleDB para fornecer uploads de imagens, navegação (com thread), edição e inclusão de comentário (anônimo ou não) e exclusão.

Na Parte 5, você ficará familiarizado com a versão de modelo do site.




Voltar para parte superior


Downloads

DescriçãoNomeTamanhoMétodo de download
SimpleDB utility functionssimpledb_utility.zip3KBHTTP
Sample script (from Part 2)s3form.zip2KBHTTP
Sample script (from Part 3)simple_go.zip4KBHTTP
Informações sobre métodos de download


Recursos

Aprender
  • Inicie com "Perl Elaborado: Perl e a Nuvem Amazon, Parte 1" (developerWorks, março de 2009) para entender os benefícios e desvantagens de usar S3 e SimpleDB da Amazon para construção de Web site. Continue então com a Parte 2 (abril de 2009) para fazer upload de um arquivo para o S3 a partir de uma página da Web através de um formulário HTML para minimizar a carga no servidor e com a Parte 3 (junho de 2009) para fazer upload de imagens através de URLs em uma tabela e gerenciar imagens e comentários.

  • Detalhes da oferta de serviço e recursos para desenvolvedores estão em Amazon.com:
  • Aprenda sobre o incrível JavaScript MimeType, uma propriedade do objeto navegador, um objeto de nível superior que é a representação de objeto do navegador da Internet do cliente ou do programa navegador da Web que está sendo usado.

  • mod_perl reúne todo o poder de Perl e do Apache HTTP Server.

  • Prototype é uma estrutura JavaScript que facilita o desenvolvimento de aplicativos da Web dinâmicos através de um kit de ferramentas para desenvolvimento orientado por classes e a biblioteca Ajax "mais legal" do mundo. E há um excelente artigo sobre como usá-lo: "Developer Notes for prototype.js" de Sergio Pereira.

  • Sim, Virgínia, é um serviço baseado na Web e, portanto, pode sofrer interrupções; uma consideração importante.

  • Na zona do Linux do developerWorks, encontre mais recursos para desenvolvedores do Linux e verifique nossos artigos e tutoriais mais populares .

  • Consulte todas as dicas do Linux e tutoriais do Linux no developerWorks.

  • Permaneça atualizado com os eventos técnicos e Webcasts do developerWorks.


Obter produtos e tecnologias

Discutir
  • Envolva-se com a comunidade My developerWorks; com seu perfil pessoal e página inicial customizada, é possível padronizar o developerWorks para seus interesses e interagir com outros usuários do developerWorks.


Sobre o autor

Teodor Zlatanov surgiu com um Mestrado em Ciências em engenharia da computação da Boston University em 1999. Trabalha como programador desde 1992, usando Perl, Java, C e C++. Seus interesses estão em trabalho em análise de textos de software livre, arquiteturas de banco de dados, interfaces com o usuário e administração do sistema UNIX.




Avalie esta página


Reserve um instante para completar este formulário para nos ajudar a servi-lo melhor.



 


 


Não
são úteis
Extremamente
úteis
 






Voltar para parte superior