function bind()
{
    var args = cloneArray(arguments), fn = args.shift(), object = args.shift();
    return function() { return fn.apply(object, arrayInsert(cloneArray(args), 0, arguments)); }
}   

function extend(d, s)
{
   for (var property in s) {
     d[property] = s[property];
   }
   return d;
}  


function cloneArray(array, fn)
{
    var newArray = [];
    
    if (fn)
       for (var i = 0; i < array.length; ++i)
          newArray.push(fn(array[i]));
    else
       for (var i = 0; i < array.length; ++i)
          newArray.push(array[i]);

    return newArray;
}

function extendArray(array, array2)
{   
    var newArray = [];
    newArray.push.apply(newArray, array);
    newArray.push.apply(newArray, array2);
    return newArray;
}

function arrayInsert(array, index, other)
{   
    for (var i = 0; i < other.length; ++i)
       array.splice(i+index, 0, other[i]);

    return array;
}

function createCookie(name,value,days)
{   
    if (days) { 
       var date = new Date();
       date.setTime(date.getTime()+(days*24*60*60*1000));
       var expires = "; expires="+date.toGMTString();
    }
    else 
       var expires = "";
    document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name)
{   
    var nameEQ = name + "=";
    var ca = document.cookie.split(';');
    for(var i=0;i < ca.length;i++) {
       var c = ca[i];
       while (c.charAt(0)==' ') c = c.substring(1,c.length);
       if (c.indexOf(nameEQ) == 0)
          return c.substring(nameEQ.length,c.length);
    }
    return null;
}

function containsElement (a, b)
{
    if(!a || !b) return false;

    while (b.parentNode)
         if ((b = b.parentNode) == a)
                return true;
    return false;

}

function validTarget(e, handle)
{
   if (browser.ie4()&&!handle.contains(e.toElement))
   {
       return true;
   }
   else if (browser.ns6()&&e.currentTarget!= e.relatedTarget&& !containsElement(e.currentTarget, e.relatedTarget))
   {
      return true;
   }

   return false;
}

function getEvent(e)
{
   if(e)
     return e;

   if(!e)
   {
      if(window.event)
        return window.event;
      else
        return event;
   }

   return null; 
}

function setOpacity (obj, opacity)
{
    opacity = (opacity == 100)?99.999:opacity;

    // IE
    obj.style.filter = "alpha(opacity:"+opacity+")";

    // Netscape/Firefox
    obj.style.MozOpacity = opacity/100;
  
    // Safari newer Firefox and Mozilla, CSS3 
    obj.style.opacity = opacity/100;
}

function findPosX(obj)
{
    var curleft = 0;
    if(obj.offsetParent)
        while(1)
        {
          curleft += obj.offsetLeft;
          if(!obj.offsetParent)
            break;
          obj = obj.offsetParent;
        }
    else if(obj.x)
        curleft += obj.x;
    return curleft;
}

function findPosY(obj)
{
    var curtop = 0;
    if(obj.offsetParent)
        while(1)
        {
          curtop += obj.offsetTop;
          if(!obj.offsetParent)
            break;
          obj = obj.offsetParent;
        }
    else if(obj.y)
        curtop += obj.y;
    return curtop;
}

var FireinputHash = function() 
{
    this.items = new Array();
}; 

FireinputHash.prototype = 
{
    foreach: function(callback) 
    {
       for (var k in this.items) 
       {
          if(callback) callback(k, this.items[k]);
       }
    },

    removeItem: function(in_key) 
    {
       var tmp_value;
       if (typeof(this.items[in_key]) != 'undefined') 
       {
          this.length--;
          var tmp_value = this.items[in_key];
          delete this.items[in_key];
       }

       return tmp_value;
    },

    getItem: function(in_key) 
    {
       if (typeof(this.items[in_key]) == 'undefined')
          return null; 
       else 
          return this.items[in_key];
    },

    setItem: function(in_key, in_value) 
    {
       if (typeof(in_value) != 'undefined') 
       {
          if (typeof(this.items[in_key]) == 'undefined') 
          {
             this.length++;
          }

          this.items[in_key] = in_value;
       }

       return in_value;
    },

    hasItem: function(in_key) {
       return typeof(this.items[in_key]) != 'undefined';
    }
};


