Noticias Weblogs Foros Wiki Código

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Sponsors

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin

Picando Código

Disponible revista Linux+ Mayo 2010 – Descarga libre

Abril 30th, 2010 - [Enlace local]

Ya está disponible para la libre descarga el número de mayo de la revista Linux+

Linux+ Mayo 2010

Linux+ Mayo 2010

Los temas principales de este número:

Y mucho más.
Visiten: Revista Linux+

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Fetishcode...Thinking in objects

Learning Library de Oracle.

Abril 30th, 2010 - [Enlace local]

A

» Leer más, comentarios, etc...

Picando Código

Eclipse PyDev + PyGame – Programando juegos en Python

Abril 30th, 2010 - [Enlace local]

Python
Python

A raíz de varias conversaciones en el trabajo, nos decidimos a comenzar a implementar un videojuego. Hace tiempo que venimos comentando la idea, pero nunca nos habíamos puesto a hacer algo concreto. Hoy Pablo vino con la noticia que los otros dos interesados en el proyecto “ya habían comenzado”, y que lo iban a implementar en Flex… (“así practicábamos”).

En el intercambio de bromas (que si en C, Assembler…), insistí en usar PyGame, la biblioteca orientada al desarrollo de videojuegos en 2D orientada al manejo de Sprites. Al llegar me puse a probar cosas. Por suerte la documentación de PyGame es mucha, y bastante simple. Iván, otro de los involucrados en el proyecto, ya estuvo jugando un rato con PyGame también.

No tocaba Python desde el post Primeros pasos con Python (donde tampoco llegué demasiado lejos). Pero no costó demasiado reescribir y adaptar los ejemplos de código que encontré. Lo de indentar es una muy buena práctica y no se hace tan difícil, lo que cuesta es no poner un “;” al final de cada línea.

Configurando Eclipse

Esta vez no usé la distribución de EasyEclipse. Descargué desde Eclipse.org la versión más liviana que encontré (C/C++ 79Mb) y le instalé el plugin de PyDev:

Agregamos nuevo repositorio de instalación para Eclipse, y pegamos el URL:
http://pydev.org/updates/

Elegí un nuevo directorio de trabajo, en ~/workspace/python y lo seleccioné por defecto.

Eclipse PyDev: Nuevo Proyecto
Eclipse PyDev: Nuevo Proyecto

Ahí mismo descarguéla biblioteca PyGame:

En el directorio examples encontramos varios ejemplos de código para ayudarnos a empezar con pyGame. El archivo readme.txt muestra un resumen de cada ejemplo.

Para agregar las bibliotecas de PyGame a nuestro proyecto, vamos a las propiedades, PyDev – PYTHONPATH y agregamos la biblioteca externa:

Agregar Pygame en Eclipse PyDev
Agregar Pygame en Eclipse PyDev

Y ya estamos prontos para salir programando. Todavía me falta muchísima práctica con Python, ni que hablar de PyGame. Sin embargo, en pocas líneas ya pude levantar una ventana con Sprites y darles movimiento. Cuando quise aprolijar el código y separar en clases, los ojos ya no daban más. Me confundí un poco con la sintaxis del lenguaje, así que dejé para otro momento. A veces la ansiedad de querer sacar algo andando rápido nos hace saltear documentación, pero veo que necesito leer algo más para poder programar algo prolijo y “mostrable”.

Tengo al menos dos ideas de videojuegos “simples” en 2 dimensiones, probablemente ideales para ser implementados con estas herramientas. Espero que pasen de idea a algo concreto y visible. Pero con estas cosas “hobby”, los tiempos nunca dan…
Al menos somos varios involucrados en el proyecto, ya comentaré cómo avanza.

These examples should help get you started with pyGame. Here is a
brief rundown of what you get. The source code for these examples
is in the public domain. Feel free to use for your own projects.
Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Picando Código

Reemplazando Amarok 2 – Clementine Player

Abril 30th, 2010 - [Enlace local]

Amarok

Amarok

Amarok 2 se encuentra (al igual que todo el entorno de escritorio KDE 4) en una etapa de evolución. Al ser un producto nuevo, pasa por varias etapas de desarrollo hasta llegar a un producto de excelencia como lo era Amarok 1.4. Hoy por hoy, hay varias pequeñas molestias que me ocasiona Amarok 2 en el uso diario, y pequeñas funcionalidades que tenía la versión 1.4 que no han implementado. Todos estos detalles me fueron frustrando de a poco. Uno de ellos bastante importante: ¡cuando no encontraba el modo de reproducción aleatoria en Amarok!

Ya van varias veces en las que reproduciendo música normalmente, Amarok estalla, y tengo que volver a ejecutarlo. Tampoco se acuerda la lista de reproducción que estaba usando antes de cerrarlo. Y ni siquiera intento más reproducir de modo aleatorio, es un cuelgue atrás del otro. Además de esto, a veces las canciones se agregan a la lista de reproducción desde la colección, otras tengo que reiniciar el programa para poder agregarlas.

En un momento Amarok era el mejor reproductor para KDE, e incluso doné dinero por Amarok. Pero al final de cuentas, me terminó cansando. Aparentemente los desarrolladores se vienen preocupando más por las funcionalidades estéticas y otras, que por la estabilidad, y lograr la funcionalidad que hizo de Amarok 1.4 un reproductor excelente.

Buscando alternativas a Amarok, pensé en Songbird, con quien ya no había logrado entenderme un tiempo antes. Justo en esto, Songbird dejó de darle soporte a GNU/Linux. Sin embargo, su versión 1.7 b1 todavía soporta este sistema operativo. De todas formas, ya se abrió un fork llamado Nightingale que además de soportar GNU/Linux basado en el código de Songbird, será dirigido por la comunidad. Otra ventaja de Nightingale sobre Songbird es que se está trabajando en una biblioteca gráfica nativa, por lo que la integración con Qt sería más amigable. Este proyecto todavía no está pronto, pero habrá que estar atento, así que por ahora está descartado.

Volver a Amarok 1.4 Fast Forward

No siendo el único desconforme con la evolución de Amarok, encontré que ya habían al menos dos forks de Amarok 1.4:

Pana -  Pana audio player nació con la idea de mantener la vieja versión de Amarok. No lo probé, ya que había que compilarlo (y por alguna razón, no estaba con ganas de resolver dependencias). Aparentemente depende todavía de componentes de KDE 3.

Clementine

Clementine

Clementine

Clementine es otro fork de Amarok 1.4 con algunas partes reescritas para aprovechar ventajas de Qt4. Es multiplataforma,

