function addListener( objet, eventName, eventHandler ) {
  var ActiveBubbling = ( arguments.length > 3 )
    ? arguments[ 3 ] : false;
  if ( objet.addEventListener ) objet.addEventListener( eventName, eventHandler, ActiveBubbling );
  else if ( objet.attachEvent ) objet.attachEvent( 'on' + eventName, eventHandler );
  else {
    var oldHandler = null;
    eval( 'if ( objet.on' + eventName + ' ) oldHandler = objet.on' + eventName + '; objet.on' + eventName + ' = function() { if ( oldHandler != null ) oldHandler(); eventHandler() };' );
  }
}

function removeListener( objet, eventName, eventHandler ) {
  var ActiveBubbling = ( arguments.length > 3 )
    ? arguments[ 3 ] : false;
  if ( objet.removeEventListener )
    objet.removeEventListener( eventName, eventHandler, ActiveBubbling );
  else if ( objet.detachEvent )
    objet.detachEvent( 'on' + eventName, eventHandler );
}

var DOMEvent = {
  toString: function() {
    return '[DOMEvent]';
  },
  get: function( e ) {
    return ( !e )
      ? window.event : e;
  },
  getTarget: function( e ) {
    return ( e.srcElement )
      ? e.srcElement : e.target;
  },
  preventDefault: function( e ) {
    if ( typeof e.preventDefault != 'undefined' )
      e.preventDefault();
    e.returnValue = false;
  },
  stopPropagation: function( e ) {
    if ( typeof e.stopPropagation != 'undefined' )
      e.stopPropagation();
    e.cancelBubble = true;
  },
  stopEvent: function( e ) {
    this.stopPropagation( e );
    this.preventDefault( e );
  }
}

var Delegate = {
  create : function( obj, methodName ) {
    var args = new Array();
    if ( arguments.length > 2 ) {
      for( var i=2; i<arguments.length; i++ )
        args.push( arguments[ i ] );
    }
  	return function() {
  	  var a = new Array();
     	for( var i=0; i<arguments.length; i++ )
    	 	a.push( arguments[ i ] );
  	  for( var i=0; i<args.length; i++ )
  	    a.push( args[ i ] );
  		obj[ methodName ].apply( obj, a );
  	}
  }
}

function Listenable() {
  /**
    @private
    @brief  Collection des écouteurs
  */
  this.listeners = new Array();

  /**
    @brief  Attache un écouteur à un évènement précis
    @param  eventName string    le nom de l'évènement auquel on attache notre fonction callback
    @param  callback  function  une fonction/méthode à appeler lorsque l'évènement sera lancé
  */
  this.addListener = function( eventName, callback ) {
    this.listeners.push( new Array( eventName, callback ) );
  }
  /**
    @brief  Cette méthode sert principalement pour des appels via setTimeout ou setInterval
    @param  obj   object  un objet
    @param  meth  string  le nom de la méthode de l'objet que l'on souhaite appeler
    @return function
  */
  this.callback = function( obj, meth ) {
    var args = new Array();
    if ( arguments.length > 2 )
      for( var i=2; i<arguments.length; i++ )
        args.push( arguments[ i ] );
    return function() {
      obj[ meth ]( args );
    }
  }
  /**
    @brief  Notifie les objets écouteurs que l'évènement eventName a été lancé
    @param  eventName string  le nom de l'évènement lancé
    @param  context   mixed   paramètre à passer lors de l'appel du callback
    @return void
  */
  this.fireEvent = function( eventName ) {
    var args = new Array();
    for( var i=1; i<arguments.length; i++ )
      args.push( arguments[ i ] );
    for( var i=0; i<this.listeners.length; i++ )
      if ( this.listeners[ i ][ 0 ] == eventName )
        if ( isInstance( this.listeners[ i ][ 1 ], Delegate ) )
          this.listeners[ i ][ 1 ].execute.apply( this.listeners[ i ][ 1 ], args );
        else
          this.listeners[ i ][ 1 ].apply( this, args );
  }
}