2010/11/30

Solucionando problema de visualización en Photoshop CS5

Usando Photoshop CS5 (instalado en Windows 7 con 2 GB de RAM, tarjeta Nvidia Geforce), encontré que al usar CTRL+0 (para hacer que encajara el lienzo en la pantalla) a veces desaparecían los elementos de la imagen.

Para volverlos a ver, lo solucionaba probando otras opciones de zoom, como CTRL+1 o CTRL++ o CTRL+-, o desmarcando/marcando los iconos de visualización de los layers.

Busqué un poco en Google y me pareció que podía deberse a un problema con la tarjeta gráfica. Tal vez no tenía tanta memoria.

Entré al menú de Photoshop, Edit, Preferences, Performance, GPU Settings, Advanced Settings, Mode: Basic (antes estaba en Normal) para que use menos memoria.

Reinicié el programa y ahora funciona bien el zoom con CTRL+0.

Cómo obtener las partes de una ruta usando javascript


Una ruta como http://par1/par2/par3/par4/par5 se puede separar en php usando algo como explode().
En javascript, una forma de hacerlo es usando split(). Por ejemplo:

var path = 'http://par1/par2/par3/par4/par5';
var parts = path.split('/');
var n = parts.length;
var par5 = parts[n-1];
var par4 = parts[n-2];
var par3 = parts[n-3]; // y así sucesivamente...

2010/09/23

Conociendo PHP (actualizado)

ESTE AÑO repetí en el Insituto José Pardo la conferencia sobre PHP que hice el año pasado.

Actualicé un poco el powerpoint, que está disponible en SlideShare y tambien en Scribd.

2010/09/17

Solucionando los gadgets flash de Windows 7 64b

Ocurre que en Windows 7-64b puede haber algunos problemas para correr gadgets que requieran flash.

Al intentar correrlos aparece un diálogo pidiéndonos permiso para correr Flash, acepto, pero nada parece ocurrir.

La solución la encontré en este post: http://www.sevenforums.com/customization/1499-windows-7-7000-x64-sidebar-flash-player-fix.html#post863632.

Allí, se facilita un parche que, al ser ejecutado, soluciona el problema: http://www.sevenforums.com/attachments/customization/87586d1280161565-windows-7-7000-x64-sidebar-flash-player-fix-windows_64bit_sidebar_flash_support.exe

A mi me ocurrió que el archivo que descargué tenía la extensión .download, en lugar del .exe esperado. Felizmente fue cuestión de renombrarlo y ponerle la extensión correcta para poder ejecutarlo.

Por si acaso, también está disponible en este enlace: http://ifile.it/q456acu/Windows_64bit_Sidebar_Flash_Support.exe

jQuery Fundamentals

jQuery Fundamentals
Por Rebecca Murphey. Es un libro online introductorio a jQuery. Me parece muy bueno.

2010/09/08

Ágiles 2010: 3ras Jornadas Latinoamericanas sobre Metodologías Ágiles

Ágiles 2010 es una excelente oportunidad para encontrase con
profesionales de IT de la región, interesados en compartir sus
experiencias, debatir y capacitarse en temas relacionados con el
desarrollo de software a través del uso de metodologías ágiles.

Esta tercera edición, con sede en la ciudad de Lima, Perú, contará
con la presencia de especialistas locales e internacionales, quienes
compartirán su conocimiento durante los cuatro días que durará el
evento.

El programa incluye distintos tipos de actividades: presentaciones,
sesiones interactivas, talleres y espacios abiertos de debate.

Entre los invitados internacionales se encuentran los keynote
speakers Lee Devin y Joshua Kerievsky, que también estarán brindando
cursos durante el evento.


¡Inscríbete y se parte de Ágiles 2010!

2010/09/02

CHM Reader en Firefox

El tipo de archivo .chm es el que tienen típicamente los archivos de ayuda en Windows. También hay algunos textos que se distribuyen de ese modo. Allí, basta con hacerles doble clic y aparecerá dentro de un navegador especial (el Control de Ayuda HTML), que nos permite explorar el documento y leerlo.

Sin embargo, puede ser algo bastante incómodo. A veces las letras son demasiado pequeñas. Para hacer crecer la fuente del navegador CHM hay que hacer un cambio en las opciones de Internet del sistema, lo que afectará a Internet Explorer, por ejemplo.

