Google Maps a pie

July 23rd, 2008

Desde hace poco Google Maps permite calcular recorridos a pie. Siempre lo ha hecho en coche pero lo nuevo es que ahora calcula los recorridos a pie si así se lo decimos. De esta forma no tiene en cuenta el sentido de circulación de las calles y simplemente calcula el camino más corto entre dos puntos. ¿O no?

Además, también te calcula el tiempo estimado a pie, algo bastante útil para ciudades que no son la tuya y en la que no te haces una idea de la escala del mapa.

He hecho la prueba en el recorrido que hago desde mi casa a la Alhambra todos los martes y los jueves para ir a trabajar y me he quedado un poco sorprendido de los resultados obtenidos:

Este es el camino que me calcula Google:

Ruta de Google

Y este el que hago yo:

Ruta que hago yo

Como podeis ver en la ruta de Google se tardan 42 minutos, mientras que en la mía, se tardan 41 minutos. Algunos detalles curiosos:

  • La ruta es de desde A (mi casa) a B (el trabajo). Si la calculamos desde B a A, el tiempo es de 37 minutos ya que el camino es cuesta abajo en este último caso.
  • Realmente yo tardo unos 30 minutos cuesta arriba y unos 25 cuesta abajo, pero como me pica la curiosidad, mañana me pienso cronometrar.
  • El único motivo que se me ocurre por el que Google no me haya dado mi ruta (se tarda menos) es porque mi ruta tiene más recorrido con una cuesta más pronunciada. Si esto fuera así es para fliparlo. El difunto Dijkstra estaría orgulloso.

Actualización: Hoy me he cronometrado en el trayecto A->B y he tardado 28 minutos. Parece que ando más rápido de lo que estima Google Maps.

Y ya van 5

July 4th, 2008

Escribo este post desde la última charla de la quinta Guadec Hispana. Quién lo diría desde aquel primer encuentro en Almendralejo, pero lo cierto es que hemos pasado ya por La Coruña, Vilanova, Granada y Fuenlabrada. Afortunadamente yo he tenido la suerte de asistir a todas ellas y ya es casi una cita obligada para mí. Más aún cuando sólo he podido ir a la Guadec internacional una vez.

Han sido dos días muy agradables viendo a viejos conocidos como Germán, los Carlos, Álvaro, Palomo, Daniel, Claudio, Roberto, Domingo y muchos otros que posiblemente olvide.

Al igual que GCubo, el grupo de personas de GNOME-Hispano es ya un grupo de amigos primero y de desarrolladores/usuarios de GNOME después. Tristemente, y al igual que GCubo otra vez, cada vez se ven menos caras nuevas. Aquí en la Guadec se ha hablado de esto y se han intentado buscar causas y soluciones sin llegar a un acuerdo concreto.

Al final, para mí no deja de ser un par de días muy agradables en un ambiente distendido y divertido en los que siempre aprendes cosas nuevas pero sobre todo mantienes el contacto con un puñado de personas que vienen todos los años porque les apasiona esto del software libre. Como a mí.

Algunas caras de esta Guadec-es

Libros que leí en el 2007

January 17th, 2008

Siguiendo un poco el ejemplo de Malglam, aunque con un poco más de retraso, aquí os dejo la lista de libros que leí el año pasado:

Conan de Cimmeria. Volumen 1. 1932 – 1933

conan-1.jpgConan siempre ha sido uno de mis héroes desde pequeño y aunque no tuviera muchos comics de él, tras ver la película Conan el Bárbaro, siempre que podía imitaba sus mandobles con una fregona. Ahora tengo la edición de coleccionista de la película y estos dos tomos que Ana me ha regalado este año. Lo que no sabía de pequeño es que Robert E. Howard, el autor del personaje, era coetáneo de H. P. Lovecraft, uno de mis autores preferidos. Eso se nota en algunas descripciones y sensaciones que transmiten los relatos de Conan, quién puede matar a un gorila de un puñetazo pero cuando se enfrenta a hechiceros y a lo desconocido en general tiene miedo y prefiere evitarlo. A través de los relatos cortos que componen el libro te haces una idea de la personalizad de Conan: bruto y primitivo pero al mismo tiempo inteligente y justo. Un libro muy recomandable si tienes los 60 eurazos que cuesta esta edición de super lujo :-)

Conan de Cimmeria. Volumen 2. 1933 – 1934

conan-2.jpgMás de lo mismo, es decir, genial. Esta vez hay menos relatos pero son más largos. El último, “La Hora del Dragón”, me ha parecido el mejor relato de Howard de los que he leido. Es casi una novela por su extensión y habla de los días en los que Conan ya era rey de Aquilonia, de cómo le arrebatan el trono y de cómo consigue recuperarlo. Ojalá alguién haga un día una película de este relato.

Añoranzas y Pesares

anoranzas-y-pesares.jpg Añoranzas y pesares es una trilogía compuesta de 4 libros. Es trilogía porque el tercer y cuarto libro originariamente eran uno solo pero por su tamaño las editoriales decidieron dividirlo en dos. Me lo he leido porque Ana me lo ha recomendado y porque en general soy muy aficionado a los libros de fantasía. El libro engancha mucho porque la historia es rápida y dinámica (me leí los 4 libros en dos meses) pero creo que eso es todo lo bueno que puede decir sobre él. Es bastante predecible y algunas cosas parecen copias literales de El Señor de los Anillos pero bueno, junto con Ken Follet o Stephen King, creo que el autor es uno de esos que hacen libros como churros y libros que enganchan mucho.

