Tabs

sábado, 15 de junio de 2013

Python for runners

Una de las cosas que más me sorprendió cuando empecé a visitar blogs de corredores, es la cantidad de informáticos con los que me encontraba... :) Tengo mis teorías al respecto, pero eso será para otro día. Hoy, voy a contar mi última experiencia de python for runners, que me sé de uno que seguramente le guste, y mientras se recupera de la Haría Extreme podrá echarle un ojo, y espero que a alguno más de los informáticos que por aquí andan le pique el gusanillo e incluso se anime a mejorar el código que os voy a mostrar, que está disponible en GitHub:

git://github.com/iZydro/python-for-runners.git

¡Si alguien se apunta, que me dé su user de GitHub y lo añado como Collaborator!

¿De qué va esto? Pues me picó la curiosidad y quería saber cuánta gente estaba tan loca como yo y había corrido la maratón de Barcelona y la de Madrid 6 semanas después, y ya que estábamos, cómo le había ido en ambas pruebas.

Primer problema: O no hay, o no he sabido encontrar un listado con la clasificación general de ambas pruebas... Pero sí que hay un formulario en la web de las dos carreras con el que podemos buscar los datos de un corredor por nombre o dorsal... Así que...

Primer reto: Conseguir el listado de participantes y sus tiempos.

La parte más complicada a priori, básicamente nunca había intentado hacer algo así, pero no es tan complejo. Una web con un formulario, sencillamente nos permite rellenar una serie de campos, y al pulsar el botón de Buscar, se envía una URL que informa al servidor qué datos queremos consultar y nos devuelve una web con los datos que hemos pedido. En el caso de Barcelona, además, el formulario está separado del resto de la página, lo que se conoce normalmente como iframe. Podéis comprobarlo vosotros mismos si vais a esta dirección:

http://www.zurichmaratobarcelona.es/cgi-bin/ZMB_result_res_maraton-es.py?value=2581

En la web de la maratón de Madrid no es un iframe, pero sí que es un formulario sencillo, como también se puede ver pinchando el enlace:

http://www.maratonmadrid.org/resultados/clasificacion.asp?carrera=10&parcial=10&clasificacion=1&dorsal=1985

Así que no iba a ser muy complicado. Básicamente, abro el navegador, voy escribiendo los enlaces, cambiando el número de dorsal, copio y pego el nombre y resultado en un Excel, y a por el siguiente, unos 14.769 en Barcelona y 10.162 en Madrid... ¿Sencillo? ¡No hijo no! ¡Mejor vamos a hacer unos scripts en python!

Para enviar formularios y descargar cosas de internet tenemos urllib2, que viene instalado de serie, y para extraer información de páginas web, opté por BeautifulSoup, que se instala muy fácilmente con easy_install o pip.

Y ahora, a picar. Lo más sencillo, enviar los formularios y recibir los datos.

 from urllib2 import urlopen  
 for number in range (1, 20000):  
      result = ""  
      feed = urlopen("http://www.zurichmaratobarcelona.es/cgi-bin/ZMB_result_res_maraton-es.py?value=" + str(number))  
      soup = BeautifulSoup(''.join(feed.read()))  

Con este sencillo programa podemos bajar 20.000 páginas web con los datos de los corredores... Pero cada web que bajamos se parece más o menos a esto...


<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"><title> ::: Zurich Marat? de Barcelona ::::::::::</title><script type="text/javascript">
    function parriba () {
        var arriba=top.window.document.getElementById("arriba");
        arriba.scrollIntoView();
    }