Otras veces, podemos toparnos con un CHM que, por alguna razón, no son abiertos adecuadamente por el navegador CHM.
Esto puede ocurrir porque el CHM está bloqueado. Para desbloquearlo, hacerle click con el botón secundario del mouse, entrar a Propiedades y elegir Desbloquear.
Una alternativa bastante útil es usar CHM Reader, una extensión para Firefox (un motivo más para usarlo). Luego de instalar Firefox, si es que no lo está usando aún, puede instalar CHM Reader entrándo a https://addons.mozilla.org/en-US/firefox/addon/3235/

Después de eso, aparecera en el menú la nueva opción File, Open CHM File (Archivo, Abrir archivo CHM).

Luego podrá usar CTRL+ y CTRL- para aumentar o disminuir el tamaño de las fuentes. También podrá abrir los CHM problemáticos (al menos como con los que me he topado).

2010/08/27

Un mapa con Raphael

Raphäel es una biblioteca javascript que permite incorporar a la página imágenes vectoriales.

Píxeles y vectores

A diferencia de una fotografía formada por pixeles, una imagen vectorial está determinada por vectores. Mientras que hay que guardar la información de cada pixel, en el caso de los vectores sólo hay que guardar la información de sus extremos o puntos notables; los demás serán calculados a partir de ellos.

Eso permite que una imagen vectorial ocupe, en general, mucho menos espacio en disco que una imagen fotográfica. Además, se escala y siempre está nítida. No ocurre el 'pixeleo' que se suele notar en las fotos cuando se fuerza una ampliación.

Esas características hacen que sean una opción atractiva para gráficos web. Flash, por ejemplo, usa imágenes vectoriales.

SVG

SVG es un estándar XML para imágenes vectoriales en web. Raphael se apoya príncipalmente en ese estandar, de modo que cada elemento gráfico sea parte del DOM (el árbol XML que representa la página web), y provee adaptadores para compatibilidad entre navegadores (todavía no todos los navegadores soportan SVG del mismo modo).

El que un elemento gráfico sea parte del DOM permite manipularlo con javascript.

Usando Raphael

¿Qué tan fácil de usar es Raphael? Bueno, la entrada me pareció relativamente sencilla. Declarar la biblioteca raphael.js, un canvas y luego crear elementos gráficos como rectángulos, círculos, etc.
...
  <script type="text/javascript" src="js/jquery-1.4.2.min.js"></script>
  <script type="text/javascript" src="js/raphael-min.js"></script>
  <script type="text/javascript">
    $(function() {
      var paper = Raphael('canvas', 800, 600);
      var circle = paper.circle(150, 150, 100);
      var circle2 = paper.circle(150, 450, 100);
      var ellipse = paper.ellipse(150, 150, 100, 50);
      var ellipse2 = paper.ellipse(150, 150, 50, 100);
      var ellipse3 = paper.ellipse(350, 350, 50, 100);
      var rect = paper.rect(0, 0, 800, 600);
      var rect2 = paper.rect(50, 50, 200, 200);
      var rect3 = paper.rect(270, 50, 200, 200, 20);
      var image = paper.image('images/bee.jpg', 490, 50, 100, 75);
      var set = paper.set();
      set.push(circle, rect3);
      set.attr({fill: "gold"});
      var text = paper.text(150, 280, 'Hello World!\nLos niños de Andalucía');
      var path = paper.path("M50 50L250 250");
      var path2 = paper.path("M250 50L50 250");
      //paper.clear();
      circle.paper.path("M10,10L50,50M50,10L10,50")
        .attr({stroke: "red"});
      ellipse2.remove();
      ellipse2.show(); // not show because previous remove
      ellipse.hide();
      ellipse.show();
      rect3.rotate(10);
      image.rotate(80, 490, 50);
      image.translate(100, 0);
      image.scale(1.1, 1.1);
      image.animate({'translation':'-100, 10'}, 1000, 'bounce');
      circle2.animate({
        "20%": {cx: 20, r: 20, easing: ">"},
        "50%": {cx: 70, r: 120, callback: function () {}},
        "100%": {cx: 10, r: 10}
      }, 2000);
      var c = paper.circle(200, 200, 50),
        r = paper.rect(200, 200, 50, 50);
      c.animate({cx: 20, r: 20}, 2000);
      r.animateWith(c, {x: 20}, 2000);
      var path3 = paper.path("M300,300c0,100 100-100 100,0c0,100 -100-100 -100,0z");
      var spot = paper.circle(300, 300, 4).attr({fill: 'red'});
      spot.animateAlong(path3, 4000);
    }
  </script>
  ...
  <div id="canvas"></div>
  ...
El paso siguiente, la interactividad y el manejo de eventos sí me pareció más complicado:
...
  circle.drag(
    function(dx, dy) {// move
      this.attr({cx: this.ox + dx, cy: this.oy + dy, opacity: .5});
    },
    function() {// start
      this.ox = this.attr("cx");
      this.oy = this.attr("cy");
      this.attr({opacity: .5});
    },
    function() {// up
      this.attr({opacity: 1});
    }
  );
...
La propiedad .node permite manipular un elemento con jQuery. Sin embargo, tardé un poco en comprender que es mejor usar las funciones de manejo de eventos que provee Raphael, al menos para los gráficos. Resulta más simple y claro.

En el caso del drag, notar que se requieren tres funciones, que definen las acciones para move, start y up (en ese orden). La función que corresponde a move tiene los parámetros dx y dy (los diferenciales de movimiento), y la que corresponde a start tiene los parámetros ox y oy (el punto donde se hace click). Mientras se arrastra el objeto, dx y dy crecen contínuamente, así que implementar el drag no es tan simple como hacer un translate(dx, dy) (hacerlo provoca un desconcertante efecto acelerado), sino que hay que reflexionar un poco, como en el ejemplo, que los suma a la posición inicial.

Para el ejemplo del mapa, tardé varios días en descubrir el modo de usar hover y drag para que funcionaran como quería.

El mapa


La idea es tener el mapa del Perú con sus departamentos, y que estos se resalten al pasar el mouse sobre ellos. Al hacer click en alguno, se dispara alguna acción, por ejemplo mostrar su nombre en una caja.

Puede ver el demo aquí, y descargar el código fuente del proyecto en GitHub aquí.

Raphael se puede usar sólo, pero es de ayuda ayuda usar también jquery.
...
<style type="text/css">
  body {
    background-color: #222;
    color: white;
  }
  #wrapper {
    _position: absolute;
    _top: 50%;
  }
  #container {
    background-color: black;
    width: 700px;
    height: 500px;
    position: absolute;
    top: 0; right: 0; bottom: 0; left: 0;
    margin: auto;
    overflow: hide;
    _position: relative;
    _margin: 0 auto;
    _top: -50%;
    _overflow: none;
  }
  .info {
    display: none;
    text-align: center;
    font-family: "Century Gothic", Helvetica, "Bitstream Vera Sans", sans-serif;
    font-size: 24pt;
    line-height: 100px;
  }
  #infobox {
    border: 1px solid #ccc;
    position: absolute;
    top: 150px;
    left: 350px;
    width: 300px;
    height: 100px;
    overlay: auto;
  }
  #test {
    display: none;
    color: #0f0;
  }