Paper Prototyping

paper-prototyping.gifEste libro trata de una técnica que me llamaba la atención desde hace algún tiempo: hacer prototipos en papel de programas informáticos. Básicamente viene a decir que es tan poco lo que cuesta hacer un prototipo en papel y tanto lo que se aprende de él que todos los proyectos de software deberían hacerlos en sus fases iniciales. El libro hace especial hincapié en los tests de usabilidad usando prototipos de papel pero yo creo que hacer prototipos de papel es también de enorme utilidad para etapas de análisis y posterior implementación.

Es un buen libro pero quizá excesivamente largo para las 4 o 5 ideas claves que explica. La verdad es que al final se me hizo algo pesado.

User Interface Design for Programmers

ui_for_programmers.jpgEste libro lo leí durante mi estancia en Brasil en la magnifica biblioteca de Async. Me gustó tanto que he decidido comprarlo y releerlo en este año pasado. Como la mayoría de los libros que me gustan, es un libro corto y escrito en un lenguaje informal y muy atractivo, como casi todo lo que escribe Joel. Se basa en la premisa de que los programadores y los usuarios tienen modelos distintos de los programas informáticos y que un programa será tanto más usable cuanto más se acerque su modelo al modelo del usuario. Este concepto tan difuso es explicado con suma claridad en los capítulos del libro, que en total, no me llevaron más de 3 tardes en leerlo.

Don’t make me think

dont-make-me-think.jpgAl igual que el User Interface Design for Programmers, este libro también lo leí en Brasil y también me fascinó. Se lee en el mismo tiempo que se lee un Mortadelo, uno se rie casi igual y se aprende un montón sobre usabilidad de páginas web. Como el anterior, el libro gira en torno a una premisa: cualquier elemento de una página web (o cualquier interfaz de usuario) que haga pensar al usuario y le obligue a tomar una decisión, sobra. En los siguientes capítulos desarrolla esta idea y pone numerosos ejemplos con webs existentes de cosas que se deben hacer y cosas que no se deben hacer. Especial mención merece un apéndice al final del libro donde encontramos una carta modelo para tu jefe o tu cliente explicándo por qué no se deben hacer páginas web con gifs animados, introducciones en flash y demás aberraciones que sólo podemos perdonarle a Homer Simpson.

The C Programming Language

the-c-programming-language.jpgHe de confesar que a estas alturas de la vida no había leído este libro y tenía una mezcla de curiosidad y mala conciencia por ello. Afortunadamente ha sido fácil de remediar y he de decir que el libro no me ha decepcionado lo más mínimo, cosa que suele pasarme por ejemplo con ciertas películas, que todo el mundo recomienda y luego la ves y dices “no es para tanto”. Pienso que este libro debería ser de obligada lectura en la carrera de informática ya que explica de forma clara y cristalina conceptos difíciles de coger la primera vez que empiezas a programar como los arrays, las cadenas de caractéres, los punteros, etc. Lo único que me falta para completar esta lectura es desarrollar un programilla sencillo pero útil donde pueda poner en práctica lo que he aprendido y/o recordado con este libro.

The Mythical Man Month

the-mythical-man-month.jpgEste es el tercer y último libro de este post de los que leí en Brasil. Es considerado un clásico en la ingeniería del software y comprende un montón de artículos sobre el desarrollo de aplicaciones software de complejidad y tamaño considerables. En él viene a decir que la tarea más compleja de hacer una aplicación es la comunicación entre las distintas partes involucradas: el cliente, el arquitecto de software, los analistas, los programadores, etc. A consecuencia de esto añadir más mano de obra a un proyecto de software que lleva retraso según la planificación original no sólo no resuelve el problema sino que lo agrava. Otro artículo interesante incluido en el libro es “No silver bullet” en el que viene decir que en la informática no hay una herramienta/tecnología/metodología mágica que mejore sustancialmente la creación de software tal y como han ido vendiendola distintos fabricantes desde finales de los años 60. Es curioso (o aterrador si se quiere) comprobar que casi 40 años después, este paper sigue siendo tan verídico como en la fecha en la que se publicó. Lo de silver bullet (bala de plata) es porque compara el proceso de creación de software con un hombre lobo por los peligros que ello conlleva y la bala de plata es lo único que mata al hombre lobo. En informática no hay balas de plata.

El tío Petros y la conjetura de Goldbach

tio_petros.jpgEsta novela la ví comentada en barrapunto y un día que estaba en Alcampo, estaba en la sección de novedades y me hice con ella. Es un libro fácil de leer y bastante realista. La verdad es que me costaba creer que fuera una novela en lugar de una biografía y estoy seguro de que está inspirada/basada en la vida de un célebre matemático. La historía trata la vida de un matemático griego con una capacidad extraordinaria que dedica su vida a resolver la conjetura de Goldbach todo contado desde la perspectiva de su sobrino, el verdadero protagonista del libro. No cuento más detalles para no fastidiarle el libro a nadie. En definitiva, es un libro ameno y muy interesante.

Snow Crash

