2011/12/19

Creando nuevas opciones

Caminando por una tienda, encontré un juguete con forma de notebook.

Lo encendí y comencé a navegar por las distintas opciones que ofrecía.

Había juegos para aprender el alfabeto, los números, las notas musicales, para escribir mensajes, y así por el estilo.

Pensé que llegaría un momento en que uno habría explorado todas las opciones. Entonces querria más.

La diferencia entre una computadora y el juguete era que no había opción para agregar cosas. O quitar cosas. O modificar las que habían.

¿Cuántas personas usan las computadoras de ese modo? Es decir, como un gran conjunto de opciones que consumir, simplemente, sin poder modificarlas. Un ejemplo que me viene a la mente es el de los diccionarios. Sería tan útil que nos permitieran agregar nuestras propias definiciones y, sin embargo, debemos conformarnos con descargar las que hayan hecho otros.

Se podría pensar que es algo que le corresponde a los programadores. Pero pienso que programar una computadora debería ser algo tan simple que podamos hacerlo todos.

Me parece que con la consola de comandos íbamos por un camino que eventualmente nos conduciria a intérpretes de lenguajes humanos. Primero por escrito y luego por voz. Un día cercano podríamos comandar una computadora como si conversáramos con ella, como en Star Trek.

Pero apareció el sistema de menús y ratón y hubo un desvío.

Un sistema de menús presenta las opciones en una estructura jerárquica. Eso permite verlas con más claridad. El ratón permite navegar en ese sistema. Comparado con escribir los comandos, puede resultar más cómodo, más rápido... para ciertas cosas.

Quienes usan la consola de comandos pueden notar que hay cosas que la consola permite y el sistema de menús no.

Si usamos la consola de comandos simplemente como un modo de llegar a las opciones que ofrece el sistema de menús, no hay mucha ventaja (sería más cómodo usar el ratón). La magia de la consola de comandos aparece cuando permite crear nuevas opciones y manipularlas con una expresividad que quizás esté más allá de las posibilidades de un sistema jerárquico de presentación.

Los lenguajes de programación son un modo de crear esas nuevas opciones. Antes, en la época de la consola de comandos, se hacía el intento de acercar estos lenguajes a la gente. Estaban BASIC, LOGO y así por el estilo. Pero eso fue decayendo conforme se popularizaba el ratón.

El problema con el mundo del ratón es que tiene un límite, igual que el juguete. Como en una tierra plana, llegará el momento, tarde o temprano, en que se habrá recorrido cada opción y, parado en el borde de ese mundo, querrá más.

Claro que los programadores se encargarán de ampliarlo, proveyendo nuevas opciones que estarán disponibles con solo pasar a la siguiente versión. Dependemos de ellos para eso. Pero ¿no sería mejor que cada uno pudiera crear por si mismo nuevas opciones, en lugar de tener que esperar a que a alguien más se les ocurra y las programe?

En el desarrollo de programas, se va tomando más en cuenta el papel del usuario en la definición del producto y su implementación. Las ideas de los usuarios (recolectadas a través de foros o emails) son tomadas en cuenta en el diseño. Los errores que encuentran ayudan a mejorar el producto. Se compite para ver quién logra escuchar mejor a los usuarios y traducir lo que dicen a mejoras en el software. Pero, viéndolo bien, es como si los usuarios programaran las computadoras a través de los programadores. ¿No sería mejor que la programación pudiera ser directa?

Yo soy programador, pero me parece que muchas veces estamos cumpliendo simplemente el rol de intermediarios es una tarea que debería poder ser realizada directamente por los usuarios. Programar debería ser algo mas simple y cualquier persona debería sentirse capaz de comunicar a la computadora lo que quisiera que hiciera. Encontrar un modo en que la gente pueda definir nuevas opciones, o expresarlas de otro modo, luego compartirlas con los demás y permitir que evolucionen.

Imagine que puede agregar opciones a su árbol de menús. Imagine que puede operar con las opciones que ya tiene para crear otras nuevas. Imagine que incluso puede crear nuevas operaciones para manipular esas opciones. Imagine que puede compartir todo eso con otros usuarios. Y todo eso de un modo que le resulta natural, lógico, simple.

Esa forma de ver la computación era más evidente cuando se usaba la consola de comandos, ese infinito universo negro poblado de letras fosforescentes. Pero pienso que también se podría hacer en el sistema de menús, si abrimos la puerta.

2011/11/17

Optimizando Photoshop

  • Edit, Preferences, General (CTRL+K)
  • Desmarcar Export Clipboard
Al parecer esto previene que una copia sea puesta además en el clipboard general de Windows. Como las copias en Photoshop suelen ser grandes, significa un ahorro significativo en la memoria disponible.

Además, es posible acceder a Edit, Purge para vaciar de memoria el clipboard (de Photoshop) y el historial.

2011/10/28

Construyendo un Wysiwyg Editor con jQuery

En HTML, normalmente un textarea no es wysiwyg, pero existen plugins javascript, como CKEditor, NicEdit, entre otros, que ayudan a que lo sea. Se instala el plugin, se configura y listo. ¿Te animarías a hacerlo tú mismo?


WYSIWYG
Whay You See Is What You Get: lo que ves es lo que obtienes
Así es como se denomina a los editores que muestran la apariencia final del documento mientras es editado.

Buscando hacerme una herramienta para tomar notas con más facilidad, entré a explorar en este tema.

Antes, estaba envuelto por un halo misterioso. Suponía que sería una cuestión demasiado complicada. Descubrí que es más fácil de lo que parece.

Antes, para hacer editable un div, lo que se me ocurría era montar encima un elemento editable, como un input text, que se muestre cuando se necesite la edición. Pero, limitándome a eso, no veía cómo era posible mostrar en negrita o cursiva algo dentro de un elemento editable. Imaginaba que tendría que ver con algún tipo de magia desconocida que involucraría código muy complejo y sofisticado.

Resulta que es posible hacer que un div sea editable (¿por qué no difunden más esas cosas?).

Cuando un div es editable, está disponible un API que permite ejecutar comandos sobre su contenido (!).

De ese modo, hacer un editor wysiwyg se convierte en una cuestión muy, muy accesible, incluso para un programador como yo :-)

designMode
Al parecer, IE fue el que primero implementó la idea de que un elemento fuera editable, luego los otros navegadores acogieron la idea y ahora ya es algo estándar.

Esto se consigue haciendo que designMode="On" para el objeto que se desea editar.

Cuando se está en designMode="On", se pueden enviar comandos de formato usando la función execCommand. Estos permanecen activos hasta que se vuelven a enviar otra vez. O se aplican sobre el texto que estuviera seleccionado. Sí, como en Word. Hasta funciona deshacer con CTRL+Z

La idea básica
Una de las primeras guías que encontré usa un iframe y botones.

Pone el iframe en designMode="On". Hecho esto, se puede editar el contenido del iframe como si se estuviera en un textarea.

Los botones permiten invocar los comandos de formato.

Este es un ejemplo basado en: http://jsfiddle.net/Kxmaf/6/ :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>WYSIWYG Demo</title>

<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>

<style type="text/css">
input[type=button] {
  border: 1px solid #ccc;
}
#editor {
  width: 500px;
  height: 170px;
}
#bold {
  font-weight: bold;
}
#italic {
  font-style: italic;
}
</style>

<script type="text/javascript">
$(document).ready(function() {
  var cw = document.getElementById('editor').contentWindow;
  var doc = cw.document;
  doc.designMode = "on";
  doc.write('');
  doc.close();
  
  $('#bold').click(function() {
    cw.focus();// IE
    doc.execCommand('bold', false, false);
    cw.focus();
  });
  $('#italic').click(function() {
    cw.focus();// IE
    doc.execCommand('italic', false, false);
    cw.focus();
  });
  $('#fontname').change(function() {
    cw.focus();// IE
    doc.execCommand('fontname', false, $(this).val());
    cw.focus();
  });
});
</script>

</head>
<body>
  <h1>WYSIWYG Demo</h1>
  
  <div id="buttons">
    <input type="button" id="bold" value="B" />
    <input type="button" id="italic" value="I" />
    <select id="fontname">
      <option value="Arial">Arial</option>
      <option value="Comic Sans MS">Comic Sans MS</option>
      <option value="Courier New">Courier New</option>
      <option value="Monotype Corsiva">Monotype</option>
      <option value="Tahoma">Tahoma</option>
      <option value="Times">Times</option>
    </select>
  </div>
  <iframe id="editor"></iframe>
  