</script><style type="text/css"></style><link href="/css/csszurich.css" rel="stylesheet" type="text/css"></link><style type="text/css"></style><style type="text/css">
a:link {
        text-decoration: none;
        color:#FFCC00
}
a:visited {
        text-decoration: none;
        color:#FFCC00
}
a:hover {
        text-decoration: none;
        color:#FFCC00
}
a:active {
        text-decoration: none;
        color:#FFCC00
}
.style2 {color: #FF9900}
.caselles1 {    font-family: Tahoma;
        font-size: 10px;
        color: #000000;
        border: 1px solid #999999;
}

</style></head><body style="background-color:transparent;" onload="parriba();"><div style="margin:0px 0px 0px 18px" align="left"><table width="698" border="0" cellspacing="0" cellpadding="0"><tr xmlns=""><td colspan="11"><div align="left"><table border="0" cellpadding="0" cellspacing="0"><tr><td colspan="11" class="tahoma11negre"><div align="left"><span class="texte">Corredores encontrados: </span><span class="zurich1"><strong>1</strong></span>.
 <br><span class="tahoma11blanc"><img src="/inscripciones/img/spacer.gif" width="10" height="5"></span><br><span class="zurich1"><img src="/imgzurich/bola.gif" width="12" height="13" align="absmiddle">Distancia:</span>?<span class="zurich2">MARAT?N</span><br><span class="tahoma11blanc"><img src="/inscripciones/img/spacer.gif" width="10" height="5"></span><br><span class="zurich1"><img src="/imgzurich/bola.gif" width="12" height="13" align="absmiddle">Mostrando:</span><span class="zurich2"> Clasificaci?n General</span><br></div></td></tr><tr><td class="tahoma11negre"><img src="/inscripciones/img/spacer.gif" width="10" height="10"></td></tr></table></div></td></tr><tr xmlns=""><td><div align="left"><img src="/inscripciones/img/spacer.gif" height="2"></div></td></tr><tr xmlns=""><td colspan="7">?</td></tr><tr xmlns=""><td width="60" bgcolor="#5982B8" class="tahoma12blanc"><img src="/imgzurich/liloso1.jpg" width="11" height="27" align="absmiddle"><span class="tahoma12blanc">Posici?n</span></td><td bgcolor="#5982B8" class="tahoma12blanc">Dorsal</td><td bgcolor="#5982B8" class="tahoma12blanc">Nombre</td><td bgcolor="#5982B8" class="tahoma12blanc">Cat.</td><td bgcolor="#5982B8" class="tahoma12blanc">Club</td><td bgcolor="#5982B8" class="tahoma12blanc">Pa?s</td><td bgcolor="#5982B8" class="tahoma12blanc">Tiempo</td><td bgcolor="#5982B8" class="tahoma12blanc" style="background-image:url(/imgzurich/liloso2.jpg);background-position:top right;background-repeat:no-repeat;">V?deo</td></tr><tr xmlns=""><td bgcolor="#F6FAFD" class="texte" style="text-transform:uppercase;padding:0px 0px 0px 11px">00002</td><td width="50" bgcolor="#F6FAFD" class="texte">00002</td><td width="140" bgcolor="#F6FAFD" class="texte"><a target="_self" href="/cgi-bin/detalles_resultados.py?lloc=2;lang=es"><span style="color:#003366; text-decoration:underline">Abraham?Keter</span></a></td><td width="40" bgcolor="#F6FAFD" class="texte">SenM</td><td width="130" bgcolor="#F6FAFD" class="texte">
                 ?
               </td><td width="55" bgcolor="#F6FAFD" class="tahoma11negre"><span class="tahoma11groc Estilo1" style="color:#FF6600">KEN</span></td><td width="60" bgcolor="#F6FAFD" class="texte">02:10:48</td><td width="40" bgcolor="#F6FAFD" class="texte"><div align="center"><a style="border: 0px solid white" target="_top" href="http://mysports.tv/events/MB13/redirect.asp?r=2"><img style="border:0px solid white" src="/resultados/img/camera.gif"></a></div></td></tr><tr xmlns=""><td colspan="7"><div align="left"><img src="/inscripciones/img/spacer.gif" height="6"></div></td></tr><tr xmlns=""><form method="post" name="form" action="ZMB_result_res_maraton-es.py" target="result"><input type="hidden" name="order_index" value="0"><input type="hidden" name="skip" value="0"><input type="hidden" name="length" value="5"><input type="hidden" name="total" value="1"><input type="hidden" name="value" value="2"><td colspan="3" bgcolor="#5881B8" class="tahoma12blanc"><div align="left">??p?gina <span class="tahoma12blanc">1</span> de <span class="tahoma12blanc">1</span></div></td><td colspan="5" align="right" bgcolor="#5881B8" height="20"><span class="tahoma12blanc"><img src="/inscripciones/img/pointiti2cinvers.gif" width="12" height="13" align="absmiddle">?
            inicio
?<img src="/inscripciones/img/pointiti2cinvers.gif" width="12" height="13" align="absmiddle">?
            anterior
?-?
            siguiente
?<img src="/inscripciones/img/pointiti2c.gif" width="12" height="13" align="absmiddle">
?
            ?ltima
?<img src="/inscripciones/img/pointiti2c.gif" width="12" height="13" align="absmiddle">??
    </span></td></form></tr></table></div></body></html>

A ver, por aquí se ve algo...

<span style="color:#003366; text-decoration:underline">Abraham?Keter</span></a></td><td width="40" bgcolor="#F6FAFD" class="texte">SenM</td><td width="130" bgcolor="#F6FAFD" class="texte">                 ?               </td><td width="55" bgcolor="#F6FAFD" class="tahoma11negre"><span class="tahoma11groc Estilo1" style="color:#FF6600">KEN</span></td><td width="60" bgcolor="#F6FAFD" class="texte">02:10:48</td> 

Vale, tenemos el nombre y el tiempo en la web. Ahora sólo hay que sacarlo de ahí. Ahí es donde entra en juego BeautifulSoup, una librería que nos permite buscar elementos en una web, recorrerlos y extraer información de ellos. Gracias al inspector del Chrome, se puede ver fácilmente en qué tabla, fila y columna están los datos que necesitamos, y con BeautifulSoup acceder a ella. Para la web de Barcelona, tan sencillo como esto:

 feed = urlopen("http://www.zurichmaratobarcelona.es/cgi-bin/ZMB_result_res_maraton-es.py?value=" + str(number))  
 soup = BeautifulSoup(''.join(feed.read()))  
 tables = soup.findAll('table')  
 for table in tables:  
      rows = table.findAll('tr')  
      trc = 1  
      for tr in rows:  
           if trc == 7:  
                cols = tr.findAll('td')  
                tdc = 1  
                for td in cols:  
                     if tdc == 3:  
                          for tde in td:  
                               for tdea in tde:  
                                    for tdeas in tdea:  
                                         result = result + tdeas  
                     if tdc == 7:  
                          for tde in td:  
                               result = result + " | " + tde  
                     tdc = tdc + 1  
           trc = trc + 1  
 if result != "":  
      print result  
      sys.stdout.flush()  

¿Qué estoy haciendo? Le pido a BeautifulSoup que me busque cuántas tablas hay en la web, que las recorra una a una, en este caso, solo había una, en cada tabla, que recorra todas las filas, y si la fila es la número 7 (trc == 7), que recorra sus columnas, y en la columna 3, extraiga el elemento que está a dos niveles de profundidad (el nombre, que está dentro de un <a> y de un <span>), y en la 7, el elemento que está a un nivel de profundidad (el tiempo). Juntamos nombre y tiempo, separados por un signo "|", y lo sacamos por stdout, para poder verlo en pantalla o escribirlo a un archivo.

¿Cómo hago esto último? Desde línea de comando, llamo a mi programa y redirecciono la salida a un comando tee, que me muestra la salida por pantalla y además la escribe a un fichero. Así que hago:

python bnc.py | tee bcn.txt

¡Y varias horas después tengo un bcn.txt con los nombres de los 14.769 finishers y sus tiempos!

Vamos ahora a Madrid. Se me complicó un poco... Resulta que hay una tabla, pero dentro de esa tabla hay otras tablas dentro de unas celdas, y BeautifulSoup parece que se lía y lo de recorrer tablas, filas y columnas no funciona bien... Pero aprovecho otra feature de BeautifulSoup y lo hago de otra manera, le pido que me devuelva una tabla que incluya una característica en concreto, que en este caso, es que su ancho sea del 98%. Como sólo hay una tabla así, que es la que muestra los resultados, mezclo una técnica con otra y consigo sacar los nombres y resultados de esta manera:

 for number in range (1, 12000):  
      result = ""  
      feed = urlopen("http://www.maratonmadrid.org/resultados/clasificacion.asp?carrera=10&parcial=10&clasificacion=1&dorsal=" + str(number))  
      soup = BeautifulSoup(''.join(feed.read()))  
      t = soup.find("table", {"width":"98%"})  
      r = t.findAll("tr")  
      if len(r) > 1:  
           d = r[1].findAll("td")  
           for tde in d[2]:  
                for tdea in tde:  
                     for tdeas in tdea:  
                          result = result + str(tdeas)  
           for tde in d[3]:  
                for tdea in tde:  
                     for tdeas in tdea:  
                          result = result + " " + str(tdeas)  
           for tde in d[6]:  
                for tdea in tde:  
                     for tdeas in tdea:  
                          result = result + " | " + str(tdeas)  
           print result  
           sys.stdout.flush()  

Sencillamente, buscar la tabla en cuestión, ver si tiene más de una fila, y si es así, coger los datos de las columnas 2, 3 y 6 de la fila 2, que son nombre, apellido y tiempo, juntarlos, y sacarlos por stdout.

Igual que en Barcelona, ejecuto, tee, y mad.txt listo. Cambio un par de líneas en el programa y saco la clasificación femenina, que lleva otra numeración. Simplemente, el for es de 1 a 1200, y al urlopen le añado una "F" después de dorsal=

Ejecuto, y guardo mad-her.txt

¡Tengo tres archivos con nombres y tiempos de maratonianos, después de dejar dos noches el Mac trabajando, ahora, a divertirse!

Mi idea: leer los dos archivos, y construir dos list de objetos con nombre y tiempo. ¿Por qué no un diccionario indexado por el nombre? Lo descarté porque seguramente habría nombres repetidos...

Además, con los archivos ya descargados, me di cuenta de que los de Barcelona tenían caracteres extraños en el nombre (el espacio no era un espacio, era una cosa muy rara, un 0xc2a0), y que los nombres en Barcelona estaban en minúsculas y los de Madrid en mayúsculas. Así que mientras rellenaba la lista, aproveché para normalizarlo todo a ASCII puro y duro, con un sencillo lower(), y la función unidecode y la propiedad decode de los Strings. Ah, y quitar el primer 0 del tiempo para que los dos tengan el mismo formato.

 def read_results(file_name, vector_name):  
      for line in open(file_name, "r"):  
           line = line.strip()  
           runner_time = line.split(" | ")  
           runner_time[0] = runner_time[0].replace(chr(0xa0), " ")  
           runner_time[0] = runner_time[0].replace(chr(0xc2), "")  
           runner_time[0] = unidecode(runner_time[0].decode("unicode-escape").lower())  
           if runner_time[1][0] == "0":  
                runner_time[1] = runner_time[1][1:]  
           vector_name.append(runner_time)  

Con esta función, simplemente haciendo:

 mad = []  
 bcn = []   
 read_results("mad-her.txt", mad)  
 read_results("bcn.txt", bcn)  
 num_mad = len(mad)  
 num_bcn = len(bcn)  

Ya tengo dos list, cada una conteniendo un objeto de dos miembros, nombre y tiempo, y precalculo la cantidad de elementos de cada uno.

Lo siguiente, recorrer una lista, y después, para cada elemento de ésta, recorrer la otra buscando si el nombre en ambos elementos coincide. En python, es tan sencillo como esto:

 for madrid in mad:  
      runner_mad = str(madrid[0])  
      for barcelona in bcn:  
           runner_bcn = barcelona[0]  
           if runner_mad == runner_bcn:  
                # Lo tenemos!  

Ahora lo más divertido, qué hacemos cuando lo tenemos. Pues varias cosas... Convierto el tiempo a un objeto datetime y voy sumando los tiempos de cada prueba en las variables total_mad y total_bcn. Como sumar dos datetime (fechas) no tiene sentido en programación ni en la vida real, uso una función que añade segundos a una fecha, y paso el resultado de la carrera a segundos y lo sumo:

 time_mad = datetime.strptime(madrid[1], "%H:%M:%S")  
 time_bcn = datetime.strptime(barcelona[1], "%H:%M:%S")  
 total_mad = total_mad + timedelta(0, time_mad.hour * 3600 + time_mad.minute * 60 + time_mad.second)  
 total_bcn = total_bcn + timedelta(0, time_bcn.hour * 3600 + time_bcn.minute * 60 + time_bcn.second)  

Después, si el tiempo en BCN es menor que en MAD, voy incrementando el contador que indica cuanta gente corrió más rápido en BCN, si no, en MAD y sumo la diferencia de tiempos en total_diff, para sacar la media al final:

 if (time_mad > time_bcn):  
      diff = " BCN faster by " + str(time_mad - time_bcn)  
      bcn_faster = bcn_faster + 1  
      total_diff += (time_mad - time_bcn)  
 else:  
      diff = " MAD faster by " + str(time_bcn - time_mad)  
      mad_faster = mad_faster + 1  
      total_diff -= (time_bcn - time_mad)  

Unas líneas más para construir un string con el nombre, número de orden, tiempos, qué maratón corrió más rápido y por cuánto, y tenemos este tipo de salida:

25: ralph schneider           BCN: 3:34:43    MAD: 3:12:01   MAD faster by 0:22:42
26: isidro gilabert             BCN: 3:21:25    MAD: 3:22:14   BCN faster by 0:00:49
27: joao carmo                  BCN: 3:04:28    MAD: 3:07:21   BCN faster by 0:02:53

Y para los amantes de la estadística, todo eso que hemos ido sumando, ahora lo podemos presentar... Una pequeña función que calcula el tiempo total acumulado dividido entre los participantes, y nos devuelve horas, minutos y segundos para luego sacarlo por pantalla:

 def divide_time(my_time, total):  
      result = {}  
      seconds = my_time.second + my_time.minute * 60 + my_time.hour * 3600 + (my_time.day - 1) * 3600 * 24  
      div = seconds / total  
      hours = int(div/3600)  
      minutes = int((div - hours*3600) / 60)  
      seconds = div - hours*3600 - minutes*60  
      result["hours"] = str(hours)  
      if minutes < 10:  
           result["minutes"] = "0" + str(minutes)  
      else:  
           result["minutes"] = str(minutes)  
      if seconds < 10:  
           result["seconds"] = "0" + str(seconds)  
      else:  
           result["seconds"] = str(seconds)  
      return result  

Y así, sencillamente, hacemos esto:

 result = divide_time(total_mad, cnt_tot)  
 print "Average MAD time " + result["hours"] + ":" + result["minutes"] + ":" + result["seconds"]  
 result = divide_time(total_bcn, cnt_tot)  
 print "Average BCN time " + result["hours"] + ":" + result["minutes"] + ":" + result["seconds"]  

Et voilá! Al final me salen estos datos:


Masculino
Ran MAD faster: 45, ran BCN faster: 71
Average MAD time 3:51:20Average BCN time 3:45:19
Average difference: BCN faster by 6 minutes, 1 seconds

Femenino
Ran MAD faster: 5, ran BCN faster: 6
Average MAD time 3:56:09Average BCN time 3:56:02
Average difference: BCN faster by 0 minutes, 6 seconds

El código y los listados, se pueden husmear aquí...


Los entrenamientos siguen bien, recuperando la forma poco a poco... Pero eso será para otro post... :)