snow-crash.jpgSnow Crash se considera uno de los libros que iniciaron el género de Ciber Punk. Tiene un estilo ágil y rápido con las descripciones justas y diálogos llenos de dobles sentidos y argot. Esto hace que se lea muy rápido pero al mismo tiempo requiere concentración por parte del lector para que no se le pase ningún detalle de la enrevesada trama. Su visión del futuro no es muy tentadora pero su gran dosis de humor negro y cinismo hace que al final sea una experiencia divertida, por lo menos al leerla. Vivir en ese mundo me imagino que y no es tán divertido. La portada de mi edición es la de la foto y es bastante más cutre: una chica en 3D encima de una patineta voladora. Es bastante dificil que te tomen en serio cuando te ven en el autobus leyendo un libro con dicha portada….

Hegemonía o Supervivencia. La estrategia imperialista de Estados Unidos

hegemonia-o-supervivencia.jpgEste libro me lo regalaron Mario y Montero el año pasado y es un poco denso de lee, lleno de referencias a otros libros, de cifras y estadísticas. Todo para poner a Estados Unidos en su lugar. Después de leer el libro lo único que se te queda es una sensación de mala leche e impotencia enorme tras ver que todas tus sospechas sobre este país eran ciertas y Chomsky simplemente las ha investigado y plasmado aquí. No apto para personas sensibles a las injusticias mundiales.

El ecologista escéptico

el-ecologista-esceptico.jpgEste libro me lo recomendó mi buen amigo Jaime, el escéptico por excelencia :-) He decir que aún no lo he terminado porque si bien el de Chomsky era denso esté es más compacto que un mantecao de maritoñis. Lo bueno es que esta dividido en distintas partes y puedes leerlas en el orden que quieras porque son más o menos independientes excepto la primera que es la introducción y que es la que deberías leer primero. El libro viene a decir básicamente que los medios de comunicación tienden a darnos malas noticias sobre el mundo y que las buenas casi nunca nos llegan. Así es normal que siempre estemos en estado de alerta y paranoia esperando que llegue el siguiente cataclismo. El autor insiste en que es necesario hacer un análisis detallado de los problemas que asolan el mundo (porque haberlos haylos, eso está claro) para poder decidir en qué emplear nuestros (escasos) recursos de la mejor forma posible. No creo que nadie pueda estar en contra de está idea tan racional.

The Alphabet of Manliness

alphabet-manliness.jpgEl alfabeto de la masculinidad es un libro escrito por el autor de la mejor página del universo y que no te decepcionará. Por favor, abstenganse las mujeres en general y las feministas en particular porque el libro es muy politicamente incorrecto. Cada letra del alfabeto la asocia con un sígno claro de la masculinidad. Algunos ejemplos son la H de Heavy Metal, la C de Costillas de Cerdo, la T de tetas o la P de patada en el culo. Como se puede ver, todos ellos claros símbolos de masculinidad. Si te gustaron las frases de Chuck Norris, este libro te encatará. El que quiera saber más, el libro tiene hasta su propia web.

Los Hijos de Húrin

hijos-hurin.jpgPor último, este año pasado me leí los Hijos de Hurín, de Tolkien padre aunque editado y juntado por Tolkien hijo. He de decir que he leido más de un libro de los que ha publicado Tolkien hijo y sólo este me ha parecido bueno. El Libro de los Cuentos Perdidos, el Retorno de la Sombra y otros como estos me parecieron un mero trabajo de corta y pega. Pero en esta ocasión parece que se ha esmerado. La historia que cuenta no es nueva si has leido el Silmarilion, eso sí esta mucho más desarrollada y se puede leer sin tener que memorizar 50 nombres para no perderte. La gente que lee el Silmarilion y no les gusta porque esperan que sea otro Señor de los Anillos se sentirán un poco menos decepcionados con este libro. Aunque la verdad, a mí el Silmarilion me encantó. Este libro me ha gustado tanto que lo he comprado 3 veces este año: uno para mí y dos para hacer regalos, a Ana y a Daniel, las otras dos personas en el mundo que conozco que están casi tan flipadas con Tolkien como yo.

¿Genialidades o aberraciones?

December 15th, 2007

Ayer paseaba con Ana por la zona de juguetes de Carrefour con la excusa barata de mirar algo para los sobrinos de Ana (imagina si es mala excusa que los regalos de dichos sobrinos ya están comprados) y es que nos encanta ver los juguetes de los niños de hoy en día.

Cuál fue nuestra sorpresa al ver, escondido entre cajas fosforitas y muñecos cabezones, esta auténtica joya del mashup jugueteril:

transformers-starwars-1.jpg

Sí, estais en lo cierto, se trata de un X-Wing que se transforma en Luke Skywalker. No diréis que el creativo de turno no tuvo un sueño chungo ese día.

transformers-starwars-2.jpg

Por cierto, es impresionante como 8 de cada 10 juguetes giran en torno a una de estas pocas temáticas: Spiderman, Piratas del Caribe, Harry Potter, Transformers o la Guerra de las Galaxias. Así no es extraño ver pistas de coches de Piratas del Caribe o patines de Spiderman.

Cena de Navidad

December 13th, 2007

Lo primero, el comunicado oficial:

Ahora que lo veis más claro os detallo el menú que me ha pasado el dueño:

Una ensalada para cada cuatro personas a elegir entre:

  • Ensalada alemana
  • Ensalada de la casa
  • Ensalada hortelana

Entrante para cada cuatro personas:

  • Albóndigas en salsa de tomate