Funcionalidades básicas:

Clementine 0.3 rc1

Clementine 0.3 rc1

En fin, instalarlo fue una pasada (hay paquetes .deb y .rpm). Lo que sí, debí instalar GStreamer y Pulseaudio para que sonara el audio. No implementa completamente todas las funcionalidades de Amarok 1.4 todavía. Pero está casi ahí. Y si bien Amarok 2 es mucho más lindo visualmente, cuando queremos escuchar música no necesitamos estar mirando el programa… Recién va por la versión 0.2 (yo me bajé la rc1 de la 0.3) pero el proyecto según Google Code tiene una actividad muy alta. Se arreglan los bugs bastante rápido.

Por ahora vengo bastante conforme, mientras pueda reproducir la música tranquilo, esperaré a que llegue una nueva versión de Amarok en Debian Testing para volver a probarlo. En esencia, no he abandonado Amarok, ya que el código de Fast Forward está presente en Clementine.

Espero nuevas versiones para seguir probándolo, pero tras todos estos palos a la nueva versión, me sentí en deuda. Más acciones menos palabras, va mi granito de arena y reconocimiento para que Amarok llegue a ser el mejor reproductor de música nuevamente:

Donando a Amarok

Donando a Amarok

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

xperiments.es

Ultra-light jQuery calendar

Abril 29th, 2010 - [Enlace local]

De los muchos calendarios realizados en jquery este es uno que me ha sorprendido por su estetica y uso.

Blog del autor: http://roberto.open-lab.com/2010/04/06/ultra-light-jquery-calendar/
Página de descarga: http://bugsvoice.com/applications/bugsVoice/site/test/calendarPickerDemo.jsp
Descargar: Ultra-light jQuery calendar

» Leer más, comentarios, etc...

Arragonán

Las entrañas de DNDzgz

Abril 29th, 2010 - [Enlace local]

Lo prometido es deuda, tenía pendiente escribir un poco acerca de la parte técnica del fin de semana del desafío AbreDatos y de DNDzgz. A grosso modo las tecnologías utilizadas fueron Google App Engine(GAE) y Python del lado servidor; del lado cliente fueron Javascript con jQuery, la versión 3 del API de Google Maps, algunas de las novedades de HTML5, unas gotas de CSS3 y jQTouch para ayudarnos para que tuviera pinta de aplicación nativa iPhone. Usamos Git como repositorio de código, el repositorio está concretamente en github; para los documentos, diseños, fotos, etc. utilizamos dropbox(antes del fin de semana yo no tenía ni cuenta :P ).

Logo DNDzgz

La elección de GAE fue casi instantánea cuando empezamos a hablar con gimenete acerca de presentarnos al AbreDatos, las razones: hosting gratis y capacidad de escalar mucho sin tener que gastarnos ni un euro, despreocuparnos de la parte de sistemas, ningún problema con las limitaciones por correr sobre la plataforma de Google.

Que usáramos Python, aún siendo más javeros que otra cosa, fue por que ninguno de los 2 teníamos experiencia con GAE en Java(okok, yo había hecho un pequeño experimento, pero muy poca cosa para llegar a ninguna conclusión). Por eso preferimos aprovechar su experiencia desarrollando la primera versión de debug_mode=ON con Python+GAE; mientras que varias semanas antes yo me ojeé un par de manuales de inicio rápido, retomé el ebook Python para todos que tenía a medio leer(hace muuuucho :P ) y un par de días antes, me hice en poco rato el proyecto de ejemplo de GAE. Para extraer los datos utilizamos tanto Beautiful Soup como expresiones regulares para hacer scraping de HTML o Javascript de Tuzsa y Bizi, y simplejson para cargar los datos JSON de datos.zaragoza.es.

Que utilizáramos jQuery como framework Javascript, fue una elección posterior a jQTouch(que está basado en jQuery) pero de todas formas, seguramente lo hubiéramos elegido. Google Maps es la elección “por defecto” para todo el que quiere hacer algo con mapas :P . Gimenete es quien estuvo peleando con esto, teníamos problemas con la fluidez en la navegación de los mapas, que al final consiguió mejorar… Eso sí, fuera del navegador Safari del iPhone no conseguimos que los mapas funcionaran correctamente, ni en terminales con distintas versiones de Android y ni si quiera en el Safari de Mac(tenemos que ver que pasa exactamente, tras algunas pruebas, el sospechoso principal es jQTouch).

Gracias a que iPhone(y las últimas versiones de Android) soportan parte de HTML5, se ponían a nuestra disposición algunas de esas novedades que molan tanto (Flash, tiemblaaa!! ;) ):

En fin, que debemos molar, porque nuestro proyecto es una pequeña colección de buzzwords: Cloud Computing vía Google App Engine, HTML5, iPhone… XD

» Leer más, comentarios, etc...

Buayacorp

Plugins de Desarrollo Web para Varios Navegadores

Abril 28th, 2010 - [Enlace local]

Una interesante lista de plugins para desarrollo web en los principales navegadores.

» Leer más, comentarios, etc...

xperiments.es

AS3 Condicional Switch Stament

Abril 28th, 2010 - [Enlace local]

Imaginemonoss que pudiesemos utilizar un switch stament utilizando operadores logicos en vez de operadores de igualdad.

De esta manera podriamos tener un codigo parecido al siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var value:int = 2;
switch(value){
    case < 1:
        trace("Value is less than 1");
        break;
    case 2:
        trace("Value definitely equals 2");
        break;
    case >= 3:
        trace("Value is greater than or equal to 3");
        break;
    case > 1 && < 3:
        trace("Value is greater than 3 and less than 5");
        break;
    case !== 5:
        trace("Value definitely doesn't equal 5");
        break;
}

Buscando por la red encontre esta solucion:

1
2
3
4
5
6
7
8
9
10
11
12
var value:int = 2;
switch (true) {
    case value < 1:
        trace("Value is less than 1");
    break;
    case value == 1:
        trace("Value equals 1");
    break;
    case value > 1:
        trace("Value is greater than 1");
    break;
}

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

Web SQL

Abril 28th, 2010 - [Enlace local]

La API Web SQL brinda la posibilidad de acceder a una base de datos local en el cliente (navegador del usuario) desde Javascript.

A día de hoy, es soportada desde Chrome/Chromium/Iron 4, Opera 10.5 y Safari 4. A nadie le sorprender que Internet Explorer 8 no lo soporte, aunque a más de uno le sorprenderá que Firefox/SeaMonkey siga apostando por la alternativa no estándar de MDM