</body>
</html>

Mejorando
Es posible usar un div en lugar de un iframe. También se puede aprovechar más cosas de jQuery.

Este es un ejemplo basado en de77: jQuery Simple WYSIWYG Editor :

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>WYSIWYG Demo</title>

<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>

<style type="text/css">
input[type=button] {
  border: 1px solid #ccc;
}
#editor {
  width: 500px;
  height: 170px;
  border: 1px solid #ccc;
}
#bold {
  font-weight: bold;
}
#italic {
  font-style: italic;
}
</style>

<script type="text/javascript">

$(document).ready(function() {
  function action(a,p) {
    $('#editor').focus();
    if (p == null) p = false;
    document.execCommand(a, null, p);
  }

  $('#editor').get(0).contentEditable = "true";
  
  $('#bold').click(function() {
    action('bold');
  });
  $('#italic').click(function() {
    action('italic');
  });
  $('#fontname').change(function() {
    action('fontname', $(this).val());
  });
  $('#html').click(function() {
    alert($('#editor').html());
  });
});
</script>

</head>
<body>
  <h1>WYSIWYG Demo</h1>
  
  <div id="buttons">
    <input type="button" id="bold" value="B" />
    <input type="button" id="italic" value="I" />
    <select id="fontname">
      <option value="Arial">Arial</option>
      <option value="Comic Sans MS">Comic Sans MS</option>
      <option value="Courier New">Courier New</option>
      <option value="Monotype Corsiva">Monotype</option>
      <option value="Tahoma">Tahoma</option>
      <option value="Times">Times</option>
    </select>
    <input type="button" id="html" value="HTML" />
  </div>
  <div id="editor"></div>
  
</body>
</html>

Me parece que esto puede ayudar a aclarar el tema para empezar. Ojalá le sirva de ayuda.

Referencias

2011/10/05

HTML + Javascript para usar cualquier framework

Todo o nada
Para hacer una aplicación web, se suele optar por alguna de las siguientes alternativas:

a) Usar completamente un framework propio.
b) Usar completamente un framework estándar.

La alternativa a) significa volver a implementar muchas de las cosas que ya se han resuelto en otros frameworks.

La alternativa b) significa depender completamente de lo que esté implementado en el framework elegido.

Pero pienso que hay otra alternativa. Una que no use la palabra completamente.

Imagine all the people
Imagine que no tiene que volver a escribir su aplicación web en otro lenguaje simplemente para usar algunas de las cosas que ofrece cierto framework escrito en ese lenguaje.

Imagine que no tiene que volver a escribir su aplicación web simplemente para usar algunas de las cosas que ofrece la siguiente versión del framework.

Imagine un framework en el que pudiera usar cualquier cosa que ya se hubiera implementado en otro framework, sin necesidad de volver a escribirlo.

Imagine que todos los frameworks pudieran trabajar juntos y usted pudiera escoger de esa feria de componentes los que mejor se adaptaran para cada cosa que necesitara. Todas las versiones y todos los lenguajes.

Cómo hacerlo
Se me ocurre al menos una manera.

Que el contenido dinámico se construya usando Javascript. Usando técnicas AJAX, se puede hacer una solicitud a cierto URL, con los parámetros que se requieran. En ese URL, un servidor procesa la solicitud, usando el framework y lenguaje de programación que sea, y devuelve una respuesta JSON. Con la respuesta, se construye la vista de la respuesta.

Pensando sobre eso, noto que en el modelo cliente-servidor del HTML, se obliga a que el navegador reemplace completamente el contenido de la página con la respuesta. Otra vez esa palabrita.

Quizás sería interesante extender la especificación HTML para admitir reemplazos parciales. AJAX es el testimonio de que eso se necesita. Flash también lo implementa (llamándolo carga dinámica).

Por el momento, la manera de hacer eso es con ayuda de Javascript (y alguna biblioteca como jQuery).

MVC
Un patrón de muy difundido en los frameworks actuales es MVC (modelo-vista-controlador).

Básicamente, se piensan las soluciones en términos de tres tipos de componentes: controladores, modelos y vistas.

Un controlador recibe la solicitud, determina qué hacer, utilizando los modelos necesarios y pasa los resultados a una vista.

Algunos dicen que la idea principal es que los diseñadores no se vean obligados a programar ni los programadores a diseñar. Pero, como nadie lo ha logrado (para hacer cualquier template se combina diseño con programación), pienso que se trata más de una cuestión de orden.

Si se usa Javascript para carga dinámica, lo que ocurre es que lo que devuelven las vistas puede ser usado no sólo para reemplazos totales, sino también para reemplazos parciales.

¿Por qué no se hace?
Eso mismo me pregunto.

He ido desarrollando estas ideas luego de observar como la comunidad Drupal está rehaciendo los módulos que funcionaban bien en Drupal 6 para que funcionen en Drupal 7. Es un riesgo. Se habla que algunos proyectos, como Perl, han perdido comunidad por hacer maniobras como esa.

Ya se ha iniciado la carrera hacia Drupal 8... llegado el momento, ¿volverán a reescribir los módulos?... ¿y así, sucesivamente?

Me parece que debe haber un camino mejor.

¿Qué le parece?

2011/10/04

Solucionar puerto 80 ocupado luego de Webmatrix

Resolver esto me ha tomado un tiempo. Espero le resulte de ayuda a alguien.

Luego lo desinstalar Webmatrix (La versión 1.0 me parece, en Windows 7), encontré que XAMPP no podía usar el puerto 80 como antes.

Con la idea de averiguar qué proceso lo ocupa, ejecuto en la consola de comandos, como administrador:

netstat -anb

pero aparece que no hay información disponible sobre el proceso que ocupa el puerto 80.

Usando la utilidad tcpview (de Sysinternals), veo que el proceso es el mismo System, con PID 4.

Hago telnet localhost 80 y veo que quién está atendiendo es Microsoft-HTTPAPI/2.0

Reviso en el Panel de Control, Herramientas Administrativas, Servicios, y desactivo "Servicio Agente remoto para Microsoft Web Deploy 2.0."

Eso era. Al parecer un issue de Webmatrix. Ahora XAMPP ya puede iniciar en el puerto 80.

Referencias

2011/09/22

Comprobar un elemento con jQuery

Para comprobar si existe un elemento, es útil comprobar su propiedad length:

if ($('selector_del_elemento').length) {
  ...
}

Ejemplos con selectores:

  • $('#section-1')
  • $('.sections a.active')
Referencias

2011/09/19

SEO

SEO es como se denomina al trabajo de optimizar páginas web para facilitar su procesamiento por los buscadores (el término proviene de las siglas de Search Engine Optimization: Optimización para Máquinas de Búsqueda).

He estado leyendo sobre SEO durante 3 días, así que ya soy un experto.

;-) Claro que es una broma. Así conociera toda la teoría, un experto, prácticamente por definición, es aquel que ha experimentado durante algún tiempo, y ha obtenido ese conocimiento que da la práctica (y que suele corregir a la teoría).
En el caso particular de SEO, el tiempo parece ser un factor casi inevitable. Un cambio SEO podría tardar al menos dos semanas en verse reflejado. Y una campaña SEO al menos 3 meses.
No, no soy un experto en SEO, pero me gustaría compartir algunas de las cosas que he encontrado, y también algunas reflexiones. Espero sea indulgente con algún error que llegara a notar, y agradezco de antemano los comentarios en buena onda.
Me parece que Optimización para Motores de Búsqueda no deja muy claro qué es lo que optimiza. ¿La página o su posicionamiento? Aquí manejo la definición de SEO como veo que lo hace Google. Como la optimización de la página para mejorar su visibilidad para los motores de búsqueda.
Sin embargo, también es frecuente encontrar que se piense en SEO como la mejora de la posición de un sitio web en los resultados de búsqueda. Es decir, mejorar su visibilidad  en la lista de resultados de los motores de búsqueda.
Como la posición de una página web suele estar determinada por el número y la calidad de los enlaces que le apuntan desde otras páginas, mejorar eso es toda una campaña. Involucra inscribirse en directorios, ser recomendado por páginas afines, aparecer en blogs, participar en foros, redes sociales, quizás algo de publicidad en otros medios, el boca a boca, etc.
Que la página pueda ser eficientemente indexada por un robot también ayuda, y es en ese sentido que uso el término SEO. 