Un plato para cada persona a elegir entre:

  • Seitan al ajillo con arroz
  • Patatas al estilo del Chef
  • Taquitos de soja en salsa de almendras
  • Arroz integral, setas y gluten
  • Cuscus con verduritas al curry
  • Cuscus al estilo tunecino
  • Espaguettis integrales con salsa de champiñon
  • Lasagna vegetal

Pan

Bebida: refresco, cerveza o vino de la casa

Postre: pastel de queso o tarta de chocolate y avellanas

Infusión digestiva

Todo esto cuesta 18 euros. También me ha dicho que, por supuesto, podemos pedir a la carta. En este caso el único inconveniente es que tardarán más en servirnos. Bueno eso, y que supongo que nos saldrá algo más caro, pero tampoco creo que mucho más.

Ya sabéis, id confirmandome en los comentarios los que vayais a venir ya que el martes le tengo que decir un número bastante cercano a los que vayamos a ser. También es importante que digais si os va mejor la opción menú o la carta.

I like Unix

December 3rd, 2007

Last friday started as any other friday. I went to the office, plugged in my laptop and logged into my Fedora 7 system. Open a shell, setup a couple of environment variables, launch postgresql and start programming in Django. What a wonderful job, isn’t it?

Well, it is until you get errors like this:

[lgs@portatil-lgs saludinnova]$ python manage.py runserver
Validating models...
0 errors found
Django version 0.97-pre-SVN-6670, using settings 'saludinnova.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Error: That port is already in use.

Wait, I run the exact same command yesterday at the end of my job day and it actually worked! I immediately thought about a virus since I swear I didn’t change the system in any way. Or maybe I did…

So first, I needed to know which program was using the Django sacred port: 8000. Of course I can run Django development server in another port. But that’s not the point. And it’s not fun!

But first let’s make sure something is listening in port 8000:

[root@portatil-lgs ~]# nmap -sT -O localhost

Starting Nmap 4.20 ( http://insecure.org ) at 2007-11-30 10:39 CET
Interesting ports on portatil-lgs (127.0.0.1):
Not shown: 1691 closed ports
PORT STATE SERVICE
22/tcp open ssh
25/tcp open smtp
111/tcp open rpcbind
631/tcp open ipp
5432/tcp open postgres
8000/tcp open http-alt
Device type: general purpose
Running: Linux 2.6.X
OS details: Linux 2.6.17.8 SMP (x86)
Uptime: 0.080 days (since Fri Nov 30 08:43:31 2007)
Network Distance: 0 hops

Right, http-alt, what’s that?

[root@portatil-lgs ~]# ps aux | grep http-alt
root 6045 0.0 0.0 4032 752 pts/0 S+ 10:40 0:00 grep http-alt

No process is called http-alt. No big surprise since it looks like a standard name not binded to a real application. Let’s check the well known services:

[root@portatil-lgs ~]# cat /etc/services | grep 8000
irdmi 8000/tcp # iRDMI
irdmi 8000/udp # iRDMI
mtl8000-matrix 8115/tcp # MTL8000 Matrix
mtl8000-matrix 8115/udp # MTL8000 Matrix
biimenu 18000/tcp # Beckman Instruments, Inc.
biimenu 18000/udp # Beckman Instruments, Inc.
nxlmd 28000/tcp # NX License Manager
nxlmd 28000/udp # NX License Manager
nimcontroller 48000/tcp # Nimbus Controller
nimcontroller 48000/udp # Nimbus Controller

Still no clue of what’s going on. Let’s try netstat:

[root@portatil-lgs ~]# netstat -anp | grep 8000
tcp 0 0 127.0.0.1:8000 0.0.0.0:* LISTEN 2333/nasd

Aha! I got you nasd daemon! Whatever you are.

[root@portatil-lgs ~]# which nasd
/usr/bin/nasd
[root@portatil-lgs ~]# rpm -qf /usr/bin/nasd
nas-1.9.1-2.fc7
[root@portatil-lgs ~]# yum remove nas
Dependencies Resolved
=============================================================================
Package Arch Version Repository Size
=============================================================================
Removing:
nas i386 1.9.1-2.fc7 installed 1.3 M
Removing for dependencies:
qt4-x11 i386 4.3.2-4.fc7 installed 16 M
skype i586 1.4.0.118-fc5 installed 15 M

Finally I see the guilty program: it was Skype (well, one of its dependencies, a sound server), which I installed on thursday night to speak with my sister, who lives in Slovaquia. So it looks like I actually changed my system but I really couldn’t think about this kind of side effects. Fortunately my box is full of tools to help my damaged brain repair this tiny little problems :-)

An address form

November 20th, 2007

In the Zope 3 app I’m working at we have person objects that can have a list of addresses associated to them. No rocket science so far. So I needed to create an add and an edit forms for this. Something with url like these:

  • http://yourhost/app/people/john/addresses/+/@@addAddress.html
  • http://yourhost/app/people/john/addresses/3/@@editAddress.html

Now you wonder how an address looks like. Quite simple, let’s look at its interface:

class IAddress(IContained):

    line = zope.schema.Text(

        title=u'Line',

        description=u'Street type and number information',

        required=True

    )
    country = zope.schema.Choice(

        title=u'Country',

        description=u'Country',

        vocabulary='CountriesVocabulary',

        required=True,

    )

    state = zope.schema.Choice(

        title=u'State',

        description=u'State',

        vocabulary='StatesVocabulary',

        required=False,

    )

    postalCode = zope.schema.Choice(

        title=u'Postal Code',

        description=u'Postal Code and City',

        vocabulary=u'PostalCodesVocabulary',

        required=False,

    )

    contact = zope.schema.TextLine(

        title=u'Contact',

        description=u'Contact information',

        required=False

    )

    notes = zope.schema.Text(

        title=u'Notes',

        description=u'Other notes',

        required=False

    )