</style>
...

<script type="text/javascript">
  $(function() {
    
    //http://www.switchonthecode.com/tutorials/xml-parsing-with-jquery
    $.ajax({
      type: 'GET',
      url: 'images/peru-h500.xml',// .svg renamed .xml for IE support
      dataType: 'xml',
      success: function(xml) {
        var r = Raphael('canvas', 700, 500);
        var map = {};
        var map_set = r.set();
        var active_fill = 'gold';
        var active_stroke = 'white';
        var normal_fill = $('body').css('background-color');
        var normal_stroke = '#ccc';
        var active = null;
        
        $(xml).find('path').each(function() {
          var id = (String)($(this).attr('id'));
          var path = (String)($(this).attr('d'));
          map[id] = r.path(path)
            .attr({fill:normal_fill, stroke: normal_stroke})
            .drag(
              // dx,dy van incrementandose
              // aqui calculo el diferencial continuamente
              function(dx, dy) {// move
                this.translate(dx-this.dx, dy-this.dy);
                this.dx = dx;
                this.dy = dy;
                //$('#test').html(dx+'--'+dy);
              },
              function(ox, oy) {// start
                //this.ox = ox;
                //this.oy = oy;
                this.dx = 0;
                this.dy = 0;
                this.toFront();
                this.attr({opacity: .5});
                //$('#test').html(ox+'-'+oy);
              },
              function() {// up
                // regresa a la posición original
                this.translate(-this.dx, -this.dy);
                this.attr({opacity: 1});
                
                // Este bloque lo hacia en un .click()
                // pero mejor aqui para que tambien funcione en IE


                // restablecer activo previo
                if (active) {
                  active.animate({fill: normal_fill, stroke: normal_stroke}, 500, '>');
                }
                // activar actual
                active = this;
                active.animate({fill: this.color, opacity: 1}, 500, '>');


                // ocultar otras info
                $('.info').hide();
                // mostrar info actual
                $('#'+id).show().css('background-color', this.color);
                
              }
            )
            .hover(function() {
              this.color = Raphael.getColor();
              if (this!=active) {
                this.animate({fill: this.color, stroke: active_stroke}, 500, '>');
              }
            }, function() {
              if (this!=active) {
                this.animate({fill: normal_fill, stroke: normal_stroke}, 500, '>');
              }
            })
          map_set.push(map[id]);
        });// end each
      } // end success
    });
    
  });