martes, 11 de junio de 2013

Vuelve el Pollo

No es exactamente una mini meta ni un objetivo secundario... Simplemente, el 7 de julio, ya que andaré por Lanzarote, aprovecharé para patear 20 kilómetros a un ritmo tranquilo con el capo local Antonio Navas, disfrutando del desierto, del paisaje y del calor, pero sobre todo de la compañía... Volveré también a subir al volcán de Montaña Roja antes del San Marcial Trial, y mientras sigo por Barcelona, sin obsesionarme, haré alguna salida por montaña, combinando Turó del Pollo, Cruz de Montigalá y Dues Pedres a discreción...

Este domingo fue un Turó del Pollo - Cruz de Montigalá. Antes, un cochinero de 9 kilómetros y medio a 5:33, bastante mejor que el 5:53 del día anterior, y el sábado otro cochinero de algo menos de 9 kilómetros y medio a 5:31, también de madrugada. La única manera de volver a recuperar ritmos y pulsaciones más bajas es volver a la rutina sin prisa pero sin pausa.

La salida por la montaña se resintió de la inactividad y la falta de forma, no quise ir más rápido de la cuenta, y aunque hubiera querido, seguro que no había podido... :) Al menos, no llegué a parar en ningún momento pese a haber tenido ganas de subir caminando alguno de los tramos asesinos con pendientes de más del 7%. Pese a que los ritmos eran muuuuuy lentos, las pulsaciones se me iban fácilmente a más de 170bpm después de una subida prolongada... Subí al Turó del Pollo con la lengua fuera, lo rodeé recuperando un poco el aliento, y en la bajada, un grupo de runners que tenía detrás despertó a la bestia y en la bajada sí que fui algo más rápido, intentando cuidar la pisada, según recomiendan los expertos, buscando pisar justo debajo de mi centro de gravedad y levantando los talones, en vez de frenando con las rodillas... La sensación de velocidad y la probabilidad de darse una buena leche son elevadas, pero llegué entero y mis perseguidores me vieron hacerme pequeñito mientras seguían corriendo y hablando... :)

