Cultured Perl: Perl y la nube Amazon - Parte 4

Sumérjase en el código base completo del sitio mod_perl

Esta serie se divide en cinco partes y le explica cómo crear una página Web simple para compartir fotos usando Perl y Apache para acceder a SimpleDB y a Simple Storage Service (S3) de Amazon. En esta parte, examinaremos el código base completo del sitio mod_perl (incluyendo cómo configurar el nivel más alto, qué hacer con los controladores y cómo configurar las dependencias externas).

Teodor ZlatanovGold Software Systems

Teodor Zlatanov graduated with an M.S. in Computer Engineering from Boston University in 1999. He has worked as a programmer since 1992, using Perl, Java, C, and C++. His interests are in open source work on text parsing, 3-tier client-server database architectures, UNIX system administration, CORBA, and project management. He can be contacted at tzz@iglou.com.



14-06-2009

En esta parte, usted podrá ver un sitio mod_perl completo (sólo el código, ya que las plantillas se ven en la siguiente parte). Ahora, nuestro paso tranquilo y relajado (un paseo o un medio galope, si así lo prefiere) pasará a ser un galope constante que nos llevará rápidamente en nuestro caballo mod_perl hacia Llanuras de Tensas Metáforas.

¿Cómo sacar el mayor provecho de esta serie?

Esta serie requiere que los lectores tengan conocimientos básicos de HTTP y HTML y conocimientos intermedios de JavaScript y Perl (dentro de un proceso mod_perl en Apache). También resultará muy útil que los lectores tengan algunos conocimientos sobre bases de datos relacionales, almacenamiento en disco y redes. La complejidad técnica de esta serie va aumentando a medida que vamos avanzando. Por lo tanto, vea la sección denominada Recursos si necesita ayuda con alguno de estos temas.

Le recomiendo especialmente leer el código fuente. El sitio es funcional, pero muchos detalles no se explican en su totalidad en esta serie, porque espero que usted ya los comprenda o aprenda todo aquello que no entendía. Sus motores de búsqueda y su biblioteca local o remota son sus amigos.

En particular, configurar un sitio mod_perl completo y usar el Template Toolkit (conjunto de herramientas de plantilla) son temas muy amplios que se trataron en repetidas ocasiones y, por lo tanto, no se los explica aquí. La mejor forma de aprender es responder a todas las preguntas y sortear todos los obstáculos hasta que el sitio quede funcionando. Esta serie le presenta el motor, las ruedas, la carrocería, etc.— Cargar combustible y poner el auto en marcha depende de usted.

Como en otras ocasiones, uso share.lifelogs.com en esta serie como nombre del dominio. Recuerde adaptarlo según lo que sea necesario para su entorno.

Configuración del nivel más alto

Necesita contar con un servidor Apache que funcione bien y soporte mod_perl. Por lo tanto, configure uno. Inserte la siguiente sección en su archivo httpd.conf de Apache, como se observa en el Listado 1:

Listado 1. ¿Cómo se habilita el soporte de mod_perl en el archivo de configuración de 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>

Todo se encuentra en /home/tzz, como puede observar.

Puntos importantes a tener en cuenta:

  • Existe un registro específico de errores (para que pueda observar los errores con este sitio aislado).
  • Usted transfiere las claves del desarrollador de Amazon dentro del entorno del proceso. De esta forma, el código fuente de Perl no tendrá conocimiento de éstas, en caso que el código fuente se filtre por alguna razón. (La configuración del servidor Web suele ser más segura que el código fuente.)

Tenga en cuenta que todo se controla por medio de SharePerlHandler. ¡Todas las solicitudes en share.lifelogs.com! Probablemente, usted no desee que esto sea así en un entorno de producción.

La directiva PerlRequire configura un entorno, que no hace nada especial. Una vez más, todo se encuentra en/home/tzz.

El Listado 2 muestra el archivo mod_perl_require_share de Perl.

Listado 2. Archivo mod_perl_require_share.pl
                #!/usr/bin/perl -w use strict; use
                lib '/home/tzz'; use SharePerlHandler; 1;

El controlador mod_perl

El controladormod_perl es un archivo SharePerlHandler.pm en su totalidad. Tiene varias secciones. En términos generales, son éstas: configuración, controlador principal, controladores de comentarios y fotos, utilidades generales y utilidades SimpleDB.

Las utilidades generales y SimpleDB podrían haber tenido su propio módulo. Pero a los fines de simplificar esta serie, opté por dejar todo en el mismo lugar. Las funciones de los controladores de comentarios y fotos, y de las utilidades SimpleDB, provienen del script simple_go.pl en su gran mayoría (ver la sección Descargas)), aunque tienen algunas modificaciones menores.