SEO es una de las muchas herramientas que se usan en la campaña para mejorar la posición. Me parece que es más claro así, que llamar SEO a las dos cosas y dar pie a confusiones.
El problema y las soluciones
Me parece que para entender lo que se hace en SEO hay que considerar cómo encontramos una página web.

En el principio, como ahora, fueron las páginas, y la necesidad de encontrar las páginas que contuvieran la información que queríamos. Para ayudar en eso, aparecieron directorios, como Yahoo, con enlaces que eran mantenidos manualmente. Quienes publicaban algo en la web, se inscribían al directorio y su página era enlazada bajo cierta categoría. Un buscador de texto ayudaba a localizar algún enlace en particular.

Luego, se automatizó el proceso, como lo hace Google, usando programas robots (llamados spiders) que navegan por la red, siguiendo enlaces y recomendaciones. De esa navegación de robots, se extrae información que permite construir listas de enlaces según las palabras clave que proporcionemos para la búsqueda.

La solución y el problema
Estos robots tienen capacidades limitadas de exploración, en comparación con los humanos. Pueden leer el texto simple contenido en los archivos HTML, pero no el que estuviera contenido en una imagen o fotografía. No pueden reconocer el significado de una forma. Aunque pueden reconocer las palabras no pueden reconocer lo que significan. Ni el mensaje contenido en un texto, o una foto, o un video. Aún no tienen esa capacidad.

A pesar de eso, son muy útiles para buscar entre las páginas de la red. Es más, tener un puesto relevante en el índice de los buscadores se ha vuelto tan importante como para que la gente se vea obligada a modificar la forma en que hace las páginas web, de modo que los robot no encuentren demasiados obstáculos al navegar por ellas.

Como los robots no pueden entrar a cierto tipo de medios, los humanos crean contenido textual alterno que los robots puedan ver e indexar. La labor del SEO es entender cómo hacerlo.

Ojalá quede un poco más claro que el SEO existe debido a las limitaciones de los robots para entender el contenido. La optimización de la que se habla es para ellos, no para los humanos.

Me parece que es importante tener presente esta situación para ver con más claridad las opciones disponibles.

El texto alterno
Quizás lo ideal sería que los robots de los motores de búsqueda pudieran entender el contenido del mismo modo que los humanos. Pero por el momento, sólo pueden reconocer texto simple así que, si tenemos contenido que no sea texto simple, hay que hacerles una versión textual para ellos.

Pero la capacidad de Internet para mostrar contenido multimedia ha ido aumentando, y probablemente continuará haciéndolo. Así que hay una porción cada vez mayor de la web a la que los robots no pueden acceder y que sería completamente invisible para los buscadores si no fuera porque introducimos manualmente contenido textual alterno.

Por otro lado, el tener contenido textual alterno puede ser útil no solo para los robots con capacidades limitadas, sino para los humanos con capacidades limitadas que accedan a las páginas.

Sin embargo, el tener contenido duplicado en diferentes versiones no parece muy eficiente. Sería mejor encontrar algún modo de presentar convenientemente las páginas según quién lo solicite. Multimedia para quién lo pueda apreciar, texto para quién solo pueda o quiera texto, etc. Pero todo a partir de la misma fuente.

El factor humano
Parece que, al menos por el momento, es un problema muy difícil aumentar las capacidades de los robots, porque se ha optado por la alternativa de usar a los humanos para eso. Por ejemplo, cuando un humano califica positivamente cierta información (haciendo click en "Me gusta" o "+1"), contribuye a hacerla más relevante para los buscadores.

Un solo individuo podría equivocarse, o manipular su voto, pero el conjunto de individuos muestra un comportamiento colectivo relevante que puede resultar de ayuda a la hora de buscamos algo.

Sin embargo, quizás nuestra inteligencia colectiva tenga ciertas preferencias y hayan espacios en la red que no se cataloguen tan bien como nuestras búsquedas quisiera.

Tal vez cuando haya robots que puedan entender más, se encarguen ellos de hacer las calificaciones positivas.

Mientras tanto, hacemos SEO.

Herramientas
Referencias

2011/07/18

Liberando la V, otra forma de usar un framework MVC

En el esquema MVC, se tienen modelos que proveen datos, y controladores que toman los datos y los procesan de algún modo antes de enviar el resultado a la vista.

En web, los framework MVC tratan de seguir este esquema para organizar el trabajo. En teoría, parte del equipo se puede enfocar en los modelos, otro en los controladores y otro en las vistas.

Al margen de si en la práctica realmente se cumple esto, es notable un problema: los modelos, vistas y controladores desarrollados determinan finalmente un API no estándar que termina "enjaulando" el producto final. Si decide actualizar el framework a la siguiente versión, encontrará que puede acarrear para el site un trabajo similar a volverlo a hacer. Aún más difícil es pasar un site de un framework a otro.

Esto genera algunos vicios. Si otro framework implementa cierta característica ventajosa, no lo podemos usar; tenemos que esperar hasta que algo similar sea implementado en el que usamos. Esa característica debe ser expresada otra vez, en los términos de nuestro framework.

En mi opinión, esto ocurre porque la página web ha sido forzada a encajar en el esquema MVC sobrescribiendo sus características estándar por otras propietarias, definidas por su sistema de templates particular.

Sí, aunque el framework sea open source, en este caso se está comportando como un ente propietario. Y eso es lo que provoca esta limitación de libertad.

Para tener más libertad, libere la vista. Puede desarrollar su sitio web de modo que las vistas sean HTML estándar y las partes dinámicas carguen con javascript (AJAX) los datos obtenidos de invocar algún framework.

Por ejemplo. Si uso Drupal como framework, puedo tener un subdirectorio drupal dentro de mi site, e invocar con javascript a algo como drupal/action.json, cuyo resultado reflejo en la página.

No hay problema con las páginas del site mientras no cambie el modo de invocar la accion. Si luego cambio la versión de drupal, no seria necesario cambiar las vistas.

Si, en lugar de usar drupal como nombre del subdirectorio, hubiera usado algo como framework, y colocara dentro acciones que se invocaran del mismo modo, entonces, podría usar cualquier framework, con tal que siguiera el protocolo esperado por las vistas.

Esta forma de trabajar puede permitir funcionar un sitio dinámico que use muchos frameworks diferentes en simultaneo. Uno para el login, otro para los listados, otro para comunicaciones, etc. El que mejor haga lo que queremos. También facilita la actualización de los frameworks a versiones superiores.

Usar javascript para esto me parece un camino relativamente asequible en este momento. Pero si alguien no desea usar javascript para eso, podría usar un framework unobstrusivo (que respete la integridad de las páginas), como uphp, para hacer el trabajo de reemplazo. uphp usa querypath para ubicar un elemento en la página (al estilo jquery, pero con php), y reemplazarlo por algún resultado; todo eso en el lado del servidor.

En este otro modo, no son las vistas las que invocan las acciones, sino los controladores que se disponen en el framework unobstrusivo (o uframework, para abreviar). El uframework podria invocar a otros frameworks para hacer los reemplazos de los resultados en las ubicaciones pertinentes en la vista. Igual, se podría usar varios frameworks a la vez.

La idea principal es que la vista salga de la jaula del framework, se respete su integridad, tal como es, y sea independiente de los motores que se usen para generar el contenido dinámico.

2011/07/08

Generación modular de HTML

Actualmente, cuando desarrolla un sitio usando cierto framework, no lo puede modificar con otro. Si está metido en esto, puede parecer obvio y hasta natural. Pero, si lo vemos en perspectiva, es algo así como una limitación por diseño. Algo que se podría mejorar.

Sites estáticos y dinámicos
Aunque el objetivo final es enviar html al navegador, en el desarrollo de sites dinamicos el paso intermedio es crear un conjunto de archivos que generen el html que se desea.

Cuando se trata de sites estáticos es más simple. Uno coloca los archivos en el directorio web y el servidor web los envía al navegador tal cual. Esos archivos son html, css, javascript, o imágenes que el desarrollador puede modificar con la libertad de elegir entre muchas herramientas para eso.

