Vote for my friend Iliana so she can run the Ragnar relay

Jueves, 4 de abril de 2013

She is a mom, with a full time job who can run any distance from the 5K to the marathon. She is one of the most dedicated runners I know and she is a source of inspiration for her family and friends!

Please help her and vote for her so she can run this relay: https://www.facebook.com/iliana.ragnars

kodegeek , , , ,

De las críticas recurrentes al blog, los ‘trolls’ y otros menesteres

Sábado, 23 de marzo de 2013

Es curioso pero así como este blog tiene seguidores también tiene sus detractores; Curiosamente hay quienes lo visitan, se van y vuelven periódicamente como es el caso de ‘mi amigo’ Piccoro. No tengo ningún problema respondiendo a las críticas pero cuando lo hacen sin el menor contexto es entonces cuando me obligan a responder criticando su pobre estilo.

Asumo que este es el articulo del cual nuestro ilustre troll sacó información (un escrito de ya hace 3 años atrás):

he leido los entradas especificas de Venezuela, y noto que son mas criticas que soluciones..

es de apreciar cierta objetividad pero ejemplo en el caso de juegos volentos, notese que un entorno violento cria niños violentos, ademas de que auqnue dicha ley es una hipocresia total, prefiero nunca lleguen juegos violentos a que mi hijo por error toque estos y se relacione mejor (ya que este ya es bastante violento de por si, con claras ventajas sobre otros niños mas grandes)

otro interesante es el de brasil vs Venezuela en materia de fabricado de software.. dime tu, como haces tu , tu, en un pais donde TODAS las interfaces para comunicarse con un basnco desde un punto VPOS de ventas usan solo .NET en ambos lados, la solucion es unica, fabricar tanto modulo de comunicacion (pa ti el “driver” papa) asi como la interfaz servicio que recibe ne el banco.. claro, nadie te va apoyar, asi que vas solo..

acoto yo si lo hice , critico, pero no me limito a eso que tu haces.. y justo hoy estoy colocando la tarea en solognu para el sistema en asistencia…

pierdo sueño, pero criticar sin aportar es ser tan vacio como lo que criticas…

Y la cosa pica y se extiende:

nota: si un padre no fue orientado, no sabra prohibir un juego violento a su hijo (y tendra mas de uno saegurado), que a su vez criara dos a cuatro nijos mas, y este despues lo duplica, por varios factores socioeconomicos..

terminando en un mar llamado barrio, creo en brasil son muuuchos los barrios violentos, y en EEUU, decir que Venezuela es violenta es algo absurdo porque eso depende de la cantidad de gente vs la pelea por los recursos.. un problema que es global.. no solo de mi pais.. que en materiqa de recursos esta aun mejor que otros con todo y la corrupción…

Amigo Piccoro, realmente es difícil leer tu comentario ya que es una mezcla de arroz con mango. No sé realmente por donde empezar. Pero después de leer tus comentarios en mi blog y ver buscar tu escritos por Internet me he topado con algo que te describe a ti y a muchos otros a la perfección: ¿Creando Conflictos, o solo Aguantando…?.

No creo que haga falta argumentar algo más.

De verdad mucha suerte y gracias por visitar el blog.

–José

internet, kodegeek , , , ,

NYC Half Maraton 2013

Sábado, 16 de marzo de 2013

Untitled
Mañana Domingo 17 de Marzo voy a correr 13.1 millas en una carrera de gran popularidad en New York

Bueno, mañana me toca correr 13.1 millas en compañía de otros 15 mil corredores, muchísimos de ellos provenientes de otros países. Yo voy a representar a Venezuela lo mejor que puedo, he estado entrenando desde Diciembre del 2012 y no les voy a negar que ha sido difícil en los últimos dos meses; El invierno ha sido duro pero todo el esfuerzo va a tener fruto mañana a las 7:30 de la mañana.

Siga leyendo, más abajo les doy algunos detalles entre ellos del entrenamiento, motivación y como pueden seguir el progreso de esta carrera por Internet.

¿Cual es mi motivación para correr 22 kilómetros?