</script>  
...

<div id="wrapper">
  <div id="container">
    <div id="canvas"></div>
    <div id="test">[TEST]</div>
    <div id="infobox">
      <div class="info" style="display:block;">Perú</div>
      <div id="Arequipa" class="info">Arequipa</div>
      <div id="Ancash" class="info">Ancash</div>
      <div id="Apurimac" class="info">Apurímac</div>
      <div id="Ica" class="info">Ica</div>
      <div id="Lima" class="info">Lima</div>
      <div id="Ayacucho" class="info">Ayacucho</div>
      <div id="Piura" class="info">Piura</div>
      <div id="Lambayeque" class="info">Lambayeque</div>
      <div id="Tumbes" class="info">Tumbes</div>
      <div id="Tacna" class="info">Tacna</div>
      <div id="Puno" class="info">Puno</div>
      <div id="Huancavelica" class="info">Huancavelica</div>
      <div id="Cuzco" class="info">Cuzco</div>
      <div id="Junin" class="info">Junín</div>
      <div id="Ucayali" class="info">Ucayali</div>
      <div id="Pasco" class="info">Pasco</div>
      <div id="Huanuco" class="info">Huánuco</div>
      <div id="San_Martin" class="info">San Martín</div>
      <div id="Cajamarca" class="info">Cajamarca</div>
      <div id="Amazonas" class="info">Amazonas</div>
      <div id="La_Libertad" class="info">La Libertad</div>
      <div id="Loreto" class="info">Loreto</div>
      <div id="Moquegua" class="info">Moquegua</div>
      <div id="Madre_de_Dios" class="info">Madre de Dios</div>
      <div id="Titicaca" class="info">Lago Titicaca</div>
    </div>
  </div>
</div>
  • En los estilos aparecen #wrapper y #container para la técnica que permite centrar el #container absolutamente en la ventana.
  • También verá un div #test, que uso durante el desarrollo como consola de salida.
  • En un comienzo, copié a mano cada path (el atributo path.d dentro del .svg). Luego me pareció más práctico cargarlos desde un archivo.
    Aquí los he cargado de un archivo svg externo peru-h500.xml
    Originalmente se llamaba peru-h500.svg, pero lo renombré cuando descubrí que IE8 no lo procesaba como .svg.
  • El svg base lo obtuve de Wikipedia. Luego use Inkscape para dejar sólo los paths que necesitaba.
    También corregí los id de los path para que fueran cadenas sin acentos ni espacios en blanco, ya que los iba a usar como claves de los arrays de propiedades que iba a crear.
    Algo especialmente complicado en Inkscape fue lograr que desapareciera la transformación translate() para el grupo de paths, y que en su lugar se aplicara a cada valor.
    Para ser sinceros, no estoy seguro de como lo logré, pero me parece que funcionó cuando desagrupé, seleccioné los paths, y elegí alinearlos respecto a la página (top y left).
    Previamente, para cambiar el tamaño escalé y para cambiar el tamaño del canvas entré a propiedades del documento, fit.
  • Cuando pruebe el demo, arrastre uno de los departamentos para comprobar el efecto del drag.
  • He probado esta aplicación en FF5 (3.6.8), Chrome 6, y IE8.
Para mí es muy interesante las cosas que se pueden hacer con SVG y con Raphael. Ojalá este material le sirva de ayuda.

2010/08/13

Personalizando la pantalla 404 en Apache

Cuando se intenta acceder a una dirección que no se reconoce en el site, el webserver responde con una página de Error 404: Document Not Found.

Es posible personalizar esta página para que sea más informativa o, al menos, más agradable de ver que el mensaje en blanco y negro que viene por default.

En un servidor web Apache , es posible hacerlo modificando la página de error 404 del sistema, o indicando en su archivo de configuración el nombre de otra que preparemos para usar en su lugar.

Sin embargo, hay una opción que me parece mas flexible. Es usar un archivo .htaccess en el directorio, indicando cuál será el archivo que se presentara para el error 404.

Esto requiere que Apache tenga activado el módulo mod_rewrite y permita el rewrite en ese directorio. Me parece que suele estar configurado de ese modo en la mayoría de hostings.

Si se tiene acceso a la configuración de Apache (/etc/httpd/conf/httpd.conf en Linux CentOS), debe haber un bloque similar a:


<Directory "/var/www/html/mydir">
    Options Includes Indexes FollowSymLinks MultiViews
    AllowOverride FileInfo
    Order allow,deny
    Allow from all
</Directory&gt


Donde mydir es el directorio donde queremos colocar el .htaccess. También puede ser AllowOverride All, que incluye la opción FileInfo.

La configuración afecta al directorio y todos sus subdirectorios, a menos que para ellos se indique otra cosa.

.htaccess
ErrorDocument 404 /error-docs/HTTP_NOT_FOUND.html

Esto indica la página que se presentará cuando ocurra el error 404. La ruta es relativa a la raíz del servidor web, como en un URL. Por ejemplo, la ruta /error-docs/HTTP_NOT_FOUND.html, puede corresponder al archivo /var/www/html/error-docs/HTTP_NOT_FOUND.html.

En la página 404.html, ya que puede ser llamada desde cualquier ubicación, los url que se usen deben ser absolutos.

Páginas de error

Las principales son:
400: Bad request
Cuando el servidor no entiende la solicitud por un error de sintaxis.
401: Unauthorized
Cuando el usuario no ha sido autenticado para acceder.
403: Forbidden
El servidor no puede ejecutar la solicitud.
404: Not Found
El servidor no puede encontrar la direccion solicitada.
500: Internal Server Error
El servidor ha encontrado una situacion inesperada que no le concretar la respuesta.
Esta es una lista más completa que se podría incluir en el .htaccess:

ErrorDocument 400 /error-docs/HTTP_BAD_REQUEST.html
ErrorDocument 401 /error-docs/HTTP_UNAUTHORIZED.html
ErrorDocument 403 /error-docs/HTTP_FORBIDDEN.html
ErrorDocument 404 /error-docs/HTTP_NOT_FOUND.html
ErrorDocument 405 /error-docs/HTTP_METHOD_NOT_ALLOWED.html
ErrorDocument 408 /error-docs/HTTP_REQUEST_TIME_OUT.html
ErrorDocument 410 /error-docs/HTTP_GONE.html
ErrorDocument 411 /error-docs/HTTP_LENGTH_REQUIRED.html
ErrorDocument 412 /error-docs/HTTP_PRECONDITION_FAILED.html
ErrorDocument 413 /error-docs/HTTP_REQUEST_ENTITY_TOO_LARGE.html
ErrorDocument 414 /error-docs/HTTP_REQUEST_URI_TOO_LARGE.html
ErrorDocument 415 /error-docs/HTTP_UNSUPPORTED_MEDIA_TYPE.html
ErrorDocument 500 /error-docs/HTTP_INTERNAL_SERVER_ERROR.html
ErrorDocument 501 /error-docs/HTTP_NOT_IMPLEMENTED.html
ErrorDocument 502 /error-docs/HTTP_BAD_GATEWAY.html
ErrorDocument 503 /error-docs/HTTP_SERVICE_UNAVAILABLE.html
ErrorDocument 506 /error-docs/HTTP_VARIANT_ALSO_VARIES.html

Notas de compatibilidad

Cuando no se define una página de error, el navegador puede presentar su propia versión personalida. Seguramente lo habra notado. Los mensajes de "Página no existe" son diferentes en IE, Firefox, Chrome, etc.

Algo curioso es que Chrome insistira en presentar su propia versión, a menos que la nuestra tenga al menos 512 bytes de tamaño.
IE7, Firefox 3.6.8 y Safari 5 sí muestran nuestra versión si estuviera disponible.

Referencias

Una forma de maquetear

El patrón base de la técnica que describo es usar un elemento posicionado absolutamente dentro de otro posicionado relativamente o absolutamente.

El uso de una imagen guía de fondo y la aplicación de transparencia a los elementos que queremos calzar es de mucha ayuda para posicionarlos con precisión.

Ojalá le sirva de ayuda en este tipo de tareas. Se agradecen comentarios y sugerencias.

Lea más aquí: http://www.scribd.com/doc/35824410/Una-forma-de-maquetear


2010/08/10

MockApp: Maquetas para iPhone

MockApp ayuda en la tarea de hacer la maqueta de una aplicación para iPhone.

Hay versiones para Keynote y Powerpoint.

Básicamente, son presentaciones que podemos reutilizar. Contienen los elementos tipicos de una aplicación para iPhone.



Puede descargarla aquí.

2010/08/04

Desbloquear archivo en Windows 7

A veces es frustrante cuando se quiere eliminar un archivo y el sistema responde que no es posible porque está siendo usado por otra aplicación. Sobre todo cuando no es evidente cuál es la otra aplicación.