Típicamente Web SQL está implementado sobre SQLite, que hace que sea ligero y rápido.

De momento no hay demasiados sites que aprovechen Web SQL, aunque dado lo sencillo que es de usar, preveo una paulatina migración de base de datos de servidor a cliente, al menos en aquellos casos que tenga sentido.

Como lo más sencillo, es verlo directamente sobre un fragmento de código, veamos que pinta tiene esta API.

Para ello he creado un sencillo programa, que puedes acceder aquí (1 Kb. en formato HTML), que crea una tabla SQLite para una agenda telefónica, la llena con 100 registros, y a partir de ahí, los cuenta, y los muestra. Dentro de la simplicidad del pequeño snippet, se muestra como conectar, crear la BD, insertar, consultar, contar, y por supuesto, comprobar si el navegador soporta Web SQL:

if (window.openDatabase)
{
var moDb=openDatabase('WebSQL', '1.0', 'HTML5 WebSQL demo', 128*1024);

moDb.transaction(
function(oTransaction)
{
oTransaction.executeSql('DROP TABLE IF EXISTS t_mstr_agenda;');
oTransaction.executeSql('CREATE TABLE t_mstr_agenda (agenda_nombre TEXT, agenda_telefono TEXT);');
for (var iCont=0; iCont<100; iCont++)
{
oTransaction.executeSql('INSERT INTO t_mstr_agenda (agenda_nombre, agenda_telefono) VALUES (\'Nombre ' + iCont + '\', \'Telefono ' + iCont + '\');');
}

oTransaction.executeSql('SELECT * FROM t_mstr_agenda', [], function (oTransaction, oResults)
{
var iLen=oResults.rows.length;
var sRes='';
for (var iCont=0; iCont {
sRes=sRes + oResults.rows.item(iCont).agenda_nombre + ': ' + oResults.rows.item(iCont).agenda_telefono + '\n';
}
alert(sRes);
});
}
);
}
else
{
alert('Web SQL no soportado.');
}

» Leer más, comentarios, etc...

Fetishcode...Thinking in objects

Nueva release de JDeveloper.

Abril 27th, 2010 - [Enlace local]

A

» Leer más, comentarios, etc...

Fetishcode...Thinking in objects

Cambiar el color de las filas en tablas

Abril 27th, 2010 - [Enlace local]

A

» Leer más, comentarios, etc...

Variable not found

Maxlength en cuadros de texto de formularios MVC

Abril 26th, 2010 - [Enlace local]

ASP.NET MVC Resulta algo paradójico que ASP.NET MVC sea capaz de generar código para comprobar tanto en cliente como en servidor que la longitud del texto introducido sea menor que la indicada con la anotación [StringLength], y sin embargo, los helpers habituales no generen el atributo maxlength en el tag <input type="text">.



Podemos comprobarlo muy fácilmente. Por ejemplo, dada una entidad del Modelo como la siguiente:



public class Persona
{
  [StringLength(20, ErrorMessage="Máximo {1} caracteres")]
  public string Nombre { get; set; }
}


Si creamos su vista de edición por defecto e introducimos en ella los validadores en cliente, obtendremos en tiempo de ejecución un resultado como el que podemos apreciar en la siguiente captura de pantalla:


image
Es decir, los validadores automáticos, tanto en cliente como en servidor, nos avisan de que hemos superado el número máximo de caracteres a introducir, pero no se impide que esto se produzca mediante el atributo maxlength de la etiqueta el tag <input type="text">.



Afortunadamente hay varias formas de solucionar este pequeño inconveniente, como creando nuevos helpers o utilizando plantillas de edición personalizadas. En este post veremos cómo implementar la primera opción, creando un helper que realice la tarea de forma automática.

Html.LimitedTextBoxFor()

Vale, sé que no es un nombre estupendo para el helper, pero de momento va a tener que valer con ese ;-P. La idea es que podamos generar text boxes que limiten el número de caracteres permitidos en función de lo indicado en las anotaciones del Modelo. Es decir, sobre el ejemplo anterior, ocurriría lo siguiente:



// En la vista:
<%= Html.LimitedTextBoxFor(model => model.Nombre ) %>
 
// HTML resultante:
<input id="Nombre" maxlength="20" name="Nombre" type="text" value="" />


El código del helper es el siguiente, y lo comento brevemente justo a continuación:



public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
                this HtmlHelper<TModel> html, 
                Expression<Func<TModel, TProperty>> expression, 
                IDictionary<string, object> htmlAttributes)
{
  // Obtenemos los metadatos de la propiedad
  ModelMetadata metadata = 
         ModelMetadata.FromLambdaExpression(expression, html.ViewData);
 
  // Obtenemos la información utilizada para validar el tamaño del texto
  ControllerContext cctx = html.ViewContext.Controller.ControllerContext;
  StringLengthAttributeAdapter stringLengthValidator =
                    metadata.GetValidators(cctx)
                   .OfType<StringLengthAttributeAdapter>()
                   .FirstOrDefault();
 
  if (stringLengthValidator != null)
  {                                               // Si hay validación de este tipo...
    var parms = stringLengthValidator               
                     .GetClientValidationRules()     
                     .First()                        
                     .ValidationParameters;
                                                 // Obtenemos el valor del
    int maxlength = (int)parms["maximumLength"]; // tamaño máximo para el texto...
 
    if (htmlAttributes == null)
      htmlAttributes = new RouteValueDictionary();
 
    htmlAttributes.Add("maxlength", maxlength);  // y añadimos el atributo maxlength
  }
 
  return html.TextBoxFor(expression, htmlAttributes);
}


En primer lugar, estamos accediendo a los metadatos de la propiedad partiendo de la expresión lambda que recibimos como parámetro. Desde estos metadatos obtenemos, si existe, el validador asociado al atributo [StringLength], que es de tipo StringLengthAttributeAdapter.



Una vez obtenido el validador, buscamos en éste la información que será suministrada a los scripts en cliente, en particular el valor del parámetro “maximumLength”, introduciéndolo en la colección de atributos HTML que finalmente se envía al helper original asociando este valor al atributo maxlength de la etiqueta a generar.



Ahora, para simplificar las llamadas al helper desde las vistas, creamos un par de sobrecargas, similares a las que utilizamos normalmente en TextBoxFor():



public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
                  this HtmlHelper<TModel> html, 
                  Expression<Func<TModel, TProperty>> expression, 
                  object htmlAttributes)
{
  return html.LimitedTextBoxFor<TModel, TProperty>(
           expression, 
           ((IDictionary<string, object>)new RouteValueDictionary(htmlAttributes))
  );
}
 
