« Febrero 2004 | Inicio | Abril 2004 »

Marzo 30, 2004

OT: Cambiar de Thunderbird a Outlook

Me encanta Thunderbird, me parece el mejor cliente de correo y noticias de todos los que he usado. Pero el caso es que me he visto obligado a volver a Outlook, y aquÌ es cuando han empezado los problemas, de los cuales, por primera vez, no voy a culpar sÛlo a Microsoft.

Importar tus carpetas de correo, libretas de direcciones, incluso las reglas de filtrado de los mensajes desde Thunderbird es muy f·cil. Dos clicks de ratÛn, y ya est·. øEntonces, cÛmo es posible que el proceso inverso haya sido tan dificil?.

Oficialmente, seg˙n las faqs de Mozilla, el formato de las carpetas de correo es "Mbox" ( el est·ndar UNIX ),por lo que importarlas desde Outlook deberÌa ser cuestiÛn de dos clicks ( import·ndolas como correo de Eudora ).

Imposible. A cada intento de acceder a las carpetas de correo, recibÌa un error de Outlook diciendo que la carpeta estaba en uso. Huelga decir que la carpeta no estaba en uso y que el usuario tenÌa permisos de administrador.

Tras la pertinente investigaciÛn ( menos mal que existe Google ), encontrÈ una utilidad escrita en Java para convertir los MxBox a eml ( el formato utilizado por Outlook Express ). Dicha utilidad se llama Mbox2eml. El caso es que funciona perfectamente, excepto para carpetas con muchos elementos. Total, que estuve pr·cticamente dos horas convirtiendo elementos, de 100 en 100, a formato eml.

Una vez hecha la conversiÛn, exportÈ desde Outlook Express a Outlook. Y °por fin!. Todos mis emails en Outlook ( aunque todavÌa tengo que asegurarme de que no se hayan perdido los attachments ).

DuraciÛn de todo el proceso: unas tres horas. Tres horas para realizar un proceso que tan sÛlo deberÌa haber costado dos o tres clicks de ratÛn a lo sumo.

øEs tan dificil implementar una soluciÛn para exportar correo desde Thunderbird? øO que Outlook importe directamente los mensajes de Thunderbird?. øCu·ndo va a dejar de ser necesario tener conocimientos m·s que b·sicos de inform·tica para poder utilizar los programas que a uno le vengan en gana?.

Normalmente no soy muy amigo de Microsoft, pero en este caso no sÈ con cual de los dos estoy m·s cabreado.......

Marzo 26, 2004

øAlguien utiliza el panel de mysql?

Hace ya un tiempo publicamos una extensiÛn para el IDE que consistÌa en un panel para poder ver la estructura de una base de datos mySQL que se estuviera ejecutando en la misma m·quina que el IDE de flash, acompaÒada de una clase php. ( Lo puedes encontrar aquÌ )

Ya hemos superado las 1000 descargas de ese panel ( entre la versiÛn inglesa y la espaÒola ), y el caso es que nadie, absolutamente nadie, nos ha comunicado ning˙n error, fallo, problema en la instalaciÛn, etc.

Esto sÛlo me lleva a una conclusiÛn: nadie lo est· utilizando realmente. O tal vez me equivoque,simplemente funciona bien... De todas formas, si lo has utilizado, me gustarÌa saber tu opiniÛn.

Marzo 25, 2004

Un post que no sirve para mucho

Tras un dÌa entero serializando y deseralizando clases, necesitaba hacer algo lo m·s "flashero" posible. Pues aquÌ est·: una clase que puede utilizarse como temporizador.

Permite ejecutar algo determinado ( que se le pasa como par·metro ) cuando ha pasado el tiempo que se le pasa como par·metro tambiÈn, y permite resetear ese temporizador de manera que act˙e como timeout, permite pararlo, eliminarlo, ...

En primer lugar, y aunque ya sÈ que la arquitectura actual de flash est· basada en eventos m·s que en callbacks, se va a definir una clase que recibe como par·metros una instancia de una clase, y un mÈtodo a ejecutar. De esta forma, se podr·n ejecutar callbaks a medida.