Untitled¿Porqué corremos?

Para mi este es un peldaño más hacia el Maratón de NYC del 2013. Si no puedo con esta carrera entonces tengo que pensar en como mejorar mi entrenamiento. También está el ejemplo que quiero dejarle a mis hijos, todo se puede con constancia y trabajo.

Esta carrera es algo que quiero compartir con mi familia. Ellos son mi principal soporte en esta aventura y sin ellos no hubiera podido dar un paso en la calle en estos últimos 4 meses de invierno.

El entrenamiento

Untitled
El entrenamiento no fué fácil. Cometí errores y aprendí lo mejor que pude de ellos

Este año decidí salirme del entrenamiento de Hal Higdon (el cual utilicé para mi previo medio maratón) y decidí utilizar el entrenado virtual de Runners World (Smart Coach). El plan fué exigente y pese a que perdí un par de sesiones por enfermedad (3 días en el hospital debido a una comida contaminada) y mal tiempo con mucha nieve, logré cumplir con las pautas. En los días que no corría practique entrenamiento de resistencia con pesos, siguiendo planes de bodybuilding.com (en particular el 6-12-25 me ayudo mucho).

El plan de Runners World fué complejo, no sólo incluyó las carreras largas del fin de semana sino que además me obligo a hacer ‘Tempo Runs‘ y ‘Speed Work‘. Según ellos espero completar el recorrido de la siguiente manera: 13.1 Mi @8:02. Tiempo: 1:45:17

Herramientas, aditamentos

Untitled
Para correr en el frio hay que vestirse en capas. Eso sin contar con otros aditamentos para registrar el entrenamiento

Siempre mantuve una bitacora de eventos en donde registré mi velocidad, datos geográficos (usando el GPS de mi Nike GPS Sports Watch) y ritmo cardíaco (con un sensor Polar compatible con el reloj). Toda la información quedo registrada en el sitio de Nike+ el cual ha mejorado bastante desde su última actualización el año pasado.

Aún sigo utilizando Vibrams 5 Fingers para correr. Compré unos Bikila y los clásicos Komodo, los Bikilas aún me lastiman los pies por lo que creo yo es un error de diseño en las correas. Así que seguiré usando lo que funciona, Komodos.

Alimentación y descanso

La alimentación incluyó más carbohidratos además de las proteínas después de entrenar. No quiero recomendar ninguna marca así que si estan interesados en saber que suplementos tomé me pueden contactar en privado (asegúrense de poner una dirección de correo electrónico valida en los comentarios). Como siempre, trato de comer balanceado (más difícil de lo que usted cree), tomo mis suplementos de vitaminas y las pastillas de aceite de pescado (para completar mi dosis de Omega-6).

Lo más importante es comer bien, natural y descansar cuando el cuerpo lo pida. Durante todo este tiempo siempre me tomé un día a la semana durante el cual no hice nada.

La carrera

Screen Shot 2013-03-16 at 3.28.38 PM
El recorrido de este año. Muy colorido

¡Apoyo moral!

Me encantaría que estuvieran conmigo para compartir los detalles de la carrera, pero como se que no es posible entonces les tengo unos detalles de como hacerlo remotamente.

No hay excusa para que no me sigan el día de la carrera, yo soy el BIB# 7466 :-)

Muchas opciones. Hay una aplicación para el Iphone, aunque también lo pueden hacer por Internet. Además de eso la carrera va a ser transmitida en vivo en ESPN3 y ABC..

Ya les escribiré en los comentarios como me fué, ahora sólo queda esperar y relajarse antes del evento.

–José

kodegeek

Nike+ REST API

Sábado, 19 de enero de 2013