Comencemos con la configuración. A medida que paso por cada sección, explicaré mis decisiones. Lo más frecuente será que haga las cosas de una forma en particular para "simplificar" el tema. Es difícil crear una buena página Web. Por lo tanto, tome todo lo que encuentre aquí como una plantilla que deberá filtrar de acuerdo con sus necesidades y su presupuesto y no como un diseño ya terminado que puede comenzar a producir. Sé que el hecho de que funcione puede, de hecho, ser una distracción, pero no pude resistir la tentación de hacerlo funcionar.


Configuración de dependencias externas

El Listado 3 muestra la configuración general del archivo SharePerlHandler.pm:

Listado 3. Configuración general de 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 muchos módulos. En primer lugar, usa el módulo strict, que es fundamental para lograr una buena programación en Perl. Personalmente, yo no comenzaría a producir nada que no funcione en use strict. Además:

  • Los módulos Carp presentan mejores errores.
  • Data::Dumper se usa para la depuración general de errores.
  • POSIX se usa para muchas funciones que necesito frecuentemente.
  • Digest::HMAC_SHA1 y MIME::Base64 se usan para la política de carga de Amazon S3.
  • El módulo Template es el Template Toolkit, que nos permitirá crear páginas HTML con algunos contenidos dinámicos de manera muy rápida.
  • Data::UUID se usa para generar IDs únicas.
  • Apache::Request y Apache::Constants se usan para la interacción de mod_perl con el servidor Apache.
  • Por último, Amazon::SimpleDB::Client es de Amazon y nos permite interactuar con SimpleDB.

Si no sabe cómo instalar estos módulos desde CPAN, se hace con cpan -e 'install MODULE'. (Si no sabe esto, es muy probable que esté muy confundido en este mismo momento...)

No usamos los módulos Net::Amazon::S3 aquí, aunque lo podríamos haber hecho (en la Parte 2, dije que lo haríamos). No eran necesarios debido a varias decisiones arquitectónicas y con el objetivo de mantener la simplicidad. Daré más detalles sobre esto cuando hable sobre las cargas.

El Listado 4 muestra la configuración global de SharePerlHandler.pm.

Listado 4. Configuración global de 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();

Usted necesitará constantes para representar el modo de imágenes contra el modo de comentarios para las operaciones SimpleDB básicas. Por lo tanto, defínalas en este mismo momento. La constante VERBOSE se puede reemplazar por cualquier otro método para controlar la verbosidad en su servidor. Recuerde que cuanto más dinámico sea el control de la verbosidad, más caro será (ya que el servidor siempre necesita verificarlo).

Luego de esto, usted obtiene un objeto $templates completamente nuevo (que cargará plantillas desde /home/tzz/templates/share y usará funciones recursivas). Por último, tendrá un generador UUID que podrá usar en cualquier lugar.


El controlador principal

¡Bien! Esto es lo más importante. Aquí es donde nace la magia. ¡PRESTE ATENCIÓN! (¿Está despierto? ¡Mejor así!) Observe bien el Listado 5.

Listado 5. Más sobre la configuración 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; }

¡Ésa sí que es una función bastante larga! Es casi demasiado larga. Yo preferiría extraer las partes que pueden existir por sí mismas (es decir, la "refactorearía", como dicen los chicos hoy en día) si tuviese que ser incluso un poquito más lógico. Sin embargo, sirve perfectamente para mostrar el aspecto que tendría el controlador principal.

En primer lugar, la función tiene el objeto de la solicitud. Luego, se configura un nombre de usuario aleatorio ("bob" o "ted"). Por lo general, usted tiene su propia forma de hacer esto (quizá por medio de cookies) o puede permitir que Apache se ocupe de la autenticación y la autorización.

En la Parte 1, dije que iba a tener una tabla de usuarios en SimpleDB, pero eso hizo que el sitio fuera demasiado complicado. Por lo tanto, descarté esa idea. No es fácil buscar usuarios en SimpleDB, ya que es necesario ofrecer una forma de iniciar sesión y gestionar la información de los usuarios. Esto hacía que el código fuese demasiado largo. Por eso, perdóneme por la omisión y tenga en cuenta que— es absolutamente factible tener una tabla de usuarios en SimpleDB.

Bueno. A continuación, usted querrá controlar los parámetros relacionados con las fotos o los comentarios. Por ejemplo, cuando observa el parámetro deletecommentid, usted trata de borrar la ID de ese comentario. Nos ocuparemos de los controladores de los parámetros de las fotos y los comentarios más adelante.

A continuación, usted debe gestionar la solicitud real. Esto se hace mediante un mapeo simple que transforma "any/request/here.html" en "any_request_here.tmpl" y, luego de esto, solicita dicha plantilla. Nos debemos asegurar de que index.tmpl sea servida para la solicitud "/".

