Archivo

Archivo para octubre, 2011

¡Llevo recorridos 200 millas (o 321.8688 kilómetros)!

Sábado, 22 de octubre de 2011

Desde que comencé a correr en 1ero de Mayo de este año hasta la fecha he recorrido 200 millas o 312.8688 kilómetros. Para darles una idea de cuanto es eso:

  • La distancia entre las ciudades de Mérida y Trujillo es de 203 kilómetros
  • La distancia entre las ciudades de Mérida y San Antonio es de 298 kilómetros
  • La distancia entre las ciudades de Caracas y Puerto La Cruz es de 320 kilómetros
  • La distancia entre Darien, CT y Manhattan, New York (Central Park) es de 38 millas (llevo aproximadamente 5 viajes a pié)

Rompí la marca de las 200 millas con una carrera con velocidad 8’20 millas / mi minuto, antes de hacer ejercicio de resistencia. Mañana me toca una carrera un poco más larga (y lenta) de 6 millas, estoy intentando mis primeros 10K :-)

Y ya paré de contar. Actualizaré el blog con una entrada como esta cuando llegue a 500 millas.

–José

kodegeek, vida sana , ,

¿Como configurar Netbeans 7.10 beta y JavaFX 2.0 beta en OSX?

Sábado, 15 de octubre de 2011

Es un poco fastidioso, pero una vez que se bajen los binarios y siguiendo las instrucciones (no muy precisas de Oracle) terminé haciendo esto:

Netbeans 1.7.1 (beta) + JavaFX 2.0 (beta)

¡Ahora a jugar! :-)

java, javafx

Opinión de libro: The Great Grete Waitz: Inspiration, Hero, Champion–The Woman Who Transformed Running

Viernes, 14 de octubre de 2011

Great Grete Waitz Inspiration, Hero, Champion–The Woman Who Transformed Running, el libro presentado por Runner’s World, es una recolección de historias cortas sobre esta atleta. Su participación casi accidental en el maratón de Nueva York y como lo ganó por 9 veces seguidas, además de establecer marcas mundiales y mostrar a las mujeres como una fuerza a ser reconocida en el mundo de las carreras de distancia es algo que no tiene nombre.

Grete Waitz murió este año, después de combatir Cáncer. Este año hemos perdido a grandes figuras y Grete es una de ellas, le recomiendo este libro para que aprenda un poco sobre verdadera dedicación que sólo una atleta de este calibre pudo ofrecer.

vida sana , , ,

Hackeando mis datos en NikeRunning.com

Miércoles, 12 de octubre de 2011


Tipos de terreno para todas mis carreras, desde NikeRunning, mostrado con JavaFX

Desde que comencé a correr he utilizado a NikeRunning.com de una u otra manera; Primero comencé con mi Itouch y ahora lo utilizó con el NikeWatch.

Sin embargo, el sitio de Nike es un poco fastidioso; El sitio web está escrito en Flash (lo cual lo hace pesado), tiene gráficos limitados pero lo mas inconveniente es que mis datos están cautivos en el sitio web. Según ellos ya llevan tiempo trabajando en una migración que eliminará Flash:

Hello Everyone,

Thank you all for your feedback.

To let everyone know, we are in the process of revamping our website. We are in transition to move away from flash to HTML. The goal is to be faster and more efficient.

We thank you for your patience as we update our sites. There is not an estimated time of when the transition will be fixed, but I can assure you that I’ve seen parts of the site and it’s looks and feels amazing.

Stay tuned!

Buscando un poco en Google me conseguí conque se puede obtener toda la información de las carreras (siempre y cuando estas esten marcadas como públicas) usando el siguiente URL:

1
http://nikerunning.nike.com/nikeplus/v1/services/widget/get_public_run_list.jsp?userID=IDENTIFICADOR_DE_USUARIO

El archivo resultante está en formato XML.

Pero, ¿y de donde obtenemos el identificador del usuario? Es sencillo, simplemente vaya a nikerunning.nike.com y una vez que entre con su usuario y clave al sitio web haga click sobre una de sus corridas. El URL resultante se verá como esto:

1
http://nikerunning.nike.com/nikeos/p/nikeplus/en_US/plus/#//runs/gps/IDENTIFICADOR_DE_USUARIO/299193444/

En donde IDENTIFICADOR_DE_USUARIO es el número mágico que queremos usar.