Cuando normalmente sigo la ruta a casa, giré a la izquierda y completé el recorrido hasta la Cruz de Montigalá, 5 kilómetros más de los 8,5 habituales de la ruta del Turó del Pollo, con toboganes y algún tramo de bajadas técnicas, que con el calor que iba empezando a apretar se me hicieron largos...

Pero llegué entero a casa, después de volver a probar el sabor de la montaña, y con ganas de sufrir un poco en Lanzarote... :)


El lunes dudaba entre correr, descansar o la elíptica. Al final opté por salir a cochinear muy tranquilo, volviendo al cochinerus maximus y completando 9,55 kilómetros a un ritmo de 5:59 y pulsaciones a 141bpm, aún muy lento y alto de pulsaciones, toca seguir trabajando con paciencia para volver a ser yo mismo... Y hoy tocaba dejar las Triumph 10 en el armario, pero darle un poco de guerra a la elíptica. 50 minutos a ritmos variados, todo un regalo para las rodillas que aún se quejaban de lo del domingo.

Entrenamientos aparte... Hoy he leído algo que me ha dejado horrorizado...

Parece que van a cambiar el recorrido de la Maratón de Madrid en 2014... Incluso han abierto una especie de concurso para que se propongan nuevos recorridos... En la página de facebook preguntan si preferiríamos que las cuestas estén en la primera mitad o en la segunda... :( Cómo pueden siquiera preguntarlo...

Sólo la he corrido una vez y seguro que hay gente que lo ha hecho más veces y con mucho mejor resultado... Pero desde la humildad de haberlo hecho al menos esa vez, manifiesto públicamente que no entiendo el porqué de esta decisión... ¿Es un recorrido duro? Sí, durísimo. Pero la gloria de acabar esa carrera no puedo compararla con ninguna otra... Si la cambian, me congratularé de haber corrido la última Maratón de Madrid auténtica. Pero me dará mucha lástima que mucha gente se quede sin experimentar esa experiencia casi mística de correr una prueba dura, muy dura, con el final más emocionante que he corrido nunca, 7 kilómetros irrepetibles de sufrimiento, lucha y público entregado animando bajo el sol o muertos de frío...Yo la corrí por eso... Había leído tantas crónicas épicas que tenía que hacerlo yo también... Si quieren cambiar el recorrido para atraer más participantes... Estarán sacrificando una experiencia única que merece la pena sentir al menos una vez...

miércoles, 5 de junio de 2013

El penúltimo dorsal del verano...

El penúltimo dorsal del verano me lo puse el domingo, no me podía perder los 10K que se corren en el circuito de Montmeló, aún sabiendo que iba a hacer mi Peor Marca Personal de largo... No he hecho nada por recuperar mi estado de forma, he ido a correr con las uñas de los pulgares sentenciadas a muerte y doliéndome un poco, y además con un calor que ya empieza a asomar... Salieron 10 kilómetros en 45:30, sufriendo con el calor, ha sido el día que menos ganas he tenido de correr pese a llevar un dorsal. En fin, un esfuerzo innecesario en plena vuelta a los entrenamientos, pero que no me quería perder, al final en esto del correr también imperan las tradiciones, carreras clásicas, etc.

¿Y por qué digo penúltimo dorsal del verano si debía ser el último? Pues... Porque he pecado... :) Este año me iré de vacaciones a principio de julio, repetiré destino en Lanzarote, así que se lo dije a mi amigo Antonio, para ver si hacíamos juntos una ruta como el año pasado... Y entonces va y me enseña esto... :)


El carte lo dice claro... ¿Estás como una cabra? Así que... Cuando el tratamiento de recuperación veraniega a base de Gin Tonics y sol ya esté en su apogeo... Me pondré un dorsal para patear entre volcanes por los alrededores de Yaiza... :)

Si quiero acabar vivo, tengo que empezar a entrenar de nuevo. Ya ha pasado más de un mes, y el cuerpo ya lo pide. Esas tres carreras de 10K y ese partido de fútbol asesino que jugué la semana pasada me han tenido entretenido pero no han hecho mucho por mi estado de forma. Así que, vuelta a los cochineros, como el de esta mañana, 9,56 kilómetros por el río a una media vertiginosa de 5:56 minutos por kilómetro...

Poco a poco, sin prisas, a ir buscando correr cómodo, bajar las pulsaciones, descansar unos días, patear Lanzarote, y a la vuelta, a mediados de julio, comenzará el plan NYC 2013.