Cuando se trata de sites dinámicos las cosas se suelen complicar. En general, primero se plasma el diseño en un site estático, que luego es desmantelado para ver el modo de generarlo. Finalmente, se obtiene el site dinámico, que actúa como un generador total del html que se desea.

Ese suele se el enfoque más usado. Practicamente siempre que use C, Java, PHP, Ruby, Python, o lo que sea, lo que construye es siempre un generador total de html.

Frameworks exclusivos
El enfoque de la generación total tiene el problema de tender a soluciones monolíticas, con sus vicios asociados.

Si quiere modificar el site, tiene que modificar el generador, y tiene que entender el framework-que-todo-lo-hace.

Cuando un framework mejora, esa nueva versión no le sirve para el site que hizo con la versión antigua y tendría que reescribir el site bajo los nuevos términos.

Si otro framework implementa una característica que le gustaría, tendrá que esperar hasta que sea implementada, otra vez, en los términos del framework que usted usa.

Un montón de trabajo repetido.

Frameworks inclusivos
Una alternativa podría ser hacer generadores modulares. En lugar de generar el html de toda la página, un generador modular sólo produce el html de cierta región específica.

Para indicar dónde colocar el html dinámico, habrían algunas alternativas:

  • Que la página use javascript, obtenga el resultado y lo coloque.
  • Que la página use un tag especial que se reemplace por el contenido dinámico.
  • Que el servidor ubique los lugares dónde hacer el reemplazo y los haga.

La primera alternativa es relativamente asequible con lo que ya tenemos. Para las otras, habría que hacer un framework que se encargue de hacer los reemplazos adecuados (por ejemplo uphp).

Ya mismo podríamos empezar a desarrollar sites de ese modo. Una ventaja grande de usar generadores modulares, es que no importa en que lenguaje de programación se hacen, ni que framework usan, ni que versión del framework. Simplemente se usan. Podría usar generadores modulares escritos en C, Java, PHP, Python y Ruby... todos juntos!

2011/06/28

Liberando los sitios dinámicos

Imagine que le hicieran una página web y, un tiempo después, usted quiere modificar el documento HTML.

Imagine que puede abrirla en cualquier editor de texto, modificarla y volverla a grabar. Sin importar si se hizo en Dreamweaver, Geany, Notepad, o cualquier otro. Qué libertad.

Claro que no sólo lo podemos imaginar, de hecho podemos hacerlo.

Entonces, ¿por qué hemos permitido que esta libertad y conveniencia sea recortada por los frameworks? Porque eso es lo que ocurre.

Cuando hacemos un sitio dinámico, digamos en CakePHP, y, un tiempo después, usted quiere modificarlo, tiene que usar no sólo CakePHP, sino la misma versión de CakePHP. Del mismo modo si hubiera usado Zend, CodeIgniter o Drupal.

Es como si le dijeran que para abrir un HTML tiene que usar Notepad 4 y no otro, porque no es compatible. Que si quiere el mismo site para Notepad 5 hay que volverlo a hacer.

Sí, un site dinámico es más complejo que un documento HTML, pero la razón es similar. Es importante que el producto sea independiente de la herramienta usada para fabricarla. No sólo porque es un gran ahorro de esfuerzo y duplicidad. Sino también para que tengamos la libertad de elegir cualquier herramienta que queramos.

En el desarrollo web han aparecido islas, o silos. Al comienzo fue entre lenguajes, como ASP, JSP, PHP, Python, Ruby. Luego entre frameworks dentro de esos lenguajes. Y entre versiones de un mismo framework.

Muchos desarrolladores se amarran a cierta plataforma porque sus productos no pueden ser modificados con otra. Expresar un sitio dinámico en otro framework (o versión de framework) puede ser tanto trabajo como hacerlo de nuevo.