LockHunter es un programa gratuito que se puede instalar para ayudar a encontrar cuál es la aplicación por la que se realiza el bloqueo, y permitir la eliminación si así lo queremos.

Disponible tanto para 32 bit como para 64 bit, lo puede encontrar en LockHunter.com

Crédito de la imágen: My System Tech

2010/07/28

Programando una mejor sociedad

Hoy, en Perú, como cada año, el Presidente da un mensaje a la nación.

Mientras lo escucho, reflexiono sobre el significado de las cosas que se hacen. Y el por qué se hacen de ese modo.

Yo no sigo con mucho detalle los acontecimientos políticos ni las noticias. Quizás podría decir que contemplo el panorama, y trato de entender.

Nacemos siendo habitantes del país de nuestros padres. Aprendemos a ser gobernados por reglas que alguien más creó. Pero luego vamos notando que podemos hacer algo al respecto.

Nuestro destino está influido por una sociedad que sigue reglas acordadas por ella misma. Es como si la sociedad se programara a sí misma.

En los detalles, tal vez la mayoría de la gente encuentre que la política y la programación son dos cosas muy diferentes, pero pienso que tienen algunas similitudes que podrían ayudarnos en la búsqueda de una sociedad mejor.

Qué tan buena es una sociedad. Cómo debería construirse. Qué tan bueno es un programa. Cómo debe construirse.

En el mundo de la programación tenemos experiencias y propuestas que quizás podrían aplicarse a la construcción de las reglas que guían nuestra sociedad. Principalmente las provenientes del movimiento de software libre, que han mostrado como cosas que antes parecían imposibles en realidad son muy posibles y prácticas. Se decía, por ejemplo, que, como cada vez que se agregaba un programador a un equipo se observaba un retraso en el avance y un aumento en la complejidad del proyecto, había un tamaño que jamás podría superarse. Los proyectos open source, como Linux, con miles de colaboradores alrededor del mundo, mostraron que el límite está determinado por la forma de organizarse. Una forma diferente de organizar el trabajo permitió coordinar el trabajo de muchísima más gente.

En nuestros proyectos locales, podemos tener la oportunidad de ver como nuestras decisiones afectan el trabajo que hacemos. Podemos ser como el soberano del proyecto de programación que implementamos. Ser el presidente de nuestro código. Y desempeñar también roles equivalentes al del legislador, magistrado, policía, etc. (quizás, cualquier sistema, alcanzado cierto nivel de complejidad, pueda generar roles como esos)

Algunas veces tenemos las mejores intenciones, y planteamos resolver las cosas de un modo que nos parece bueno, pero luego nos estrellamos con muros que nosotros mismos construimos.

Después de mucha prueba y error, los programadores han reunido un conjunto de buenas prácticas que sirven como pautas en nuestro trabajo. La experiencia de los miles de programadores en proyectos extensos también ha sido util para los programadores de proyectos más pequeños. Aquí menciono algunas:

El principio KISS (Keep It Simple as poSible*). Si hay dos maneras de hacer algo, es mejor usar la más simple. ¿Por qué? Cuando algo puede fallar, falla; así que es mejor minimizar el número de cosas que pueden fallar para facilitar el inevitable proceso de mantenimiento y mejora. Además, hay cierto grado de complejidad que los humanos podemos manejar con comodidad. Cuanto más simple, hay más capacidad mental disponible para la creatividad.

Reutilizar las cosas tanto como sea posible. Si algo funciona bien, no hay que estar repitiendo una y otra vez el mismo trabajo. Sin embargo, tener al mismo tiempo la libertad de reinventar la rueda y proponer alternativas, porque así es como se encuentran mejores opciones que puedan reemplazar a la anterior.

Minimizar el acoplamiento. Es decir procurar que el cambio que se hace en un componente no requiera hacer cambios coordinados en los demás. Esto facilita su mantenimiento y evolución.

Me pregunto por los montones de procedimientos que hay en nuestra sociedad. Por las duplicidades y los acoplamientos en las funciones municipales y ministeriales, en la policía y en el serenazgo. Por los pequeños feudos administrativos en los que se convierten las universidades, e incluso las facultades dentro de la misma universidad aunque sea pública. Por las absurdas reglas que se plantean y no se evalúan. Por el sistema de justicia que obliga a pelear una y otra vez las mismas batallas (¿por qué, si la justicia debiera ser igual para todos?). Por las reglas que no se siguen y las coordinaciones que no se hacen porque el protocolo resulta más complejo que el problema que se quiere resolver.