public static MvcHtmlString LimitedTextBoxFor<TModel, TProperty>(
                  this HtmlHelper<TModel> html, 
                  Expression<Func<TModel, TProperty>> expression)
{
  return html.LimitedTextBoxFor(expression, null);
}


Y eso es todo. Si sustituimos en nuestras vistas las llamadas a TextBoxFor  por LimitedTextBoxFor tendremos la cuestión solucionada. Otra posibilidad, bastante más cómoda, sería retocar las plantillas de edición generadas por Visual Studio para que incluyan las llamadas a estos nuevos helpers.



Podéis encontrar el código fuente completo en Skydrive.



Publicado en: Variable not found.

Hey, ¿sabes que estoy en Twitter?



» Leer más, comentarios, etc...

Picando Código

Cambio de imagen en Picando Código

Abril 26th, 2010 - [Enlace local]

Hola soy Fernando el pseudo diseñador gráfico / programador:

Después de más de dos años con el mismo tema de WordPress, decidí renovar un poco el blog. Este tema fue comenzado desde cero, sin basarme en otros temas de WordPress, como había hecho anteriormente. Empecé con un directorio vacío, y fui agregando archivo y escribiéndolos en Kate: style.css, index.php, etc.

El CSS, XHTML y los colores fueron decididos a medias con Rosina, a quien le debo también el nuevo logo :D
El resto del arte fue diseñado con GIMP con una onda “Pixel art” que traté de imitar :P

Debo agregar que todo el código del tema validaba como XHTML 1.0 Transitional y CSS 2.1, pero al subirlo se rompió la validación debido a algunos plugins que agregan su propio CSS y XHTML inválido. Voy a ir corrigiendo esto, así como otros detalles que fueron surgiendo al tenerlo “en producción”.

Dos sitios que me fueron de mucha ayuda durante el proceso:

W3c Schools – Referencia de CSS, donde todavía tengo poca práctica, pero aprendí varias cosas al haber hecho el tema de cero.

WordPress Template Tags – Las funciones PHP de WordPress que fui usando.

Espero comentarios de todos, si les gusta, si no, si le cambiarían algo. Como siempre, el tema está sujeto a modificaciones que iré haciendo en el camino. Se puede decir que todavía no está completo, pero la nueva imagen de Picando Código ya está definida :)

Espero comentarios de todos, si les gusta, si no, si le cambiarían algo. Como siempre, el tema está sujeto a modificaciones que iré haciendo en el camino. Se puede decir que todavía no está completo, pero la nueva imagen de Picando Código ya está definida :)

Comparte: Print del.icio.us Facebook Google Bookmarks BarraPunto Bitacoras.com Tumblr Twitter

» Leer más, comentarios, etc...

Variable not found

Enlaces interesantes 3

Abril 25th, 2010 - [Enlace local]

Estos son los enlaces publicados en Variable not found en Facebook desde el lunes, 12 de abril de 2010 hasta el domingo, 25 de abril de 2010. Espero que os resulten interesantes :-)

Y no olvides que, si te interesa, puedes seguir esta información en vivo y en directo desde Variable not found en Facebook, o a través de Twitter.



Publicado en: Variable not found



» Leer más, comentarios, etc...

Picando Código

Mañana FLISOL 2010 en Latinoamérica y España :D

Abril 24th, 2010 - [Enlace local]

Mañana sábado 24 de abril de 2010, no se olviden de asistir al FLISOL: Festival Latinoamericano de Instalación de Software Libre.

¡LA ENTRADA ES LIBRE Y GRATUITA!

FLISOL 2010

FLISOL 2010

Personalmente voy a asistir, igual que los últimos dos años, a la edición de Montevideo. Para que no se me pongan quisquillosos en los comentarios, cito todas las ciudades confirmadas en Uruguay:

¿Dónde y cuándo?

Instituto PAOF (Programa de Fortalecimiento de las Artes, Artesanías y Oficios del Uruguay)

Cabe destacar que contaremos con la presencia de representantes de OpenOffice y Mozilla Argentina, además de expositores de alto nivel de la comunidad del software libre uruguayo.

FLISOL

FLISOL

Visita el sitio oficial de FLISOL, para ver dónde se realiza en tu país y ciudad. Además de Argentina, Bolivia, Brasil, Chile, Colombia, Costa Rica, Cuba, Ecuador, El Salvador, Guatemala, Honduras, México, Nicaragua, Panamá, Paraguay, Perú, Rep. Dominicana, Venezuela y Uruguay, este año se suman los hermanos de España también! :)

Ya comentaré cómo estuvo, feliz FLISOL para todos! :D

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

LOCs en programas Open Source

Abril 22nd, 2010 - [Enlace local]

Hace 5 años, en Lenguajes y programas, analizaba el lenguaje de programación principal en el que estaban escritas aplicaciones de uso mayoritario.

En el índice de proyectos de código abierto de Ohloh, se nos muestran multitud de proyectos con el código fuente disponible. El punto interesante, es que ofrecen la cifra de LOCs (Lines Of Code) de cada uno de ellos.

Los LOC fueron una métrica muy utilizada en el pasado para el análisis de la complejidad de los proyectos informáticos, y aunque hoy día, se tiende a otras fórmulas, siguen teniendo la ventaja de reflejar con mucha claridad el esfuerzo de implementación necesario.

Sabías por ejemplo que OpenOffice son casi 100.000 archivos en su mayoría de código C++, y que roza los 30 millones de lineas de código?
¿O que el servidor web Apache son 1.700 ficheros en su mayoría XML y C, totalizando 1 millón de lineas?
¿Te sorprende que Wget roce las 100.000 lineas de código C?

» Leer más, comentarios, etc...

Cerebro en la Sombra » Técnico

Nuevo proyecto en 5 horas: UsayTira.me, direcciones de correo de usar y tirar explicado paso a paso

Abril 21st, 2010 - [Enlace local]

Parece que últimamente me aburro mucho :P . Hace unos días, leyendo un artículo, se me ocurrió de nuevo explicar cómo se hacen esos sistemas de correo instantáneos que se suelen utilizar para registrarse en webs y que después no te envíen spam :P . La idea me pareció muy adecuada para poner un ejemplo práctico de algo que vimos hace tiempo sobre otras utilidades para un servidor de correo y, tal y como me ocurrió hace unos meses, lo que era un artículo se convierte en proyecto.

