// Array Extensions  v1.0.7
// documentation: http://www.dithered.com/javascript/array/index.html
// license: http://creativecommons.org/licenses/by/1.0/
// code by Chris Nott (chris[at]dithered[dot]com)
// code by Ilya Lebedev (ilya[at]lebedev[dot]net)

var undefined;
function isUndefined(property) {
  return (typeof property == 'undefined');
}


// Array.concat() - Join two arrays
if (isUndefined(Array.prototype.concat) == true) {
  Array.prototype.concat = function (secondArray) {
     var firstArray = this.copy();
     for (var i = 0, saL = secondArray.length; i < saL; i++) {
        firstArray[firstArray.length] = secondArray[i];
     }
     return firstArray;
  };
}

// Array.copy() - Copy an array
if (isUndefined(Array.prototype.copy) == true) {
  Array.prototype.copy = function() {
     var copy = new Array();
     for (var i = 0, tL = this.length; i < tL; i++) {
        copy[i] = this[i];
     }
     return copy;
  };
}

// Array.pop() - Remove the last element of an array and return it
if (isUndefined(Array.prototype.pop) == true) {
  Array.prototype.pop = function() {
    var lastItem = undefined;
    if ( this.length > 0 ) {
        lastItem = this[this.length - 1];
        this.length--;
    }
    return lastItem;
  };
}

// Array.push() - Add an element to the end of an array
if (isUndefined(Array.prototype.push) == true) {
  Array.prototype.push = function() {
     var currentLength = this.length;
     for (var i = 0; i < arguments.length; i++) {
        this[currentLength + i] = arguments[i];
     }
     return this.length;
  };
}

// Array.shift() - Remove the first element of an array and return it
if (isUndefined(Array.prototype.shift) == true) {
  Array.prototype.shift = function() {
     var firstItem = this[0];
     for (var i = 0, tL = this.length - 1; i < tL; i++) {
        this[i] = this[i + 1];
     }
     this.length--;
     return firstItem;
  };
}

// Array.slice() - Copy several elements of an array and return them
if (isUndefined(Array.prototype.slice) == true) {
  Array.prototype.slice = function(start, end) {
     var temp;
     
     if (end == null || end == '') end = this.length;
     
     // negative arguments measure from the end of the array
     else if (end < 0) end = this.length + end;
     if (start < 0) start = this.length + start;
     
     // swap limits if they are backwards
     if (end < start) {
        temp  = end;
        end   = start;
        start = temp;
     }
     
     // copy elements from array to a new array and return the new array
     var newArray = new Array();
     for (var i = 0; i < end - start; i++) {
        newArray[i] = this[start + i];
     }
     return newArray;
  };
}

// Array.splice() - Splice out and / or replace several elements of an array and return any deleted elements
if (isUndefined(Array.prototype.splice) == true) {
  Array.prototype.splice = function(start, deleteCount) {
     if (deleteCount == null || deleteCount == '') deleteCount = this.length - start;
     
     // create a temporary copy of the array
     var tempArray = this.copy();
     
     // Copy new elements into array (over-writing old entries)
     for (var i = start, aL = start + arguments.length - 2; i < aL; i++) {
        this[i] = arguments[i - start + 2];
     }
     
     // Copy old entries after the end of the splice back into array and return
     var dC = deleteCount - arguments.length + 2;
     for (var i = start + arguments.length - 2, tL = this.length - deleteCount + arguments.length - 2; i < tL; i++) {
        this[i] = tempArray[i + dC];
     }
     this.length = this.length - dC;
     return tempArray.slice(start, start + deleteCount);
  };
}

// Array.unshift - Add an element to the beginning of an array
if (isUndefined(Array.prototype.unshift) == true) {
  Array.prototype.unshift = function(the_item) {
     for (var loop = this.length-1 ; loop >= 0; loop--) {
        this[loop+1] = this[loop];
     }
     this[0] = the_item;
     return this.length;
  };
}

// Array.indexOf - return index of found element or -1 (similar to String.indexOf)
if (isUndefined(Array.prototype.indexOf) == true) {
  Array.prototype.indexOf = function(needle,begin) {
     for (var i=(null==begin||isNaN(begin)||begin<0)?0:Math.round(begin),len = this.length, idx = -1; idx==-1 & i<len; i++) {
       idx = (this[i]==needle)?i:idx;
     }
     return idx;
  };
}
// Array.lastIndexOf - return index of found element or -1 (similar to String.lastIndexOf)
if (isUndefined(Array.prototype.lastIndexOf) == true) {
  Array.prototype.lastIndexOf = function(needle,end) {
     for (var i=(null==end||isNaN(end)||end>this.length)?this.length:Math.round(end), idx = -1; idx==-1 & i>-1; i--) {
       idx = (this[i]==needle)?i:idx;
     }
     return idx;
  };
}

/***********
****
****  Object extensions
****
***********/
/*
*  Merge objects
*
*  @param object to merge
*  @return void
*  @access public
*/
Object.prototype.merge = function (obj) {
  for (var i in obj) {
    if (obj.constructor.prototype[i]) continue;
    if (undefined == this[i] && 'object' == typeof obj[i]) this[i] = {};
    if ('object' == typeof obj[i]) this[i].merge(obj[i]);
    else this[i] = obj[i];
  }
}

/***********
****
****  Function extensions
****
***********/
if (undefined == Function.call)
  Function.prototype.call = function () {
    var context, oldprop, s = [], i=1, aL = arguments.length;
    if (arguments.length == 0) context = window;
    else context = arguments[0];
    oldprop = context.______________tmp______________;
    context.______________tmp______________ = this;
    for (;i<aL;i++) s[s.length] = 'arguments['+i+']';
    var ret = eval ("context.______________tmp______________("+s.join(",")+")");
    context.______________tmp______________ = oldprop;
    return ret;
  }
if (undefined == Function.apply)
  Function.prototype.apply = function () {
    var context, oldprop, s = [], i=0, aL = arguments[1].length;
    if (arguments.length == 0) context = window;
    else context = arguments[0];
    oldprop = context.______________tmp______________;
    context.______________tmp______________ = this;
    for (;i<aL;i++) s[s.length] = 'arguments[1]['+i+']';
    var ret = eval ("context.______________tmp______________("+s.join(",")+")");
    context.______________tmp______________ = oldprop;
    return ret;
  }