// event 
if (!window.Event) {
  var Event = new Object();
} 

extend(Event, {
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,

  element: function(event) {
    return event.target || event.srcElement;
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },

  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },

  addEvent: function(obj, type, fn) {
    if ( obj.attachEvent )
    {
       obj['e'+type+fn] = fn;
       obj[type+fn] = function()
       {
          obj['e'+type+fn]( window.event );
       }

       obj.attachEvent( 'on'+type, obj[type+fn] );

    } else
       obj.addEventListener( type, fn, true);
  },

  removeEvent: function(obj, type, fn ) {
     if ( obj.detachEvent )
     {
       if(obj[type+fn] != null && obj[type+fn] != undefined)
       {
         obj.detachEvent( 'on'+type, obj[type+fn] );
       }

       obj[type+fn] = null;
     }
     else
       obj.removeEventListener( type, fn, true );
  }
});

var Ajax = function() {};
Ajax.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.prototype = 
{
    transport: null, 

    setOptions: function(options) 
    {
       this.options = 
       {
          method:       'post',
          asynchronous: true,
          contextType:  'application/x-www-form-urlencoded',
          parameters:   ''
       }

       extend(this.options, options || {})
    },

    responseIsSuccess: function() 
    {
       return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
    },
  
    responseIsFailure: function() 
    {
       return !this.responseIsSuccess();
    }, 

    request: function(url) 
    {
       this.transport = new XMLHttpRequest(); 

       var parameters = this.options.parameters || '';
       if (parameters.length > 0) parameters += '&_=';

       try 
       {
          this.url = url;
          if (this.options.method == 'get' && parameters.length > 0)
             this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

          this.transport.open(this.options.method, this.url,
             this.options.asynchronous);
          if (this.options.asynchronous) 
          {
             this.transport.onreadystatechange = bind(this.onStateChange, this); 
             setTimeout(bind(function() {this.respondToReadyState(1)}, this), 10);
          }

          this.setRequestHeaders();

          var body = this.options.postBody ? this.options.postBody : parameters;
          this.transport.send(this.options.method == 'post' ? body : null);

       } 
       catch (e) 
       {
          this.dispatchException(e);
       }
    },

    setRequestHeaders: function() 
    {
       var requestHeaders =
          ['X-Requested-With', 'XMLHttpRequest',
           'X-Prototype-Version', '1.0',
           'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];

       if (this.options.method == 'post') 
       {
          requestHeaders.push('Content-type', this.options.contentType);

          if (this.transport.overrideMimeType)
             requestHeaders.push('Connection', 'close');
       }

       if (this.options.requestHeaders)
          requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

       for (var i = 0; i < requestHeaders.length; i += 2)
          this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
    },

    onStateChange: function() 
    {
       var readyState = this.transport.readyState;
       if (readyState != 1)
          this.respondToReadyState(this.transport.readyState);
    },

    header: function(name) 
    {
       try {
          return this.transport.getResponseHeader(name);
       }
       catch (e) {}

       return null; 
    },

    evalJSON: function() 
    {
       try {
          return eval('(' + this.header('X-JSON') + ')');
       } catch (e) {}

       return null; 
    },

    evalResponse: function() 
    {
       try {
          return eval(this.transport.responseText);
       }
       catch (e) 
       {
          this.dispatchException(e);
       }

       return null; 
    },


    respondToReadyState: function(readyState) 
    {
       var event = Ajax.Events[readyState];
       var transport = this.transport, json = this.evalJSON();

       if (event == 'Complete') 
       {
          try {
             (this.options['on' + this.transport.status]
             || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
             )(transport, json);
          } 
          catch (e) 
          {
             this.dispatchException(e);
          }
          if ((this.header('Content-type') || '').match(/^text\/javascript/i))
             this.evalResponse();
       }

       try {
          if(typeof(this.options['on' + event]) != "undefined")
             (this.options['on' + event])(transport, json);
       }
       catch (e) {
          this.dispatchException(e);
       }

    },
    dispatchException: function(exception) 
    {
       if(this.options.onException)
          (this.options.onException)(this, exception);
    }
};

 
