Correo desde ASP sin CDO

Utilizar CDO obliga a incluir líneas tales como:

miMensaje.Configuration.Fields.Item _
(“http://schemas.microsoft.com/cdo/configuration/sendusing“)=2

miMensaje.Configuration.Fields.Item _
(“http://schemas.microsoft.com/cdo/configuration/smtpserver“) _
=”IPServidorSMTP”

miMensaje.Configuration.Fields.Item _
(“http://schemas.microsoft.com/cdo/configuration/smtpserverport“) _
=25

Con esto, obligamos al servidor de web obligatoriamente a tener internet, y en caso de caída del servicio, dejaremos de tener correo electrónico, fallando la aplicación.

He encontrado esta utilidad gratuita para sustituir CDO. Se llama JMail (sí, con J).

Su página es http://www.webwiz.co.uk/kb/asp-tutorials/email-using-jmail-tutorial.htm

Yo he probado en un Windows Server 2003. Se instala el ejecutable, y luego con este pequeño código ya se puede utilizar:

Dim objJMail Set objJMail = Server.CreateObject(“Jmail.Message”) objJMail.From = “remite” objJMail.AddRecipient “destinatario” objJMail.Subject = “Asunto del correo” objJMail.HTMLBody = “<html>Salida del correo</html>” objJMail.Send(“192.168.1.131:25“)

Obtener los usuarios de un grupo del directorio activo

Desde consola:

net group /domain gadministracion

Impresión de planos de Solid Edge desde Visual Studio 2010

El ordenador donde se vaya a ejecutar el programa ha de tener Solid Edge instalado. En este caso, las pruebas se han hecho para Solid Edge ST4.

Primero hay que agregar las siguientes referencias, que se pueden coger de la carpeta donde se haya instalado Solid Edge.

Además, en este código se inserta un cajetín de texto donde introducir a voluntad lo que queramos.

También se indica la impresora donde imprimir.

VBRUN.dll

Interop.SolidEdgeConstants.dll

SolidEdgeFramework.dll

SolidEdgeFrameworkSupport.dll

Interop.VBA.dll

Luego, el código es el siguiente:

On Error Resume Next

objApp = GetObject(, "SolidEdge.Application")

If Err.Number Then

‘ Solid Edge is not running. Clear the previous error.

Err.Clear()

‘ Start Solid Edge.

objApp = CreateObject("SolidEdge.Application")

‘ Cannot start Solid Edge, so exit the program.

If Err.Number Then

MsgBox("Cannot start Solid Edge.", MsgBoxStyle.Critical + MsgBoxStyle.OkOnly, "Open & Save")

End

End If

‘ Make Solid Edge visible.

objApp.Visible = True

End If

On Error Resume Next

‘ Open the document.

objDoc = Nothing

objDoc = objApp.Documents.Open(rutadeldocumento)

Dim objSheet As Object

Dim objTextBoxes As Object

Dim X1 As Double, X2 As Double

Dim Y1 As Double, Y2 As Double

Dim objTextBox1 As Object

Dim objTextEdit As Object

Dim seTextSelectRange As String

‘Make sure the active environment is Draft.

‘Reference the active sheet.

objSheet = objApp.ActiveDocument.ActiveSheet

‘Reference the Sheet object.

‘Reference the TextBoxes collection.

objTextBoxes = objApp.ActiveDocument.ActiveSheet.TextBoxes

‘Use the AddByTwoPoints method to create a text box.

‘The points are defined by the X1, Y1, X2, Y2 variables.

‘The z values of the point are defined as zero.

X1 = 0 : Y1 = 0

X2 = 30 : Y2 = 0.007

objTextBox1 = objTextBoxes.AddByTwoPoints _

(X1, Y1, 0, X2, Y2, 0)

‘Place the text in the text box.

objTextBox1.Text = textodelcajetin

‘Reference the new TextEdit object.

objTextEdit = objTextBox1.Edit

‘Bold the word "TextBox."

‘First, select the range of characters in the editor. El tamaño va en pulgadas, no en el tamaño de fuente que estamos acostumbrados.

objTextEdit.TextSize = 0.003

‘Then set the bold flag.

objTextEdit.Bold = True

‘ Set a default, so response for unhandled cases is consistent. Aquí indicamos DINA4 como predeterminado.

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPSA4

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORLandscape

‘ Determine the size of the sheet.

Select Case objDoc.ActiveSheet.SheetSetup.SheetSizeOption

Case SolidEdgeConstants.PaperSizeConstants.igIsoA3Tall

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPSA3

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORPortrait

Case SolidEdgeConstants.PaperSizeConstants.igIsoA3Wide

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPSA3

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORLandscape

Case SolidEdgeConstants.PaperSizeConstants.igIsoA4Tall

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPSA4

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORPortrait

Case SolidEdgeConstants.PaperSizeConstants.igIsoA4Wide

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPSA4

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORLandscape

Case SolidEdgeConstants.PaperSizeConstants.igAnsiBWide

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPS11x17

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORLandscape

Case SolidEdgeConstants.PaperSizeConstants.igAnsiBTall

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPS11x17

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORPortrait

Case SolidEdgeConstants.PaperSizeConstants.igAnsiAWide

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPSLetter

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORLandscape

Case SolidEdgeConstants.PaperSizeConstants.igAnsiATall

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPSLetter

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORPortrait

Case SolidEdgeConstants.PaperSizeConstants.igAnsiDWide

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPS11x17

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORLandscape

Case SolidEdgeConstants.PaperSizeConstants.igAnsiDTall

lPaperSize = VBRUN.PrinterObjectConstants.vbPRPS11x17

lPaperOrient = VBRUN.PrinterObjectConstants.vbPRORPortrait

End Select

On Error GoTo 0

‘El parámetro PrintRange:=2 es para que imprima sólo la primera hoja del plano.

objDoc.PrintOut(Printer:=nombredeimpresora, Orientation:=lPaperOrient, ColorAsBlack:=True, PaperSize:=lPaperSize, Scale:=1.0#, PrintRange:=2)

‘Cierra el plano sin guardar.

objDoc.Close(False)

objApp.quit()

objDoc = Nothing

‘ Give the application time to process the document closure

objApp.DoIdle()

Cómo beber en carrera de un vaso

1.- El vaso

2.- En vez de cogerlo de la base, como haríamos de normal, lo hacemos de la parte superior.

3.- Apretamos, de forma que sólo quede un agujero pequeño. Si nos mojamos, nos mojamos la mano. Mejor eso que no beber.

4.- Bebemos por el agujero que queda. Podemos hacerlo como si fuera un botellín.

Insisto en que algo de líquido siempre cae, pero es una técnica muy fácil de aprender y funciona realmente bien.

Programación en el cron de Debian la ejecución de un PHP

Hay tres partes: Archivo de ejecución por lotes (archivo.sh), archivo php (archivo.php), y programación de la tarea en CRON.

1.- Archivo de ejecución por lotes.

Deberá ser del estilo:

#!/bin/sh

/usr/bin/php –c /etc/php5/apache2/php.ini /var/www/jobs/archivo.php

Lo guardamos en /etc/cron.daily/archivo.sh. En sí, no hace falta que esté aquí, pero así quedan los ejecutables en su sitio. Luego le daremos la programación “personalizada”.

2.- Archivo PHP.

Por ejemplo, mandar un correo desde PHP. Hará falta tener las librerías de phpMailer:

require_once(‘phpMailer/class.phpmailer.php’);

$mail = new PHPMailer();

$mail->IsSMTP();

$mail->IsHTML(true);

$mail->Timeout=30;

$mail->Host = “ServidorDeCorreo”;

$mail->SMTPDebug = 2;

$mail->SMTPAuth = false;

$mail->Port = 25;

$mail->SetFrom(‘no_reply@dominio.com’, ‘Correo automatico’);

$mail->AddReplyTo(“no_reply@dominio.com”,”Correo automatico”);

$mail->Subject = “Correo enviado automaticamente”;

$body.=”Correo enviado automaticamente”;

$mail->MsgHTML($body);

@$mail->AddAddress(“destinatario@dominio.com”, “”);

@$mail->Send();

Este archivo deberá estar guardado imperiosamente según la ruta del punto 1, en /var/www/Jobs/archivo.php

3.- Programación en CRON.

Desde línea de comandos, tecleamos:

crontab –e

Agregamos una línea que ponga 10 11 * * * /etc/cron.daily/archivo.sh

Tal y como está, se ejecuta a las 11 y 10.

Campos personalizados GLPI

Versión 0.83.10 de GLPI – add custom folders

Ejemplo para agregar campos personalizados en Teléfonos. Queda totalmente integrado en el sistema. La forma de hacerlo es rudimentaria, pero luego se integra perfectamente.

1.- Campos.

Agregar los campos que queramos en la tabla glpi_phones.

Por ejemplo imei, pin, puk, extensión.

Yo los he puesto en formato texto, por lo que pueda pasar…. ;-).

2.- Idioma.

En /locales/es_ES.php ponemos las opciones de español.

$LANG[‘common’][110]=”Extensión”;

$LANG[‘common’][111]=”IMEI”;

$LANG[‘common’][112]=”PIN”;

$LANG[‘common’][113]=”PUK”;

En los archivos correspondientes al idioma que queramos traducir, hay que hacer los mismo, respetando los números entre corchetes (110, 111, 112, 113), ya que han de coincidir.

3.- Formulario de datos: Inventario à Teléfonos à Selección de uno.

En inc/phone.class.php hay una función llamada showForm.

A partir del “<tr class=’tab_bg_1′>” es donde empieza a estar el código que muestra el formulario.

Hemos de saber un poco de tablas en HTML para ubicar los datos donde queramos, o para borrar los campos que no nos hacen falta.

Para agregar un campo, hay que escribir dos cosas:

– El literal, es decir, la descripción del campo. à <td>”.$LANG[‘common’][110].”&nbsp;:</td>” à Esto para la extensión.

– El campo en sí. à “<td>”.autocompletionTextField($this, “extension”).”</td>” à Esto para que saque el valor del campo desde la tabla, o para que pueda guardar lo que escribimos.

Hacemos lo mismo con el resto de campos, modificando el valor numérico de entre los corchetes y el valor que representa el nombre del campo de la tabla.

4.- Tabla de resumen de todos los teléfonos. La que aparece tras pinchar en Inventario à Teléfonos.

Lo que haremos es que nuestros campos, los nuevos, aparezcan en los desplegables de personalización de tabla.

En inc/phone.class.php hay una función llamada getSearchOptions.

Agregamos las líneas :

$tab[101][‘table’] = $this->getTable();

$tab[101][‘field’] = ‘extension’;

$tab[101][‘name’] = $LANG[‘common’][114];

$tab[101][‘datatype’] = ‘string’;

$tab[102][‘table’] = $this->getTable();

$tab[102][‘field’] = ‘imei’;

$tab[102][‘name’] = $LANG[‘common’][115];

$tab[102][‘datatype’] = ‘string’;

$tab[103][‘table’] = $this->getTable();

$tab[103][‘field’] = ‘pin’;

$tab[103][‘name’] = $LANG[‘common’][116];

$tab[103][‘datatype’] = ‘string’;

$tab[105][‘table’] = $this->getTable();

$tab[105][‘field’] = ‘puk’;

$tab[105][‘name’] = $LANG[‘common’][117];

$tab[105][‘datatype’] = ‘string’;

Habremos de tener cuidado en:

– El número de $tab es el que toque, yo he empezado del 101. No es el de la traducción.

– Respetar el nombre de campo (extension, imei, pin, puk)

– El número de = $LANG[‘common’] sí que es el de la traducción.

Después de esto, podremos ir a la configuración habitual de visualización (el símbolo + de arriba a la izquierda) y configurar los campos que queremos que aparezcan.

Consultas varias LDAP

Este cacho de código, común a todos

$ldap_host = “IPDelServidor”;

$ldap_dn = “DC=dominio,DC=local”; //à Menos este, que puede variar

$ldap = ldap_connect($ldap_host);

ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION,3);

ldap_set_option($ldap, LDAP_OPT_REFERRALS,0);

ldap_bind($ldap, “usuarioDA”, “contraseña”);

Después solo habría que añadir el resto:

Muestra de las unidades organizativas de primer nivel.

$justthese = array(“ou”);

$sr = ldap_list($ldap, $base_dn, “ou=*”, $justthese);

$info = ldap_get_entries($ldap, $sr);

for ($i=0; $i < $info[“count”]; $i++) {

echo $info[$i][“ou”][0].”<br>”;

}

Unidades organizativas dentro de UOEspecial junto con sus usuarios

$justthese = array(“ou”);

$sr = ldap_list($ldap, $base_dn, “ou=*”, $justthese);

$info = ldap_get_entries($ldap, $sr);

for ($i=0; $i < $info[“count”]; $i++) {

echo $info[$i][“ou”][0].”<br>”;

$filter = “(&(samaccountname=*) (objectClass=user) (objectCategory=person))”;

$base_dn2=”OU=”.$info[$i][“ou”][0].”,OU=UOEspecial,DC=dominio,DC=local”;

$sr2=ldap_search($ldap, $base_dn2, $filter);

$info2 = ldap_get_entries($ldap, $sr2);

for ($i2=0; $i2 < $info2[“count”]; $i2++) {

echo “—-“.$info2[$i2][“cn”][0].”<br>”;

}

//exit();

}

Listado de todos los grupos del DA

$filter = “(&(objectCategory=group))”; //puede ser user, computer…

$sr=ldap_search($ldap, $base_dn, $filter);

$info = ldap_get_entries($ldap, $sr);

for ($i=0; $i < $info[“count”]; $i++) {

echo $info[$i][“name”][0].”<br>”;

}

Usuarios de un grupo del directorio activo

$filter = “(&(objectCategory=user) (memberOf=cn=SUBGRUPO,OU=UOGRUPO,DC=dominio,DC=local))”;

$sr=ldap_search($ldap, $base_dn, $filter);

$info = ldap_get_entries($ldap, $sr);

for ($i=0; $i < $info[“count”]; $i++) {

echo $info[$i][“name”][0].”<br>”;

}

Pertenencia de un usuario a un grupo del directorio activo

$filter = “(&(objectClass=user) (samaccountname=USUARIO) (memberOf=cn=GUTConsulta,OU=UOGUtillajes,OU=UOAplicaciones,DC=dominio,DC=local))”;

$sr=ldap_search($ldap, $base_dn, $filter);

if (count(ldap_get_entries($ldap, $sr))==1){

echo “No pertenece”;

}

else{

echo “Pertenece”;

};

Extracción de todos los atributos de DA de un usuario

$filter = “(&(objectCategory=user)(samAccountName=USUARIO))”;

$sr=ldap_search($ldap, $base_dn, $filter);

$info = ldap_get_entries($ldap, $sr);

$entry = ldap_first_entry($ldap, $sr);

$attrs = ldap_get_attributes($ldap, $entry);

echo $attrs[“count”] . ” atributos mantenidos por esta entrada:<p>”;

//Esto sólo sacaría los atributos. Lo dejo para que se entienda lo de abajo.

//for ($i2=0; $i2 < $attrs[“count”]; $i2++) {

// echo $attrs[$i2] . “<br />”;

//}

for ($i=0; $i < $info[“count”]; $i++) {

for($i2=0;$i2<count($attrs);$i2++){

echo $attrs[$i2].” –> “.$info[$i][$attrs[$i2]][0].”<br>”;

}

}

Búsqueda del responsable del departamento

En las propiedades del usuario, en la pestaña Organización, en puesto, le hemos puesto el valor DDDDdddDDD.

$filter = “(&(samaccountname=*)(title=DDDDdddDDD)(objectClass=user) (objectCategory=person))”;

$sr=ldap_search($ldap, $ldap_dn, $filter);

$info = ldap_get_entries($ldap, $sr);

for ($i=0; $i < $info[“count”]; $i++) {

echo $info[$i][“name”][0].”<br>”;

}

Script para borrado de archivos

A veces las aplicaciones generan logs, pero no hay en ningún sitio dónde indicar que los borre cuando superen cierta fecha. Esto ocasiona que se llene el disco duro. Para evitarlo, la mejor opción, y siempre que sea posible el borrado “a mano”, es programar una tarea den el administrador de tareas que borre los archivos.

He encontrado en http://urpiano.wordpress.com/2007/02/09/script-para-borrar-ficheros-viejos/ un script para el borrado de archivos en función de fecha. Funciona realmente bien.

El código que pongo abajo, como comprobaréis es un copia pega, añadiendo una simple modificación à En vez de meter como parámetro la fecha de borrado, lo que hago es que borre los archivos con más de 30 días de antigüedad. Por lo demás, el código es totalmente de El Blog de Gualtrysoft.

***********************************************************

‘Este script recibe como parámetros una ruta de carpeta y una fecha en

‘formato DD/MM/YYYY y borra todos aquellos ficheros ubicados en la ruta

‘que indica la carpeta que tengan como fecha de última modificación

‘una igual o anterior a la recibida como parámetro. Si se añade el

‘modificador /R el borrado se hará en todo el árbol cuya raíz es el

‘parámetro de ruta recibido. Ejemplo:

‘cscript borrar-ficheros-hasta-fecha.vbs /R c:Carpeta 23/11/2003

‘© Noviembre de 2006 – Fernando Reyes

‘Febrero de 2007:

‘Se añade el parámetro /R por el cual se realizará un borrado de forma

‘recursiva, esto es, de la carpeta recibida y de todo el subárbol que

‘contiene

Option Explicit

Dim str_Fecha

Dim bol_Recursivo

Dim str_Ruta

Dim dth_Fecha

WScript.Echo “1.- ” & WScript.Arguments(0)

‘WScript.Echo “2.- ” & WScript.Arguments(1)

‘WScript.Quit

‘Comprobamos que hemos recibido el número correcto de parámetros

‘recibidos

If WScript.Arguments.Unnamed.Count <> 1 Then

WScript.Echo “Error 1: Número de parámetros incorrecto. ” & _

“Se deben pasar 2:” & _

vbCrLf & vbCrLf & _

” 1.- Ruta de la carpeta donde borrar los ficheros.” & _

vbCrLf & _

” 2.- Fecha de última modificación a partir de la cual” & _

vbCrLf & _

” se borrarán los ficheros anteriores y de la misma fecha ” & _

“(DD/MM/YYYY).” & vbCrLf & vbCrLf & _

“Se puede agregar el modificador /R para que haga ” & _

“el borrado de forma recursiva” & vbCrLf & _

vbCrLf & _

“Ejemplo:” & vbCrLf & vbCrLf & _

“cscript borrar-ficheros-hasta-fecha.vbs /R ” & _

“c:Carpeta 23/11/2003”

WScript.Quit 1

End If

If WScript.Arguments.Named.Exists(“R”) Then bol_Recursivo = True

str_Ruta = WScript.Arguments.Unnamed(0)

‘dth_Fecha = WScript.Arguments.Unnamed(1)

dth_Fecha=Now()-30

Call s_BorrarFicheros(str_Ruta, dth_Fecha, bol_Recursivo)

Sub s_BorrarFicheros(str_Ruta, dth_Fecha, bol_Recursivo)

Dim obj_FSO

Dim obj_Carpeta

Dim obj_Fichero

‘Creamos el objeto FileSystemObject

Set obj_FSO = CreateObject(“Scripting.FileSystemObject”)

‘Comprobamos que la ruta recibida sea válida

If not obj_FSO.FolderExists(str_Ruta) Then

WScript.Echo “Error 2: La carpeta ” & str_Ruta & _

” recibida como parámetro no existe.”

Set obj_FSO = Nothing

WScript.Quit 2

End If

‘C:\tmp\W3SVC1

‘Comprobamos que la fecha recibida sea válida

If not IsDate(dth_Fecha) Then

WScript.Echo “Error 3: La fecha ” & dth_Fecha & _

” recibida como parámetro no es una fecha válida.”

Set obj_FSO = Nothing

WScript.Quit 3

End If

‘Creamos el objeto carpeta

Set obj_Carpeta = obj_FSO.GetFolder(str_Ruta)

‘Recorremos los ficheros contenidos en la carpeta

For Each obj_Fichero In obj_Carpeta.Files

‘Comprobamos que la fecha de última modificación del fichero

‘sea anterior o igual a la recibida como parámetro

If DateValue(obj_Fichero.DateLastModified) <= _

DateValue(dth_Fecha) Then

‘En caso afirmativo, mostramos el nombre y fecha del fichero

‘y lo borramos

WScript.Echo “Borrando ” & obj_Fichero.Name & _

“: Modificado el ” & _

obj_Fichero.DateLastModified

‘Borramos el fichero incluso en el caso de ser de sistema, si

‘quisiéramos que no se borren los de sistema, tan sólo

‘debemos eliminar el True o sustituirlo por False

obj_Fichero.Delete True

End If

Next

‘Si queremos que se recorra todo el subárbol de carpetas…

If bol_Recursivo Then

‘Definimos un objeto para las subcarpetas

Dim obj_Subcarpeta

‘Recorremos las subcarpetas en este bucle

For Each obj_Subcarpeta In obj_Carpeta.Subfolders

‘Llamada recursiva para borrar los ficheros de la

‘subcarpeta

Call s_BorrarFicheros(obj_Subcarpeta.Path,dth_Fecha, _

bol_Recursivo)

Next

Set obj_Subcarpeta = Nothing

End If

‘Nos limpiamos el culito antes de terminar :-))