Toda URL que no tenga una plantilla correspondiente no producirá ningún dato y, de hecho, dará un error. Ésta no es una técnica de producción. Dejemos eso bien en claro. Pero sirve para configurar una página Web con unas pocas líneas. Por lo tanto, resulta muy útil cuando el objetivo consiste en lograr un demo breve y simple.

Luego, si el archivo plantilla es "upload.tmpl", usted sabe que tendrá que generar una política de cargas para S3. Por lo tanto, usted hace esto usando el archivo policy.tmpl. El nombre de usuario se pasa a esa plantilla, que es muy similar a la que aparece en la Parte 2 de esta serie. El Listado 6 le muestra una plantilla para la política.

Listado 6. Lista de código de muestra de ancho máximo
                {"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] ] }

La principal diferencia aquí es que, en vez de hacer que el nombre de usuario sea parte de la URL exitosa, usted hace que sea un parámetro, ya que esto hace que el controlador del parámetro de la imagen sea más simple. Seguiré desarrollando este tema más adelante.

Ahora, firme la política y pase a enviar los encabezados HTTP. (¡Buen trabajo, Apache!). A continuación, genere el archivo de salida necesario con los siguientes parámetros, como se observa a continuación:

  • request es la solicitud de Apache.
  • username es el nombre de usuario aleatorio
  • policy es la política de cargas de S3 (podría estar en blanco).
  • signature es la firma de la política de S3 (podría estar en blanco).
  • env es el entorno del proceso (¡No haga esto en producción!).
  • params son los parámetros, como por ejemplo de una solicitudPOST o GET.
  • fimages es una función para devolver todas las imágenes.
  • fcomments es una función para devolver todos los comentarios, bloqueados por la ID de la imagen.

Eso es todo en relación con el controlador general. El resto de la magia ocurre en los controladores de los parámetros de los comentarios y las imágenes, y en las plantillas propiamente dichas. Continuemos con nuestro viaje de arriba hacia abajo.

Los controladores de imágenes y comentarios se llaman para cada solicitud. Si encuentran parámetros que parecen aplicables, realizan una operación: agregan, modifican o borran una imagen o un comentario. Las plantillas, que estudiaremos luego de SharePerlHandler.pm, incluyen estos parámetros en formularios POST.

¡Pero no se apresure! Aquí hay suficiente información para mantenerlo entretenido,— un código de mala calidad, un arquitectura incierta y la esperanza de que usted encuentre un error que valga la pena postear en Twitter ("haha @tzlatanov sux teh worst check this out map used in void context and omg b0rken templates obv not a real h4ck3r mod_perl issolastmllnm").


El controlador de parámetros de comentarios

El Listado 7 muestra el controlador de parámetros de comentarios.

Listado 7. Controlador de parámetros de comentarios
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; }

El controlador de parámetros de comentarios tiene tres modos posibles, dependiendo de los parámetros que se le hayan transferido. Los modos son mutuamente excluyentes. En cualquier caso, el parámetro de consulta result se configura de manera apropiada para indicar el éxito si está definido. Por lo tanto, las plantillas luego pueden verificar si está configurado y actuar según sea necesario. A medida que el sitio crece, es probable que usted desee agregar otros parámetros, como last_operation o error_message.

Si el parámetro deletecommentid está configurado, el controlador llama a delete_simpledb con los valores correspondientes. Éste es el modo más simple e incondicional.

El próximo modo modifica un comentario. No verifica si el comentario ya existe. Por lo tanto, una ID incorrecta aquí crearía un comentario nuevo. La verificación no es difícil, pero es cara (hay que realizar una llamada adicional a SimpleDB, lo que es lento porque hay que pasar por toda la HTTP y a esto agregarle el tiempo de procesamiento por parte de Amazon).

Tenga en cuenta que, como cada comentario tiene su propia ID, la edición es fácil. Sin registros de comentarios individuales, usted podría haber agrupado comentarios como un atributo de imagen (un array de cadenas; cada una, un comentario). Pero en este caso, habría sido mucho más difícil editar o borrar un comentario individual. Básicamente, usted habría tenido que implementar su propia estructura de registro dentro de un comentario para representar una ID, un usuario de reparto, etc.

El modo de edición se activa por la presencia de los parámetros de consulta commentid y comment, que establecen los UUID del destino de edición y los nuevos contenidos del comentario respectivamente. El resultado es la recuperación del mismo UUID desde SimpleDB. Por lo tanto, usted podría verificar esto para ver si el campo de comentario resultante es el que usted deseaba. De lo contario, algo salió mal. Yo no verifico todo aquí con el objetivo de contribuir con la simplicidad.

