Meaning Tool

jueves, 24 de septiembre de 2009
Popego es un prometedor startup Argentino encabezado por Santiago Siri, que si mis cálculos no fallan es además el hermano del talentoso humorista Liniers. La idea básica del sitio web es que utilizando técnicas de aprendizaje automático puede reconocer los intereses de sus usuarios (consultando por ejemplo tu Flickr, tu blog o tu Twitter) y recomendar contenidos nuevos de la web que se relacionen con dichos intereses. La idea sin duda es interesante, y con la creciente proliferación de contenidos creados por usuarios en la red, la organización y filtrado de los mismos se vuelve muy trabajosa.

Conocí Popego cuando un compañero de la facultad, Pablo Ridríguez Zivic (que en su momento era ayudante en mi cursada de Algoritmos 2), entró a trabajar ahí. Popego fue sponsor de la PyCon y tuve la oportunidad de charlar con Francisco, uno de sus empleados en el stand que habían armado.

La novedad

Francisco estaba presentando Meaning Tool, una herramienta derivada de la investigación y desarrollo realizados para Popego y que ahora estará disponible para su uso mediante una API por otros desarrolladores y sitios web. Meaning Tool es (por el momento) una herramienta de clasificación automática de contenido, que se diferencia básicamente de todo lo que yo conocía en que es amigable y puede ser utilizada por cualquiera.

La idea de Meaning Tool es que uno construye un listado de categorías y entrena al sistema con contenidos categorizados para que éste aprenda a reconocer qué temas son tratados por un determinado contenido. Por ejemplo, esta herramienta podría servir para que los posts de mi blog se etiqueten automáticamente en las distintas categorías sin que tenga que hacerlo yo manualmente. Si bien me ahorraría un poco de trabajo, la verdadera magia del sistema está en que puede aplicarse sobre cantidades masivas de contenido (a diferencia de los miserables 2 posts por año de este blog), y las posibilidades son inmensas.

Sin ir muy lejos, el negocio de publicidad de Google comenzó porque tenían a disposición las herramientas de procesamiento semántico que le permitían (y le permiten) colocar avisos publicitarios relacionados con el contenido de las páginas web en qué aparecían. Así, no te encontrás con que mi blog te muestra un aviso sobre licuadoras, sino temas relacionados con el contenido que yo escribo, lo que aumenta muchísimo el impacto de la publicidad. Cosas como esta ahora se democratizan gracias a Meaning Tool, que las pone al alcance de muchos más desarrolladores.

Una ¿loca? opción electoral en la UBA

sábado, 19 de septiembre de 2009
Como todos los años, la última semana se eligieron en Exactas los representantes tanto de estudiantes como de graduados para el Consejo Directivo. Dicho consejo se compone por una mitad de representantes de profesores, y una cuarta parte tanto para alumnos como para graduados. El panorama como siempre es colorido (en cuanto a afiches y trifulcas), y siempre presente está el infaltable acoso electoral, también conocido como ¿ya votaste?


NO es democracia

Este año se presentó a elecciones un grupo de personas con una propuesta particular, la primera que me toca vivir de lo que podríamos llamar Gobierno 2.0. El argumento esgrimido es simple: hoy por hoy, la informática hace que la democracia directa vuelva a ser practicable.

En Atenas las cosas eran más bien simples, dado que las personas con voz y voto constituían un grupo relativamente reducido que se reunía periódicamente para votar a mano alzada. Con el paso del tiempo, la democracia representativa se volvió más viable, tanto por las ventajas del voto secreto como por la dificultad logística de poner a varios millones de personas a votar en un mismo cuarto. Hoy por hoy, la revolución en las comunicaciones hace que podamos sobrellevar estas dos cuestiones y así evitar la problemática de la representación indirecta.

Bajo el curioso lema de No es democracia, el "No" se compromete a organizar un sitio web donde los alumnos de la facultad puedan votar de forma directa en cada una de las cuestiones que se discuten en el consejo directivo. Dada una resolución, los integrantes de dicho foro podrán votar y argumentar a favor o en contra de las medidas a tomar. Finalmente, los consejeros electos del NO asisten a la reunión de consejo directivo, leen los argumentos concensuados en el foro y votan de la manera en que la elección online lo indique1.

Con un sistema de automoderación (hoy por hoy bastante común en la web), los mejores argumentos flotan sobre los peores y la gente puede acceder a la información necesaria para decidir de forma efectiva. En teoría. Asimismo, plantean soluciones técnicas a los problemas usualmente relacionados con la organización de un comicio, desde la integridad de los votos hasta la seguridad del sistema, pasando por las garantías de anonimato para los votantes.