Se me ocurrió por ejemplo escribir un pequeño programa en Jython y JavaFX el cual muestra la distribución de tipos de terreno encontrados mientras corrí:

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
#!/usr/bin/env jython
# Author: Jose Vicente Nunez Zuleta, josevnz@kodegeek.com
# This script parses the user run data and creates a simple distribtion by terrain types
# See: http://nikerunning.nike.com/nikeos/p/nikeplus/en_EMEA/plus/#//dashboard/
# Nike and Nikeplus/Nike+ are trademarks owned by Nike.
# License: BSD
import sys
from javafx.application import Application
from javafx.collections import FXCollections
from javafx.collections import ObservableList
from javafx.scene import Scene
from javafx.stage import Stage
from javafx.scene.chart import PieChart
from javafx.scene import Group
from com.kodegeek.fitness.nikerun.query import CannedQuery
from com.kodegeek.fitness.nikerun.public import PlusPublicService
 
class TerrainTypesChart(Application):
 
    def __getData__(self):
        args = self.getParameters().getRaw()
        pServ = PlusPublicService(args[0])
        data = pServ.getUserData()
        dp = CannedQuery('string', data)
        return dp.getTypesOfTerrain()
 
    def start(self, stage):
        scene = Scene(Group())
        stage.setTitle("Terrain types found in all races")
        stage.setWidth(500)
        stage.setHeight(500)
 
        count = self.__getData__()
        data = [PieChart.Data(key, value) for (key, value) in count.iteritems()]
        pieChartData = FXCollections.observableArrayList(data)
        chart = PieChart(pieChartData)
        chart.setTitle("Terrain types found")
 
        scene.getRoot().getChildren().add(chart)
        stage.setScene(scene)
        stage.show()
 
if __name__ == "__main__":
        Application.launch(TerrainTypesChart().class, sys.argv[1:])

La clase ‘PlusPublicService’ no es más que un simple cliente GET el cual se baja los datos del sitio de Nike:

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
!/usr/bin/env jython
#
# Author: Jose Vicente Nunez Zuleta, josevnz@kodegeek.com
# See: http://nikerunning.nike.com/nikeos/p/nikeplus/en_EMEA/plus/#//dashboard/
# Nike and Nikeplus/Nike+ are trademarks owned by Nike.
# License: BSD
#
from httplib import HTTPConnection, HTTP_PORT
import sys
 
__URL__ = 'nikerunning.nike.com'
__SERVICE__ = '/nikeplus/v1/services/widget/get_public_run_list.jsp?userID='
 
class PlusPublicService:
 
        def __init__(self, userId, port = HTTP_PORT):
                self.service = __SERVICE__ + userId
                self.userId = userId
                self.port = port
 
        def getUserData(self, debug=0):
                data = None
                con = HTTPConnection(__URL__, self.port)
                con.set_debuglevel(debug)
                con.request('GET', self.service)
                response = con.getresponse()
                if response.status == 200:
                        data = response.read()
                else:
                        raise Exception("Error. Status = %s, reason = %s" % (response.status, response.reason))
                con.close()
                return data
 
if __name__ == "__main__":
        argv = sys.argv[1:]
        if len(argv) > 0:
                pServ = PlusPublicService(argv[0])
                print "%s" % pServ.getUserData(8)
        else:
                print "NikeRunning user id is required!"
                sys.exit(192)

Y para procesar mis datos utilizo un poco de XPATH en la clase ‘CannedQuery’ la cual tiene un método el cual se encarga de crear la distribución para los distintos tipos de terreno:

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
/usr/bin/env jython
# Author: Jose Vicente Nunez Zuleta, josevnz@kodegeek.com
# See: http://nikerunning.nike.com/nikeos/p/nikeplus/en_EMEA/plus/#//dashboard/
# Nike and Nikeplus/Nike+ are trademarks owned by Nike.
# License: BSD
 
from xml.dom.minidom import parse, parseString
from xml.etree import ElementTree
import sys
 
class DataParser(object):
 
        def __init__(self, type='string'):
                self.type = type
 
        def __parseDomFile__(self, file):
                return parse(open(file, 'r'))
 
        def __parseDomString__(self, string):
                return parseString(string)
 
        def __parseXpathFile__(self, file):
                return ElementTree.parse(file)
 
        def __parseXpathString__(self, string):
                return ElementTree.fromstring(string)
 
        def __getDom__(self, source):
                if self.type == 'string':
                        return self.__parseDomString__(source)
                else:
                        return self.__parseDomFile__(source)
 
        def __getTree__(self, source):
                if self.type == 'string':
                        return self.__parseXpathString__(source)
                else:
                        return self.__parseXpathFile__(source)
 
class CannedQuery(DataParser):
 
        def __init__(self, type, source):
                super(CannedQuery, self).__init__(type)
                self.source = source
                self.terrainMap = { '0': 'Not defined', '1': 'Road', '2': 'Trail', '3': 'Treadmill', '4': 'Track' }
 
        def getTypesOfTerrain(self):
                tree = self.__getTree__(self.source)
                count = {}
                for elem in tree.findall(".//terrain"):
                        key = 'Never collected'
                        if elem.text in self.terrainMap:
                                key = self.terrainMap[elem.text]
                        if key in count:
                                count[key] += 1
                        else:
                                count[key] = 1
                return count
 