As you can see the country, state and postal code are choices taken from different vocabularies. I have models for those objects and the structure is hierarchical: A country contains state and a state contains postal codes.

I could just store the postal code inside the address since I can retrieve its state and its country just from the postal code. We decided not to do so to because of two reasons:

  • To keep our queries and business logic simpler. For example, consider you want a report of all your customer living in Spain…
  • So we could use the hierarchical relationships to aid our users in the addresses forms.

I’ll explain the second reason in more detail in this post. What I wanted to accomplish was something like what you see in this small screencast:

addres-form-screncast.gif

As you see, the user first select the country in the first dropdown list, this will fill the state dropdown list with all the states belonging to that country. Similarily, when the user chooses a state the postal codes
dropdown list will be filtered.

I started implementing this with the wrong approach which I will also describe here for the record.

Wrong approach

In Zope 3 a choice field gets it list of possible values from something called a vocabulary (or more recently, a source). This can be anything that returns a list of terms. In our case the country vocabulary will
get the list of country objects from the database. I have a countries folder registered with an ICountries interface so the task of getting the list of country objects is quite easy:

class CountriesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        for name, countries in zope.component.getUtilitiesFor(ICountries):
            terms += [SimpleTerm(country, country.__name__, country.name)
                      for country in countries.values()]
        super(CountriesVocabulary, self).__init__(terms)

Building the states and postal codes vocabularies is a little more difficult since they depend on a context. This mean that the states vocabulary will depend on a specific country and the postal codes vocabulary will depend on a specific state. But the context won’t be the country neither the state in this two cases but the address object since the vocabularies are used in fields of the IAddress interface. Using this idea I coded these vocabularies:

class StatesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        if IAddress.providedBy(context):
            country = IAddress(context).country
            if country:
                terms = [SimpleTerm(state, state.__name__, state.name)
                         for state in country.values()]

        super(StatesVocabulary, self).__init__(terms)

class PostalCodesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        if IAddress.providedBy(context):
            state = IAddress(context).state
            if state:
                terms = [SimpleTerm(pc,
                                    pc.__name__,
                                    u'%s - %s' % (pc.code, pc.city))
                         for pc in state.values()]
        super(PostalCodesVocabulary, self).__init__(terms)

So far so good but here is my problem: when you create or edit an address object you need to hit the save button three times to store the country, state and postal code. Why is this? Let’s try to reproduce these three steps:

  1. Step 1: You select a country and save the address
  2. Step 2: Now the states vocabulary will be filled with the list of states for the country you choosed in step 1
  3. Step 3: Finally you can choose a postal code from the postal codes of the state you choosed in step 2.

Note that until you saved the country the vocabulary for states won’t have that information and thus, will return an empty term list. Same thing happens with the postal codes.

Even if you can get the proper information using AJAX in the form and fill the dropdown lists with the right information you won’t be able to save the address object since the vocabularies are also used for validation
purposes.

No need to say this was a pain in the ass and kepts my brain busy for a few days until I found the right solution.

Right approach

The lesson learned from the previous approach was that something was wrong with dictionaries which depended on a context in such a strict way. In the IAddress interface I should keep the fields simple enough to let the form set any state on the state field and any postal code in the postal code
field. As I still want some integrity in my data it’s time to delegate that to an invariant. In other words, I will any value of the right type into the state and postal code attributes and after that I will validate these
fields with an invariant that will make sure the state is inside the country and the postal code is inside the state. An invariant like this:

def postalCodeInsideStateInsideCountry(address):
    country = address.country
    state = address.state
    postalCode = address.postalCode
    if country is not None and state is not None:
        if state not in country.values():
            st = state.name or state.__name__
            co = country.name or country.__name__
            raise zope.schema.ValidationError(
                u"The state %s does not belongs to country %s" % (st, co)
                )

        if postalCode is not None:
            if postalCode not in state.values():
                pc = postalCode.code or postalCode.__name__
                st = state.name or state.__name__
                raise zope.schema.ValidationError(
                    u"The postal code %s does not belongs to state %s" % (pc, st)
                    )

Then I just add this declaration inside the IAddress interface:

class IAddress(IContained):
    ...

    zope.interface.invariant(postalCodeInsideStateInsideCountry)

Next I’ll have to rewrite my vocabularies to be context-free and return the full list of objects in each case:

class PostalCodesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        for name, countries in zope.component.getUtilitiesFor(ICountries):
            for country in countries.values():
                for state in country.values():
                    prefix = country.__name__ + '/' + state.__name__ + '/'
                    terms += [SimpleTerm(RSP(pc),
                                         prefix + pc.__name__,
                                         u'%s - %s' % (pc.code, pc.city))
                              for pc in state.values()]

        super(PostalCodesVocabulary, self).__init__(terms)

class StatesVocabulary(SimpleVocabulary):
    zope.interface.classProvides(IVocabularyFactory)

    def __init__(self, context):
        terms = []
        for name, countries in zope.component.getUtilitiesFor(ICountries):
            for country in countries.values():
                terms += [SimpleTerm(RSP(state),
                                     country.__name__ + '/' + state.__name__,
                                     state.name)
                          for state in country.values()]

        super(StatesVocabulary, self).__init__(terms)