Pero...

No hace falta mucho cráneo para llenar un par de pliegos con potenciales cosas que pueden salir mal en un proyecto de este tipo. Sin duda el problema primordial es que la política universitaria se caracteriza por sobre todas las cosas por la omnipresente apatía del alumnado. Darle la oportunidad a la gente de que tome decisiones potencialmente críticas con la misma liviandad que decide ¿qué Pokemon sos?2 en un jueguito del Facebook puede no ser lo más feliz.

Por otra parte, cualquier comunidad online de tamaño significativo, aún sin intereses profundos de por medio (por ejemplo, un foro de jueguitos o de fotografía), se torna en todos los casos que pude observar en un pequeño caos similar a un programa de chimentos. En general, la gente es muy susceptible y poco cuidadosa con las cosas que escribe, y enseguida las aguas se caldean.

Y sin embargo...

Es innegable que la propuesta es intrigante, y la muestra de estudio es casi utópica para un experimento sociológico como este: un grupo bastante amplio de gente bastante bien calificada en el uso tanto de la tecnología como del marote. Sin más, el solo compromiso de que las discusiones del consejo directivo se publiquen regularmente en Internet para que los alumnos puedan seguirlas con facilidad sin asistir a rallys ni instancias similares, es un gran paso en la dirección correcta.

Al momento de escribir estas líneas, no tengo ni idea de como salieron las elecciones. Pero no puedo negar que estoy intrigado. Hay mucha más información sobre este tema en Meta Government.

1 Para los que estén familiarizados con el movimiento del software libre, es destacable el paralelismo entre el procedimiento de "usar un representante como medio para lograr la democracia directa", y la forma en que la licencia GPL utiliza la legislación sobre copyright para ceder derechos en lugar de restringirlos.

2 Ejemplo cortesía de Manuel Giménez.

Actualización: resultados de la elección


Me quedaré con la intriga al menos hasta el año próximo!

Ilustraciones de Cristoph Niemann

viernes, 18 de septiembre de 2009
Me topé en la web con el trabajo de Cristoph Niemann, un diseñador gráfico e ilustrador americano muy talentoso. Tiene un blog gráfico en el sitio web del New York Times, donde regularmente muestra sus "editoriales". Son muy simpáticas sus creaciones, y me recuerda inevitablemente al espíritu juguetón que tanto me gusta de Liniers.


Como armar un gateway SMS con tu celular

jueves, 17 de septiembre de 2009
Estuve averiguando y al parecer la única manera de hacer una aplicación que reciba mensajes de texto y pueda responder a los mismos, es apersonarse muy bien trajeado en una empresa que brinde servicios de alertas SMS y cuestiones afines, y firmar un jugoso contrato para obtener el muy preciado servicio. Ojo, enviar mensajes SMS desde una computadora es mucho más sencillo: la mayoría de los carriers permiten hacerlo enviando un correo electrónico a una dirección conveniente. El problema está en recibir los benditos textos: ¿qué pasa si quiero hacer el Twitter argentino, y quiero que mis usuarios posteen actualizaciones desde su celular? ¿qué pasa si quiero preguntarle a mi máquina como va la descarga de mi torrent?

El servicio necesario para enviar o recibir SMS desde una computadora conectada a Internet se denomina gateway SMS, y si bien el servicio de envío lo proveen las mismas compañías de telefonía celular, la recepción es más delicada, ya que nadie provee un servicio de acceso sencillo para forwardearme los mensajes que lleguen a un determinado número a mi aplicación. A continuación voy a explicar como se puede fabricar un gateway SMS fatto in casa utilizando un celular común y silvestre.

Ingredientes
  • Una computadora con un adaptador Bluetooth (o no, ver nota a continuación)
  • Un celular con Bluetooth
  • Python + python-bluez
En mi caso utilicé mi maltrecho Nokia 6103, y la solución que propongo debería funcionar en cualquier celular con dos dedos de frente (o sea, la gran mayoría de los Nokia y Sony Ericcsson, y tal vez algún que otro Motorola).

Técnicamente no es necesario usar bluetooth puesto que lo que vamos a hacer es enviar comandos AT estándar sobre un enlace serial. Esto se puede hacer tanto por Bluetooth como con el cable adaptador USB o serial correspondiente, artículo del que no dispongo. Debería ser trivial portar las ideas de mi programa para funcionar con un enlace cableado.