Last year I started playing with the Nike+ website; So Nike finally decided to release a proper API to interact with their website. The API is small yet looks functional, but I am having a hard time trying to figure out how to reproduce the results from a simple REST client:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Macintosh:python josevnz$ ./nikeplus_unit_test.py 
send: 'GET /me/sport?access_token=XXXXXX HTTP/1.1\r\nHost: api.nike.com:443\r\nAccept-Encoding: identity\r\nContent-Type: application/jsonrequest\r\nAccept: application/jsonrequest\r\nAppid: Kodegeek/NikePlus\r\n\r\n'
E
======================================================================
ERROR: test_getAggregateSportData (__main__.TestNikePlus)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "./nikeplus_unit_test.py", line 16, in test_getAggregateSportData
    activities = activity.getAggregateSportData(True)
  File "/Users/josevnz/Documents/src/python/com/kodegeek/fitness/nikeplus/activity/wrapper.py", line 30, in getAggregateSportData
    res = con.getresponse()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 1013, in getresponse
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 402, in begin
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/httplib.py", line 360, in _read_status
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 430, in readline
error: [Errno 54] Connection reset by peer
 
----------------------------------------------------------------------
Ran 1 test in 0.570s
 
FAILED (errors=1)

Contacted the developers, lets see how it goes. But it is exiting, so many possibilities!

correr, kodegeek, programación, python , ,

Creando entradas para mi calendario en Ical usando Python

Sábado, 29 de diciembre de 2012
Runners World Half Marathon training plan

Runners World Half Marathon training plan

Para quienes siguen esta bitácora, seguramente recordarán que me aceptaron en el NYC Half Marathon del 2013. Eso significa que me va a tocar entrenar este inverno, en esta ocasión quise probar los planes gratuitos de la gente de Runners World para ver que tan buenos son.

Después de registrarme y de colocar varios parámetros, esto fué más o menos lo que el plan me generó:

El plan básico de Runners World Smart Coach no soporta enviar correos electrónicos para recordarte acerca de tus entrenamientos; Esto es algo que puedo hacer yo sólo y no creo que justifique que pagué por la mejora al servicio pago, dado lo corto de la carrera (para el maratón es otra cosa y allí les recomiendo que paguen su suscripción).

Para tener mis recordatorios lo único que tengo que hacer es guardar el plan en formato de texto plano, simplemente seleccionamos la tabla del sitio web y la guardamos en un archivo de texto:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#Macintosh:Documents josevnz$ vim half.txt
 
WEEK 1: 4 Mi
Sun     Dec 30  Long Run        Dist: 4 Mi @9:35
 
WEEK 2: 11 Mi
Tue     Jan 1   Easy Run        Dist: 4 Mi @9:36
Thu     Jan 3   Easy Run        Dist: 3 Mi @9:36
Sun     Jan 6   Easy Run        Dist: 4 Mi @9:36
 
WEEK 3: 12 Mi
Tue     Jan 8   Easy Run        Dist: 3 Mi @9:35
Thu     Jan 10  Tempo Run       Dist: 4 Mi, inc Warm; 2 Mi @ 7:59; Cool
Sun     Jan 13  Long Run        Dist: 5 Mi @9:35
 
WEEK 4: 10 Mi
Tue     Jan 15  Easy Run        Dist: 3 Mi @9:32
Thu     Jan 17  Easy Run        Dist: 3 Mi @9:32
Sun     Jan 20  Easy Run        Dist: 4 Mi @9:32
 
WEEK 5: 13 Mi
Tue     Jan 22  Easy Run        Dist: 4 Mi @9:32
Thu     Jan 24  Tempo Run       Dist: 4 Mi, inc Warm; 2 Mi @ 7:57; Cool
Sun     Jan 27  Long Run        Dist: 5 Mi @9:32
 
WEEK 6: 14 Mi
Tue     Jan 29  Easy Run        Dist: 4 Mi @9:30
Thu     Jan 31  Speedwork       Dist: 4 Mi, inc Warm; 2x1600 in 7:32 w/800 jogs; Cool
Sun     Feb 3   Long Run        Dist: 6 Mi @9:30
 
WEEK 7: 15 Mi
Tue     Feb 5   Easy Run        Dist: 3 Mi @9:27
Thu     Feb 7   Tempo Run       Dist: 4 Mi, inc Warm; 2 Mi @ 7:52; Cool
Fri     Feb 8   Easy Run        Dist: 2 Mi @9:27
Sun     Feb 10  Long Run        Dist: 6 Mi @9:27
 
