[Jde-dev] mencoderRecorder

Roberto Calvo rocapal en libresoft.es
Mar Abr 27 20:00:13 CEST 2010


Al final dio tiempo! :-) Te cuento como ha quedado:

 - RecorderConfig ha cambiado. Ahora tiene protocol y device, donde se
le puede pasar tanto un dispositivo v4l como un dispositivo cameraServer
(como cualquier otro protocolo y device que nos inventemos en un
futuro).

 - ffmpegRecorder ha cambiado a deviceRecorder.

 - El componente Recorder, tiene en su fichero de configuración con que
"provider" va a grabar (ffmpeg, mencoder ...). Es lo único que conoce,
todo lo demás le llega a través de RecorderConfig. Quizás tenga sentido
que el provider también le llegue por el RecorderConfig, aunque mejor
vamos poco a poco.

 - Si miras el método startRecording de recorder.cpp, sobre la línea 90,
te he dejado ya el esqueleto para que cargues tu clase que sabe grabar
"RECORDING_PROTOCOL_CAMERASERVER". 

- Echale un ojo al deviceRecorder, para hacer tu cameraServerRecorder
(ponle el nombre que tu quieras) porque tienes que controlar con que
provider se graba (ffmpeg, mencoder). No tienes que implementar todos,
pero si al menos controlar los que no soportes.

Y creo que nada más. Cuando te pongas con ello, dime si ves algo raro o
se te ocurre otra manera para hacerlo.

un saludete!