La idea, por tanto, es crear un sistema que, sin necesidad de ningún registro, te permita crear una cuenta de correo y recibir y leer emails en ella por espacio de una hora, al cabo de este tiempo la cuenta se autodestruye y todos los emails serán devueltos. En nuestra aplicación tendremos dos opciones para crear la cuenta, aleatoria o personalizada, creo que no hacen falta más explicaciones. Una vez usas una cuenta puedes volver a ella más tarde cuando la necesites volviendo a crear una cuenta personalizada con el mismo usuario. Esto es útil, por ejemplo, para que te recuerden la contraseña que utilizaste para registrar en aquella web de descarga de películas y de la que ya no te acuerdas ;) .

Qué necesitamos

Eso es todo, sólo hay que juntar las piezas adecuadamente.

Preparando Qmail

Nuestro primer paso, antes de ponernos con los temas puramente web, será configurar adecuadamente el servidor de correo para nuestro propósito. Para ello necesitamos crear un usuario del sistema que reciba todo el correo dirigido a un dominio. Esto lo podemos hacer del siguiente modo:

  1. adduser -g users -s /dev/null usaytirame
  2. passwd usaytirame UNACLAVESUPERCOMPLICADA

Añadimos nuestro nombre de host en:

/var/qmail/control/rcpthosts

  1. usaytira.me

Y el usuario al que dirigiremos los correos en:

/var/qmail/control/virtualdomains

  1. usaytira.me:usaytirame

Reiniciando Qmail conseguiremos que los correos enviados a cualquier cuenta del dominio vayan al buzón del usuario indicado, es decir cualquiercosa[arroba]usaytira.me.

Pero no queremos que los correos vayan al buzón del usuario sino simplemente procesarlos. Para eso editamos el archivo:

/home/usaytirame/.qmail-default

  1. |preline /usr/bin/php /home/usaytirame/procesa.php

Sólo con esa línea. Con este comando conseguimos redirigir los correos entrantes a un script en el que podremos recuperarlos y reutilizarlos a nuestro antojo como veremos a continuación.

Procesando los emails entrantes