You may note that the token of each term has a prefix now. This is because the token should be unique inside that vocabulary. I’m using the country code and the state code with a slash separating them because I will use
this token later in javascript.

This fixed my problem as now I’m able to create an address object with just a save button hit without losing data integrity but I still have one more problem: my forms list all states and postal codes no matter which
country is selected in the case of states and what state is selected in the case of postal codes. Seems like all these efforts didn’t help me to accomplish what I initially wanted.

It’s time for some javascript to make things truly dynamic.

Adding javascript for a richer user experience

My solution was to add a small jQuery script and a couple of related views to fill the dropdown lists every time the user changes them. This mean that if the user selects a country, an ajax request will be made to retrieve the list of states for that country and will populate the state select tag with those options. Similar behaviour happens when the user changes the state.

Let’s see the jQuery code:

(function($){

$(document).ready(function () {

    function fillSelect(data) {
        var options = $.map(data, function (obj, index) {
            return '<option value="' + obj.id + '">' + obj.name + '</option>';
        });
        return '<option value="">(no value)</option>n' + options.join("n");
    }

    $("select#form.country").change(function () {
        var value = $(this).val();
        if (value) {
            var currentState = $("select#form.state").val();
            var url = '../../Countries/' + value + '/@@states.json';
            $.getJSON(url, function (data) {
                $("select#form.state")
                  .html(fillSelect(data))
                  .val(currentState)
                  .change();
            });
        } else {
            $("select#form.state").html(fillSelect([])).change();
        }
    });

    $("select#form.state").change(function () {
        var value = $(this).val();
        if (value) {
            var currentPostalCode = $("select#form.postalCode").val();
            var url = '../../Countries/' + value + '/@@postalCodes.json';
            $.getJSON(url, function (data) {
                $("select#form.postalCode")
                  .html(fillSelect(data))
                  .val(currentPostalCode);
            });
        } else {
            $("select#form.postalCode").html(fillSelect([]));
        }
    });

    /* initialize combos */
    $("select#form.country").change();
});

})(jQuery);

Final thoughts

The last bit of love that this form need is some support for adding countries/states/postalCodes when the user is filling an address and that information is not yet in the database. It shouldn’t be too hard to add some javascript buttons that ask the user for that and post it to the server. Then update the selects and let the user choose the new created object.

Pycha 0.1.0 released. Just another pet project

October 17th, 2007

I’ve been writing Pycha in the last days. It is a Python library for drawing Charts as its name suggests :-) You can learn more about it at http://www.lorenzogil.com/projects/pycha/

Sample pycha chart

What I’d like to comment here is the amount of work needed for releasing a piece of free software. We usually think that’s not too much but I always get surprised about how many things you need to do besides writing the code.

You need to choose a license, this will probably means reading for a while about the options out there and try to make a balance between a license that will make your software easy to distribute and a license that won’t make you (or your users) lose freedom.

You need to package the software. I chosed setuptools for this task as I like the idea of Python Eggs. As this is my first egg, I needed to read the manual, do some tests, try again and so on.

You need to write some decent docs. This means installation instruction, examples, general overview, etc. I did it in English and Spanish as some times I think I do too many things in that foreign language forgetting about my own language. Writing this blog is one of them :|

You need to setup a website with the docs, some instructions for downloading and getting the software, a bug tracking system and probably a wiki. Fortunately we have Trac which makes this pretty easy. I got a problem with Trac in Fedora 7 but reading Trac’s Wiki solved it (tip: you need the python-sqlite2 package).

You need to write some tests, otherwise nobody with a sane brain will want to use your risky library. This is something I still need to do but hopefully I’ll be able to do it before the weekend.

You need to do the actual release. This involve writing an entry in the CHANGES.txt file, updating the version, tagging the repository, uploading to PyPi, etc. I used this document as a release guide.

Nothing is really mandatory but if you want to get some value from releasing a project with a free software license you pretty much need to do all of the above. In other words, no docs, no tests, no bug tracking system means no people interested, no community, no feedback, no bug reports, no patches, nothing.

So go and play with pycha and tell me what you think!

A captcha for Chuck Norris

October 8th, 2007

My friend Juan sent me this captcha today.

captcha-ruso.jpg

I guess it’s only for Chuck :-)

 Some other funny captchas here

The Making Of AnaLogica.es

October 4th, 2007

It’s been almost a month since my last post and now it’s when I say it’s because I’ve been busy and think I meant lazy. For this time I have a proof: I’ve been making a website for a friend’s pop band, Ana Lógica It’s not completely finished but most of the work is already done.

I’ll try to describe the proccess of creating such a site so beware of a very boring post if you are not into web development.

First Steps: requirements gathering

The first thing I did was talk with my friend/client about what they wanted. We decided to take another website as a model for a start point. That website is http://www.lombardafolk.com/ and I did it too, some years ago.

As this was very vague talking I had the feeling I lack more information from them about what exactly they wanted. The model website was about an old folk band and this one was about a new pop band and some requirements are different.