Set obj_Fichero = Nothing

Set obj_Carpeta = Nothing

Set obj_FSO = Nothing

End Sub

PHPMailer. Problema al mandar una tabla con muchas filas

Problema à Al mandar un correo HTML utilizando PHPMailer, puede que cada ciertas filas dé error, no cogiendo bien los “tdes – <td>”, poniéndoles espacios en medio. Esto causa que la columna no se visualice bien ya que mezcla el código con el texto a mostrar en la columna.

Para solucionar esto, basta con poner

$mail->Encoding = "base64";

Debajo de $mail = new PHPMailer();

Temporada 2011 / 2012

Estas son las carreras en las que he participado este año. Llevaba ya 10 años sin hacer nada y no sé si por la operación bikini, o por la Behobia San Sebastián, empecé a correr…., y hasta hoy.

Fecha Carrera Distancia (Km) Tiempo
25-09-2011 Lazkao, Memorial Josetxo Imaz 10 00:45:37
09-10-2011 San Sebastián, XXII Cross Amstel 3 Playas 10 00:42:16
16-10-2011 San Sebastián, 15km San Sebastián 15 01:04:25
23-10-2011 San Juan de Luz, Media Marathon de Euskal Herria San Juan de Luz Hondarribia 21,096 01.36:40
13-11-2011 San Sebastián, 47 Behobia – San Sebastián 20 01:31:30
27-11-2011 San Sebastián, Maratón DKV de San Sebastián 42,195 03:20:12
31-12-2011 Beasain, San Silbestre Beasain 10 00:38:06
31-12-2011 San Sebastián, XXVII San Silvestre Donostiarra 10 00:35:23
25-02-2012 Zumaia, Zumaiako XVIII Herri Lasterketa 10 00:41:40
26-02-2012 Ormaiztegi, Sahara-Cross. Memorial Salem Hach Embarek 10 00:42:14
04-03-2012 Santander 21,096 01:30:08
18-03-2012 San Sebastián, Carrera de Primavera Donostiarrak-UPV/EHU 10 00:40:21
31-03-2012 Azkoitia, XIX Medio Maratón Azkoitia-Azpeitia memorial Diego Garcia 21,096 01:31:28
08-04-2012 Dueñas, Medio Maratón Canal de Castilla 21,096 01:44:30
06-05-2012 Maratón de Vitoria, Maratón Martin Fiz 42,195 03:30:13
20-05-2012 San Sebastián, Medio Maratón de San Sebastián 21,096 01:30:35
27-05-2012 Logroño, Medio Maratón de La Rioja 21.096 01:39:04
03-06-2012 Bilbao, XXX Maratón de Bilbao 42.196 03:42:48
03-06-2012 Burgos, XVII Medio Maratón de Burgos 21.096 01:34:29