Vamos a comenzar por crear una base de datos donde guardaremos los emails recibidos. Como queremos poder acceder a los emails dirigidos a cada cuenta independientemente, haremos dos tablas, una (emails) la utilizaremos como tabla maestra para las cuentas de correo que se creen y en la otra (correos) iremos almacenando los emails recibidos para cada una de esas cuentas.  La estructura sería poco más o menos la siguiente:

  1. CREATE TABLE IF NOT EXISTS `emails` (
  2.   `idEmail` int(11) NOT NULL auto_increment,
  3.   `fecha` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
  4.   `email` varchar(255) NOT NULL,
  5.   `ip` varchar(15) NOT NULL,
  6.   PRIMARY KEY  (`idEmail`),
  7.   KEY `email` (`email`)
  8. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
  9.  
  10. CREATE TABLE IF NOT EXISTS `correos` (
  11.   `id` int(11) NOT NULL auto_increment,
  12.   `idEmail` int(11) NOT NULL,
  13.   `de` varchar(255) NOT NULL,
  14.   `para` varchar(255) NOT NULL,
  15.   `subject` varchar(255) NOT NULL,
  16.   `fecha` varchar(255) NOT NULL,
  17.   `body` text NOT NULL,
  18.   `fullmail` text NOT NULL,
  19.   PRIMARY KEY  (`id`),
  20.   KEY `idEmail` (`idEmail`)
  21. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

Creo que es suficientemente descriptiva. El campo fecha de emails nos servirá para controlar los 60 minutos de duración máxima.

Pues ya tenemos todo preparado. Veamos cómo procesamos los emails.

/home/usaytirame/procesa.php

  1. include ("mimeDecode.php");
  2.  
  3. $email=file("php://stdin");
  4. $email=implode("", $email);
  5.  
  6. $params[‘include_bodies’] = true;
  7. $params[‘decode_bodies’] = true;
  8. $params[‘decode_headers’] = true;
  9. $params[‘input’] = $email;
  10. $structure = Mail_mimeDecode::decode($params);
  11.  
  12. $subject = quoted_printable_decode(trim($structure->headers[’subject’]));
  13. $ddate = quoted_printable_decode(trim($structure->headers[‘date’]));
  14. $from = quoted_printable_decode(trim($structure->headers[‘from’]));
  15. $to = quoted_printable_decode(trim($structure->headers[‘to’]));
  16.  
  17. if(ereg("<(.*)>", $to, $p))
  18.     $to=$p[1];
  19. $to=strtolower($to);

Tenemos la primera parte del procesado preparada. De aquí debemos destacar:

  1. $email=file("php://stdin");

Con esto leemos desde la entrada estandar el contenido del email. Recordad que no estamos en una aplicación web sino en un script ejecutado en la consola del sistema.

La otra línea importante es:

  1. $structure = Mail_mimeDecode::decode($params);

Con ella conseguimos procesar el email y separar su estructura en un array asociativo con los distintos parámetros. Os ayudará mucho ver el contenido de ese array:

  1. print_r($structure)

Llegados a este punto podemos hacer una prueba. Necesitamos el contenido completo de un email, podemos sacarlo de nuestro cliente de correo o del propio servidor.

  1. cat prueba.eml | /home/usaytirame/procesa.php

Si todo ha ido bien veremos en pantalla un array con la estructura del correo.

No voy a detallar todo el proceso ya que alargaría mucho el artículo. Vamos con el siguiente paso:

  1. $query="select idEmail from emails where email=".$conn->quote($to);
  2. $rs=$conn->Execute($query);
  3. if($rs->recordcount()==0){
  4.         exit(100);
  5. }else{
  6.         $idEmail=$rs->fields[‘idEmail’];
  7.         $content = get_content($structure);
  8.         $query="insert into correos
  9.            (idEmail, de, para, subject, fecha, body, fullmail)
  10.            VALUES
  11.           ($idEmail,
  12.            ".$conn->Quote($from).",
  13.            ".$conn->Quote($to).",
  14.            ".$conn->Quote($subject).",
  15.            ".$conn->Quote($ddate).",
  16.            ".$conn->Quote($content).",
  17.            ".$conn->Quote($email).")";
  18.         $rs=$conn->Execute($query);
  19. }

En la primera parte del script comprobamos si la cuenta a la que va destinado el email existe en nuestra base de datos, si no, muy importante, devolvemos un código 100 que indica a qmail que debe devolver el correo ya que no existe el usuario.

Si la cuenta existe recogemos el cuerpo del mensaje. Yo lo hago con la función get_content, que analiza la estructura del correo y devuelve el contenido. Esta parte os la dejo a vosotros. Básicamente consiste en comprobar las distintas partes que puede tener un correo y devolver lo que estimemos oportuno. Un detalle muy importante a tener en cuenta es la codificación tanto del email como de nuestra base de datos y la aplicación web. En mi caso las dos últimas están en UTF-8, con lo que debo convertir todos los textos del email a esta misma codificación. La estructura que teníamos inicialmente en un array tendrá parámetros que nos indican el charset en el que viene el email. Las funciones de conversión de PHP te pueden ser útiles: iconv, utf8_encode, etc.Finalmente introducimos todos los campos del email en la base de datos.

Puedes volver a probar a procesar el email de prueba tal y como hicimos antes. Recuerda que debes añadir el registro de la tabla emails para que  guarde el correo, si no la cuenta no existirá. Una vez te funcione desde la línea de comandos ya puedes probar a enviarte un correo real :) .

La aplicación web

No creo que hacer la parte web propiamente dicha necesite muchas explicaciones. Tenemos ya todos los elementos preparados, sólo debemos añadir los formularios para crear la cuenta de correo (aleatoria o personalizada) y, con un poco de ajax, ir cargando los correos a medida que van llegando. No  hay más truco.

Añadiré, eso sí, algunas aclaraciones interesantes.

Para crear las cuentas aleatorias, en vez de utilizar una secuencia aleatoria de números y letras, que daría como resultado algo ininteligible, usamos los diccionarios que comentaba más arriba. Los importamos en una tabla de la base de datos y simplemente tenemos que buscar aleatoriamente una palabra que no esté utilizada todavía como cuenta de correo, sencillo y muy impactante visualmente ya que estás ofreciendo cuentas legibles y con sentido.

Como en cualquier otra aplicación accesible públicamente, hay que añadir algún tipo de mecanismo de seguridad. En mi caso lo he hecho implementando una blacklist de direcciones IP. Cada vez que se crea una cuenta actualizo en una base de datos el número de cuentas que se han creado desde esa IP, si pasa del límite que estimemos oportuno, esa IP se pasa a la tabla de lista negra y cuando intente crear una nueva cuenta no se le dejará.

Nos falta una cosa: Eliminar las cuentas que tienen más de una hora. Muy sencillo, una tarea en el CRON que ejecuta un script que lanza una consulta a la base de datos que elimina las cuentas (y sus correos asociados) que se crearon hace más de 60 minutos.

Finalmente he añadido la opción de reiniciar esos 60 minutos de tiempo, simplemente actualizando el timestamp de la base de datos y algunos efectos visuales para plegar y desplegar los mensajes usando Jquery.

No hay mucho más, en unas cinco horas tenemos la aplicación hecha y funcionando.

Conclusiones

Como conclusión, la misma que hice hace unos meses con el primer proyecto. La copio tal cual porque es igual de válida.

Bueno, y todo este rollo ¿para qué?. Pues muy sencillo, para que veais que hoy en día la tecnología está al alcance de todos, es sencillo y rápido crear un proyecto en Internet, hay de todo por todas las esquinas, la tecnología no es lo importante, lo que verdaderamente cuenta es cómo mueves ese producto tecnológico para rentabilizarlo y obtener un beneficio de él.

Ya tengo mi proyecto superchulo funcionando, sólo me ha costado unas 5 horas de trabajo. Le he puesto un poco de Adsense por aquí y por allí. ¿Y ahora qué? ¿A esperar a que la gente entre y me haga millonario? :P Es mucho más complicado que eso como todos sabéis, primero tienes que tener una masa de usuarios elevada que le dé movimiento al proyecto y después tienes que conseguir que la mayoría de ellos sean gente normal, no gente técnica, usuarios avanzados que no pagamos por nada ni pinchamos en publicidad :P .

Hoy en día, en Internet, como en cualquier negocio, las técnicas de marketing y venta son mucho más importantes que la tecnología en sí misma, es duro reconocerlo, pero es así. De nada sirve que tengas el mejor producto del mundo mundial si no consigues que la gente lo utilice y se deje dinero, así de claro. Si tienes los conocimientos adecuados para mover el negocio, no te preocupes, la tecnología te la aporta cualquier partner por un módico precio, pero poner en manos de otro toda la estrategia de ventas de tu negocio no está tan claro ¿no?.

Espero que os sirva de algo el artículo. He querido mostrar, fundamentalmente, cómo utilizando algunas librerías que puedes obtener sin coste puedes hacer algo realmente útil y funcional con muy poco esfuerzo. Seguro que sacáis alguna idea.

Perdón por el rollo :P , al final me ha costado mucho más escribir el artículo que implementarlo.

Podíamos haber añadido una opción que he visto por ahí que consiste en crear una cuenta automáticamente cada vez que entra un email para una cuenta que no existe, pero estaríamos creando cuentas para todo el spam que recibamos, así que prefiero no hacerlo. Si quisierais hacerlo creo que ya sabéis cómo.

» Leer más, comentarios, etc...

Arragonán

¿Quién tiene más servidores?

Abril 20th, 2010 - [Enlace local]

Basado en los datos de Who Has the Most Web Servers? de Data Center Knowledge

Vía @javahispano

» Leer más, comentarios, etc...

Variable not found

¿Esa enumeración está vacía?

Abril 20th, 2010 - [Enlace local]

¿Sómos los primeros en llegar al estadio? Casualmente encuentro en el post de Chris Eargle “Any() versus Count()” un tema del que pensaba escribir hace tiempo y al final dejé en el tintero: ¿cómo podemos determinar si una enumeración está vacía? Vale, es bien fácil, una enumeración está vacía si tiene cero elementos.



Si trabajamos con un array, podemos consultar la propiedad Length; si se trata de una colección, podemos utilizar la propiedad Count, que también nos devolverá el mismo dato de forma directa.



Sin embargo, cuando procesamos información es frecuente tratar con tipos de datos enumerables cuya implementación exacta desconocemos, y en los que no tenemos acceso a ninguna propiedad que nos permita conocer el número de elementos exactos que tiene almacenados. Por ejemplo, esto ocurre cuando obtenemos un conjunto de datos en forma de IEnumerable o trabajamos con LINQ sobre alguna fuente de información.



Pues bien, en estos casos hay que ser algo prudentes con la forma de consultar el número de elementos. Me he topado con código propio en el que, simplemente por despiste, utilizaba el método Count(), facilitado por LINQ para las enumeraciones y otras colecciones de datos, con objeto de saber si una lista estaba vacía:



var prods = services.GetProductsByCategory(category);
if (prods.Count() > 0)
{
   // Hacer algo con los elementos de la lista
}
else
{
   // No hay elementos
}


Seguro que ya os habréis percatado de que eso está mal, muy mal. El método Count() recorrerá uno por uno los elementos para contarlos, retornando el número exacto de ellos. En escenarios de un gran número de elementos, o cuando es costoso obtener cada elemento (como al traerlos de una base de datos) puede suponer un consumo de recursos enorme.



Y justo por esto existe el método Any(), que comprueba únicamente si existe al menos un elemento en la colección. Internamente este método itera sobre la colección retornando true cuando encuentra el primer elemento, por lo que es mucho más eficiente que el anterior:



var prods = services.GetProductsByCategory(category);
if (prods.Any()) // Mucho mejor :-)
{
  // Hacer algo con los elementos de la lista
}
else
{
  // No hay elementos
}


La utilización de Any() también es interesante para comprobar la existencia de elementos que cumplan una condición, expresada en forma de predicado; retornará true cuando encuentre el primer elemento que lo haga cierto:



if (pedidos.Any(p => p.Pendiente))
{
   // Mostrar alerta, hay al menos un pedido pendiente
}


Estamos en la puerta de un Estadio y queremos saber si vamos a ser los primeros en entrar al recinto… ¿le preguntaríamos al portero el número exacto de aficionados que ya están dentro para, si es cero, saber que somos los primeros? ¿O nos bastaría simplemente con preguntarle si hay alguien? ;-P



Publicado en: Variable not found

Hey: ¡estoy en Twitter!



» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

Cuidado: Descargas automáticas

Abril 20th, 2010 - [Enlace local]

En la mayoría de navegadores recientes, con la salvedad de Internet Explorer, se pueden configurar las descargas para que automáticamente se guarden en una carpeta determinada sin intervención alguna del usuario.

En el caso de Safari, Firefox, Seamonkey u Opera, las opciones están relativamente escondidas, y no suele ser habitual que los usuarios lo cambien.

Con Internet Explorer, sencillamente no existe tal opción.

En cambio, con Chrome/Chromium/Iron, la mencionada preferencia está más que accesible, y he visto en varios equipos que está configurada de esta manera, lo cual, es sin duda una grave brecha de seguridad.

Además, como lo más común es fijar la ubicación por defecto para el contenido descargado en un lugar bien accesible, nada es tan sencillo como crear una página que obtenga archives con nombre más o menos engañosos, y que pretendan ser ejecutados accidentalmente. Pienso en los ya tradicionales backdoors como keygen.exe o crack.exe.

Aquí, he creado una sencilla página HTML que fuerza la descarga de un archivo VBS que alberga en su interior un VBS sacando un mensaje por pantalla. No os preocupéis, porque lo único que hará es obtener un ZIP, que VBS que saca por pantalla un mensaje inofensivo.

Hay que reconocer que ciertas extensiones de archivos directamente ejecutables como EXE o VBS muestran una advertencia en la implementación del navegador de Google, aunque el riesgo de descargar un ZIP como el demostrado, es evidente.

Claro que no tendría por qué ser así, y podría ser un contenido realmente malicioso, que se descargaría sin que apenas te dieras cuenta, y que quedaría alojado en tu carpeta predeterminada de descargas esperando a que lo ejecutaras por accidente o curiosidad.

» Leer más, comentarios, etc...

4 bits blog

Manejando varias claves con SSH

Abril 20th, 2010 - [Enlace local]

La mejor funcionalidad de SSH es poder usar pares de claves (pública/privada) para autenticarse en una máquina sin necesidad de introducir una contraseña. El problema radica cuando necesitas usar varios pares de claves, por ejemplo: para acceder diferentes máquinas sin compartir un mismo par de claves. Pero como con todo, siempre hay una solución para poder usar varios pares de claves distintos.

Partiendo de que se han generado dos pares de claves:

$ ssh-keygen -t rsa -f ~/.ssh/id_rsa.work -C "fran@trabajo"
$ ssh-keygen -t rsa -f ~/.ssh/id_rsa.home -C "fran@casa"

La forma sencilla es crear el archivo «~/.ssh/config», añadiéndole las siguientes líneas:

IdentityFile ~/.ssh/id_rsa.work
IdentityFile ~/.ssh/id_rsa.home

De este modo, cada vez que SSH conecte con una máquina intentará usar alguna de esas dos claves. Sin embargo, SSH permite realizar un control más granular sobre las claves, para ello habría que tener un archivo «~/.ssh/config» similar al siguiente:

Host 192.168.0.100
  IdentityFile ~/.ssh/id_dsa.home
  User franchukelly

Host ssh.trabajo.com
  IdentityFile ~/.ssh/id_rsa.work
  User fran
  Port 2211

Dónde cada campo Host permite definir una pequeña configuración que se usará de forma predeterminada cuando se realice una conexión a la dirección indicada. Por ejemplo:

$ ssh ssh.trabajo.com

SSH usaría la clave «id_rsa.work», junto al usuario «fran» y el puerto 2211.

Basado en Multiple ssh private keys.

» Leer más, comentarios, etc...

phpleo.Blog

Lima Agile Day 2010

Abril 20th, 2010 - [Enlace local]

El sábado pasado (17 de abril) se celebró por segundo año consecutivo el “Lima Agile Day” en su edición 2010. Ha sido toda una experiencia tanto organizarla como exponer en él, con el tema de “Visual Management”. Una de las técnicas que he estado usando en diferentes trabajos después del Cerfied ScrumMaster y que me ha ayudado muchísimo al momento [...]

» Leer más, comentarios, etc...

Arragonán

Nuestra aportación en el Desafío AbreDatos 2010: DNDzgz.com

Abril 19th, 2010 - [Enlace local]

Este fin de semana se celebró el Desafío AbreDatos 2010, desde las 00:00 de la noche del Viernes al Sábado hasta las 00:00 del Domingo al Lunes, 48 horitas trabajando para desarrollar servicios que utilizaran datos de fuentes públicas. El desafío lo convocaba la asociación Pro Bono Publico para tratar de concienciar de la necesidad de que se abran los datos generados con dinero público(o sea, el nuestro); y por lo que dicen, nos habíamos presentado 47 equipos de los que hemos conseguido algo funcional unos 30. Y como publiqué en el anterior post, estuve participando.

El equipo del que formaba parte era closin, donde he programado con Alberto Gimeno, la encargada de diseño es Mamen Pradel y el responsable de marketing y comunicación es Lucas Aisa. Aún con la desventaja de que sólo habíamos trabajado anteriormente juntos Mamen y yo, creo que hemos sido un equipo muy compensado y junto al buen rollo durante todo el fin de semana, se ha notado en el resultado final con DNDzgz(o Dónde en Zaragoza ;) ).

