

if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function (obj, fromIndex) {
  	if (fromIndex == null) {
  		fromIndex = 0;
  	} 
  	else if (fromIndex < 0) {
  		fromIndex = Math.max(0, this.length + fromIndex);
  	}
  	for (var i = fromIndex; i < this.length; i++) {
  		if (this[i] === obj)
  			return i;
  	}
  	return -1;
  };
}

if (!Array.prototype.lastIndexOf) {
	Array.prototype.lastIndexOf = function (obj, fromIndex) {
		if (fromIndex == null) {
			fromIndex = this.length - 1;
		} 
		else if (fromIndex < 0) {
			fromIndex = Math.max(0, this.length + fromIndex);
		}
		for (var i = fromIndex; i >= 0; i--) {
			if (this[i] === obj)
				return i;
		}
		return -1;
	};
}

if (!Array.prototype.forEach) {
	Array.prototype.forEach = function (f, obj) {
		var l = this.length;	// must be fixed during loop... see docs
		for (var i = 0; i < l; i++) {
		    f.call(obj, this[i], i, this);
		}
	};
}

if (!Array.prototype.filter) {
	Array.prototype.filter = function (f, obj) {
		var l = this.length;	// must be fixed during loop... see docs
		var res = [];
		for (var i = 0; i < l; i++) {
		    if (f.call(obj, this[i], i, this)) {
                res.push(this[i]);
            }
		}
		return res;
	};
}

if (!Array.prototype.map) {
	Array.prototype.map = function (f, obj) {
		var l = this.length;	// must be fixed during loop... see docs
		var res = [];
		for (var i = 0; i < l; i++) {
			res.push(f.call(obj, this[i], i, this));
		}
		return res;
	};
}

if (!Array.prototype.some) {
	Array.prototype.some = function (f, obj) {
  	var l = this.length;	// must be fixed during loop... see docs
  	for (var i = 0; i < l; i++) {
  		if (f.call(obj, this[i], i, this)) {
  			return true;
  		}
  	}
    return false;
	};
}

if (!Array.prototype.every) {
	Array.prototype.every = function (f, obj) {
		var l = this.length;	// must be fixed during loop... see docs
		for (var i = 0; i < l; i++) {
			if (!f.call(obj, this[i], i, this)) {
				return false;
			}
		}
		return true;
	};
}

if (!Array.forEach) {
    Array.forEach = function(a, f, obj) {
        Array.prototype.forEach.call(a, f, obj);
    }
}


if (!Array.filter) {
	Array.filter = function (a, f, obj) {
        return Array.prototype.filter.call(a, f, obj);
	};
}

if (!Array.map) {
	Array.map = function (a, f, obj) {
    return Array.prototype.map.call(a, f, obj);
	};
}

if (!Array.some) {
	Array.some = function (a, f, obj) {
    return Array.prototype.some.call(a, f, obj);
	};
}

if (!Array.every) {
	Array.every = function (a, f, obj) {
        return Array.prototype.every.call(a, f, obj);
	};
}

Array.prototype.contains = function (obj) {
  if (obj.constructor == Array) {
    return obj.every(this.contains, this);
  }
	return this.indexOf(obj) != -1;
}

Array.prototype.copy = function (obj) {
	return this.concat();
}

Array.prototype.insertAt = function (obj, i) {
	this.splice(i, 0, obj);
}

Array.prototype.insertBefore = function (obj, obj2) {
	var i = this.indexOf(obj2);
	if (i == -1)
		this.push(obj);
	else
		this.splice(i, 0, obj);
}

Array.prototype.removeAt = function (i) {
	this.splice(i, 1);
}

Array.prototype.remove = function (obj) {
	var i = this.indexOf(obj);
	if (i != -1)
		this.splice(i, 1);
}

Array.prototype.last = function() {
    return this[this.length - 1];
}

Array.prototype.random = function() {
    /*
        a.random()
            Returns a randomly chosen element of a.
            
        a.random(n)
            Returns an array of n randomly chosen elements of a.
    */
    var rv;
    if (arguments.length == 0) {
        rv = this[Math.floor(Math.random() * this.length)];
    }
    else {
        rv = [];
        while (rv.length < arguments[0]) {
            var i = this.random();
            if (rv.contains(i)) continue;
            rv.push(i);
        }
    }
    return rv;
}