Después de todos los discursos que nos dan sobre la reinvención de la rueda, KISS (Keep It Simple, Stupid: Mantenlo Simple, Estúpido), DRY (Don't Repeat Yourself: No te Repitas), etc ¿no le parece poco razonable?

Hay razones por las que se prefirió que los protocolos web usaran texto simple. Para que cualquiera pudiera entrar a manejarlos. Quizás debemos recordarlo más seguido.


Imagine que le hicieran un sitio dinámico y, un tiempo después, usted quiere modificar el site.

Imagine que puede usar cualquier framework, modificarlo y guardarlo. Sin importar si se hizo en Drupal 6 o Drupal 7. O si se hizo en Zend o CodeIgniter. Incluso sin importar si se hizo en PHP, Ruby, Python o ASP. Qué libertad.

Claro que sólo lo podemos imaginar, pero podemos hacerlo.

2011/06/19

Proyectos como sistemas biológicos

Los proyectos de software no salen tan bien como se quisiera.

Un programador solitario, con talento, puede hacer código muy bonito, hasta cierto punto.
Cuando el proyecto llega a cierto tamaño o complejidad, es cada vez más difícil continuar.

Varios programadores, con talento, formando un equipo, pueden hacer algo muy bueno, muy por encima de lo que serían capaces con sus talentos individuales, hasta cierto punto.
Cuando el proyecto llega a cierto tamaño o complejidad, es cada vez más difícil continuar.

Los proyectos exitosos son aquellos que alcanzan ese punto límite no tan lejos de la meta que se proponían.

Pero la mayoría lo alcanza mucho antes.

Tratando de explicarse esto, hay quienes culpan a la gente. Pero sucede incluso en equipos compuestos de gente talentosa.

Parece que la respuesta es la organización.

La forma en cómo se organiza a las personas, las reglas o normas que siguen, de algún modo, van tejiendo una trama que, eventualmente, ahoga el proyecto.

Quizás haya un modo de lograr una organización sostenible.

Por lo pronto, se ha visto algunas cosas que funcionan mejor que otras.

Algo visible es más fácil de corregir. Algo simple es más fácil de ver. Algo modular es más simple de hacer. Algo descentralizado es más modular. Algo libre es más descentralizado. Algo que podemos corregir es más libre.

Cada ser vivo puede considerarse un tipo de sistema. Cada ser vivo tiene una vida, corta o larga, con un patrón de nacimiento, desarrollo, apogeo y remisión. Quizás sea propio de cada sistema. Quizás cada sistema está condenado por la complejidad que es capaz de alcanzar. El apogeo sería el aviso de la remisión inminente. Y la remisión el preámbulo de un nuevo nacimiento.

Quizás debamos dejar de comportarnos como si pudiéramos diseñar proyectos eternos, que muchas veces conducen a intentos efímeros, y diseñar proyectos con ciclos de ascenso y remisión, que inspiren y exhalen, que corran y duerman. Y todo eso, mientras evolucionan.

2011/06/17

Ubuntu menú de aplicaciones con iconos

En Ubuntu Natty Narwhal, no me agrada mucho que Unity, el nuevo sistema de escritorio de Ubuntu, requiera que uno descienda varios niveles para encontrar el menú de aplicaciones (Ubuntu logo, More Apps, All Applications).

Así que he instalado Cairo, que provee un docker similar al que se usa en Mac, o al que provee también RocketDock en Windows. Lo bueno de Cairo es que provee un acceso directo al menú de aplicaciones.

Sin embargo, noto que el menú de aplicaciones no muestra los iconos sino sólo la etiqueta de cada opción.

Encontré en tips4linux.com una manera de solucionarlo. Ejecutar en la consola de comandos:

gconftool-2 --type Boolean --set /desktop/gnome/interface/menus_have_icons True

Referencias

2011/06/16

Resolviendo inicio MySQL con Xampp en Ubuntu

Instalé Lampp (Xampp para Linux, xampp-linux-1.7.4.tar.gz) en Ubuntu (Natty Narwhal).

La ruta de instalación es /opt/lampp

Para iniciar lampp:

sudo /opt/lampp/lampp start

Obtuve un mensaje de error, indicando que MySQL no podía iniciar.

Parece que el problema tiene que ver con los derechos de escritura. La solución que me funcionó fue:

sudo -s
cd /opt
chmod -R 777 lampp
chmod 755 lampp/etc/my.cnf

Espero le sea de ayuda. Quizás alguien encuentre una mejor solución.

2011/06/14

Copia en Linux convirtiendo symlinks

En Linux, para copiar un directorio completo, se puede usar algo como:

cp -a origen destino

Si origen tuviera symlinks (enlaces simbólicos), estos se copiarían tal cual.

Si se desea que los symlinks se conviertan en los archivos a los cuales apuntan:

cp -aL origen destino

Esto parece que no esta muy documentado. Ojalá le sea de ayuda.

2011/06/11

Acceder a Nokia 3220 usando Gammu

El Nokia 3220 es un teléfono celular que vengo usando varios años. Ahora, quizás se puede considerar un modelo antiguo, pero puede tomar fotos de 640x480 px que se ven bien.

Para descargar las fotos, uso un cable tipo DKU5 que va del puerto serial del teléfono a un puerto USB de la computadora.

En el lado de la computadora, con Windows, se puede usar el Nokia PC Suite. Me ha funcionado bien con Windows XP. Con Windows 7 parecía no conectar bien, así que lo que hice fue correr Windows XP en un vmware para correr allí el Nokia PC Suite.

Muchas veces he tenido problemas para lograr la conexión. El teléfono suele decir 'Data enhancement not support', aún cuando finalmente la conexión se logre.

Ahora que estoy usando Ubuntu Linux (Natty Narwhal), encontré que se puede usar Gammu/Wammu para acceder al celular.

Instalé Wammu y lo probé. Tiene un wizard que permite identificar el celular conectado. Se logra hacer la conexión, pero no logré encontrar en la interfaz del programa el modo de descargar las fotos.

Entonces encontré el artículo COMO: Archivos de Nokia 3220 ( u otro ) a Ubuntu que me mostró el camino por la consola de comandos.

Primero instale Gammu (yo pensaba que Wammu lo había instalado pero no era así):

sudo apt-get install gammu

Luego, verifico que en ~/.gammurc esté lo siguiente (generado previamente por el wizard de Wammu):

[gammu]
port = /dev/ttyUSB0
connection = dku5fbus
name = Nokia 3220

Para comprobar la conexión, ejecuto:

gammu --identify

Obtengo:

Device               : /dev/ttyUSB0
Manufacturer         : Nokia
Model                : 3220 (RH-49)
Firmware             : 05.10 I (07-09-05)
Hardware             : 6203
...
Old simlock          : TIM Peru (716 10)
UEM                  : 400

Se puede obtener un listado de los archivos (en un formato tipo árbol):

gammu --getfilesystem

O también un listado plano:

gammu --getfilesystem -flatall

Con el listado plano, veo que los archivos de las fotos están en d:/predefgallery/predefphotos. Entonces, ejecuto:

gammu --getfilefolder d:/predefgallery/predefphotos

Y logré descargar mis fotos.

Para más ayuda sobre el comando gammu:

gammu --help
gammu --help filesystem

Al querer eliminar los archivos Image*.jpg, encontré que no funcionaba gammu --deletefiles d:/predefgallery/predefphotos/Image*.

Entonces, ubicado en el directorio donde descargué las fotos, ejecuté este comando:

for p in $(ls Image*); do echo $p; gammu --deletefiles d:/predefgallery/predefphotos/$p; done

Quizás les sirva de ayuda.

Referencias

2011/06/07

Acceder a un Server en Virtualbox desde el Host

Virtualbox es una aplicación que permite instalar un sistema operativo dentro de otro. Por ejemplo, puedo instalar Ubuntu Linux dentro de Windows 7. En el caso que describo a continuación, está instalado Windows XP dentro de Ubuntu Linux (Natty Narwhal).

Por qué
Al requerir un entorno de desarrollo Drupal que sea portable, la solución que encontré fue usar XamppLite portable (disponible para Windows) en un USB.

Como trabajar directamente en el USB me parece muy lento, copio el directorio de xampplite al disco duro y trabajo allí. Luego, al final del día, sincronizo esa copia con el USB.

Como todo el estado de la base de datos MySQL está en los archivos generados, al copiarlos todas las bases de datos, tablas y cambios se reflejan idénticamente.

Al volver a trabajar en Linux, me interesó encontrar un modo de levantar el xampplite. Intenté con Wine y, aunque arranca el panel de control de xampp, no se puede iniciar el servidor apache. Entonces, lo hice con Virtualbox.

Instalé Virtualbox 4.0.8 para Ubuntu y allí instalé Windows XP.

De modo que, en la jerga de la virtualización, Ubuntu es el Host y Windows XP es el Guest.

Pude correr xampplite y funcionaba apache. Pero no encontraba el modo de acceder al servicio web del Guest desde el Host.

Usando VBoxManage
No logré encontrar en la interfaz de Virtualbox un modo de configurar eso.

Después de navegar un poco en Internet, encontré en Sitepoint el artículo Build Your Own Dev Server with VirtualBox. Allí, la solución consiste en editar a mano el archivo XML de la configuración de la máquina virtual.

Si uno revisa ese archivo (VirtualBox.xml) puede encontrar la advertencia de no editarlo a mano. Así que indagué un poco más para ver si había otro modo y lo encontré en el artículo How to access a server running in a VirtualBox guest, que indica cómo hacer los cambios usando el comando VBoxManage.

Primero hay que apagar la máquina virtual. Los cambios se harán efectivos al reiniciarla.

Para listar las máquinas virtuales:

VBoxManage list vms

Hay que establecer varios extradata en el Guest "Windows XP":

VBoxManage setextradata "Windows XP" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/apache/HostPort" 8888
VBoxManage setextradata "Windows XP" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/apache/GuestPort" 80
VBoxManage setextradata "Windows XP" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/apache/Protocol" TCP

Para verificar:

VBoxManage getextradata "Windows XP" enumerate

Si hubiera que eliminar alguno, bastaría con darle un valor en blanco. Por ejemplo:

VBoxManage setextradata "Windows XP" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/apache/HostPort" 8888

A continuación inicié el Guest, y el servidor apache que contiene.

En el Host pude acceder al servicio web entrando a:

http://localhost:8888

Referencias

2011/06/03

XAMPP en Ubuntu

XAMPP empaqueta Apache, MySQL, PHP y otros programas que se suelen usar en programación web.

Instalar y usar XAMPP para desarrollo me ha venido resultando una alternativa más práctica que buscar/instalar/configurar cada uno de sus componentes por separado.

Para instalar XAMPP en Ubuntu se pueden seguir las instrucciones para el caso Linux, que aparecen en el sitio de ApacheFriends: http://www.apachefriends.org/en/xampp-linux.html.

Básicamente, consiste en descargar el tar.gz de la versión que se desea y extraer el contenido a /opt.

En mi caso, se trata de instalar XAMPP 1.7.1, que es la versión compatible con Drupal 6.
  • Descargo xampp-linux-1.7.1.tar.gz (http://sourceforge.net/projects/xampp/files/XAMPP%20Linux/1.7.1/).
  • Abro una consola de comandos y cambio a usuario root:
    sudo -s
  • Extraigo el contenido del tar.gz a /opt:
    tar -xvzf xampp-linux-1.7.1.tar.gz -C /opt
  • Para iniciar xampp:
    /opt/lampp/lampp start
  • Para detener xampp:
    /opt/lampp/lampp stop
  • Para establecer contraseñas (que se recomienda por seguridad):
    /opt/lampp/lampp security
Se puede observar que el comando es lampp. Ese era el nombre que ApacheFriends le había puesto. Sin embargo, es xampp para Linux.

Panel de Control
Para tener un panel de control similar al que estaba disponible en Windows:
  • En la consola de comandos:
    sudo gedit ~/.local/share/applications/xampp-control-panel.desktop
    En este caso uso gedit, pero también se pudo haber invocado otro editor de texto, como nano o vi.
  • En el editor de texto:

    [Desktop Entry]
    Comment=Start and Stop XAMPP
    Name=XAMPP Control Panel
    Exec=gksudo python /opt/lampp/share/xampp-control-panel/xampp-control-panel.py
    Icon[en_CA]=/usr/share/icons/Humanity/devices/24/network-wired.svg
    Encoding=UTF-8
    Terminal=false
    Name[en_CA]=XAMPP Control Panel
    Comment[en_CA]=Start and Stop XAMPP
    Type=Application
    Icon=/usr/share/icons/Humanity/devices/24/network-wired.svg
    

Después de eso, podrá encontrar una nueva opción en el menú: Applications/Other/XAMPP Control Panel.

Moviendo Dropbox

Hace algún tiempo que vengo usando Dropbox, el programa que facilita la sincronización de una carpeta en nuestro disco con otra en dropbox.com

De ese modo, los archivos que tenga en el dropbox de la computadora de la casa se sincronizan con el de dropbox de Internet y luego con el dropbox de la computadora de la oficina. Es como la idea del USB, pero automático.

Ahora que estoy empezando a trabajar con Ubuntu Linux, noté que Dropbox ha cambiado el nombre de su directorio por default. Antes se llamaba "My Dropbox" y había muchas quejas por eso en los foros. Ahora se llama simplemente "Dropbox". Es decir, que si elige que su directorio para dropbox esté en /home/rulo, por ejemplo, entonces el directorio de dropbox será  /home/rulo/Dropbox.

Como uso Linux al lado de Windows, y el disco de Windows es visible desde Linux, me parece buena idea que el dropbox que instale en Linux apunte al mismo directorio que el que tengo instalado en Windows.

Pero alli el directorio es "My Dropbox". Pensé que podría usarlo pero no, dropbox insiste en que el directorio se llame "Dropbox". Entonces, entré a Windows, fui a la configuración de dropbox e indiqué mover el directorio a una nueva ubicación. En micaso, elegí el directorio C:\Users\compaq, de modo que el nuevo directorio de dropbox es C:\Users\compaq\Dropbox.


Advertencia
Luego de esto fui a Linux e indiqué a dropbox que use la misma carpeta que Windows. Empezó por eliminar todo el contenido (!!!) y luego procedió a descargar lo que tenia en Internet.

Tome sus precauciones. Una mejor alternativa sería tener una copia del dropbox en otra carpeta y, luego de instalar dropbox, pausar la sincronización, pasar a mano los archivos, y reiniciar la sincronización. Quizás así se ahorraría tiempo en la sincronización inicial.

2011/06/01

Ubuntu Natty Narwhal con Windows 7

Hoy he instalado Ubuntu Natty Narwhal (ubuntu-11.04-desktop-i386.iso) junto a Windows 7, que ya estaba instalado. Aunque no ha sido tan fácil como parecía.

Intro
La PC de la oficina es una Compaq Presario CQ5310LA PC, con Windows 7 instalado de fábrica. Hace muchos años, en otra oficina, habitualmente usaba RedHat o Suse, pero recientemente la he pasado más con Windows XP y Windows 7.

Cuando necesito hacer alguna tarea en el servidor Linux, abro un terminal con Putty. Si quiero experimentar alguna aplicación Linux, puedo usar VMWare o VirtualBox para instalar allí alguna distribución.

Me gusta mucho la opción de la virtualización con VMWare o VirtualBox pero, si no hay mucha memoria,  todo el sistema se vuelve bastante lento.

Viendo a los amigos de la comunidad Drupal Perú usando Linux y, considerando los temas que me gusta investigar, me animé a dar el salto para volver a usarlo más intensivamente.

Sin embargo, hay algunas cosas de desarrollo web para las que tengo herramientas habituales en Windows. Así que lo tengo a la vuelta para cuando lo necesite, mientras voy desarrollando alternativas.

No tan fácil como parecía
No es la primera vez que instalo Ubuntu. Incluso antes he hecho una instalación dual con Windows XP. En aquella ocasión aprendí que a veces el sistema de arranque de Windows y el de Linux se cruzan y hay que hacer algunas correcciones luego del proceso.

Esta vez, vi con agrado que había una interfaz incluida en el proceso de instalación para cambiar el tamaño de la partición Windows existente para hacer espacio a la nueva partición para Ubuntu. Además, no requería de ninguna operación previa de defragmentación. Supuese que era una señal de que el proceso sería más facil ahora, pero no fue así.

Puse el instalador en un USB (usando Lili USB Creator) y reinicié el sistema para arrancar desde ahí.

En el proceso de instalación, el reparticionamiento fue casi automático. Indiqué 50 GB para la nueva partición Linux. Luego continuó bien pero, casi al final, falló por alguna razón. Un mensaje de error irrecuperable. Reinicié el proceso.

La segunda vez hice el proceso desde el escritorio del Live CD. Ya no ocurrió el error irrecuperable y la instalación se completó, pero tardó bastante tiempo la descarga de los archivos de actualización y otros. Quizás hubiera dejado esa opción para después. Sin embargo, como estaba en el escritorio, podía navegar mientras esperaba :)

Cuando reinicié, esperaba que apareciera el menú de inicio de Grub (usado para iniciar Linux), pero la pantalla se quedó en negro, con el rectángulo que muestra el monitor cuando no recibe ninguna señal.

Probé reiniciar varias veces, sin resultado. Felizmente hice backup, pensé.

Por si acaso, repetí el proceso de instalación. Para no descargar las actualizaciones, desconecté el cable de red y así fue un poco menos el tiempo. Pero el resultado fue el mismo.

Felizmente, usando el navegador de archivos del Live CD podía comprobar que los archivos de Windows estaban allí. El problema era que se había perdido el arranque.

Hice un disco de rescate en otra máquina que también tiene Windows 7 y seguí el procedimiento de reparar el sector de inicio. Reinicié, pero seguía igual.

Una esperanza
Entonces, cruzado de brazos, vi como después de casi un minuto, en la pantalla apareció Ubuntu. Al parecer, el sistema si iniciaba, pero con un Grub silente. Sin Grub, ¿cómo escoger la opción de iniciar con Windows?

Investigando, encontré una solución para corregir el inicio perdido de Windows. Consiste en usar el disco de rescate para iniciar una consola y desde allí ejecutar:

bootrec /fixmbr
bootrec /fixboot

Funcionó y se inició Windows 7 normalmente.

Más o menos
Ahora, para tener un acceso a Ubuntu iba a intentar tratar con Grub, pero antes probé bajar el utilitario EasyBCD, que había visto mencionaban en los foros.

Allí, modifiqué el menú de inicio, agregando un nuevo item para sistema operativo Linux, tipo de inicio Grub2 (el usado por Ubuntu 11). Salve los cambios y reinicié.

Esta vez, apareció un menú de inicio provisto por Windows. Elegí Ubuntu. La pantalla se puso negra y, luego de un rato, apareció Ubuntu.

Corrigiendo el menú de Grub
Encontré una solución al problema de la pantalla negra antes de Ubuntu. Al parecer, no se estaba presentando bien el menú de grub. En la consola ejecuté:

sudo gedit /etc/default/grub.conf

Para editar el archivo de configuración de grub. En lugar de gedit también se puede usar otro editor, como nano.

En grub.conf, localizar la línea #GFX640x480 y descomentarla, de modo que queda:

GFX640x480

A continuación:

sudo update-grub

Al reiniciar la máquina, aparece primero el menú de inicio de Windows (el que configuré con ayuda de EasyBCD). Si elijo Ubuntu, aparece el menú de inicio de Grub. Bien.

Restableciendo el arranque de Grub
Quizás se podría simplificar el pasar primero del menú de inicio de Windows al menú de inicio de Grub.

Se puede conseguir reinstalando el menú de inicio Grub:

sudo grub-install /dev/sda

En mi caso, /dev/sda es el disco donde se coloca el inicio.

Al reiniciar la máquina, aparece primero el menú de inicio de Grub. Si elijo Windows, aparece el menú de inicio de Windows. Tiene sentido.

Para que no aparezca el menú de inicio de Windows, uso EasyBCD para quitar la opcion Ubuntu y además indicar que omita el menú de inicio.

Una vez hecho esto, al reiniciar la máquina, aparece sólamente el menú de inicio de Grub, desde donde se puede elegir Linux o Windows.

En resumen
Para instalar Ubuntu (11, Natty Narwhal) junto a un Windows 7, ya instalado:

  • No es necesario reparticionar el disco antes de correr el instalador de Ubuntu. Tampoco es necesario defragmentarlo.
  • Ejecutar el instalador de Ubuntu, eligiendo la instalación lado a lado, junto al Windows 7 existente e indicando el tamaño de la partición destinada a Ubuntu. Un mínimo recomendable suele ser 20 GB. Yo elegí 40 GB, pero puede ser tanto como se quiera.
  • Sí, luego de ejecutar la instalación, no se ve ningún menú que permita elegir qué sistema iniciar, aguardar un poco. En mi caso, me parece que luego de 30 segundos, se iniciaba Ubuntu.
  • Para corregir la falta de visualización del menú de inicio de Grub, editar el archivo /etc/default/grub.conf y descomentar la linea #GFX640x480.

Referencias

2011/05/16

2011/04/27

.htaccess para proteger index.html

Se puede usar .htaccess para proteger el acceso a un determinado archivo en un directorio. En este caso, se desea proteger el acceso a http://example.com/protegido/

.htaccess
En el directorio que contiene a index.html:

<FilesMatch index.html>
AuthUserFile /var/www/.htpasswd
AuthType Basic
AuthName "Pagina Privada"
Require valid-user
</FilesMatch>

.htpasswd
/var/www/.htpasswd se puede crear usando el comando htpasswd:

cd /var/www
htpasswd -c .htpasswd uuu

Donde uuu es el nombre del usuario al que se quiere dar acceso a ese directorio.

Files o FilesMatch
Inicialmente habia usado Files en lugar de FilesMatch, pero me permitía entrar al directorio omitiendo index.html en el url.

Por ejemplo, si el url era:

http://example.com/protegido/index.html

Podía entrar con:

http://example.com/protegido/

En cambio, con FilesMatch se protegieron ambos accesos.

2011/04/23

Cómo sombrear filas alternas con CSS3

A esta forma de presentar filas se le suele llamar cebra.

Caso Tabla

HTML
<table class="zebra">
  <thead>
    <tr>
      <th>Col0</th>
      <th>Col1</th>
      <th>Col2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Item</td>
      <td>Item</td>
      <td>Item</td>
    </tr>
    <tr>
      <td>Item</td>
      <td>Item</td>
      <td>Item</td>
    </tr>
    <tr>
      <td>Item</td>
      <td>Item</td>
      <td>Item</td>
    </tr>
  </tbody>
</table>

CSS
table.zebra tbody tr:nth-child(2n+1) {
  background-color: #eef;
}

Normalmente, las tablas presentan sus celdas con un borde. Para ocultarlo, se puede usar el atributo html border="0". Sin embargo, también se puede hacer usando estilos, con algo como:

table.zebra {
  border-collapse: collapse;
  border-spacing: 0;
}

Caso Lista

HTML
<ul class="zebra">
  <li>Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>

CSS
ul.zebra li:nth-child(2n+1) {
  background-color: #eef;
}

Normalmente, las listas presentan sus filas con un bullet. Para ocultarlo, se puede usar estilos, con algo como:

ul.zebra {
  list-style: none;
  padding: 0;
}

2011/04/15

uphp


Con HTML, el contenido se mezcla con etiquetas que permiten mostrarlo en un navegador.
CSS permite separar la data del formato de la data del contenido.
Javascript permite poner código en las etiquetas para manipular el documento e interactuar con sus elementos.
Unobstrusive javascript es una forma de usar javascript que procura mantener el código aparte. jQuery ayuda mucho en esto.
JSP, PHP, etc, permiten generar HTML, abriendo la puerta a la automatización y al uso de recursos como las bases de datos.
Frameworks web permiten para manejar el desarrollo de un site relativamente extenso o complejo.
El modelo de framework MVC (Modelo-Vista-Controlador), viene del mundo Smalltalk a la web para separar el desarrollo en esas tres capas.
En mi opinión, aumenta la inercia del proceso de desarrollo. Expresar una solución web en términos MVC se convierte en un problema adicional.
Drupal usa un modelo de framework diferente, ingenioso, permitiendo agregar libremente componentes que pueden colaborar entre sí.
También requiere algo de tiempo y trabajo aprender a pensar y expresar cualquier solución en sus términos. A cambio, a mi parecer, permite ser mucho más productivo que en cualquiera de las alternativas anteriores.
En general, estos frameworks requieren que aprendamos una nueva versión de lo que ya sabemos hacer en web. A veces, incluso hay que hacer ese reaprendizaje de una versión a otra del mismo framework.
¿No le parece que algo tiene que cambiar?
¿Habrá alguna forma de hacer dinámica una página estática sin tener que reescribirla? 
Encontrando a QueryPath, algo como un puerto de jQuery para PHP, que facilita la manipulación de una página, me pareció que podría haber alternativas.
uphp es la búsqueda de una forma de desarrollar web en la que el código afecta al contenido pero se manteniene aparte.
De ese modo, se pueden respetar las páginas estáticas de un site mientras se lo vuelve dinámico.
Además, se podría usar, tal cual, soluciones HTML/CSS/Javascript que sean independientes del framework.
Quien sabe, quizás tambien se halle una forma de hacer todo eso y además separar la data del contenido de la data HTML.

2011/04/07

Cómo definir un selector CSS que requiera dos clases

El problema que tenía involucraba bloques similares a:

proyectos-vista_1
<div class="view view-proyectos view-display-id-page_1">
  ...
</div>

proyectos-vista_2
<div class="view view-proyectos view-display-id-page_2">
  ...
</div>

noticias-vista_1
<div class="view view-noticias view-display-id-page_1">
  ...
</div>

noticias-vista_2
<div class="view view-noticias view-display-id-page_2">
  ...
</div>

Necesitaba aplicar un estilo únicamente al bloque proyectos-vista_1. Podría ser más fácil si éste tuviera un id, pero no lo tenía (así lo construye Drupal, en este caso).

La solución la encontré en este artículo. Consiste en usar un selector como:

.view-proyectos.view-display-id-page_1 {
  ...
}

Qué sencillo. No me lo imaginaba :-) Ojalá te sirva de ayuda tambien.