WEEK 8: 13 Mi
Tue     Feb 12  Easy Run        Dist: 3 Mi @9:25
Thu     Feb 14  Easy Run        Dist: 3 Mi @9:25
Fri     Feb 15  Easy Run        Dist: 3 Mi @9:25
Sun     Feb 17  Easy Run        Dist: 4 Mi @9:25
 
WEEK 9: 17 Mi
Tue     Feb 19  Easy Run        Dist: 2 Mi @9:25
Thu     Feb 21  Tempo Run       Dist: 5 Mi, inc Warm; 3 Mi @ 7:54; Cool
Fri     Feb 22  Easy Run        Dist: 2 Mi @9:25
Sun     Feb 24  Long Run        Dist: 8 Mi @9:25
 
WEEK 10: 18 Mi
Tue     Feb 26  Easy Run        Dist: 3 Mi @9:22
Thu     Feb 28  Speedwork       Dist: 4 Mi, inc Warm; 2x1600 in 7:25 w/800 jogs; Cool
Fri     Mar 1   Easy Run        Dist: 2 Mi @9:22
Sun     Mar 3   Long Run        Dist: 9 Mi @9:22
 
WEEK 11: 19 Mi
Tue     Mar 5   Easy Run        Dist: 2 Mi @9:20
Thu     Mar 7   Tempo Run       Dist: 5 Mi, inc Warm; 3 Mi @ 7:50; Cool
Fri     Mar 8   Easy Run        Dist: 2 Mi @9:20
Sun     Mar 10  Long Run        Dist: 10 Mi @9:20
 
WEEK 12: 18 Mi
Tue     Mar 12  Easy Run        Dist: 2 Mi @9:17
Thu     Mar 14  Speedwork       Dist: 3 Mi, inc Warm; 1x1600 in 7:21 w/800 jogs; Cool
Sun     Mar 17  Half Marathon Race Day  13.1 Mi @8:02 Time: 1:45:17

El formato es super fácil de digerir; Con un poco de ayuda para entender el formato de iCalendar, escribí un pequeño script en Python el cual toma el archivo de texto y lo convierte al formato adecuado:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env python
# Simple script to parse output from the Runners World Smart Coach calendar to convert it to Ical entries. PLEASE CONSIDER BUYING THEIR PLAN, IS WORTH IT
# http://kodegeek.com/blog
import os, sys, re
from datetime import *
 
class Cal:
        def __init__(self, params):
                self.params = params
 
        def __str__(self):
                return '''BEGIN:VEVENT
DTEND;TZID=%(date)s
TRANSP:OPAQUE
SUMMARY:%(summary)s
DTSTART;TZID=%(date)s
SEQUENCE:4
BEGIN:VALARM
X-WR-ALARMUID:454BC86C-A39E-4C87-8CF9-7D79D80AC01B
TRIGGER:-PT1M
ATTACH;VALUE=URI:Basso
ACTION:AUDIO
END:VALARM
END:VEVENT''' % self.params
 
(Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec) = range(0, 12)
 
def parseLine(line, now, format):
        if len(line) == 1 or re.search('WEEK', line):
                return None
        ''' Parsing the data. Each line format looks like this:
        Sun     Dec 30  Long Run        Dist: 4 Mi @9:35
        Tue     Jan 29  Easy Run        Dist: 4 Mi @9:30
        Thu     Jan 31  Speedwork       Dist: 4 Mi, inc Warm; 2x1600 in 7:32 w/800 jogs; Cool
        Sun     Mar 17  Half Marathon Race Day  13.1 Mi @8:02 Time: 1:45:17
        '''
        matcher = re.search('(.*)\s+Dist:(.*)', line.strip())
        if matcher == None:
                matcher = re.search('(.*)\s+Race Day(.*)', line.strip())
                if matcher == None:
                        return None # Don't know how to handle this!
        params = {}
        # Runs finish and end the same day
        tokens = matcher.group(1).strip().split(' ', -1)
        cdate = ' '.join(tokens[:3]).strip()
        time = "05:00"
        if tokens[0] in [ "Sun", "Sat" ]:
                time = "06:00"
        # We add the year and start time to the date. Start time is the time I want to run
        # We figure out the year as none of these plans are longer than 13 weeks
        year = 2013 # Yes, it is hardcoded. This version of the script doesn't handle the special case of dates across years
 
        # For date we expect something like: Sun Dec 30 2012 05:00
        date = "%s %s %s" % (cdate, year, time)
        ndate = datetime.strptime(date, "%a %b %d %Y %H:%M")
        if ndate == None:
                raise Exception("Unable to parse date, won't continue: '%s'" % date)
        params['date'] = ndate.strftime(format)
        desc = ' '.join(tokens[3:])
        params['summary'] = '%s %s' % (desc.strip(), matcher.group(2).strip())
        return Cal(params)
 