if __name__ == "__main__":
        argv = sys.argv[1:]
        if len(argv) > 0:
                dp = CannedQuery('file', argv[0])
                count = dp.getTypesOfTerrain()
                print "%s" % count

Pienso abrir un proyecto con todas estas clases de Python (Jython) en unos pocos días. Quiero agregarle un par de cosas más antes de soltarlas al aire libre :-)

internet, java, javafx, kodegeek, vida sana

Jython + JavaFX: Comienzo duro

Domingo, 9 de octubre de 2011

Al fin Oracle liberó su versión final de JavFX en JavaOne 2011; También hay una versión beta para OSX la cual me baje de una vez.

Jugando con los ejemplos me dediqué a experimentar con el ejemplo de un gráfico de torta el cual se ve sencillo:

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
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.chart.PieChart;
import javafx.scene.Group;
 
public class PieChartSample extends Application {
 
    @Override public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Imported Fruits");
        stage.setWidth(500);
        stage.setHeight(500);
 
        ObservableList pieChartData =
                FXCollections.observableArrayList(
                new PieChart.Data("Grapefruit", 13),
                new PieChart.Data("Oranges", 25),
                new PieChart.Data("Plums", 10),
                new PieChart.Data("Pears", 22),
                new PieChart.Data("Apples", 30));
        final PieChart chart = new PieChart(pieChartData);
        chart.setTitle("Imported Fruits");
 
        ((Group) scene.getRoot()).getChildren().add(chart);
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}

Lo compilamos y corremos:

1
2
3
Macintosh:javafx josevnz$ export CLASSPATH=/Users/Shared/javafx-sdk2.0.2-beta//rt/lib/jfxrt.jar:.
Macintosh:javafx josevnz$ javac PieChartSample.java -d .
Macintosh:javafx josevnz$ java PieChartSample

JavaFX Pie chartJavaFX gráfico de torta en acción

Así que traté de convertir este sencillo código a Jython:

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
#!/usr/bin/env jython
import sys
from javafx.application import Application
from javafx.collections import FXCollections
from javafx.collections import ObservableList
from javafx.scene import Scene
from javafx.stage import Stage
from javafx.scene.chart import PieChart
from javafx.scene import Group
 
class PieChartSample(Application):
 
    def __init__(self):
        pass
 
    def start(self, stage):
        scene = Scene(Group())
        stage.setTitle("Imported Fruits")
        stage.setWidth(500)
        stage.setHeight(500)
 
        pieChartData = FXCollections.observableArrayList(
                PieChart.Data("Grapefruit", 13),
                PieChart.Data("Oranges", 25),
                PieChart.Data("Plums", 10),
                PieChart.Data("Pears", 22),
                PieChart.Data("Apples", 30))
        chart = PieChart(pieChartData)
        chart.setTitle("Imported Fruits")
 
        scene.getRoot().getChildren().add(chart)
        stage.setScene(scene)
        stage.show()
 
if __name__ == "__main__":
        PieChartSample().launch(sys.argv[1:])

Pero al correrlo me se queja que no estoy extendiendo bien la clase ‘Aplication’ y por eso falla:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Macintosh:javafx josevnz$ ./piechart.py 
*sys-package-mgr*: can't create package cache dir, '/Users/Shared/jython2.5.2/cachedir/packages'
Traceback (most recent call last):
  File "./piechart.py", line 36, in <module>
    PieChartSample().launch(sys.argv[1:])
	at javafx.application.Application.launch(Application.java:186)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
 
java.lang.RuntimeException: java.lang.RuntimeException: Error: class sun.reflect.NativeMethodAccessorImpl is not a subclass of javafx.application.Application
 
</module>

No tengo ni idea en donde esta el error, ¿alguno de ustedes tiene una pista? De verdad me muero de ganas por usar JavaFX con Jython, ya otros han tenido éxito similar con JRuby y Groovy.

Amanecerá y veremos.

Actualización: De la lista de Jython me llegaron muchas sugerencias, al final Weiqi Gao encontró cual era el verdadero problema y esta es la solución:

1
2
3
# The key to happiness in JavaFX + Jython is this:
if __name__ == "__main__":
    Application.launch(PieChartSample().class, sys.argv[1:])

La explicación detallada a continuación:

The trick is with the last line of code that launches the application, which is accomplished with the javafx.application.Application.launch() method. There are two overloaded versions of this method:

1
public static void launch(String[] args);

and

1
public static void launch(Class< ? extends Application> appClass, String[] args);

The first version must be called from a method in a class that extends Application, which is not the case in the above python code. So we have to use the second version.