El último modo, la creación de un comentario nuevo, se activa por medio de los parámetros imageid y comment. De manera opcional, tomará un UUID de referencia (cuando el comentario es un respuesta a otro comentario) y un nombre de usuario (cuando el comentario no es anónimos). Al igual que en el modo de edición, usted put_simpledblos atributos y luego los recupera sin verificar si los campos se modificaron correctamente.


El controlador de parámetros de la imagen

Este controlador es muy similar al controlador de comentarios. Por lo tanto, si se durmió durante la explicación anterior, retome desde ese punto y preste atención.

La URL de la imagen, si no se la transfiere, se construye a partir de la clave y el sector de almacenamiento de S3. De esta forma, usted tiene una interfaz consistente para controlar los redireccionamientos luego de las cargas exitosas de S3. El Listado 8 presenta el controlador de parámetros de imagen.

Listado 8. Controlador de parámetros de imagen
                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; }

El borrado de la imagen se activa por medio del parámetro deleteimageid. La edición del nombre de la imagen se realiza con los parámetros name e imageid. La creación de una imagen nueva se lleva a cabo con una URL, un nombre de usuario y un nombre de imagen. El sector de almacenamiento de la imagen es opcional y sólo debería aparecer si se llama a este controlador luego de que una carga exitosa de S3 nos redirecciona a nuestro sitio.

Recuerde lo siguiente de la política: el redireccionamiento exitoso de S3 tiene el nombre de usuario como parte de la URL como parámetro. Además, también tendrá la clave y el sector de almacenamiento, para que todo lo que tenga que hacer sea crear una imagen a partir de ellos.


Funciones de utilidad

Analicemos las funciones verdaderamente misceláneas.

Listado 9. Funciones verdaderamente misceláneas
                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 es una buena opción cuando no desee escribir printf STDERRtodas las veces. Además, también escribe un final de línea para usted. Usted será el encargado de decidir si los resultados misceláneos se dirigirán al registro de errores de Apache. Además:

  • new_uuid se usa para generar un UUID nuevo.
  • simpledb_domain_name, simpledb_image_domain_name y simpledb_comment_domain_name usan el parámetro del modo (que puede ser IMAGE_MODE o COMMENT_MODE) para dar un dominio SimpleDB.

Funciones de la utilidad SimpleDB

Las funciones de la utilidad SimpleDB son casi idénticas a las que figuran en la Parte 3 (simple_go.pl). Descárguelas de la sección Descargas, que se incluye a continuación. Éstas son las modificaciones:

  • get_comments es una función nueva para obtener todos los comentarios, codificados por ID de imagen y luego tanto la ID del comentario principal como el término noparent (no principal).
  • qlog se usa en vez deprinty la constante VERBOSE se usa en vez de $verbose.
  • El servicio se inicializa para cada solicitud que usa las claves AWS_KEY y AWS_SECRET_KEY del entorno.
  • El modo ($mode) se transfiere en vez de ser global.
  • En el caso de los errores, en vez de usar die(), usted los debe controlar de la mejor forma posible.
  • Para obtener el nombre del dominio, se usa simpledb_domain_nameen vez de una variable global.
  • Se cambió el nombre de las funciones porque "get" y "put" no son buenos nombres en un espacio de nombre que no cumple con un único propósito, como lo solía hacer simple_go.pl script.

Debería volver a mencionar que este código sólo considerará valores únicos por atributo. Si un atributo tiene un array de cadenas, sólo se devolverá una de ellas. Cuando se escriben los atributos, sólo permanecerá un valor, incluso cuando solía haber un array de valores. El código es mucho más simple gracias a esto, pero no es adecuado para usar SimpleDB con propósitos generales.


Resumen

Acaban de ver el código correspondiente a todo un sitio mod_perl, usando los fragmentos que escribimos en las Partes 2 y 3 de esta serie (los archivos a descargar también están disponibles a continuación). El sitio resultante usa Template Toolkit, S3 y SimpleDB para ofrecer funciones de carga, navegación (encadenada), edición, comentarios (anónimos o no) y borrado de imágenes.

En la Parte 5, usted se familiarizará con la versión en plantilla del sitio.


Descargas

DescripciónNombretamaño
SimpleDB utility functionssimpledb_utility.zip3KB
Sample script (from Part 2)s3form.zip2KB
Sample script (from Part 3)simple_go.zip4KB

Recursos

Aprender

Obtener los productos y tecnologías

Comentar

  • Involúcrese en la comunidad My developerWorks. Con su perfil personal y página de inicio personalizada, usted puede personalizar developerWorks según sus intereses e interactuar con otros usuarios de developerWorks.

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Lotus, WebSphere
ArticleID=412608
ArticleTitle=Cultured Perl: Perl y la nube Amazon - Parte 4
publish-date=06142009