I drew all the screens in paper in a fairly detailed manner (10 screens in total). Then I photocopied them and got 5 copies and scheduled a meeting with all the members of the band. We met in a bar and while drinking some beers we discussed my design. They liked it generally but gave me some new ideas and spotted minor things they didn’t like or I did fogotten. We also made a list of the multimedia and information material they needed to give to me. I was really happy with the results of that initial meeting because:

  • They got a pretty realistic view of how their website was going to look like
  • The paper prototype allowed us to speak about something touchable and not about abstract concepts
  • That made possible to discuss improvements and changes of my design and also to make a good checklist of the material needed

It took us less than one hour and a half (including other chats, drinking and eating) and I got everything I needed to get me started. Lesson learned: always meet the client before you make any coding and if you can, make a paper prototype, you can’t imagine how much work and frustration you will save by doing so.

Mockup 1

Mockup 2

Mockup 3

Mockup 4

Mockup 5a

Mockup 5b

Mockup 5c

Choosing the technology

Now that I knew what I had to do I needed to choose how to do it. In other words, the technology. I choosed Django over Zope or PHP for this project for the following reasons:

  • It was a well defined project that is not going to change or grow a lot in the future. No need for a component architecture here.
  • Most of the information is read only (except for the guest book) so no fancy forms were needed. This is one of the weak points of Django in my opinion but I didn’t needed them for this project.
  • The users (the members of the band) are young savvy computer users so the Django Admin interface is perfectly usable for them. I didn’t want to maintain the content of the website so this is a big +1 for Django’s admin interface. These three reasons pushed me to decided Django over Zope3 and for PHP…
  • I only choose PHP if the application is already done in PHP (and I need to extend it or fix it) and/or the hosting is fixed and it doesn’t allow my other favourite technologies. Neither the case for this project.

Coding, the fun part

It was time to get my hands dirty so I created a subversion repository to put my code in and started to make a Django 0.96 application. I only worked in my (not so frequent) spare time. I started on the 5th of September and got a beta version yesterday. Acording to my commits I worked 13 days and I estimate an average of 2-3 hours each day: around 30 hours in total. Not too bad, huh?

First I designed the models and created the database. For development I used SQLite and for deployment I used MySQL. I set up some fixtures so I didn’t have to input all the data again and again. By designing almost all the models initially, rebuilding the database was something I didn’t have to do very often.

Then I started to write views for each tab page. It’s important to note that I didn’t write any CSS code yet. The pages were really ugly but at the same time were pretty clean and allowed me to focus on the functionality and structure without distractions. I made 80% of all view code before even thinking on any visual design issue.

Then my friend sent me the material. He sent me the graphics for all their home-made records and reminded me that they want the website to look similar to the last record graphical design. So I opened my vector graphics application (Inkscape) and designed the homepage of the website. I thought about doing that in a raster graphics application (GIMP) but happily I used Inkscape which let you change a lot of stuff much more easily than with GIMP.

When I finished the graphical design I sent it to my friend for validation and after some minor corrections they all agreed with it so I could continue. Then I started moving that desing into the website using CSS and some graphics. I’m pretty proud of the final result since it’s quite elastical and adapt to a wide range of screen resolutions. Of course its XHTML and CSS validates and it’s quite accesible. Long life to web standards!

Next challengue was to make a template tag for the navigation tabs so it could automatically detect which one was selected in each view. In the settings.py file I had a list of tabs:

NAVTABS = (
('/', 'Noticias'),
('/songs/', 'Canciones'),
('/pictures/', 'Fotos'),
('/concerts/', 'Conciertos'),
('/band/', 'El Grupo'),
('/contact/', 'Contacto'),
)

Each tuple having an url prefix and the label of the tab. Then my custom templatetag looks like this:

@register.inclusion_tag('navtabs.html', takes_context=True)
def navtabs(context):
    request = context['request']
    path = request.get_full_path()
    tabs = [dict(url=url, title=title, current=path.startswith(url))
            for url, title in settings.NAVTABS]
    active_tabs = [t for t in tabs if t['current'] is True]

    # We may have two or more current tabs if prefixes are the same
    # In this case the longest matching prefix wins
    if len(active_tabs) > 1:
        # sort the tabs by its length
        def sorter(tab1, tab2):
            return cmp(len(tab1['url']), len(tab2['url']))
        active_tabs.sort(sorter)

        # The only current one is the longest one (the last)
        for tab in active_tabs[:-1]:
            tab['current'] = False

    return {'navtabs': tabs}

And the template navtabs.html looks like this:

<ul id="nav-tabs">
{% for tab in navtabs %}
<li {% if tab.current %}class="current"{% endif %}><a href="{{ tab.url }}">{{
tab.title }}</a></li>
{% endfor %}
</ul>

Now, all I have to do in my master template file is add this piece of code to have automatic navigation tabs! :

{% load navtabs %}
{% navtabs %}

And if I change, add or remove a tab I just need to update the settings.py file.

Automatic downloads

Something the band wanted is that the users could download their songs. I thought about two options: a) downloading each songs individually so you can get a grasp of how the band sounds like and b) download the whole album if you liked them. This way everybody saves bandwidth :-) But I didn’t want to store the mp3 files twice in the storage server. Each one individually and a ZIP for each record with the mp3s inside it.

So I decided to create the zip files on the fly:

def record_download(request, record_id):
    record = get_object_or_404(Record, id=record_id)
    buffer = StringIO.StringIO()
    zip = zipfile.ZipFile(buffer, "w")
    for song in record.song_set.all():
        filename = song.get_audio_filename()
        zip.write(filename, os.path.basename(filename))
    zip.close()

    name = u'Ana Logica - %s.zip' % unicode(record.title, 'utf-8')
    name = name.encode('utf-8')
    response = HttpResponse(mimetype="application/zip")
    response['Content-Disposition'] = 'attachment;filename="%s"' % name
    response.write(buffer.getvalue())
    return response