Referencia
Defining A CSS Selector That Requires A Multi-Class Union

2011/04/05

Separación entre párrafos en Flash

Para aprovechar esta característica, el documento flash debe ser para Flash 10 y Actionscript 3.

Cuando defina un texto, asegúrese de que es de tipo TLF (no la opción Classic Text). Esto permite acceder a propiedades avanzadas para el control de texto como Spacing, que permite controlar el espaciado entre párrafos.

Algo que hay que tomar en cuenta es que, a diferencia de la mayoría de procesadores de texto, donde el espaciado después del párrafo se suma al espaciado anterior del párrafo siguiente, en flash se solapan. Lo que significa que si el espaciado antes del párrafo es 12px y el espaciado despues del párrafo es 24px, el espaciado entre dos párrafos no será 36px, sino 24px.

Referencia:
http://www.flashconf.com/flash-cs5/flash-cs5-paragraph-styles/

2011/03/23

Cómo evitar que Chrome abra un PDF

Normalmente, Chrome abre los enlaces a documentos PDF en la misma ventana. Quizás esto le parezca cómodo a algunas personas pero, al menos para mí, no lo es.

El problema
Si el documento es muy pesado, podemos tener una página en blanco largo rato, sin mayor indicación de lo que esta pasando. Prefiero descargar el documento y luego abrirlo cuando yo quiera.

