Uploading files to wordpress and SELinux problems

July 24th, 2008

If you use Fedora and Wordpress and you get this error while trying to upload an image to your post:

The uploaded file could not be moved to /usr/share/wordpress/wp-content

All you need to do is labeling your uploads directory with the httpd_sys_content_t type:

[root@nyarlathotep wp-content]# pwd
/usr/share/wordpress/wp-content

[root@nyarlathotep wp-content]# chcon -t httpd_sys_content_t uploads/ -R

I hope this is useful for somebody else.

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