# You may want to override some defaults here
def writeEvents(cals, calendarName='Races', tz='America/New_York'):
        vals = {}
        vals['tz'] = tz
        vals['calname'] = calendarName
        print '''BEGIN:VCALENDAR
METHOD:PUBLISH
VERSION:2.0
X-WR-CALNAME:%(calname)s
PRODID:-//Apple Inc.//iCal 5.0.3//EN
X-APPLE-CALENDAR-COLOR:#B90E28
X-WR-TIMEZONE:%(tz)s
CALSCALE:GREGORIAN
BEGIN:VTIMEZONE
TZID:%(tz)s
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
DTSTART:20070311T020000
TZNAME:EDT
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
DTSTART:20071104T020000
TZNAME:EST
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE''' % vals
        for cal in cals:
                print "%s" % cal
        print '''END:VCALENDAR'''
 
def main(args):
        format = "America/New_York:%Y%m%dT%H%M00" # America/New_York:20130101T060000
        now = date.today()
        fh = open(args[0], 'r')
        cals = []
        for line in fh.xreadlines():
                cal = parseLine(line, now, format)
                if cal != None:
                        cals.append(cal)
        writeEvents(cals)
 
if __name__ == "__main__":
        main(sys.argv[1:])
# End of script

Para correrlo sólo tiene que escribir lo siguiente:
bin/runnersworld_to_ical.py ~/Documents/half.ics

Después sólo hay que importarlo en la aplicación Ical en OSX.

Espero que le sea de utilidad, mañana me toca correr en nieve (a 25F), así que aún no ando seguro si me toca usar un Treadmil o si voy a correr en la carretera. Si sólo eso se pudiera resolver con un pequeño programita…

kodegeek

Jugando con MongoDB, recolectando eventos (Mongo Tail-Log)

Domingo, 23 de diciembre de 2012

Esta es una idea con la cual he venido jugando desde hace tiempo, la cual es capturar eventos usando MongoDB como base de datos. Me gusta la idea que se pueden controlar el espacio en disco usando un arreglo circular (en MongoDB se llaman ‘capped collections‘), además de que definir el esquema de los datos es muy sencillo.

Preparación

Lo primero es bajarse e instalar MongoDB (yo utilizo OSX):

1
2
3
4
cd /usr/share && mkdir mongodb
tar -xzvf /Users/josevnz/Downloads/mongodb-osx-x86_64-2.2.2.tgz
sudo ln -s mongodb-osx-x86_64-2.2.2 mongo
cd mongo && sudo mkdir data etc log scripts

Luego creamos un archivo de configuración básico:

1
2
3
4
5
6
7
8
9
10
Macintosh:mongo josevnz$ cat etc/mongodb.conf 
fork = true
bind_ip = 127.0.0.1
port = 27017
quiet = true
dbpath = /usr/share/mongodb/mongo/data
logpath = /usr/share/mongodb/mongo/log/mongodb.log
pidfilepath = /usr/share/mongodb/mongo/mongodb.pid
logappend = true
journal = true

Y un par de ‘scripts’ para hacernos la vida más sencilla:

1
2
3
4
5
6
7
8
9
10
Macintosh:mongo josevnz$ cat etc/mongodb.conf 
fork = true
bind_ip = 127.0.0.1
port = 27017
quiet = true
dbpath = /usr/share/mongodb/mongo/data
logpath = /usr/share/mongodb/mongo/log/mongodb.log
pidfilepath = /usr/share/mongodb/mongo/mongodb.pid
logappend = true
journal = true

Y la arrancamos:

1
2
3
4
5
Macintosh:~ josevnz$ sudo mongod -f $MONGO_HOME/etc/mongodb.conf 
Password:
forked process: 2782
all output going to: /usr/share/mongodb/mongo/log/mongodb.log
child process started successfully, parent exiting

Preparando la colección

Ahora hay que preparar el sitio en donde vamos a poner los datos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Macintosh:mongo josevnz$ mongo
MongoDB shell version: 2.2.2
connecting to: test
Welcome to the MongoDB shell.
For interactive help, type "help".
For more comprehensive documentation, see
	http://docs.mongodb.org/
Questions? Try the support group
	http://groups.google.com/group/mongodb-user
> use logdb
switched to db logdb
> db.createCollection("logs", {capped:true, size:100000})
{ "ok" : 1 }
> db.logs.isCapped()
true

Código del cliente que inserta los datos

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#!/usr/bin/env jython
# Simple class that simulates an event writer
# Author: josevnz@kodegeek.com
# BLOG: http://kodegeek.com/blog
# Asumes that you created a database called 'logsdb' and a collection called 'logs':
# use logdb
# db.createCollection("logs", {capped:true, size:100000})
#
from com.mongodb import Mongo, MongoException, WriteConcern, DB, DBCollection, BasicDBObject, DBObject, DBCursor, ServerAddress
from java.util import Arrays, Date, Random
from java.util.concurrent import Executors, TimeUnit
from java.lang import Runnable, Thread
import sys, os
 
class EventWriter(Runnable):
 
        def __init__(self, db):
                self.db = db
                self.col = db.getCollection("logs")
                self.random = Random(1973)
 
        def run(self):
                number = self.random.nextLong()
                event = BasicDBObject('datetime', Date().toString()).append('text', 'This is an event, random # %d' % number)
                print "New event: %s" % event
                self.col.insert(event)
 
def main(args):
 
        initialDelay = 0
        delay = 5
        # Do not use 'localhost', that makes the driver to report a stupid error and hung
        list = Arrays.asList(ServerAddress("127.0.0.1", 27017))
        m = Mongo(list)
        # m.setWriteConcern(WriteConcern.JOURNALED)
        m.setWriteConcern(WriteConcern.NONE) # Do not care if the write makes it or not
        db = m.getDB( "logsdb" )
        print "Connected to %s" % db.getName()
 
        command = EventWriter(db)
        # Use a sigle thread for this example, but in reality the report uses a separate thread to avoid blocking the application
        executor = Executors.newSingleThreadScheduledExecutor()
        print "Press Ctrl-C to abort this script, events will be written periodically into the database"
        future = executor.scheduleWithFixedDelay(command, initialDelay, delay, TimeUnit.SECONDS)
        #sys.exit(0)
 
if __name__ == "__main__":
        main(sys.argv[1:])

La salida se ve asi:

Macintosh:mongodb josevnz$./log_writer.py
Connected to logsdb
Press Ctrl-C to abort this script, events will be written periodically into the database
New event: { "datetime" : "Thu Dec 13 10:13:21 EST 2012" , "text" : "This is an event, random # -6901132129250388696"}
New event: { "datetime" : "Thu Dec 13 10:13:27 EST 2012" , "text" : "This is an event, random # 2141911474641068654"}
New event: { "datetime" : "Thu Dec 13 10:13:32 EST 2012" , "text" : "This is an event, random # -7447082860282012741"}
New event: { "datetime" : "Thu Dec 13 10:13:37 EST 2012" , "text" : "This is an event, random # 3042277681337134497"}
New event: { "datetime" : "Thu Dec 13 10:13:42 EST 2012" , "text" : "This is an event, random # -2682038860783877385"}
New event: { "datetime" : "Thu Dec 13 10:13:47 EST 2012" , "text" : "This is an event, random # -6576368686118448135"}
New event: { "datetime" : "Thu Dec 13 10:13:52 EST 2012" , "text" : "This is an event, random # -294840040020254100"}
New event: { "datetime" : "Thu Dec 13 10:13:57 EST 2012" , "text" : "This is an event, random # 4202626908153060298"}
New event: { "datetime" : "Thu Dec 13 10:14:02 EST 2012" , "text" : "This is an event, random # -6313895213434337152"}
New event: { "datetime" : "Thu Dec 13 10:14:07 EST 2012" , "text" : "This is an event, random # 983475561958631366"}
New event: { "datetime" : "Thu Dec 13 10:14:12 EST 2012" , "text" : "This is an event, random # -6651143639772223084"}
New event: { "datetime" : "Thu Dec 13 10:14:17 EST 2012" , "text" : "This is an event, random # -7909942155638967101"}