The idiom for using the first version of launch() in Java is the following:

1
2
3
4
5
6
7
8
9
10
public class Foo extends Application {
    @Override
    public void start(Stage stage) {
      // build the scene graph and show it
    }
 
    public static void main(String[] args) {
      Application.launch(args); 
    }
}

The idiom for using the second version of launch() in Java is the following:

1
2
3
4
5
6
7
8
9
10
11
12
public class Foo extends Application {
  @Override
  public void start(Stage stage) {
    // build the scene graph and show it
  }
}
 
public class Launcher {
  public static void main(String[] args) {
    Application.launch(Foo.class, args);
  }
}

There is an inefficiency in my python code in that I instantiated PieChartSample once only to get its class. I think there is a better way of doing it but can’t think of how at the moment.

java, javafx, python

El placer de correr temprano en la mañana

Jueves, 6 de octubre de 2011

Park near the pond, Darien CT
Un nuevo sitio para correr, ¡cerca de la casa!

En una de esas cosas del destino conseguí un parque con una pista de asfalto a no más de 2 millas de mi casa; El parque abre de 5:30 de la mañana hasta las 10:00 de la noche y aunque no se compara con Central Park con sus subidas y bajadas esta bien cuidado y tiene un lazo de casi una milla, ideal para correr.

Hoy manejé hasta allá a las 5:30 AM y después de quitarme la ropa que no necesitaba para correr comencé a darle vueltas al circuito; En un principio el frio de otoño me carcomía todo el cuerpo mientras un hilo nada modesto de mocos me corría por la nariz. Lo otro es que el recorrido no me era familiar, así que tenia que ir con cuidado especialmente en los pedazos que estaban totalmente a oscuras (se puede correr sin ver muy bien con poca luz, se sorprenderían de ver como se acostumbran los ojos).

Pero el cuerpo se adaptó rápido; El frio en las manos y cuerpo cedió a la euforia de correr para ir acelerando el paso hasta alcanzar la velocidad requerida.

Lo mejor es que el parque era prácticamente mio; Sólo unas pocas personas con linternas paseando sus perros pero nadie corriendo, nadie más rápido que yo.

Mi ego se inflama y poco a poco le pierdo respeto a las curvas y huecos del parque, ahora estoy corriendo. Ya no hay mocos en la nariz sino sudor por todo el cuerpo. No estoy llevando cuenta del tiempo ni las millas, sólo disfruto el sonido del agua que choca contra la orilla (el parque queda cerca del mar), mientras veo que ya hay más gente en el parque y ahora si, algunos corredores.

El reloj me recuerda que mis 5 kilómetros ya están listos; Mis manos me recuerdan que me ponga guantes la próxima vez, porque seguro va a haber una próxima vez.

Ah si, y una lampara para ver el camino mejor en la oscuridad :-)

vida sana

Opinión de libros: The Long Run (O como Matt Long nos muestra que si se puede)

Domingo, 2 de octubre de 2011

Normalmente no leo biografías de nadie; No me malentiendan, la historia de individuos que resaltan por haber hecho cosas extraordinarias es algo que debería motivarnos a ser mejores a todos.

Simplemente no es lo mio. Pero la historia del bombero y atleta Matt Long es digna de una película de super heroes.

Este libro es especial dado lo inusual de su personaje; Imagínese que usted es un corredor / atleta que se hizo desde cero, comenzando primero a pujar para poder correr hasta lograr conquistar varias metas: El maratón ING de New York (el más famoso del mundo), el de Chicago Boston (con su fama de invitar sólo a los más rápidos) y luego el triatlón Iron Man (si nadar, montar bicicleta y correr por varias millas no lo intimidan entonces usted seguro no es normal).

Todo va muy bien hasta un fatídico día en el cual en vez de entrenar con sus amigos es atropellado por un autobús el cual casi lo deja muerto, todo gracias a un paro de transporte en la gran manzana y a un conductor descuidado.

Pero Matt no se rindió. Peleó por recuperarse y al final logró volver a correr el maratón de New York y no sólo eso, logró hacer otro Iron Man.

Su lucha no fué fácil, ya que le dieron sólo %5 de posibilidades de éxito; Leer sus dudas y dolor físico es angustiante pero lo que realmente lo que cautiva de este libro es que aún con sus dudas el pudo salir a adelante y cambiar su suerte.

Mucha gente se ríe cuando les digo que me levanto a las 4:00 de la mañana 3 veces a la semana para entrenar en el gimnasio. Yo les digo que eso no es nada, no es un esfuerzo de verdad. Si no lean la historia de Matt Long para que vean que si se puede; Si eso no los inspira a ser mejores entonces no se que pueda :-)

kodegeek, vida sana , , , , , , ,