Una forma es usando el clic secundario, Guardar como, en lugar de hacerle clic al enlace. El problema es que algunas veces no es obvio que el enlace va a abrir un PDF y es un poco molesto retroceder y corregir la acción.

Además, algunas veces no hay enlace, sino un botón de formulario, y entonces no se puede usar el Guardar como.

Configurando Chrome
Deshabilitar esto en Chrome no es tan obvio. No se encuentra la opción en la pantalla de configuración.

Una forma de hacerlo es entrar a la dirección:

chrome://plugins/

Aparecerá una lista de los plugins instalados. Ubique Chrome PDF Viewer y deshabilítelo.

2011/02/19

Organizar ventanas en un snap

AquaSnap es una utilidad que puede ser de mucha ayuda en el manejo de las ventanas.

Puede descargarla de http://www.nurgo-software.com/products/aquasnap, o también la versión portable desde http://portableapps.com/apps/utilities/aquasnap_portable.

Cuando la ejecuta, se coloca como tray icon (por la zona de su reloj) para que haciéndole doble clic pueda cambiar su configuración, si lo desea.

La forma de usar aquasnap es simple:

  • Si arrastra una ventana hacia uno de los bordes, la ventana se pegará hacia ese borde y, además, sus dimensiones ocuparán esa mitad de la pantalla.
  • Si arrastra una ventana hacia una de las esquinas, la ventana se pegará hacia esa esquina y, además, sus dimensiones ocuparán ese cuarto de la pantalla.
  • Si arrastra una ventana y la sacude, se tornará translúcida; podrá ver lo que hay debajo y se mantendrá así hasta que la sacuda otra vez.