En otra ventana verificamos que en verdad estamos recibiendo eventos, usando la mongo Shell:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Macintosh:mongodb josevnz$ mongo
MongoDB shell version: 2.2.2
connecting to: test
> use logsdb
switched to db logsdb
// Imprime el último registro recibido
> db.logs.find().skip(db.logs.count()-1).forEach(printjson)
{
	"_id" : ObjectId("50d6ec7cef869f82b3f656ea"),
	"datetime" : "Sun Dec 23 06:35:24 EST 2012",
	"text" : "This is an event, random # -8356391245437638799"
}
 
// Imprime el primer registro recibido
> db.logs.findOne()
{
	"_id" : ObjectId("50c9f092ef863d028e1ab74b"),
	"datetime" : "Thu Dec 13 10:13:21 EST 2012",
	"text" : "This is an event, random # -6901132129250388696"
}

Código del cliente que lee continuamente de la base de datos

Siempre ayuda tener a la mano la equivalencia de MongoDB a SQL. Aqui queremos simular el mismo comportamiento de la herramienta de UNIX ‘tail’, asi que utilizamos algo llamado ‘Tailable cursors‘:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/usr/bin/env jython
# Simple class that simulates an event reader
# Author: josevnz@kodegeek.com
# BLOG: http://kodegeek.com/blog
# Asumes that you created a database called 'logsdb' and a collection called 'logs':
# use logdb
# db.createCollection("logs", {capped:true, size:100000})
# Or convert an existing one to capped: db.runCommand({"convertToCapped": "logs", size: 100000})
# It is very important that you get a driver version more recent than 2.7.1 (Collection.isCapped is broken there)
#
from com.mongodb import Mongo, BasicDBObjectBuilder, DB, DBCollection, BasicDBObject, DBObject, ServerAddress, Bytes
from java.util import Arrays, Date
from java.util.concurrent import Executors, TimeUnit
from java.lang import Runnable, Thread
import sys, os
 
class EventReader(Runnable):
 
        def __init__(self, db):
                self.db = db
                if not db.collectionExists("logs"):
                        raise Exception("Logs doesn't exist, please create!")
                self.coll = db.getCollection("logs")
                if not self.coll.isCapped():
                        raise Exception("Logs is not a capped collection!")
                self.sortBy = BasicDBObjectBuilder().start("$natural", 1).get()
                print "Ready to read events..."
 
        def run(self):
                lastVal = None # This could be refined to get the last event
                cursor = self.coll.find(lastVal).sort(self.sortBy).addOption(Bytes.QUERYOPTION_TAILABLE).addOption(Bytes.QUERYOPTION_AWAITDATA)
                while cursor.hasNext():
                        print "%s" % cursor.next()
 
def main(args):
 
        delay = 1
 
        list = Arrays.asList(ServerAddress("127.0.0.1", 27017))
        m = Mongo(list)
        db = m.getDB( "logsdb" )
        print "Connected to %s" % db.getName()
 
        command = EventReader(db)
        executor = Executors.newSingleThreadScheduledExecutor()
        print "Press Ctrl-C to abort this script, reading events from the database"
        future = executor.schedule(command, delay, TimeUnit.SECONDS)
        #sys.exit(0)
 
