function URI(href) {
	var md = URI.regExp.exec(href)
	if (md) {
		this.protocol = md[1] || '';
		this.hostname = md[2] || '';
		this.port = md[3] || '';
		this.pathname = md[4] || '';
		this.search = md[5] || '';
	}
	else throw 'URI parsing failed for "' + href + '"';
}
function URI_getHost() {
	return this.hostname + (this.port ? ':' + this.port : '');
}
function URI_getHref() {
	return (this.protocol ? this.protocol + '://' : '') + this.getHost() + this.pathname + (this.search ? '?' + this.search : '');
}
URI.prototype.getHost = URI_getHost;
URI.prototype.getHref = URI_getHref;
URI.regExp = new RegExp('^(?:([a-zA-Z]+?)://(?:([^/?:]+)(?::([0-9]+))?)?)?(?:((?:.*?)?))?(?:\\?(.*))?$')

/***** class List *****
*
* Implements a list-like base class.
* Array-derived classes don't work in IE, the length of
* instances would always be 0.
*
**********************************************************/

function List() {
  this.array = new Array;
  Array.apply(this.array, arguments);
}
/* adds element el, returns its index
*/
function List_add(el) {
  this.array.push(el);
  return this.getLength() - 1;
}
/* removes first occurance of element el, returns removed element
   Uses removeAt(), so overwrite that method for custom behaviour on remove.
*/
function List_remove(el) {
  var index = this.indexOf(el);
  return this.removeAt(index);
}
/* removes element at index, returns removed element
*/
function List_removeAt(index) {
  return this.array.splice(index, 1)[0];
}
/* replaces element oldel with element newel, returns oldel
   Uses replaceAt(), so overwrite that method for custom behaviour on replace.
*/
function List_replace(oldel, newel) {
  var index = this.indexOf(oldel);
  return this.replaceAt(index, newel);
}
/* replaces element at index with element el, returns replaced el */
function List_replaceAt(index, el) {
  var oldel = this.get(index);
  this.array[index] = el;
  return oldel;
}
/* returns the element at index
*/
function List_get(index) {
  return this.array[index];
}
/* returns last element
*/
function List_getLast() {
  return this.get(this.getLength() - 1);
}
/* returns the number of elements
*/
function List_getLength() {
  return this.array.length;
}
/* returns the index of first occurance of element el
*/
function List_indexOf(el) {
  for (var i=0; i<this.getLength(); i++) {
    if (this.get(i) == el) return i;
  }
  return -1;
}
/* clears the list
   Does *not* use removeAt() - for performance reasons.
   So additionally overwrite this method for custom behaviour on remove.
*/
function List_clear() {
  this.array.splice(0, this.getLength());
}
List.prototype.add = List_add;
List.prototype.remove = List_remove;
List.prototype.removeAt = List_removeAt;
List.prototype.replace = List_replace;
List.prototype.replaceAt = List_replaceAt;
List.prototype.get = List_get;
List.prototype.getLast = List_getLast;
List.prototype.getLength = List_getLength;
List.prototype.indexOf = List_indexOf;
List.prototype.clear = List_clear;


/***** class Array *****
*
* We enhance the class Array with our handy List functions.
* So it provides the same interface.
*
*************************************************/
function Array_add(el) {
  this.push(el);
  return this.length - 1;
}
function Array_remove(el) {
  var index = this.indexOf(el);
  this.removeAt(index);
}
function Array_removeAt(index) {
  return this.splice(index, 1)[0];
}
function Array_replace(oldel, newel) {
  var index = this.indexOf(oldel);
  return this.replaceAt(index, newel);
}
function Array_replaceAt(index, el) {
  var oldel = this[index];
  this[index] = el;
  return oldel;
}
function Array_get(index) {
  return this[index];
}
function Array_getLast() {
  return this[this.length - 1];
}
function Array_getLength() {
  return this.length;
}
function Array_indexOf(el) {
  for (var i=0; i<this.length; i++)
    if (this[i] == el) return i;
  return -1;
}
function Array_clear() {
  this.splice(0, this.length);
}
Array.prototype.add = Array_add;
Array.prototype.remove = Array_remove;
Array.prototype.removeAt = Array_removeAt;
Array.prototype.replace = Array_replace;
Array.prototype.replaceAt = Array_replaceAt;
Array.prototype.get = Array_get;
Array.prototype.getLast = Array_getLast;
Array.prototype.getLength = Array_getLength;
Array.prototype.indexOf = Array_indexOf;
Array.prototype.clear = Array_clear;


/***** class CallbackList extends List *****/

/* private */ function CallbackListItem(scope, method) {
  this.scope = scope;
  this.method = method;
}

function CallbackList() {
  this._activeStack = [true];
  List.apply(this, arguments); // superclass constructor
}
function CallbackList_add(scope, method) {
  List.prototype.add.call(this, new CallbackListItem(scope, method));
}
function CallbackList_remove(scope, method) {
  List.prototype.remove.call(this, new CallbackListItem(scope, method));
}
function CallbackList_indexOf(callbackListItem) {
  for (var i=0; i<this.getLength(); i++)
    if (this.get(i).scope == callbackListItem.scope
      && this.get(i).method == callbackListItem.method)
      return i;
  return -1;
}
function CallbackList_invoke() {
  if (!this.isActive()) return;
  for (var i=0; i<this.getLength(); i++)
    this.get(i).method.apply(this.get(i).scope, arguments);
}
function CallbackList_isActive() {
  return this._activeStack.getLast();
}
function CallbackList_pushActive(state) {
  this._activeStack.push(state);
}
function CallbackList_popActive() {
  return this._activeStack.pop();
}
CallbackList.prototype = new List;
CallbackList.prototype.add = CallbackList_add;
CallbackList.prototype.remove = CallbackList_remove;
CallbackList.prototype.indexOf = CallbackList_indexOf;
CallbackList.prototype.invoke = CallbackList_invoke;
CallbackList.prototype.isActive = CallbackList_isActive;
CallbackList.prototype.pushActive = CallbackList_pushActive;
CallbackList.prototype.popActive = CallbackList_popActive;