DNDzgz TEAM

La idea de DNDzgz, era principalmente crear una aplicación web móvil que mostrara servicios ciudadanos de Zaragoza geolocalizados y su información útil asociada, que además tuviera aspecto de aplicación nativa de iPhone(sin cerrarnos a que funcionara en otros terminales/navegadores, claro).

Nuestra idea inicial fue extraer los datos sólo de las fuentes que aparecen en datos.zaragoza.es, pero la información de servicios como el autobús urbano o el bizi no eran suficientes para nuestro objetivo:

Tarde/noche del sábado #abredatos #t10 #dndzgz

Hay muchas cosas que seguramente se echarán de menos en la aplicación, a bote pronto: favoritos/acceso rápido para ver si hay bizis en mis estaciones habituales, conocer la parada del 30 más cercana a mi posición, la estación de bizi con aparcamientos libres más cercana a mi posición… además de añadir otros servicios ciudadanos.

Se puede pensar que muchas de estas funcionalidades no han sido posibles de añadirse a causa de la limitación de las 48 horas, pero la principal razón de no poder añadir más funcionalidades, fue el tener que perder tiempo haciendo scraping para hacernos con todos los datos que necesitábamos. Y hay que ser consciente que eso habrá pasado en casi todos(por no decir todos) de los 47 equipos que nos presentamos al desafío… con el nivel que se ve en los resultados, ¿que se hubiera conseguido con datos abiertos?