if __name__ == "__main__":
        main(sys.argv[1:])

Pienso implementar una herramienta que use esto en mi trabajo, pero el código se ve fácil de usar y promete mucho :-)

java, kodegeek, python , , ,

¡Me aceptaron en el NYC Half Marathon del 2013!

Viernes, 21 de diciembre de 2012

The true story of ‘Samba de Janeiro’, by Hugo Fattoruso

Domingo, 2 de diciembre de 2012

Did you knew that Hugo Fattoruso composed “Samba de Janeiro”? This famous artist from Uruguay has not received all the credit he deserves for his work, check this out:

 

Samba de Janeiro

Samba de Janeiro by Hugo Fattoruso

By all means I invite you to his official Facebook site, and please spread the word so the world knows about the truth about this song and his work.

kodegeek ,

GoDaddy milking the Java cow

Miércoles, 7 de noviembre de 2012

So how do you manage to tell your customers that you want to charge them more for Java? Easy, just mix it a little bit with the hurricane Sandy and offer a poor excuse that you cannot share a Servlet engine on the cheap hosting option (the same way you share CGI or PHP pages):

Dear Jose Vicente Nunez Zuleta,

To assist our customers affected by Hurricane Sandy, we are
extending the Java discontinuation date to November 16, 2012.

This message is to notify you of upcoming changes to your hosting account,
kodegeek.com.

On November 16, 2012 we are removing Java (not JavaScript) from our servers.

Why the change? Quite frankly, you deserve more flexibility than what we offer
in a shared hosting environment. Shared hosting is not ideal for Java
Enterprise hosting because multiple customers share the same services
powering Java.

If you need Java, you should consider moving your site(s) to a Virtual Private
Server (VPS) or Dedicated Hosting
before November 16, 2012.

NOTE: If you have JavaScript running on your website, it’s going
to still work. A common misconception is that you have to use the Java framework
for JavaScript code. You don’t! It works just fine without it.

To help get you started, use this code XXXXXX before 2/28/13
to receive 20 percent off your switch to Economy VPS.

If you have questions or need assistance, you can contact our Support Team 24/7 at
(480) 505-8877, or support@godaddy.com.

Sincerely,
Go Daddy

- – - – - – - – - – - – - – - – - – - – - – - – - – - – - – -
Copyright 2012 Go Daddy All rights reserved.

What do you think, is GoDaddy trying to milk the Java cow?

kodegeek

Maratón de Nueva York del 2012: Nos vemos en el 2013

Domingo, 4 de noviembre de 2012

Todo el mundo tiene una opinión

Si usted es un corredor entonces seguro ya leyó las noticias. Sin más preámbulos, les copio la notificación oficial del NYRR:

Screen Shot 2012-11-03 at 6.14.30 PM
Primera vez que se cancela el evento en 40 años de vida

Sin embargo hay explicaciones alternativas.

¿Y que opina los corredores sobre la cancelación?:

¿Y que pienso yo?

Yo sólo perdí mi registro al Dash to the Finish Line. La tormenta sólo me hizo difícil trabajar durante 3 días, tuve que buscar un sitio en donde pudiéramos bañarnos con agua caliente y comer comida decente. Pero la casa salió intacta de ese lio. La familia está bien.

Cancelar el maratón fué la decisión acertada. Fué difícil. Pero no quedó otra alternativa.

Ya vendrán otros maratones, incluyendo la versión del 2013 del medio y completo maratón. Si Dios quiere, nos vemos allá.

¿Qué es lo realmente importante?

La gente se va a recuperar de este bajón. Hoy los corredores del maratón se fueron a Long Island a ayudar a repartir comida y otras cosas; Hay donativos. Los corredores no son egoístas, simplemente querían ver a su ciudad en pie lo más pronto posible.

Hoy hay gente corriendo el viejo recorrido del maratón, 4 vueltas y algo más alrededor de Central Park. Yo les digo a esos corredores que con el favor de Dios nos vemos en el 2013. Y esa será la mejor carrera de todas.

correr, kodegeek