El mar, 27-04-2010 a las 18:24 +0200, Roberto Calvo escribió:
> Si lees esto a tiempo, no subas aún el código. Si no ha llegado a
> tiempo, tampoco pasa nada :-)
> 
> Al estar cambiando el diseño que hemos comentado, me he dado cosa de una
> cuenta. El recorder en principio no tenía nada de configuración para
> saber donde grabar, el llega todo a través del RecorderConfig, y
> deberíamos seguir haciendolo así. Estoy cambiando el ICE para que no
> tenga v4ldevice y v4lversion, sino protocol y device. De esa forma
> podríamos tener estas configuraciones:
> 
> protocol=v4l - device=/dev/video1
> 
> protocol=cameraServer - device= proxy correspondiente.
> 
> ¿Que te parece?
> 
> El mar, 27-04-2010 a las 18:07 +0200, Sara Marugan escribió:
> > Jeje, la verdad es que sí había pensado lo de uno fuera de tipo "device" 
> > y otro "camera" (o image como dices tú) recorder. Así que si tú también 
> > lo has pensado cambiemoslo.
> > 
> > Vale, pues lo subo al svn ya con el nombre cambiado y sólo quedaría por 
> > retocar lo de los procesos zombies, que no influye en la funcionalidad, 
> > pero está mejor liberar los recursos bien.
> > 
> > 
> > Roberto Calvo wrote:
> > > Genial!
> > >
> > > Los cambios que comentas no les veo problema. De hecho creo que tienes
> > > permisos para subir al subversion no? Por mi no hay problema que lo
> > > subas mientras compruebes que sigue todo funcionando, que la entrega del
> > > TFM se acerca :-)
> > >
> > > Por cierto, echando un ojo al diseño, quizás tengo más sentido que
> > > tengamos recorders dependiendo de como graban, y no dependiendo del
> > > programa que usen. Por ejemplo podemos tener:
> > >
> > >   - DeviceRecorder: Graban directamente del dispositivo físico
> > >   - ImageRecorder: Graban utilizando imágenes 
> > >
> > > ¿Que te parece esta separación? 
> > > La veo mucho más útil y si en el futuro tenemos 4 programas diferentes
> > > para generar ImageRecorder no hace falta tener 4 clases distintas,
> > > simplemente configurar a esta clase de una manera determinada. En el
> > > fichero de config podríamos indicar que programa se quiere utilizar para
> > > grabar.
> > >
> > > De todas formas sube esto que has hecho al subversion para tenerlo. Yo
> > > voy a pasar el ffmpegRecorder a DeviceRecorder para que soporte ffmpeg y
> > > mencoder.
> > >
> > > un saludo!
> > >
> > > El mar, 27-04-2010 a las 13:27 +0200, Sara Marugan escribió:
> > >   
> > >> Hola,
> > >>
> > >> mencoderRecorder graba vídeo desde una cámara de jderobot. Sólo hay que 
> > >> indicarle el proxy de la cámara.
> > >>
> > >> Adjunto el parche que cambia alguna cosilla en recoder y en 
> > >> recorderconfig le he cambiado el tipo a duration porque al ser int daba 
> > >> problemas para llegar bien pasando por la red no sé por qué. Además 
> > >> width y height también son string.
> > >>
> > >> Adjunto también los nuevos ficheros de código.
> > >>
> > >> Un saludo!
> > >> código fuente en C++ adjunto (parche_mencoderRecorder.cpp)
> > >> Index: src/interfaces/slice/jderobot/recorder.ice
> > >> ===================================================================
> > >> --- src/interfaces/slice/jderobot/recorder.ice	(revisión: 463)
> > >> +++ src/interfaces/slice/jderobot/recorder.ice	(copia de trabajo)
> > >> @@ -64,7 +64,7 @@
> > >>  		string frameRate;
> > >>  		
> > >>  		//! Seconds of recording
> > >> -		int duration;
> > >> +		string duration;
> > >>  		
> > >>  		//! Status
> > >>  		// 0: In progress
> > >> Index: src/components/recorder/ffmpegRecorder.h
> > >> ===================================================================
> > >> --- src/components/recorder/ffmpegRecorder.h	(revisión: 463)
> > >> +++ src/components/recorder/ffmpegRecorder.h	(copia de trabajo)
> > >> @@ -31,7 +31,7 @@
> > >>  
> > >>  	public:
> > >>  		/// \brief Recorder
> > >> -		ffmpegRecorder(const jderobotice::Context& context);
> > >> +		ffmpegRecorder(const jderobotice::Context& context,const jderobot::RecorderConfigPtr& recConfig);
> > >>  
> > >>
> > >>  	private:
> > >> Index: src/components/recorder/recorder.cpp
> > >> ===================================================================
> > >> --- src/components/recorder/recorder.cpp	(revisión: 463)
> > >> +++ src/components/recorder/recorder.cpp	(copia de trabajo)
> > >> @@ -26,6 +26,7 @@
> > >>  #include <list>
> > >>  
> > >>  #include "ffmpegRecorder.h"
> > >> +#include "mencoderRecorder.h"
> > >>  
> > >>  namespace RecorderProcess {
> > >>  
> > >> @@ -44,8 +45,13 @@
> > >>  										  const Ice::Current& c)
> > >>  		  {
> > >>  
> > >> -	    	  ffmpegRecorder* myRecorder = new ffmpegRecorder(context);
> > >> -	    	  myRecorder->setConfig(recConfig);
> > >> +		  GenericRecorder *myRecorder;
> > >> +	    	  if(recConfig->cameraProxy.length()==0){
> > >> +			myRecorder =(ffmpegRecorder*) new ffmpegRecorder(context,recConfig);
> > >> +		  }
> > >> +		  else{
> > >> +			myRecorder = (mencoderRecorder*) new mencoderRecorder(context,recConfig);
> > >> +		  }
> > >>  
> > >>  	    	  myRecorder->startRecording();
> > >>  
> > >> Index: src/components/recorder/GenericRecorder.h
> > >> ===================================================================
> > >> --- src/components/recorder/GenericRecorder.h	(revisión: 463)
> > >> +++ src/components/recorder/GenericRecorder.h	(copia de trabajo)
> > >> @@ -37,7 +37,7 @@
> > >>  
> > >>  	public:
> > >>  		/// \brief Constructor
> > >> -		GenericRecorder(const jderobotice::Context& context) : mContext(context),mRecConfig(NULL), mId(), mStatus() {};
> > >> +		GenericRecorder(const jderobotice::Context& context,const jderobot::RecorderConfigPtr& recConfig) : mContext(context),mRecConfig(recConfig), mId(), mStatus() {};
> > >>  
> > >>
> > >>  		void setId (int id) {mId = id;};
> > >> Index: src/components/recorder/Makefile.am
> > >> ===================================================================
> > >> --- src/components/recorder/Makefile.am	(revisión: 463)
> > >> +++ src/components/recorder/Makefile.am	(copia de trabajo)
> > >> @@ -2,19 +2,20 @@
> > >>  bin_PROGRAMS = recorder recorder_client
> > >>  endif
> > >>  
> > >> -recorder_SOURCES = recorder.cpp ffmpegRecorder.cpp  ffmpegRecorder.h  GenericRecorder.h GenericRecorder.cpp 
> > >> +recorder_SOURCES = recorder.cpp ffmpegRecorder.cpp  ffmpegRecorder.h  mencoderRecorder.cpp mencoderRecorder.h GenericRecorder.h GenericRecorder.cpp 
> > >>  
> > >> -recorder_CXXFLAGS = -I$(top_srcdir)/src/interfaces/cpp $(LIBJDEROBOTICE_CPPFLAGS) 
> > >> +recorder_CPPFLAGS = -I$(top_srcdir)/src/interfaces/cpp $(LIBJDEROBOTICE_CPPFLAGS) $(LIBCOLORSPACESMM_LDFLAGS)
> > >>  
> > >> -recorder_LDFLAGS =  $(LIBICE) $(LIBICEUTIL) $(RECORDER_LIBS)
> > >> +recorder_LDFLAGS =  $(LIBICE) $(LIBICEUTIL) $(RECORDER_LIBS) $(LIBICEBOX) $(LIBICESTORM) $(LIBICESTORMSERVICE) $(LIBCOLORSPACESMM_LDFLAGS)
> > >>  
> > >>  recorder_LDADD = $(top_srcdir)/src/interfaces/cpp/jderobot/libJderobotInterfaces.la \
> > >> -		 		 $(top_srcdir)/src/libs/jderobotice/libJderobotIce.la 
> > >> +		 		 $(top_srcdir)/src/libs/jderobotice/libJderobotIce.la \
> > >> +				 $(top_srcdir)/src/libs/colorspaces/libcolorspacesmm.la
> > >>  
> > >>
> > >>  recorder_client_SOURCES = recorder_client.cpp
> > >>  
> > >> -recorder_client_CXXFLAGS = -I$(top_srcdir)/src/interfaces/cpp $(LIBJDEROBOTICE_CPPFLAGS)
> > >> +recorder_client_CPPFLAGS = -I$(top_srcdir)/src/interfaces/cpp $(LIBJDEROBOTICE_CPPFLAGS)
> > >>  
> > >>  recorder_client_LDFLAGS =  $(LIBICE) $(LIBICEUTIL) $(RECORDER_LIBS) -pthread
> > >>  
> > >> Index: src/components/recorder/ffmpegRecorder.cpp
> > >> ===================================================================
> > >> --- src/components/recorder/ffmpegRecorder.cpp	(revisión: 463)
> > >> +++ src/components/recorder/ffmpegRecorder.cpp	(copia de trabajo)
> > >> @@ -27,7 +27,7 @@
> > >>  
> > >>  void *record_function( void *ptr );
> > >>  
> > >> -ffmpegRecorder::ffmpegRecorder(const jderobotice::Context& context) : GenericRecorder(context)
> > >> +ffmpegRecorder::ffmpegRecorder(const jderobotice::Context& context,const jderobot::RecorderConfigPtr& recConfig) : GenericRecorder(context,recConfig)
> > >>  {
> > >>  
> > >>  }
> > >> Index: src/components/surveillance/surveillance.cpp
> > >> ===================================================================
> > >> --- src/components/surveillance/surveillance.cpp	(revisión: 463)
> > >> +++ src/components/surveillance/surveillance.cpp	(copia de trabajo)
> > >> @@ -89,7 +89,7 @@
> > >>  
> > >>  		std::cout << " [*] New Recording launched, with ID = " << recId << " - " + timeRecording << " min." << std::endl;
> > >>  
> > >> -		sleep( recConfig->duration );
> > >> +		sleep( atoi(recConfig->duration.c_str()) );
> > >>  
> > >>  		recManagerPrx->stopRecording(recId);
> > >>      }
> > >> cabecera de código fuente en C adjunto (mencoderRecorder.h)
> > >> /*
> > >>  *
> > >>  *  Copyright (C) 1997-2010 JDE Developers Team
> > >>  *
> > >>  *  This program is free software: you can redistribute it and/or modify
> > >>  *  it under the terms of the GNU General Public License as published by
> > >>  *  the Free Software Foundation, either version 3 of the License, or
> > >>  *  (at your option) any later version.
> > >>  *
> > >>  *  This program is distributed in the hope that it will be useful,
> > >>  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> > >>  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > >>  *  GNU General Public License for more details.
> > >>  *
> > >>  *  You should have received a copy of the GNU General Public License
> > >>  *  along with this program.  If not, see http://www.gnu.org/licenses/.
> > >>  *
> > >>  *  Author : Sara Marugán Alonso <smarugan en gsyc.es>
> > >>  *
> > >>  */
> > >>
> > >> #ifndef MECODER_RECORDER_H
> > >> #define MECODER_RECORDER_H
> > >>
> > >> #include "GenericRecorder.h"
> > >> #include <jderobotice/component.h>
> > >> #include <jderobotice/application.h>
> > >> #include <jderobot/camera.h>
> > >>
> > >> class mencoderRecorder : public GenericRecorder
> > >> {
> > >>
> > >> 	public:
> > >> 		/// \brief Recorder
> > >> 		mencoderRecorder(const jderobotice::Context& context,const jderobot::RecorderConfigPtr& recConfig);
> > >>
> > >> 	private:
> > >>
> > >> 		int doRecording();
> > >> };
> > >>
> > >> #endif MECODER_RECORDER_H
> > >> código fuente en C++ adjunto (mencoderRecorder.cpp)
> > >> /*
> > >>  *
> > >>  *  Copyright (C) 1997-2010 JDE Developers Team
> > >>  *
> > >>  *  This program is free software: you can redistribute it and/or modify
> > >>  *  it under the terms of the GNU General Public License as published by
> > >>  *  the Free Software Foundation, either version 3 of the License, or
> > >>  *  (at your option) any later version.
> > >>  *
> > >>  *  This program is distributed in the hope that it will be useful,
> > >>  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> > >>  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> > >>  *  GNU General Public License for more details.
> > >>  *
> > >>  *  You should have received a copy of the GNU General Public License
> > >>  *  along with this program.  If not, see http://www.gnu.org/licenses/.
> > >>  *
> > >>  *  Author : Sara Marugán Alonso <smarugan en gsyc.es>
> > >>  *
> > >>  */
> > >>
> > >> #include "mencoderRecorder.h"
> > >> #include <unistd.h>
> > >> #include <signal.h>
> > >> #include <sys/wait.h>
> > >> #include <sys/types.h>
> > >> #include <string.h>
> > >> #include <strings.h>
> > >> #include <jderobot/image.h>
> > >> #include <stdio.h>
> > >> #include <stdlib.h>
> > >> #include <fcntl.h>
> > >> #include <Ice/Ice.h>
> > >> #include <IceUtil/Thread.h>
> > >> #include <IceUtil/Time.h>
> > >> #include <IceUtil/IceUtil.h>
> > >> #include <IceUtil/Handle.h>
> > >> #include <IceStorm/IceStorm.h>
> > >> #include <iostream>
> > >> #include <jderobot/camera.h>
> > >> #include <colorspaces/colorspacesmm.h>
> > >> #include <ctime>
> > >>
> > >>
> > >> //////////////////////////////////////////////////////// IMAGE CONSUMER INTERFACE IMPLEMENTATION
> > >> class ImageConsumerI: virtual public jderobot::ImageConsumer {
> > >> 	private:
> > >>             jderobot::Time timeStampOld;
> > >>             jderobot::Time timeStampNew;
> > >> 	    int size;
> > >>   	    int fifo_fd;
> > >>     	    char *imageData;
> > >> 	public:
> > >> 	    ImageConsumerI(int width,int height){
> > >> 		size=width*height*3;
> > >> 	        imageData = (char*) malloc(size);
> > >> 		timeStampOld.seconds=timeStampNew.seconds=0;
> > >> 		timeStampOld.useconds=timeStampNew.useconds=0;
> > >> 		
> > >> 		// open fifo
> > >> 		if ((fifo_fd=open("fifovid", O_WRONLY))<0){
> > >> 			fprintf (stderr, "mencoderRecorder error: could not open fifo\n");
> > >> 		}
> > >> 	    }
> > >>
> > >> 	    ~ImageConsumerI(){
> > >> 		// close fifo
> > >> 		close (fifo_fd);
> > >> 		unlink("fifovid");
> > >>
> > >> 		free(imageData); 
> > >> 	    }
> > >>
> > >>
> > >> 	    virtual void report(const ::jderobot::ImageDataPtr& data,
> > >> 		                const Ice::Current&) {
> > >>
> > >> 		colorspaces::Image::FormatPtr fmt = colorspaces::Image::Format::searchFormat(data->description->format);
> > >> 		if (!fmt)
> > >> 		  throw "Format not supported";
> > >>
> > >> 		colorspaces::Image img(data->description->width,
> > >> 				       data->description->height,
> > >> 				       fmt,
> > >> 				       &(data->pixelData[0]));
> > >>
> > >> 		timeStampOld=timeStampNew;
> > >> 		timeStampNew=data->timeStamp;
> > >>
> > >> 		if(timeStampOld!=timeStampNew){
> > >> 			int s=size/3;
> > >> 			for (int j=0; j<s; j++) {
> > >> 				imageData[j*3] = img.data[(s-1-j)*3];
> > >> 				imageData[j*3+1] = img.data[(s-1-j)*3+1];
> > >> 				imageData[j*3+2] = img.data[(s-1-j)*3+2];
> > >> 			}	
> > >>
> > >> 			if (write (fifo_fd, imageData, size)>size){
> > >> 				fprintf (stderr, "mencoderRecorder error: could not write on fifo\n");
> > >> 			}
> > >> 		}
> > >> 	    }
> > >> };
> > >>
> > >>
> > >> //////////////////////////////////////////////////////////// THREAD
> > >>
> > >>   void* callback(void* obj);
> > >>
> > >>   class Thread { 
> > >>   private:
> > >>     Ice::CommunicatorPtr communicator;
> > >>     jderobot::RecorderConfigPtr configuration;
> > >>
> > >>   public:
> > >>     int main()
> > >>     {
> > >> 	int imgwidth= atoi((char*)configuration->width.c_str());
> > >> 	int imgheight= atoi((char*)configuration->height.c_str());
> > >> 	int duration= atoi((char*)configuration->duration.c_str());
> > >> 	IceStorm::TopicPrx topic;
> > >>
> > >>         //IMAGE CONSUMERS INIT
> > >>
> > >> 	// generate camera adapter endpoint randomly
> > >>     	srand((unsigned)time(0));
> > >>     	char adapter_endpoint [256];
> > >>
> > >>     	int adapter_port = 10010 + (rand()%500)+1;
> > >>     	sprintf(adapter_endpoint,"default -t 5000 -p %d",adapter_port); 
> > >>
> > >> 	Ice::ObjectAdapterPtr adapter= communicator->createObjectAdapterWithEndpoints(adapter_endpoint,adapter_endpoint);
> > >>
> > >> 	if (adapter==0){
> > >> 		fprintf(stderr,"mencoderRecorder error: could not create adapter for camera");
> > >> 		return -1;
> > >> 	}
> > >>
> > >>         Ice::ObjectPrx obj = communicator->stringToProxy(configuration->cameraProxy);
> > >>
> > >>         if (obj==0){
> > >> 		fprintf(stderr,"mencoderRecorder error: could not create proxy\n");
> > >> 		return(-1);
> > >>         }
> > >>
> > >> 	std::string topicName = configuration->name;
> > >>
> > >> 	IceStorm::TopicManagerPrx topicManager=IceStorm::TopicManagerPrx::checkedCast(obj);
> > >>
> > >> 	ImageConsumerI *imageConsumer = new ImageConsumerI(imgwidth,imgheight);
> > >> 	Ice::ObjectPrx proxy = adapter->addWithUUID(imageConsumer)->ice_oneway();
> > >>
> > >> 	try {
> > >> 		topic = topicManager->retrieve(topicName);
> > >> 		IceStorm::QoS qos;
> > >> 		topic->subscribeAndGetPublisher(qos, proxy);
> > >> 	}
> > >> 	catch (const IceStorm::NoSuchTopic& ex) {
> > >> 		std::cerr << ex << std::endl;
> > >> 		return -1;
> > >> 	}
> > >>
> > >> 	adapter->activate();
> > >>
> > >>         //communicator->waitForShutdown();
> > >> 	sleep(duration);
> > >>
> > >>         topic->unsubscribe(proxy);
> > >>
> > >> 	adapter->deactivate();
> > >>
> > >> 	delete imageConsumer;
> > >> 	adapter=NULL;
> > >>
> > >> 	pthread_exit(0);
> > >>     }
> > >> 	  
> > >>     void run(Ice::CommunicatorPtr comm,jderobot::RecorderConfigPtr config)
> > >>     {
> > >>       communicator=comm;
> > >>       configuration=config;
> > >>       pthread_create(&thread, 0, &callback, this);
> > >>       sleep(1);
> > >>     }
> > >>
> > >>     void stop(){
> > >>     }
> > >>
> > >>     int join()
> > >>     {
> > >>       return pthread_join(thread, ret);
> > >>     }
> > >>     
> > >>     pthread_t thread;
> > >>     void** ret;
> > >>   }; // class Thread
> > >>
> > >>
> > >>   void* callback(void* obj)
> > >>   {
> > >>     static_cast<Thread*>(obj)->main();
> > >>     return(0);
> > >>   } // callback
> > >>
> > >>
> > >> ///////////////////////////////////////// MENCODER_RECORDER FUCNTIONS
> > >>
> > >> mencoderRecorder::mencoderRecorder(const jderobotice::Context& context,
> > >> 		const jderobot::RecorderConfigPtr& recConfig) : GenericRecorder(context,recConfig)
> > >> {
> > >> 	// create fifo
> > >> 	unlink ("fifovid");
> > >> 	if ( (mkfifo ("fifovid", 0600) != 0) ){
> > >> 		 fprintf (stderr, "mencoderRecorder error: could not create fifo\n");
> > >> 	}
> > >>
> > >> 	// create thread for getting images
> > >> 	Thread thread;
> > >> 	thread.run(getContext().communicator(),recConfig);
> > >> }
> > >>
> > >> int mencoderRecorder::doRecording()
> > >> {
> > >>
> > >> 	int imgwidth= atoi((char*)getConfig()->width.c_str());
> > >> 	int imgheight= atoi((char*)getConfig()->height.c_str());
> > >>
> > >>
> > >> 	getContext().tracer().info ( "starting recording: Path = " +
> > >> 									 getConfig()->path + " - FrameRate = " +
> > >> 									 getConfig()->frameRate + " fps - ");
> > >>
> > >> 	char str[50];
> > >> 	int file;
> > >> 	file = open("/dev/null",O_RDWR);
> > >> 	close(0); dup(file);
> > >> 	close(1); dup(file);
> > >> 	close(2); dup(file);
> > >>
> > >> 	// execute mencoder
> > >> 	sprintf(str,"fps=%.1f:w=%d:h=%d:format=%s",atof((char*)getConfig()->frameRate.c_str()),imgwidth,imgheight, "rgb24");
> > >> 	execlp("mencoder","mencoder","fifovid","-demuxer","rawvideo", "-rawvideo",
> > >> 		str, "-o", (char*) (getConfig()->path).c_str(), "-ovc", "lavc" ,NULL);
> > >>
> > >> 	printf("mencoderRecorder error: cannot execute mencoder\n");
> > >> 	return -1;
> > >> }
> > >>
> > >>
> > >>
> > >> _______________________________________________
> > >> Jde-developers mailing list
> > >> Jde-developers en gsyc.es
> > >> http://gsyc.escet.urjc.es/cgi-bin/mailman/listinfo/jde-developers
> > >>     
> > >
> > >   
> > 
> > _______________________________________________
> > Jde-developers mailing list
> > Jde-developers en gsyc.es
> > http://gsyc.escet.urjc.es/cgi-bin/mailman/listinfo/jde-developers
> 
> _______________________________________________
> Jde-developers mailing list
> Jde-developers en gsyc.es
> http://gsyc.escet.urjc.es/cgi-bin/mailman/listinfo/jde-developers

-- 
Roberto Calvo Palomino          | Libre Software Engineering Lab (GSyC)
Tel: (+34) 91 488 85 23         | Universidad Rey Juan Carlos
rocapal en libresoft.es            | Edif. Departamental II - Despacho 116
http://libresoft.es/            | c/Tulipán s/n 28933 Móstoles (Madrid)

GPG-KEY: http://gsyc.es/~rocapal/rocapal.gpg
------------ próxima parte ------------
Se ha borrado un mensaje que no está en formato texto plano...
Nombre     : no disponible
Tipo       : application/pgp-signature
Tamaño     : 198 bytes
Descripción: Esta parte del mensaje =?ISO-8859-1?Q?est=E1?= firmada
 digitalmente
Url        : http://gsyc.escet.urjc.es/pipermail/jde-developers/attachments/20100427/77d55964/attachment.pgp 


More information about the Jde-developers mailing list