Esto es con la configuración por default. Haciendo doble clic en el tray icon puede elegir otras opciones.

2011/02/17

Resolviendo keys para Putty SSH a Hostmonster

Hoy he pasado algunas horas resolviendo este tema.

ssh genera dos llaves (por ejemplo id_dsa -la privada-, e id_dsa.pub -la pública-).

Se pueden generar con alguno de los comandos:

ssh-keygen -t dsa

ssh-keygen -t rsa

Según el tipo que se desee.

Hostmonster también tiene un generador de llaves (al parecer ssh) que puede producir archivos similares.

Uno puede producir llaves de diverso tipo (dsa, rsa), con o sin password.

[ssh]----> id_dsa     (llave privada)
       +-> id_dsa.pub (llave pública)

[ssh]----> id_rsa     (llave privada)
       +-> id_rsa.pub (llave pública)

Los nombres pueden ser id_dsa, id_rsa, u otro cualquiera. Por ejemplo, yo estuve practicando con kobaonli_id_dsa, hp_id_dsa.

Putty es un programa que permite hacer conexiones SSH usando estas llaves (Connection/SSH/Auth).
Pero no puede usar las llaves privadas así generadas, requiere que antes sean convertidas a .ppk, con un programa como puttygen.

Puttygen tiene la opción Conversions/Import que permite importar una llave privada generada con ssh (u OpenSSH) y generar el .ppk correspondiente.
Sin embargo, tuve problemas para que puttygen (versión 0.60) reconociera llaves privadas que tuvieran password, así que generé llaves sin password.

[ssh]----> id_dsa ----[puttygen]----> id_dsa.ppk
       +-> id_dsa.pub

[ssh]----> id_rsa ----[puttygen]----> id_rsa.ppk
       +-> id_rsa.pub

Así que, en resúmen:

A) Usando llaves locales

- Usé ssh-keygen -t dsa para crear hp_id_dsa/hp_id_dsa.pub, sin password.
- Usé puttygen para importar hp_id_dsa y crear hp_id_dsa.ppk, sin password.
- En Hostmonster, CPanel, SSH/Shell Access, Manage SSH Keys, importé hp_id_dsa/hp_id_dsa.pub y luego en Manage Authorization autoricé su uso.
- Indiqué a putty que usara hp_id_dsa.ppk para el SSH/Auth.
- Me pude conectar a Hostmonster usando las llaves hp_id_dsa[.ppk]/hp_id_dsa.pub

[ssh]----> hp_id_dsa ----[puttygen]----> hp_id_dsa.ppk
       +-> hp_id_dsa.pub
           |
           v
          [hostmonster]

B) Usando llaves remotas

- En Hostmonster, CPanel, SSH/Shell Access, Manage SSH Keys, creé kobaonli_id_dsa/kobaonli_id_dsa.pub, sin password. Descargué la llave privada kobaonli_id_dsa a mi PC.
- Usé puttygen para importar kobaonli_id_dsa y crear kobaonli_id_dsa.ppk, sin password.
- Indiqué a putty que usara kobaonli_id_dsa.ppk para el SSH/Auth.
- Me pude conectar a Hostmonster usando las llaves kobaonli_id_dsa[.ppk]/kobaonli_id_dsa.pub

[hostmonster]----> hp_id_dsa ---->[pc]----[puttygen]----> hp_id_dsa.ppk
               +-> hp_id_dsa.pub

Referencias

2011/02/16

Cómo centrar un bloque en una página 2

En el artículo Cómo centrar un bloque en una página, contaba sobre un método que venía utilizando para lograr centrar un bloque en una página.

Ayer, un amigo me mostró una página posicionada de ese modo que no cabía en la ventana de su navegador Safari. Este mostraba el centro pero no permitía alcanzar la cabecera, ni siquiera usando la barra de scroll. En otros navegadores, como Firefox, Chrome e incluso Internet Explorer, si un bloque no cabe en la ventana, se muestra lo que quepa, de arriba hacia abajo. Pero en el suyo lo hacía desde el centro hacia afuera.

Comprobé que otras páginas que había hecho usando ese método presentaban el mismo problema cuando las veía con Safari y reducía las dimensiones de la ventana.

Buscando la explicacion a esto, encontré el artículo Easy Vertical Centering with CSS, que muestra un método diferente a los usuales, bastante simple y que, sorprendentemente, funciona en todos los navegadores en los que lo he probado, incluyendo Firefox 3.6, Chrome 9, Safari 5, IE8 e IE6.

La idea
La idea básica es mover el top del bloque de contenido al centro de la página y luego corregir el desplazamiento subiéndolo la mitad de la altura del bloque de contenido.

Usualmente, en el bloque de contenido, se usa algo como:

#page {
  width: 960px;
  height: 684px;
  position: absolute;
  top: 50%;
  left: 50%;
  margin-top: -342px;
  margin-left: -480px;
}

Pero presenta el problema del que estamos hablando, que cuando la página es mas alta que la ventana es difícil alcanzar la cima.

Hay otro método que usa una técnica ingeniosa: usar un bloque flotante para jalar al bloque de contenido. Una propiedad del bloque flotante es que jalará mientras se pueda; si algo se interpone (como otro bloque o el borde de la ventana), dejara de hacerlo. Es justamente lo que se necesita.

Aquí, el HTML de una página que usa ese método:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Page Center</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<style type="text/css">
html, body {
 height: 100%;
 margin: 0;
 padding: 0;
}
body {
 background-color: #eed;
 min-width: 960px;
 min-height: 683px;
}
#vertical-float {
 float: left;
 height: 50%;
 margin-top: -342px; /* half vertical height*/
 width: 100%;
}
#page {
 clear: both;
 background: #fff;
 width: 960px;
 height: 683px;
 margin: 0 auto;
 overflow: auto;
}
</style>
</head>
<body>
<div id="vertical-float"></div>
<div id="page-wrapper">
  <div id="page">
    <h1>Content</h1>
  </div>
</div>
</body>
</html>

Observar que la información de la altura del bloque de contenido (#page) está presente tanto en el bloque de contenido como en el bloque auxiliar (#vertical-float).

Referencias

2011/02/15

Instalando Git en Centos 5

Para comprobar si se tiene instalado Git, ejecutar:

git --version

Si no está instalado, puede instalarlo usando yum. Pero, en Centos 5, normalmente no está disponible un repositorio que contenga el paquete git.

Para comprobarlo, como usuario root, en la consola de comandos, ejecute:

yum install git

Obtendrá un mensaje que le dirá que el paquete git no está presente.

Puede agregar el repositorio EPEL (Extra Packages for Enterprise Linux), creando el archivo /etc/yum.repos.d/epel.repo:

/etc/yum.repos.d/epel.repo
[epel]
name=Extra Packages for Enterprise Linux 5 - $basearch
#baseurl=http://download.fedoraproject.org/pub/epel/5/$basearch
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-5&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL

[epel-debuginfo]
name=Extra Packages for Enterprise Linux 5 - $basearch - Debug
#baseurl=http://download.fedoraproject.org/pub/epel/5/$basearch/debug
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-debug-5&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL
gpgcheck=1

[epel-source]
name=Extra Packages for Enterprise Linux 5 - $basearch - Source
#baseurl=http://download.fedoraproject.org/pub/epel/5/SRPMS
mirrorlist=http://mirrors.fedoraproject.org/mirrorlist?repo=epel-source-5&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL
gpgcheck=1

Si se procediera a la instalación ahora, la instalación no se completaría porque yum solicitaría /etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL.

Para prevenir eso, descargue ese archivo antes:

cd /etc/pki/rpm-gpg
wget http://download.fedora.redhat.com/pub/epel/RPM-GPG-KEY-EPEL

Luego, ejecute:

yum install git git-daemon

Al final, debería aparecer una indicación de que el proceso se completó con éxito.

Para comprobar si se tiene instalado Git, ejecutar:

git --version

Buscar

Más artículos

Archivo