Como sistema operativo utilicé Ubuntu 9.04, pero debería funcionar en casi cualquier sistema actual puesto que las librerías necesarias funcionan también en Windows.

Pasos a seguir

El funcionamiento del gateway que propongo es sencillo; se conecta al teléfono mediante la conexión inalámbrica y puede realizar una de tres acciones:
  • Enviar un mensaje de texto a un número determinado
  • Obtener todos los mensajes de texto almacenados en el teléfono
  • Borrar todos los mensajes de texto almacenados en el teléfono
El único paso manual consiste en identificar la dirección de hardware del teléfono para indicarla al conectarse. En Linux esto puede hacerse habilitando Bluetooth tanto en el celular como en la computadora, activando en el teléfono el modo "visible", y finalmente ejecutando el comando hcitool scan.

Tras ingresar dicho valor en el script que pongo a continuación, se realizará la conexión con el celular. Es probable que el celular requiera una aprobación manual para cada vez que se realice una conexión (un mensaje del tipo "¿Desea conectarse con el dispositivo XXX?"). Como esto no es muy cómodo en un servidor, en los teléfonos Nokia esta opción puede desactivarse una vez que se ha establecido la conexión (en el apartado "Conexiones activas" del menú Bluetooth, se puede indicar que un cierto dispositivo no requiere confirmación).

El código que adjunto a continuación hace el resto del trabajo, gran parte del cual consiste en parsear el extraño formato PDU en que el teléfono entrega los mensajes de texto cuando se le pide. El código que hace esto está fuertemente basado en smspdu, que modifiqué para hacer un poco más amigable.

Seguir leyendo >>

gateway.py

#!/usr/bin/python

#Copyright (c) 2009 Gonzalo Sainz-Trapaga
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.

import bluetooth
import select
import pdu

DEBUG = False

class Nokia6103:
    def __init__(self, hwaddr, port):
        self.sockfd = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
        self.sockfd.connect((hwaddr, port))
        self._send('ATZ')

    def _log(self, s):
        if DEBUG:
            print s

    def _read(self):
        i = [self.sockfd]
        w = []
        e = [self.sockfd]
        out = ''
        while True:
            ir, wr, er = select.select(i, w, e, 3)
            if len(ir) == 0:
                self._log("Select: espera finalizada - saliendo.")
                break
            if len(er) > 0:
                self._log("Select: condicion de excepcion - saliendo.")
                break
    
            out += i[0].recv(1000)
            if out.find('OK\r\n') != -1:
                self._log("Select: OK alcanzado - saliendo.")
                break
        return out
    
    
    def _send(self, s):
        self.sockfd.send('%s\r' % s)
        out = self._read()
        self._log(out)
        return out

    def sendSMS(self, num, txt):
        self._send('AT+CMGF=1')
        self._send('AT+CMGS="%s"' % num)
        self.sockfd.send(txt + "\n")
        self.sockfd.send(chr(26))

    def getAllSMS(self):
        s = self._send('AT+CMGL=4')
        lines = s.split('\r\n')
        lines.pop(0)
        msgs = []
        for i, msg in enumerate(lines):
            if i % 2 == 0:
                if not msg.startswith('+CMGL'):
                    break
            else:
                msgs.append(pdu.decodePdu(msg))
        return msgs

    def deleteAllSMS(self):
        self._send('AT+CMGD=1,4')

    def close(self):
        self.sockfd.close()

if __name__ == '__main__':
    port = 1
    hwaddr = '00:19:B7:XX:XX:XX'
    n = Nokia6103(hwaddr, port)
    print n.sendSMS('+541150501234', 'Mensaje de prueba!')
    print n.getAllSMS()

pdu.py

#Copyright (c) 2009 Eric Gradman, Gonzalo Sainz-Trapaga
#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:
#
#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.
from cStringIO import StringIO
from math import ceil
from binascii import unhexlify, hexlify
from itertools import cycle
from datetime import datetime


def decodePdu(s):
    s = unhexlify(s)
    d = StringIO(s)

    # parse SMSC information
    p = {}
    p['smsc_len'] = d.read(1)
    p['type_of_address'] = d.read(1)
    p['sc_num'] = unsemi(d.read(ord(p['smsc_len'])-1))

    p['msg_type'] = d.read(1)
    p['address_len'] = d.read(1)
    p['type_of_address'] = d.read(1)

    p['sender_num'] = unsemi(d.read(int(ceil(ord(p['address_len'])/2.0))))
    p['pid'] = d.read(1)
    p['dcs'] = d.read(1)
    ts = d.read(7)
    p['ts'], p['tz'] = parseTimeStamp(ts)

    p['udl'] = d.read(1)
    p['user_data'] = d.read(ord(p['udl']))
    p['user_data'] = decodeUserData(p['user_data'])

    
    for f in ['sc_num', 'sender_num']:
        if p[f].endswith('f'):
            p[f] = p[f][:-1]
    
    return p

