function Mutex( cmdObject, methodName ) {
	if (!Mutex.Wait) Mutex.Wait = new Map();
      	Mutex.SLICE = function( cmdID, startID ) {
		Mutex.Wait.get(cmdID).attempt( Mutex.Wait.get(startID) );
       	}
        this.attempt = function( start ) {
        	for (var j=start; j; j=Mutex.Wait.next(j.c.id)) {
	       		if (j.enter || (j.number && (j.number < this.number ||
	            		(j.number == this.number && j.c.id < this.c.id) ) ) )
		        	return setTimeout("Mutex.SLICE("+this.c.id+","+j.c.id+")",10);
		}
	     	this.c[ this.methodID ]();    //run with exclusive access
	     	this.number = 0;              //release exclusive access
		Mutex.Wait.remove( this.c.id );
	}
	this.c        = cmdObject;
	this.methodID = methodName;
	Mutex.Wait.add( this.c.id, this );    //enter and number are
	this.enter    = true;
	this.number   = (new Date()).getTime();
	this.enter    = false;
   	this.attempt( Mutex.Wait.first() );
}


function Map() {
	this.map  = new Object();
   	this.add     = function(k,o){ this.map[k] = o; }
    	this.remove  = function( k ){ delete this.map[k]; }
        this.get     = function( k ){ return k==null ? null : this.map[k]; }
       	this.first   = function(   ){ return this.get( this.nextKey( ) ); }
     	this.next    = function( k ){ return this.get( this.nextKey(k) ); }
        this.nextKey = function( k ){ 
		for (i in this.map) {
	        	if (!k) return i;
	        	if (k==i) k=null;    /*tricky*/
	   	}
	        return null;
        }
}