class net.designnation.blog.Callback { private var callbackObjVal: Object; private var callbackMethodVal: String; public function Callback( objParam: Object, methodParam: String ) { this.callbackObj = objParam; this.callbackMethod = methodParam; } public function set callbackObj( objParam: Object ) { this.callbackObjVal= objParam; } public function get callbackObj( ): Object { return this.callbackObjVal; } public function set callbackMethod( methodParam: String ) { this.callbackMethodVal= methodParam; } public function get callbackMethod( ): String { return this.callbackMethodVal; } public function fire( parameter: Object ): Object { return this.callbackObjVal[ this.callbackMethodVal ]( parameter ); } }

La clase Timer es:

import net.designnation.blog.* class net.designnation.blog.Timer { private static var FRAMERATE: Number = 12; private var timelineVal : MovieClip; private var clip : MovieClip; private var timeoutVal : Number; private var callBackVal : Callback; private var startedFlag : Boolean; private var actualCount : Number; function Timer( timelineParam: MovieClip, timeoutParam: Number, callBack: Callback ) { this.timeline = timelineParam; this.timeout = timeoutParam; this.callback = callBack; } public function set timeline( value: MovieClip ) { this.timelineVal = value; } public function set timeout( value: Number ) { this.timeoutVal = value* FRAMERATE/ 1000; } public function set callback( value: Callback ) { this.callBackVal = value; } public function init( ) { this.actualCount = 0; this.clip = this.timelineVal.createEmptyMovieClip( "clip", this.timelineVal.getNextHighestDepth( ) ); this.clip[ "owner" ] = this; this.clip.onEnterFrame = function( ) { if ( this[ "owner" ].startedFlag ) { if ( this[ "owner" ].actualCount< this[ "owner" ].timeoutVal ) { this[ "owner" ].actualCount++; } else { this[ "owner" ].onFinish( ); } } }; } public function start( ) { this.startedFlag = true; } public function stop( ) { this.startedFlag = false; } public function reset( ) { this.actualCount = 0; this.startedFlag = true; } public function resetTo( newTimeOut: Number ) { this.actualCount = 0; this.timeout = newTimeOut; this.startedFlag = true; } public function remove( ) { this.clip.removeMovieClip( ); delete this.clip; } private function onFinish( ) { this.startedFlag = false; this.actualCount = 0; this.callBackVal.fire( { reqTime: this.timeoutVal } ); } }

Y finalmente, una clase para realizar el test:

import net.designnation.blog.* class net.designnation.blog.TimerTest { private var timeline: MovieClip; private var time : Number; private var theTimer: Timer; function TimerTest( timelineParam: MovieClip, timeoutParam: Number ) { this.timeline = timelineParam; this.time = timeoutParam; this.init( ); } public function init( ) { this.theTimer = new Timer( this.timeline, this.time, new Callback( this, "timeOutCallback" ) ); this.theTimer.init( ); this.theTimer.start( ); } public function timeOutCallback( ) { trace( "Time goes by..." ); /// Y por ejemplo: this.theTimer.resetTo( this.time ); } }

Y finalmente, en el frame:

import net.designnation.blog.* var theTest: TimerTest = new TimerTest( this, 1000 );

Feliz viernes....

Marzo 23, 2004

Nueva CSS

Esto ha sido como un parto. Por fin hemos encontrado el tiempo y el coraje para ponernos a generar una css para este blog.

Lo que veis es el resultado. Est· probado en todos los distintos sabores de navegadores en windows, pero no en Mac, asÌ que si veis algo raro, por favor decÌdnoslo.

Y si os parece que hay algo que no se ve bien ( ya sÈ, el cÛdigo, por ejemplo ), pues decidlo tambiÈn.

Las fotografÌas son nuestras, son parte de lo que vemos a diario.

Gracias de antemano. Y a los que hayais sufrido las pruebas, pues gracias doblemente! ;)

Marzo 20, 2004

Mi experiencia con el desarrollo de un framework en AS2

Durante los dos ˙ltimos meses, he estado trabajando en el desarrollo de un framework escrito en AS2, como parte de un proyecto de dos aÒos, que incluye el desarrollo de unos 200 juegos y de una plataforma de e-learning.

Este framework ser· la base del desarrollo de esos 200 juegos, de heco, ya hemos realizado algunos juegos con fÌsica sencilla ( tiros parabÛlicos, rebotes,.. ) en unas cuatro o cinco horas.

El desarrollo est· basado en la aplicaciÛn de patrons de diseÒo, sobre todo de m·quinas de estados, aunque tambiÈn estamos implmentando otros patrones, como el Modelo-vista-controlador, Fachada, Singleton, Decorator, etc.

Teniendo en cuenta que yo provengo del mundo del script puro y duro no me ha resultado muy facil adaptarme ( y no creo que realmente lo consiga del todo nunca ), aunque debo reconocer que tanta abstracciÛn en el cÛdigo nos va a permitir, no sÛlo sacar adelante el proyecto, sino mantener el cÛdigo con mucha mayor facilidad.

Merece la pena intentar zambullirse a fondo el POO. Pero sobre todo merece la pena hacerlo en flash, porque, antes o despuÈs, va a llegar el momento en el que va a hacer falta recurrir a lo mejor que tiene este lenguaje: su flexibilidad, las animaciones procedurales, ...

Marzo 13, 2004

Lo que debemos tener claro

Ahora que parece que se va aclarando la verdadera autorÌa del atentado de Madrid, todos debemos tener muy claro varias cosas:

Los extranjeros no son culpables por el hecho de ser extranjeros, y sobre todo, los marroquÌes, a los que tanto nos gusta odiar. Por favor, no convirtamos nuestro dolor en odio contra gente inocente que no tiene culpa de nada.

No convirtamos nuestras vidas diarias en un delirio paranoico, como ha sucedido en otros paÌses. No estamos en guerra, no debemos convertirnos en un estado policial, no debemos acabar con los derechos y libertades que tanto nos ha costado conseguir, sobre todo a las generaciones anteriores.

Y en cuanto a la actuaciÛn de nuestro gobierno, pues que cada uno saque sus propias conclusiones.

Marzo 11, 2004

El estilo de mi cÛdigo

Ultimamente, he leido varios posts sobre estilo de cÛdigo, o coding standards( como Èste de Dominick ). Bueno, pues Èste es mi estilo:

En primer lugar, el cÛdigo debe explicarse por sÌ mismo. Por eso, en mi trabajo no escribimos demasiados comentarios, aunque sÌ escribimos diagramas UML.

Pero lo podreis ver todo mucho m·s claro con una clase de ejemplo:

/* El nombre de la clase est· precedido de las iniciales del proyecto. En este caso, esta clase extiende a otra */ class net.designnation.pnTestClass extends pnSuperClass { /* Primero, definimos las variables privadas. Como las vamos a manipular a travÈs de getter/setters, todas terminan con el sufijo "Val" */ private var strVal : String; private var boolVal : String; private var mcVal : MovieClip private var arg : Number; /* Ahora va el constructor */ function pnTestClass( argParam: Number ) { this.arg = argParam } /* Y los getter/setters. SÛlo definiremos los que hagan falta, es decir, si no necesitamos un getter, no lo definiremos. */ function set str( value: String ) { this.strVal = value; } function get str( ): String { return this.strVal; } /* AquÌ sÛlo definimos el setter */ function set bool( value: Param ) { this.boolVal = value; } function set mc( value: MovieClip ) { this.mcVal = value; } //Los mÈtodos privados private function privateMethod( Void ): Void { } // El resto de mÈtodos p˙blicos e // implementaciÛn de interfaces public function publicMethod( Void ): Boolean { //Accedemos a una propiedad privada desde //la clase, por lo que no necesitamos un getter var returnVal: Boolean = false; if ( this.boolVal ) { returnVal = true; } return returnVal; } /* Y finalmente, callbacks y listeners */ public function onKeyUp( ) { } }

Un par de detalles importantes. Siempre utilizamos el "this", para que asÌ sea m·s facil ver cu·ndo estamos utilizando un mÈtodo o propiedad que pertenece a la clase. Si no utilizamos el this, se sobreentiende que el mÈtodo o propiedad es de la superclase

El espaciado muy importante. HAce que el cÛdigo sea m·s facil de leer, y de comprender. No nos importa que la calse tenga muchas lÌneas en blanco, si eso ayuda a ver "bloques" de cÛdigo

Las llaves van siempre pareadas. Y siempre hay un espacio en blanco entre operadores

Los mÈtodos que devuelvan un valor, deber·n tener un ˙nico punto de salida ( "return" )

Espero que os resulte util. Para nosotros, la verdad, lo es.

Atentado en Madrid

Estoy muy nervioso. Parece que hana habido al menos tres explosiones en distintas estaciones de cercanÌas de Madrid.

Yo he oÌdo dos de ellas desde mi casa ( vivo en Vallecas ). Me voy ahora mismo a ver si puedo ayudar en algo.

Esto no es justo. No nos lo merecemos

Marzo 09, 2004

MXNA

Acabamos de recibir el e-mail en el que nos comunican que la versiÛn inglesa ( bueno, en eso que parece inglÈs ) de este blog va a ser agregado por el MXNA desde hoy.

Sobra decir que lo consideramos, a la vez, un honor, y desde luego una gran responsabilidad.

MXNA ( Macromedia XML News Aggregator ) es, como su nombre indica, un agregador de blogs, que aunque sÛlo agrega webs en inglÈs, es uno de los recursos m·s importantes para que cualquier usuario ( sea diseÒador, programador, o cualquier perfil entre medias) pueda encontrar informaciÛn actualizada sobre cualquiera de las herramientas de Macromedia ( Flash, Director, Dreamweaver, Flex, ... ).

En fin, algo, que al menos para nosotros, siempre ha sido una de las visitas diarias obligatorias. Esperamos que, aunque ahora estemos tambiÈn nosotros, lo sigais visitando ;P

Marzo 01, 2004

Patrones de diseÒo: Modelo-vista-controlador ( de verdad )

Darron Schall comentÛ ayer en la versiÛn inglesa de este blog que la implementaciÛn presentada de este patrÛn no se ajustaba a los c·nones establecidos.

Efectivamente, en mi implementaciÛn, era el controlador el que se encargaba de realizar la comunicaciÛn entre el modelo y la vista, de manera que esas dos capas no tuvieran conocimiento la una de la otra. Hace ya tiempo que lo hago asÌ, y habÌa olvidado que lo que dicen los libros es que es la vista la que debe escuchar los eventos emitidos por el modelo.

Bueno, pues rectificar es de sabios (dicen). Lo cierto es que el cÛdigo del post de ayer en realidad no era un MVC, y por eso, he refactorizado el cÛdigo para cumplir estrictamente con el patrÛn.

Ahora el controlador agrega una instancia de la vista y otra del modelo. La vista escucha los eventos del modelo, y se comunica con el modelo utilizando el controlador.

Probablemente lo veais m·s claro viendo el cÛdigo fuente

Patrones de diseÒo: MVC (Modelo.vista-controlador)

Vamos a hacer un contador de tiempo inverso. Al hacer un click en el fondo se inicializa el contador, que se puede poner en pausa haciendo otro click en el fondo. Haciendo otro click m·s se vuelve a arrancar

Podeis encontrar una explicaciÛn muy completa de en quÈ consiste el patrÛn MVC aquÌ

B·sicamente, se trata de dividir la aplicaciÛn en tres capas. El modelo, son los datos o la lÛgica de la aplicaciÛn, la vista el interfaz, y el controlador el encargado de unir uno y otro, es decir, de actualizar los datos cuando se manipula el interfaz, y de actualizar el interfaz cuando cambian los datos.

En nuestro caso, el modelo es una clase AS2 que es la encargada de llevar la cuenta del tiempo. A cada segundo, emite un evento, que recibe el controlador, que a su vez, se encargar· de actualizar la vista, que es un campo de texto donde se presenta el tiempo restante. Cuando se hace un click en el fondo, la vista comunica el click al controlador, que a su vez, comunica al modelo que debe cambiar su estado (para si estaba arrancado, o arrancar si estaba parado).

Aprovechamos que el orden de carga ( configuraciÛn de publicaciÛn ) del swf es de abajo a arriba, para instanciar el controlador en la primera capa del primer frame , y la vista en la segunda capa del primer frame.

Para instanciar el controlador:

import net.designnation.patterns.* var myController: controller = new controller( this ); myController.init( 60 );

El controlador tiene agregado una instancia del modelo, de manera que en el modelo se instancia en el mÈtodo init( ) del controlador :

public function init( time: Number ) { this.myClock = new clock( this.timeline, time ); this.myClock.addEventListener( "endOfTime", this ); this.myClock.addEventListener( "updateTime", this ); this.myClock.init( ); }

De este modo, se instancia la clase clock, pas·ndola como par·metros una referencia al _root, y el tiempo total. Esa referencia al _root se utiliza para crear un clip vacÌo, en cuyo onEnterFrame se decrementa el tiempo total.

public function init( ) { this.clockClip = timeline.createEmptyMovieClip( "empty", this.timeline.getNextHighestDepth( ) ); this.clockClip[ "owner" ] = this; this.clockClip.onEnterFrame = function ( ) { if ( this[ "owner" ].workingFlag ) { if ( this[ "owner" ].actualTime>= 1 ) { this[ "owner" ].actualTime--; if ( this[ "owner" ].actualTime % FRAMERATE == 0 ) { this[ "owner" ].dispatchTime( this[ "owner"].actualTime ); } } else { this[ "owner" ].dispatchTime( ); delete this.onEnterFrame; } } } }

Observemos la sintaxis de la lÌnea

this.clockClip[ "owner" ] = this;

Es lo mismo que escribir

this.clockClip.owner = this;

El hecho de meter "owner" entre corchetes es tan sÛlo para identificar esa propiedad con un vistazo como una propiedad que he creado din·micamente. Por tanto, es una de las convenciones que yo utilizo, no tiene mayor significado.

Como puede verse, cuando hace falta actualizar el campo de texto con el tiempo restante, la instancia de clock dispara un evento

private function dispatchTime( actualTime: Number ) { if ( actualTime == null ) { var event = "endOfTime"; } else { var event = "updateTime"; } this.dispatchEvent( {type: event, target: this, time: ( actualTime/ FRAMERATE ) } ); }

Como el controlador est· registrado como listener de clock, se ejecuta el mÈtodo correspondiente:

public function updateTime( arg: Object ) { this.timeline.clock.text = arg.time; }

que es el que se encarga de actualizar la vista.

En sentido contrario, la lÛgica es parecida, salvo que se ejecutan directamente los mÈtodos p˙blicos correspondientes ( que, en realidad deberÌan formar parte de un interfaz de comunicaciÛn, pero eso ya es complicarnos demasiado por hoy ).

Cuando se hace click en el fondo,

this.onMouseUp = function( ) { myController.changeClockState( "clock" ); }

Y en el controlador:

public function changeClockState( ) { this.myClock.changeClockState( ); }

Y finalmente, en la clase clock:

public function changeClockState( ) { this.workingFlag = !this.workingFlag; }

Resumiendo, todas las comunicaciones en uno u otro sentido se har·n a travÈs del controlador. De ese modo, aseguramos la independencia entre la parte gr·fica de la aplicaciÛn y los datos de la misma, y por tanto nuestra aplicaciÛn ser· m·s modular, m·s f·cil de mantener, de modificar, nuestro cÛdigo estar· m·s estructurado, ....

Por otra parte, podeis ver cÛmo la vista no est· estructurada como clase AS2, ya que no parece necesario hacerlo. Es una de las cosas que me encantan de flash. Podemos mezclar cÛdigo en uno u otro estandar, dependiendo de lo que nos interese en cada momento....

Descarga el cÛdigo fuente y el fla aquÌ