def unnibleSwapChar(c):
    c = ord(c)
    d1 = c & 0x0F
    d2 = c >> 4
    return int(str(d1) + str(d2))

def parseTimeZone(c):
    c = ord(c)
    d1 = c & 0x0F
    d2 = c >> 4

    neg = d1 >> 3
    d1 = d1 & 0x7
    
    units = int(str(d1) + str(d2))
    if neg:
        zona = '-'
    else:
        zona = ''
    zona += str(units // 4)
    zona += ':'
    zona += "%.02d" % ((units % 4) * 15)

    return zona


def parseTimeStamp(s):
    ts = s[:6]
    tz = s[-1:]

    f = [unnibleSwapChar(c) for c in ts]
    f[0] = f[0] + 2000

    zona = parseTimeZone(tz)
    return datetime(*f), zona

def decodeUserData(s):
    bytes = map(ord, s)
    strips = cycle(range(1,9))
    out = ""
    c = 0    # carry
    clen = 0 # carry length in bits
    while len(bytes):
      strip = strips.next()
      if strip == 8:
        byte = 0
        ms = 0
        ls = 0
      else:
        byte = bytes.pop(0)
        # take strip bytes off the top
        ms = byte >> (8-strip)
        ls = byte & (0xff >> strip)
      #print "%d byte %x ms %x ls %x" % (strip, byte, ms, ls)

      # append the previous
      byte = ((ls << clen) | c) & 0xff
      out += chr(byte)

      c = ms
      clen = strip % 8

    if strip == 7:  out += chr(ls) # changed 6/11/09 to incorporate Carl's suggestion in comments
    return out

def unsemi(s):
    """turn PDU semi-octets into a string"""
    l = list(hexlify(s))
    out = ""
    while len(l):
      out += l.pop(1)
      out += l.pop(0)
    return out

PyCon AR 2009 en Buenos Aires

viernes, 14 de agosto de 2009


Hace un tiempo vi en la facultad los primeros afiches llamando a enviar charlas y presentaciones para realizarse en la PyCon 2009, la primera conferencia sobre Python en español! Se va a realizar los días 4 y 5 de septiembre en la sede de la Universidad de Belgrano, las charlas plenarias son de:
  • Jacob Kaplan-Moss, uno de los lead developers de Django
  • Collin Winter, uno de los core developers de Python que está trabajando en Google en el proyecto Unladen Swallow (un intérprete optimizado que busca multiplicar por 5 la velocidad actual de Python).

Además de éstas que son plenarias, está plagado de otras charlas de menor envergadura, además de las llamadas charlas relámpago que duran solo 5 minutos. Los temas son de los más diversos, y van desde una introducción al lenguaje a cómo usar Python para manipular su propio bytecode.

En resumen, novatos, hackers añejos e incluso personas que solo haya oído hablar de Python van a tener cosas para mirar y aprender. La inscripción es gratuita, solo hay que registrarse en el sitio web de la conferencia.

Fotos de la Patagonia Chilena

lunes, 13 de julio de 2009
Buenas, estuve un tiempito sin postear por el ajetreo universitario. No faltan cosas en el tintero, solo el tiempo para volcarlas. De momento terminé de editar un largo batch de fotos que saqué en febrero pasado cuando estuvimos de viaje por Chile con mi familia. A continuación van cuatro seleccionadas y si les interesa pueden ver el set de Flickr (o el slideshow!).




Olympus anuncia la E-P1

martes, 16 de junio de 2009
Como comentaba hace un tiempo, el nuevo sistema Micro Cuatro Tercios de Olympus es un guiño al pasado y la tradición de la marca que comenzara hace 50 años con sus cámaras portables y compactas. Hoy se anunció la primera cámara Olympus para este sistema (ya existía la Panasonic G1), y me sorprende agradablemente ver que no solo el estilo de la cámara sigue de cerca al de la Pen F, sino que la línea se lanza bajo el nombre de "Pen digital".


Hay un preview de la Olympus E-P1 en DPreview. Además del tamaño compacto, la cámara tiene estabilizador de imagen, limpieza automática del sensor y sale con un lente de 17mm f/2.8 pancake en dos colores (blanca o gris).