Y nada, sólo quería felicitar a la gente de Pro Bono Publico tras la organización del evento a los equipos por sus resultados, y por supuesto agradecer a todos los que se han presentado su esfuerzo por tratar de crear servicios que nos resulten de utilidad a los ciudadanos.

Y ahora la segunda parte, para que haya valido la pena la paliza de este fin de semana, a intentar hacer llegar estos servicios a los ciudadanos! :)

Comida del domingo #abredatos #t10 #dndzgz

PD: Como ha quedado un tocho bastante largo, intentaré escribir durante la semana otro post sobre detalles más técnicos de las tripas de DNDzgz

» Leer más, comentarios, etc...

Variable not found

Cambios recomendables en el retorno de helpers en MVC 2

Abril 19th, 2010 - [Enlace local]

En la versión 1.0 de MVC, lo habitual era que los métodos helpers destinados a generar código de marcado retornaran un cadena de caracteres, como en el siguiente ejemplo:



public static class Helpers
{
  public static string Image(this HtmlHelper helper, string src, string alt)
  {
    TagBuilder tb = new TagBuilder("img");
    tb.Attributes["src"] = src;
    tb.Attributes["alt"] = alt;
    return tb.ToString(TagRenderMode.SelfClosing);
  } 
}


Que podía ser utilizado desde una vista de la siguiente forma, enviándolo al cliente con un bloque de salida directa de texto:



<%= Html.Image("/img/logo.gif", "Logo") %> 


Hasta aquí todo correcto. Ahora, ASP.NET 4 ha introducido un nuevo bloque de salida de texto capaz de codificar automáticamente en HTML, lo cual ayuda a evitar ataques relacionados con la inyección de scripts:



// Lo que antes (ASP.NET < 4) era...
<%= Html.Encode(Model.FirstName) %>
 
// En ASP.NET 4 es:
<%: Model.FirstName %>


El nuevo bloque de salida codificada es el método aconsejado para emitir contenido al cliente y se espera que los desarrolladores vayamos acostumbrándonos progresivamente a utilizarlo siempre, dejando a un lado al actual antiguo <%= %>.



Esto tiene un efecto lateral no deseado cuando estamos utilizando helpers que generen HTML. Por ejemplo, si emitimos la salida del helper anterior utilizando esta nueva técnica, observad el resultado que obtendremos:



// En la vista Index.aspx:
<%: Html.Image("/img/logo.gif", "Logo") %> 


image 
La solución a este problema se consigue utilizando como tipo de retorno del helper la nueva clase MvcHtmlString, introducida en ASP.NET MVC 2, que indica explícitamente a ASP.NET que no debe codificar la salida pues se trata de una cadena HTML controlada.



Así, modificando el código del helper de la siguiente forma, obtendremos el resultado esperado:



public static class Helpers
{
  public static MvcHtmlString Image(this HtmlHelper helper, string src, string alt)
  {
    TagBuilder tb = new TagBuilder("img");
    tb.Attributes["src"] = src;
    tb.Attributes["alt"] = alt;
    return MvcHtmlString.Create(tb.ToString(TagRenderMode.SelfClosing));
  } 
}


Todos los helpers del framework  MVC destinados a generar marcado retornan ahora, en la versión 2, este nuevo tipo de datos, y esto es lo mismo que deberíamos hacer con nuestros helpers personalizados. Además, gracias a unos curiosos malabarismos realizados en el interior de MvcHtmlString, nuestros helpers funcionarán tanto con ASP.NET 3.5 SP1 como con ASP.NET 4, tanto si utilizamos salida codificada como si no.



Publicado en: Variable not found.

Hey: ¡estoy en twitter!



» Leer más, comentarios, etc...

avemundi, blog de un micro-isv » Desarrollo de software

colossus 4.5

Abril 19th, 2010 - [Enlace local]

Ya se encuentra disponible la versión 4.5 de Colossus, mi programa de gestión de contraseñas. La principal novedad de esta versión es el cambio en la manera en que el programa muestra las claves, puesto que en ningún momento se llega a desencriptar el fichero de claves sino que se desencriptan unicamente para visualizarlas. El método anterior de desencriptado del fichero de claves podía ocasionar la perdida de consistencia del fichero, y alguna vez he tenido un disgusto con esto. Con el nuevo sistema no hay peligro de inconsistencia puesto que el fichero no sufre procesos completos de encriptado y desencriptado. Además hay alguna mejora estética nueva, como la rejilla de datos a la Windows 7 y alguna cosilla más.

Colossus se distribuye bajo licencia Creative Commons Reconocimiento - No Comercial - Sin Obras Derivadas 2.0.

cls45-acercade

» Leer más, comentarios, etc...

Información legal y técnica