Las leyes y reglas mál dadas se observan en la práctica, al tratar de ejecutarlas. Igual que los frameworks en programación. Por más buenas intenciones que se hayan tenido al momento de darlas, por más que hayan funcionado en otros casos, para otras personas y otras circunstancias, cuando vemos que no funcionan en nuestro caso particular, debemos aceptar los hechos y tratar de hacer algo constructivo al respecto.

Es importante que las reglas sean simples, claras en sus intenciones, transparentes en su funcionamiento, y corregibles en su evolución. ¿Son así las leyes que tratan de aplicar en nuestra sociedad?.

Me parece también importante reconocer que telarañas de complejidad se pueden tejer cuando se trata de aplicar una regla que no se puede cumplir. Imaginemos el ejemplo absurdo de alguien que pusiera la regla de no respirar más de 30 veces por minuto. De pronto, todo el comportamiento de la gente cambiaría radicalmente. La gente no podría correr o hacer mucho esfuerzo porque la conduciría a un acto ilegal. Para verificar el cumplimiento de la norma se necesitaría policías que eligieran individuos sospechos (quizás demasiado chaposos) y les hicieran una auditoría. Seguramente habría excepciones para esos policías (que a veces tendrían que perseguir a los criminales) y los militares y agentes secretos. Aumentaría el trabajo de los jueces y abogados. Líderes sociales reclamarían ampliar el número a 31. Fuerzas conservadoras presionarían para disminuirlo a 29. Aparecerían libros y películas contando anécdotas y actos heroicos al respecto. Con el tiempo, tendríamos demasiada gente cuyo bienestar depende de la existencia de tal regla que, si alguien se preguntara por ella, nos tildarían primero de soñadores, luego de locos, y después de subversivos. Nos amedentrarían hasta que ellos mismos tuvieran una razón para hacerse la misma cuestión. He visto reglas así surgir incluso familias y en pequeños grupos de amigos. ¿Cuántas reglas como esa habrán en nuestra sociedad? Incluso las podrá reconocer en algunos dogmas religiosos.

Como programadores, podemos experimientar con reglas en las sociedades que representamos en un proyecto de desarrollo de software y aceptar con humildad que funciona y qué no funciona. Podemos tomar nota de ello, ganar experiencia, y desarrollar una intuición que puede servirnos para hacer una mejor tarea cuando tengamos la oportunidad de contribuir por una sociedad mejor.

* KISS, Keep It Simple, Stupid, era la versión original. Creo que el tono tenía la intención de llamar la atención entre amigos. Aquí uso una versión más cordial.


Crédito de la imágen: canada.com

2010/07/26

Fondo de página redimensionable

PROBLEMA

Cómo lograr que el fondo de una página sea redimensionable.

SOLUCION

La técnica consiste en colocar un img con un width=100%:

<img src="friends-and-moon.jpg" width="100%"/>

Sin embargo, a menos que se trate de un popup, aparecerán barras de scroll para permitir ver el resto de la imagen que no esté en pantalla.

Para evitar eso, se coloca el img dentro de un div con estilos adecuados:

body {
  margin:0;
}
#bg {
  width: 100%; height: 100%; left: 0px; top: 0px; position: fixed;
}
#container {
  position: absolute; top: 0; left: 0; width: 100%;
}
<!-- ... -->
<div id="bg"><img src="friends-and-moon.jpg" width="100%"/></div>
<div id="container">
<!-- content -->
</div>
Como se observa, luego el contenido de la página se puede colocar en un div posicionado absolutamente sobre la imagen. De ese modo se simula un fondo de página redimensionable.

El problema de la presentación del scroll se soluciona de este modo en los navegadores estandar, pero persiste en IE6.

Puede ver un demo aquí.

REFERENCIAS

2010/07/23

Personalizando bullets

Normalmente, una lista tipo ul luce así:
  • Item 1
  • Item 2
  • Item 3
Se puede usar CSS para cambiar el tipo del bullet (que por default es disc):
list-style:disc
  • Item 1
  • Item 2
  • Item 3
list-style:circle
  • Item 1
  • Item 2
  • Item 3
list-style:square
  • Item 1
  • Item 2
  • Item 3
list-style:none
  • Item 1
  • Item 2
  • Item 3
list-style:url(flecha_roja.gif)
  • Item 1
  • Item 2
  • Item 3
Para controlar la posición del bullet, se puede usar la técnica de poner la imagen como fondo del item.
En este ejemplo aplico los estilos en línea, para ilustrar la idea. Sin embargo, en un caso real, lo usual es que use clases y bloques u hojas de estilo para indicar lo mismo.