Layout problems and JQuery rescue

My layout is the typical header – main content with right sidebar – foot layout and I wanted to apply a soft background image tileable vertically in the sidebar. Usually you go for a liquid layout where you fix the width of the website and create a big horizontal image (something like 800×5 pixels) and repeat it all over the main content. That way, when you float right the sidebar everything looks like the height of the sidebar is the same as the height of the main content even when that is not actually the case. But I had two problems:

  • My width was not fixed but a percentage of the screen width resolution
  • My background image was not 5 pixel tall but 356 pixels height

So how did I solved it? Using a javascript oneliner :-) :

$(document).ready(function () { $("#sidebar").height($("#body").height()); });

Now my sidebar is always as tall as the main content (div id=”body”) of my website and the background image is applied properly.

I had a problem with 800×600 screen resolutions: as the main content has a width of 80%, in those resolutions it was not big enough and the tabs collide with the logo. Some more javascript and problem solved:

function fix_layout() {
  /* If the window is too small, no margins */
  if ($(window).width() < 880) {
    $("div#page-wrapper").css("margin", "0");
  } else {
    $("div#page-wrapper").css("margin", "0 10% 0 10%");
  }
  /* Make the sidebar as tall as the #body element */
  $("#sidebar").animate({height: $("#body").height()}, 1000);
}

$(document).ready(fix_layout);
$(window).resize(fix_layout);

Now you can see that when the user has an old screen he/she can still view the website properly but with no margins. I love the way javascript looks after dressing it with JQuery :-)

Automatic thumbnailing

As the band is going to update the content and not me I wanted the design to stay as good as initially. This mean no big images popping suddenly in the middle of a news item or a gallery. This also means I can’t trust my users to resize the images because they are humans and humans usually forget those tedious things. So I stolen this small template tag to get automatic thumbnailing for free:

def thumbnail(file, size='200x200'):
    # defining the size
    x, y = [int(x) for x in size.split('x')]
    # defining the filename and the miniature filename
    basename, format = file.rsplit('.', 1)
    miniature = basename + '_' + size + '.' +  format
    miniature_filename = os.path.join(settings.MEDIA_ROOT, miniature)
    miniature_url = os.path.join(settings.MEDIA_URL, miniature)
    # if the image wasn't already resized, resize it
    if not os.path.exists(miniature_filename):
        filename = os.path.join(settings.MEDIA_ROOT, file)
        image = Image.open(filename)
        image.thumbnail([x, y], Image.ANTIALIAS)
        image.save(miniature_filename, image.format)
    return miniature_url

register.filter(thumbnail)

This is an example of how to use it:

{% if newsItem.picture %}
<img alt="" src="{{ newsItem.picture|thumbnail:"100x100" }}" width="100" height="100"/>
{% endif %}

Stop spam, read books

Something I had learned from the past is this rule: every public HTML form you put in a website is going to be used for spam sooner or later. You need to assume it and live with it: either you don’t put public forms or you fight spammers with a captcha or similar techique. I decided to go with recaptcha.net as it looks quite nice and they use the information the users write for digitalizing books. Really smart.

Adding support for recaptcha is fairly easy:

  1. Register in recaptcha.net and get a pair of keys. Put them in the settings.py file
  2. Download the python package for recaptcha and just put the captcha.py file inside your application
  3. Write a template tag stupidly simple using the displayhtml function of the previous captcha.py file:
    @register.simple_tag
    def recaptcha():
        return captcha.displayhtml(settings.RECAPTCHA_PUBLIC_KEY)
  4. Add this to your template, inside the form:
    {% load recaptcha %}
    <form method="post" action=".">
    {{ form.as_p }}
    {% recaptcha %}
    <p class="center"><input type="submit" value="Enviar" /></p>
    </form>
    {% endblock %}
  5. Add this function to your view:
    def captcha_is_valid(request):
        challengue = request.POST.get('recaptcha_challenge_field', '')
        response = request.POST.get('recaptcha_response_field', '')
        ip = request.META.get('HTTP_X_FORWARDED_FOR', '')
        captcha = submit(challengue, response, settings.RECAPTCHA_PRIVATE_KEY, ip)
        return captcha.is_valid
    
    def contact_form(request):
        if request.method == 'POST':
            form = ContactForm(request.POST)
    
            if captcha_is_valid(request) and form.is_valid():
                # send the mail
                ...

The problem with recaptcha is that you need to type two words instead of one and the band members have complained to me saying it may be too difficult for their visitors. Sigh :-(

Conclusion

I probably forget to mention some stuff but I guess this post is already way too long so I will stop now. I’ll just mention that I developed the whole thing using Firefox 2.0 and I tried the page in Internet Explorer 7.0 I was happily surprised since it looked pretty good. I know it doesn’t look as nice in Internet Explorer 6.0 and I need to do some more work to fix it but the success with IE 7.0 made me happy and I have hopes in a web development future where we can finally say, write one surf everywhere :-)

Besides using strict standards I recommend you using ‘em’ instead of ‘px’ in your stylesheet as much as you can to get best results.

Well, that’s all for now, I hope you learn something from my experience. I certainly did with this project and get some fun with it!