<ul style="list-style:none;">
<li 
  style="background:url(flecha_roja.gif) 1px 2px
  no-repeat; padding-left:10px;">
  Item 1: Bullet más cerca y centrado</li>
<li
  style="background:url(flecha_roja.gif) right 2px
  no-repeat; width: 250px;">
  Item 2: Bullet a la derecha</li>
</ul>

  • Item 1: Bullet más cerca y centrado
  • Item 2: Bullet a la derecha

Puede ver un demo en aquí

Crédito de la imagen: http://www.robbinssports.com

2010/07/09

Cómo centrar un bloque en una página

Centrar un bloque tanto horizontal como verticalmente es algo que se requiere a veces. Lo ideal es que el centrado se acomode automáticamente cuando la ventana del navegador se redimensiona. La solución podría ser más fácil, pero la familia IE, dificulta un poco el problema.

Nota
Estas soluciones funcionan en la mayoría de navegadores, incluso en IE6, pero recientemente encontré que no es así en Safari. Puede encontrar un método alternativo, que funciona en todos los navegadores, en el artículo Cómo centrar un bloque en una página 2.
    Soluciones
    • En los navegadores estandar (principalmente no-IE6), para lograr que un bloque, por ejemplo #content, de 400px por 100px, quede centrado en la página, se le puede aplicar los siguientes estilos:

          #content {
            width: 400px;
            height: 100px;
            position: absolute;
            top: 0; right: 0; bottom: 0; left: 0;
            margin: auto;
            overflow: auto;
        }

      El truco aquí es que el margin: auto también sirve para el centrado vertical si se especifica height, position: absolute, y además top: 0; right: 0; bottom: 0; left: 0;
      Una limitacion de esta solución es que la altura es fija. El overflow: auto es para que, cuando el contenido haga que #content sobrepase la altura especificada, aparezca un scroll.
    • En IE6, lo anterior no funciona. Es necesario colocar #content dentro de un #container, y usar los siguientes estilos:

          #container {
            position: absolute;
            top: 50%;
        }
        #content {
            width: 400px;
            height: 100px;
            position: relative;
            margin: 0 auto;
            top: -50%;
            overflow: none;
        }

      Aqui se usa la técnica de mover el top del #container hacia abajo el 50% de la altura de su contenedor, body, y luego el top del #content 50% hacia arriba de la altura del mismo #content (debería ser de su contenedor, #container, pero este es un bug de IE6, paradójicamente util para resolver este problema mejor que en el caso estándar, pues permite que la altura vaya más allá del inicial de 100px mientras el bloque se acomoda automáticamente siempre en el centro).
    • En IE7, lo anterior no funciona (así que hay cosas que funcionan diferente en IE6, IE7 y IE8). Es necesario agregar un #container2, y usar los siguientes estilos:

        #container {
          position: absolute;
          height: 50%;
          width: 100%;
        }
        #container2 {
          width: 100%;
          position: absolute;
          bottom: 0;      
        }
        #content {
          background-color: gold;
          width: 400px;
          height: 100px;
          overflow: auto;
          position: relative;
          margin: 0 auto;
          top: 50%;
        }

    • Para combinar estas soluciones en un paquete que funcione para ambos casos, se puede usar la técnica del hack underscore.
      La idea de la técnica es simple e ingeniosa: Normalmente, una propiedad css que comienza con un _, #, un punto, o un número es ignorada por los navegadores estándar (de hecho, anteponer un número al nombre de la propiedad es un truco util para desactivarla), pero IE6 filtra la cadena quitándole ese primer caracter, si es _ o #, para usárla normalmente. De ese modo, sólo para IE6, _position, o #position, se vuelven position, por ejemplo. Del mismo modo, IE7 filtra el punto y .position se vuelve position.
      Asi, luego de tener las cosas listas para los navegadores estándar, se puede intentar agregar o sobrescribir lo que necesitemos para IE6 e IE7, como se muestra a continuación:

        #container {
          _position: absolute;
          _top: 50%;
          .position: absolute;
          .height: 50%;
          .width: 100%;
        }
        #container2 {
          .width: 100%;
          .position: absolute;
          .bottom: 0;      
        }
        #content {
          background-color: gold;
          width: 400px;
          height: 100px;
          position: absolute;
          top: 0; right: 0; bottom: 0; left: 0;
          margin: auto;
          overflow: auto;
          _position: relative;
          _margin: 0 auto;
          _top: -50%;
          _overflow: none;
          .position: relative;
          .margin: 0 auto;
          .top: 50%;
        }

    Referencias

    Más artículos

    Archivo