/**
 * @fileoverview BWin Javascript STL
 *
 * <pre>
 * Copyright(c) 2003-2007 by BWin Technologies Ltd.
 * http://www.bwintech.com
 * Quay House, South Esplanade, St. Peter Port
 * GY1 4EJ Guernsey, CI, UK
 * All rights reserved.
 * </pre>
 */

//<script type="text/javascript">

function bwin()
{
	// Do nothing
}

bwin.prototype.map = function(less)
{
	return new bwinMap(less);
}

bwin.prototype.multimap = function(less)
{
	return new bwinMultiMap(less);
}

bwin.prototype.set = function(less)
{
	return new bwinSet(less);
}

bwin.prototype.multiset = function(less)
{
	return new bwinMultiSet(less);
}

bwin.prototype.list = function()
{
	return new bwinList();
}

bwin.prototype.vector = function()
{
	return new bwinVector();
}

bwin.prototype.deque = function()
{
	return new bwinDeque();
}

bwin.prototype.equal_to =
{
	fn:function(a,b)
	{
		return a == b;
	}
};

bwin.prototype.greater =
{
	fn:function(a,b)
	{
		return a > b;
	}
};

bwin.prototype.greater_equal =
{
	fn:function(a,b)
	{
		return a >= b;
	}
};

bwin.prototype.less =
{
	fn:function(a,b)
	{
		return a < b;
	}
};

bwin.prototype.less_equal =
{
	fn:function(a,b)
	{
		return a <= b;
	}
};

bwin.prototype.ref = function(v)													// create a reference object referencing a value
{
	return {value:v};
}

bwin.prototype.deRef = function(ftor)											// create a functor to operate on references
{
	return { functor:ftor, fn:function(a,b){return this.functor(a.value,b.value);}};
}

bwin.prototype.isIterator = function(it,bMyType,bMine)		// useful function to test whether an object is an iterator
{
	if ( !it ) return false;																// test whether it is an iterator, options: if it is also a list type, if it is for this list
	if ( !it.isIterator ) return false;											// assumes all iterators have the following property
	if ( bMyType && (it.type != this.type) ) return false;	// also that to be the same type, it has a type property
	if ( bMine && (it.container !== this) ) return false;		// and to be contained in this, it has a container property

	return true;
}

bwin.prototype.hash_map = function(hash,less)
{
	return new bwinHashMap(hash,less);
}

bwin.prototype.hash_multimap = function(hash,less)
{
	return new bwinHashMultiMap(hash,less);
}

bwin.prototype.hash_set = function(hash,less)
{
	return new bwinHashSet(hash,less);
}

bwin.prototype.hash_multiset = function(hash,less)
{
	return new bwinHashMultiSet(hash,less);
}

bwin.prototype.hash =
{
	fn:function(a)																					// standard hash behaviour is to assume value is already an integer
	{
		return a;
	}
};

var BWinSTL = new bwin();

//=============================================================================
function bwinLinkIterator(container,node,bForward,type)		// An iterator for linked nodes
{
	this.container = container;
	this.node = node;
	this.bForward = bForward;
	this.type = type;

	this.item = node.item;
}

bwinLinkIterator.prototype.clone = function()
{
	return new bwinLinkIterator(this.container,this.node,this.bForward,this.type);
}

bwinLinkIterator.prototype.isIterator = true;

bwinLinkIterator.prototype.incImpl = function(pos, nIncrement, bF)
{
	if ( bF ) while ( nIncrement-- && pos.next ) pos = pos.next;
	else while ( nIncrement-- && pos.prev ) pos = pos.prev;
	return pos;
}

bwinLinkIterator.prototype.increment = function(nIncrement)
{
	if ( arguments.length == 0 ) nIncrement = 1;
	this.node = this.incImpl(this.node, nIncrement, this.bForward);
	this.item = this.node.item;
}

bwinLinkIterator.prototype.decrement = function(nDecrement)
{
	if ( arguments.length == 0 ) nDecrement = 1;
	this.node = this.incImpl(this.node, nDecrement, !this.bForward);
	this.item = this.node.item;
}

bwinLinkIterator.prototype.minus = function(other)
{
	var n = 0;
	var pos = other.node;
	while ( (pos !== this.node) && !pos.bSentinel )
	{
		n++;
		pos = this.incImpl(pos, 1, this.bForward);
	}
	return n;
}

bwinLinkIterator.prototype.equal_to = function(other)
{
	return (this.node === other.node);
}

bwinLinkIterator.prototype.insert = function(value)
{
	var it = this.container.insert(this,value);
	this.node = it.node;
	this.item = it.item;
}

//=============================================================================
function bwinTree()											// bwinTree: basic associative container. Wraps RBTree to provide more STL type interface
{
}

bwinTree.prototype.initialise = function()
{
	this.tree = new RBTree(this.less);								// initialise the tree.
}

bwinTree.prototype.iterator = function(node,bForward)
{
	if ( arguments.length == 1 ) bForward = true;
	return new bwinLinkIterator(this,node,bForward,this.type);
}

bwinTree.prototype.isIterator = bwin.prototype.isIterator;

bwinTree.prototype.createItem = function(key)
{
	return key;
}

bwinTree.prototype.begin = function()
{
	return this.iterator(this.tree.head.next);						// return iterator at start of collection
}

bwinTree.prototype.clear = function()
{
	this.tree = new RBTree(this.less);								// remove all items from collection
}

bwinTree.prototype.count = function(key)
{
	var lb = this.lower_bound(key);										// count the number of items that match key
	var ub = this.upper_bound(key);
	return ub.minus(lb);
}

bwinTree.prototype.empty = function()
{
	return this.tree.nSize == 0;										// return true if no items contained.
}

bwinTree.prototype.end = function()
{
	return this.iterator(this.tree.tail);								// return iterator one step beyond the last item
}

bwinTree.prototype.equal_range = function(key)
{
	var lb = this.lower_bound(key);										// return lower and upper bounds of key
	var ub = this.upper_bound(key);
	return {first:lb,second:ub};
}

bwinTree.prototype.eraseImpl = function(nBegin, nEnd)
{
	while ( nBegin !== nEnd )
	{
		nBegin = this.tree.remove(nBegin);
	}
	return nBegin;
}

bwinTree.prototype.erase = function(a,b)
{
	if ( arguments.length == 0 ) return;								// erase items from the collection

	if ( !this.isIterator(a,true,true) )
	{
		var value = this.createItem(a);									// a is a key
		var lb = this.tree.lower_bound(value);
		var ub = this.tree.upper_bound(value);
		return this.iterator(this.eraseImpl(lb,ub));
	}

	if ( arguments.length == 1 )										// if b not specified, set it to one past a
	{
		if ( !a.node.bSentinel ) return this.iterator(this.eraseImpl(a.node, a.node.next));
		else return this.end();
	}
	else
	{
		return this.iterator(this.eraseImpl(a.node, b.node));
	}
}

bwinTree.prototype.find = function(key)
{
	var item = this.createItem(key);									// return iterator pointing to matching item, or end() if not found
	var lb = this.tree.lower_bound(item);
	if ( this.less.fn(item,lb.item) ) return this.end();
	else return this.iterator(lb);
}

bwinTree.prototype.insertReturn = function(item, bIterator, bPair, bSecond)
{
	if ( bIterator == undefined ) bIterator = false;				// private function to return the correct type of object for  insert(). This can be either the item, an iterator to the  item, or a pair containing the item and a boolean value.
	if ( bPair == undefined ) bPair = false;
	if ( bSecond == undefined ) bSecond = false;
	if ( bIterator && bPair ) return {first:this.iterator(item),second:bSecond};
	else if ( bIterator ) return this.iterator(item);
	else return item;
}

bwinTree.prototype.insertImpl = function(hint, value, bIterator, bPair)
{
	if ( hint && this.less.fn(value,hint.item) ) hint = null;	// private function to insert a value will an optionally supplied hint position.
	else if ( hint && !hint.next.bSentinel && this.less.fn(hint.next.item,value) ) hint = null;

	if ( this.bMultiContainer )
	{
		return this.insertReturn(this.tree.insert(value,hint),bIterator);	// always insert into multi container
	}
	else
	{
		if ( !hint )																						// test whether item or key is unique
		{
			hint = this.tree.lower_bound(value);
			if ( !hint.bSentinel && !this.less.fn(value,hint.item) )
			{
				return this.insertReturn(hint, bIterator, bPair, false);
			}
			if ( !hint.bSentinel && !hint.prev.bSentinel ) hint = hint.prev;	// by preference, chose the node just before the insertion point
		}
		else
		{
			if ( !this.less.fn(hint.item,value) )
			{
				return this.insertReturn(hint, bIterator, bPair, false);
			}
			if ( !hint.next.bSentinel && !this.less.fn(value,hint.next.item) )
			{
				return this.insertReturn(hint.next, bIterator, bPair, false);
			}

		}
		var node = this.tree.insert(value,hint);
		return this.insertReturn(node, bIterator, bPair, true);
	}
}

bwinTree.prototype.insert = function(a,b)
{
	if ( arguments.length == 0 ) return;									// insert item(s) into collection

	var node = null;
	var hint;
	if ( arguments.length == 1 )
	{
		return this.insertImpl(null, a, true, true);						// case 1: a is value type
	}

	if ( this.isIterator(a) && this.isIterator(b) )
	{
		hint = null;														// case 2: a and b are input iterators. Insert [a,b)
		a = a.clone();
		while ( !a.equal_to(b) )
		{
			hint = this.insertImpl(hint,a.item, false);
			a.increment();
		}
	}

	if ( this.isIterator(a,true,true) )
	{
		return this.insertImpl(a.node,b,true, false);						// case 3: a is a hint. Test and insert,
	}
}

bwinTree.prototype.key_comp = function()
{
	return this.less;
}

bwinTree.prototype.lower_bound = function(key)
{
	var node = this.tree.lower_bound(this.createItem(key));
	return this.iterator(node);
}

bwinTree.prototype.rbegin = function()
{
	return this.iterator(this.tree.tail.prev,false);
}

bwinTree.prototype.rend = function()
{
	return this.iterator(this.tree.head,false);
}

bwinTree.prototype.size = function()
{
	return this.tree.nSize;
}

bwinTree.prototype.swap = function(other)
{
	var tree = this.tree;
	this.tree = other.tree;
	other.tree = tree;

	var less = this.less;
	this.less = other.less;
	other.less = less;
}

bwinTree.prototype.upper_bound = function(key)
{
	var node = this.tree.upper_bound(this.createItem(key));
	return this.iterator(node);
}

bwinTree.prototype.value_comp = function()
{
	return this.less;
}

//=============================================================================
function bwinSet(less)										// bwinSet - an associative container, reversible, sorted, unique
{
	this.type = "set";										// initialise map settings
	if ( less ) this.less = less;
	else this.less = bwin.prototype.less;
	this.bMultiContainer = false;
	this.initialise();										// initialise bwinTree settings
}

bwinSet.prototype = bwinTree.prototype;						// inherit behaviour from bwinTree

//=============================================================================
function bwinMultiSet(less)									// bwinMultiSet
{
	this.type = "multiset";									// initialise map settings
	if ( less ) this.less = less;
	else this.less = bwin.prototype.less;
	this.bMultiContainer = true;
	this.initialise();										// initialise bwinTree settings
}

bwinMultiSet.prototype = bwinTree.prototype;				// inherit behaviour from bwinTree

//=============================================================================
function bwinMapLess(less)									// bwinMapLess, helper class to bwinMap
{
	if ( less ) this.less = less;
}

bwinMapLess.prototype.fn = function(a,b)
{
	return this.less.fn(a.first,b.first);
}

bwinMapLess.prototype.less = bwin.prototype.less;
//=============================================================================
function bwinMap(less)										// bwinMap - a pair associative container (key and value), reversible, sorted, unique
{
	this.createItem = bwinMap_createItem;					// add special map behaviour
	this.key_comp = bwinMap_key_comp;
	this.value_comp = bwinMap_key_comp;
	this.type = "map";										// initialise map settings
	this.less = new bwinMapLess(less);
	this.bMultiContainer = false;
	this.initialise();										// initialise bwinTree settings
}

bwinMap.prototype = bwinTree.prototype;						// inherit behaviour from bwinTree

bwinMap_createItem = function(key,value)
{
	return {first:key,second:value};
}

bwinMap_key_comp = function()
{
	return this.less.less;
}

//=============================================================================
function bwinMultiMap(less)									// bwinMultiMap - a pair associative container (key and value), reversible, sorted
{
	this.createItem = bwinMap_createItem;					// add special map behaviour
	this.key_comp = bwinMap_key_comp;
	this.value_comp = bwinMap_key_comp;
	this.type = "multimap";									// initialise map settings
	this.less = new bwinMapLess(less);
	this.bMultiContainer = true;
	this.initialise();										// initialise bwinTree settings
}

bwinMultiMap.prototype = bwinTree.prototype;				// inherit behaviour from bwinTree

//=============================================================================
function bwinList()											// bwinList - an ordered container, reversible
{
	this.head = {item:"head",prev:null,bSentinel:true};
	this.tail = {item:"tail",tail:null,bSentinel:true};
	this.clear();
}

bwinList.prototype.type = "list";

bwinList.prototype.createNode = function(item)
{
	return {item:item,prev:null,next:null};					// create a leaf node containing the item
}

bwinList.prototype.insertNode = function(node,prev,next)
{
	prev.next = node;										// insert a node between prev and next nodes
	node.prev = prev;
	next.prev = node;
	node.next = next;
	this.nSize++;
}

bwinList.prototype.removeNode = function(node)
{
	node.prev.next = node.next;								// remove a node from its current position
	node.next.prev = node.prev;
	this.nSize--;
}

bwinList.prototype.iterator = function(node,bForward)
{
	if ( arguments.length == 1 ) bForward = true;
	return new bwinLinkIterator(this,node,bForward,this.type);
}

bwinList.prototype.isIterator = bwin.prototype.isIterator;

bwinList.prototype.assign = function(a,b)
{
	this.clear();																							// replace list contents with inputs
	var i = this.head;
	var node;
	if ( this.isIterator(a) && this.isIterator(b) )
	{
		while ( !a.equal_to(b) )																// insert range [a,b)
		{
			node = this.createNode(a.item);
			i.next = node;
			node.prev = i;
			i = node;
			this.nSize++;
			a.increment();
		}
	}
	else
	{
		while ( a > 0 )																					// insert value b, a times
		{
			node = this.createNode(b);
			i.next = node;
			node.prev = i;
			i = node;
			this.nSize++;
		}
	}
	this.tail.prev = i;
	i.next = this.tail;
}

bwinList.prototype.back = function()
{
	return (this.nSize > 0) ? this.tail.prev.item : undefined;	// return the last element (or undefined if there isn't one)
}

bwinList.prototype.begin = function()
{
	return this.iterator(this.head.next);											// return iterator at start of list
}

bwinList.prototype.clear = function()
{
	this.head.next = this.tail;																// remove all elements from list
	this.tail.prev = this.head;
	this.nSize = 0;
}

bwinList.prototype.empty = function()
{
	return this.nSize == 0;
}

bwinList.prototype.end = function()
{
	return this.iterator(this.tail);
}

bwinList.prototype.erase = function(begin,end)
{
	var a,b;
	a = begin.node;
	if ( this.isIterator(end) ) b = end.node;
	else b = a.next;

	var prev = a.prev;
	while ( a !== b )
	{
		this.nSize--;
		a = a.next;
	}
	prev.next = b;
	b.prev = prev;
}

bwinList.prototype.front = function()
{
	return (this.nSize > 0) ? this.head.next.item : undefined;	// return value at start of list (or undefined if there isn't one)
}

bwinList.prototype.insert = function(where,a,b)
{
	var next = where.node;
	var prev = next.prev;
	if ( arguments.length == 2 )															// insert an item or items into the list
	{
		node = this.createNode(a);
		this.insertNode(node,where.node.prev,where.node);
	}
	else
	{
		if ( this.isIterator(a) && this.isIterator(b) )
		{
			while ( !a.equal_to(b) )
			{
				node = this.createNode(a.item);
				this.insertNode(node,prev,null);
				a.increment();
			}
		}
		else
		{
			while ( a > 0 )
			{
				node = this.createNode(b);
				this.insertNode(node,prev,null);
				a--;
			}
		}
		next.prev = prev;
		prev.next = next;
	}
}

bwinList.prototype.merge = function(right,less)
{
	this.mergeItems(this.head,this.tail,											// merge items from another list, both lists must already be ordered by less
					this.head.next,this.tail,false,
					right.head.next,right.tail,true,
					less ? less : bwin.prototype.less);

}

bwinList.prototype.pop_back = function()
{
	this.removeNode(this.tail.prev);													// removes last element from list
}

bwinList.prototype.pop_front = function()
{
	this.removeNode(this.head.next);													// removes first element from list
}

bwinList.prototype.push_back = function(value)
{
	var node = this.createNode(value);												// add item to end of list
	this.insertNode(node,this.tail.prev,this.tail);
}

bwinList.prototype.push_front = function(value)
{
	var node = this.createNode(value);												// add item to front of list
	this.insertNode(node,this.head,this.head.next);
}

bwinList.prototype.rbegin = function()
{
	return this.iterator(this.tail.prev,false);								// return reverse iterator at end of list
}

bwinList.prototype.remove = function(value)
{
	var next;																									// remove all elements that match a value
	for ( var i = this.head.next; i != this.tail; i = next )
	{
		next = i.next;
		if ( this.equal_to.fn(i.item,value) ) this.removeNode(i);
	}
}

bwinList.prototype.remove_if = function(pred)
{
	var next;																									// remove all elements for which pred.fn(value) is true
	for ( var i = this.head.next; i != this.tail; i = next )
	{
		next = i.next;
		if ( pred.fn(i.item,value) ) this.removeNode(i);
	}
}

bwinList.prototype.rend = function()
{
	return this.iterator(this.head,false);										// return reverse iterator at head of list
}

bwinList.prototype.resize = function(nSize, value)
{
	while ( nSize < this.nSize ) this.pop_back();
	while ( nSize > this.nSize ) this.push_back(value);
}

bwinList.prototype.reverse = function()
{
	var n = Math.floor(this.nSize / 2);												// swap items around
	var h = this.head.next;
	var t = this.tail.prev;
	while ( n > 0 )
	{
		var tmp = h.item;
		h.item = t.item;
		t.item = tmp;
		n--;
	}
}

bwinList.prototype.size = function()
{
	return this.nSize;
}

bwinList.prototype.mergeItems = function(wBefore,wAfter,aBegin,aEnd,bCountA,bBegin,bEnd,bCountB,less)
{
	var i = wBefore;
	var a = aBegin;
	var b = bBegin;
	while ( (a !== aEnd) || (b !== bEnd) )
	{
		var bA;
		if ( a === aEnd ) bA = false;
		else if ( b === bEnd ) bA = true;
		else bA = less.fn(a,b);

		if ( bA )
		{
			i.next = a;
			a.prev = i;
			i = a;
			a = a.next;
			if ( bCountA ) this.nSize++;
		}
		else
		{
			i.next = b;
			b.prev = i;
			i = b;
			b = b.next;
			if ( bCountB ) this.nSize++;
		}
	}
	i.next = wAfter;
	wAfter.prev = i;
}

bwinList.prototype.mergeSort = function(begin,end,nCount,less)
{
	if ( nCount < 2 ) return;																	// nothing to do if zero or one items
	if ( nCount == 2 )																				// if just two items, swap them
	{
		var other = begin.next;
		if ( less.fn(other, begin) )
		{
			var temp = begin.item;
			begin.item = other.item;
			other.item = temp;
		}
		return;
	}

	var nHalf = Math.floor(nCount/2);													// else find the mid point and recurse
	var mid = begin;
	for ( var i = 0; i < nHalf; i++ ) mid = mid.next;
	this.mergeSort(begin,mid,nHalf,less);
	this.mergeSort(mid,end,nCount-nHalf,less);
	this.mergeItems(begin.prev,end,begin,mid,false,mid,end,false,less);		// now merge the two
}

bwinList.prototype.sort = function(less)
{
	this.mergeSort(this.head.next,this.tail,this.nSize,less?less:bwin.prototype.less);
}

bwinList.prototype.splice = function(where,right,begin,end)
{
	switch ( arguments.length )
	{
	case 2:
		begin = right.begin();
		end = right.end();
		break;
	case 3:
		end = right.end();
		break;
	case 4:
		break;
	}
	var lBegin = begin.node;
	var lEnd = end.node;
	var lPrev = lBegin.prev;

	var wNext = where.node;
	var wPrev = wNext.prev;
	while ( lBegin !== lEnd )
	{
		var node = lBegin;
		lBegin = lBegin.next;
		this.insertNode(node,wPrev);
		wPrev = node;
		right.nSize--;
	}
	wNext.prev = wPrev;
	pPrev.next = wNext;

	lPrev.next = lEnd;
	lEnd.prev = lPrev;
}

bwinList.prototype.swap = function(right)
{
	var head = this.head;																			// swap contents with right
	var tail = this.tail;
	var nSize = this.nSize;
	this.head = right.head;
	this.tail = right.tail;
	this.nSize = right.nSize;
	right.head = head;
	right.tail = tail;
	right.nSize = nSize;
}

bwinList.prototype.unique = function(equal_to)
{
	if ( equal_to == undefined ) equal_to = bwin.prototype.equal_to;
	for ( var i = this.head.next; i !== this.tail; i = i.next )		// remove adjacent duplicate items
	{
		var iNext = i.next;
		while ( (iNext!==this.tail) && equal_to.fn(i.item,iNext.item) )
		{
			iNext = iNext.next;
			i.next = iNext;
			iNext.prev = i;
		}
	}
}
//=============================================================================
function bwinVectorIterator(container, nIndex, bForward, type)	// bwinVectorIterator
{
	this.container = container;
	this.data = container.data;
	this.bForward = bForward;
	this.type = type;

	this.setPos(nIndex);
}

bwinVectorIterator.prototype.clone = function()
{
	return new bwinVectorIterator(this.container,this.getPos(),this.bForward,this.type);
}

bwinVectorIterator.prototype.setPos = function(nIndex)
{
	delete this.item;
	this.nIndex = nIndex;
	if ( this.nIndex >= this.container.nEnd ) return;
	if ( this.nIndex < this.container.nBegin ) return;
	this.item = this.data[nIndex];
}

bwinVectorIterator.prototype.getPos = function()
{
	return this.nIndex = Math.min(
		Math.max(this.nIndex,this.container.nBegin-1),
		this.container.nEnd);
}

bwinVectorIterator.prototype.increment = function(value)
{
	if ( arguments.length == 0 ) value = 1;
	this.setPos(this.nIndex + (this.bForward ? value : -value));
}

bwinVectorIterator.prototype.decrement = function(value)
{
	if ( arguments.length == 0 ) value = 1;
	this.setPos(this.nIndex + this.bForward ? -value : value);
}

bwinVectorIterator.prototype.equal_to = function(it)
{
	return (this.container === it.container) &&
			(this.getPos() == it.getPos());
}

bwinVectorIterator.prototype.isIterator = true;

bwinVectorIterator.assign = function(value)
{
	if ( (this.nIndex < this.container.nEnd) &&
		 (this.nIndex >= this.container.nBegin) ) this.data[this.nIndex] = value;
}

bwinVectorIterator.prototype.minus = function(other)
{
	return this.getPos() - other.getPos();
}

bwinLinkIterator.prototype.insert = function(value)
{
	this.container.insert(this,value);
}

//=============================================================================
function bwinVector()																				// bwinVector
{
	this.data = new Array();
	this.nBegin = 0;
	this.nEnd = 0;
	this.type = "vector";
}

bwinVector.prototype.iterator = function(nPos,bForward)
{
	bForward = arguments.length == 1 ? true : bForward;
	return new bwinVectorIterator(this,nPos,bForward,this.type);
}

bwinVector.prototype.isIterator = bwin.prototype.isIterator;

bwinVector.prototype.assign = function(a,b)
{
	if ( this.isIterator(a) && this.isIterator(b) )						// replace list contents with inputs
	{
		this.clear();
		while ( !a.equal_to(b) )
		{
			this.data.push(a.item);
			a.increment();
			this.nEnd++;
		}
	}
	else
	{
		this.data = new Array(a);
		this.nBegin = 0;
		this.nEnd = a;
		for ( var i = 0; i < a; i++ ) this.data[i] = b;
	}
}

bwinVector.prototype.at = function(pos)
{
	return this.data[pos+this.nBegin];
}

bwinVector.prototype.back = function()
{
	return this.data[this.nEnd-1];
}

bwinVector.prototype.begin = function()
{
	return this.iterator(this.nBegin);
}

bwinVector.prototype.capacity = function()
{
	return this.data.length;
}

bwinVector.prototype.clear = function()
{
	this.data = new Array();
	this.nBegin = 0;
	this.nEnd = 0;
}

bwinVector.prototype.empty = function()
{
	return this.data.length == 0;
}

bwinVector.prototype.end = function()
{
	return this.iterator(this.nEnd);
}

bwinVector.prototype.erase = function(first, last)
{
	var nFirst = first.getPos();
	if ( nFirst == this.nEnd ) return;
	var nLast;
	if ( arguments.length == 1 ) nLast = nFirst + 1;
	else nLast = last.getPos();

	var nCount = nLast - nFirst;
	this.data.splice(nFirst, nCount);
	this.nEnd -= nCount;
}

bwinVector.prototype.front = function()
{
	return this.data[this.nBegin];
}

bwinVector.prototype.insert = function(where,a,b)
{
	var nWhere = where.getPos();
	if ( arguments.length == 2 )
	{
		this.data.splice(nWhere,0,a);
		this.nEnd++;
		where.item = a;
		return where;
	}

	var aTail = this.data.splice(nWhere,this.nEnd-nWhere);
	if ( this.isIterator(a) && this.isIterator(b) )
	{
		while ( !a.equal_to(b) )
		{
			this.data.push(a);
			this.nEnd++;
		}
	}
	else
	{
		for ( var i = 0; i < a; i++ ) this.data.push(b);
		this.nEnd += a;
	}
	for ( i in aTail ) this.data.push(aTail[i]);
}

bwinVector.prototype.pop_back = function()
{
	if ( this.nEnd > this.nBegin ) delete this.data[--this.nEnd];
}

bwinVector.prototype.push_back = function(value)
{
	this.data[this.nEnd++] = value;
}

bwinVector.prototype.rbegin = function()
{
	return this.iterator(this.nEnd-1, false);
}

bwinVector.prototype.rend = function()
{
	return this.iterator(this.nBegin-1,false);
}

bwinVector.prototype.size = function()
{
	return this.nEnd - this.nBegin;
}

bwinVector.prototype.swap = function(right)
{
	var data = this.data;
	var nBegin = this.nBegin;
	var nEnd = this.nEnd;
	this.data = right.data;
	this.nBegin = right.nBegin;
	this.nEnd = right.nEnd;
	right.data = data;
	right.nBegin = nBegin;
	right.nEnd = nEnd;
}

//=============================================================================
function bwinDeque()																				// bwinDeque
{
	this.data = new Array();
	this.nBegin = 0;
	this.nEnd = 0;
	this.type = "deque";
	this.push_front = bwinDeque_push_front;										// add a few specialisations...
	this.pop_front = bwinDeque_pop_front;
}

bwinDeque.prototype = bwinVector.prototype;									// inherit methods from bwinVector

bwinDeque_push_front = function(value)
{
	this.data[--this.nBegin] = value;
}

bwinDeque_pop_front = function()
{
	if ( this.nEnd > this.nBegin ) delete this.data[this.nBegin++];
}

//=============================================================================
// bwinHash
// basic hash based associative container.
// assumed member list:
// this.createNode() - create a node from a value with the following members
//    node.item - the item
//    node.key - the key used for hashing and comparisons
//    node.next & node.prev - initially set to null
// this.less - comparison functor to determine ordering within a hash bucket
// this.hash - hash functor to determine to which hash bucket a key belongs
// this.type - string identifying the class
function bwinHash()
{
}

bwinHash.prototype.initialise = function(hash,less)
{
	this.hash = hash ? hash : bwin.prototype.hash;						// assign appropriate hash and less functors
	this.less = less ? less : bwin.prototype.less;
	this.bucket = new Array();																// create the hash-indexed collection
	this.head = {item:"head",prev:null,bSentinel:true};				// add list sentinels
	this.tail = {item:"tail",tail:null,bSentinel:true};
	this.head.next = this.tail;
	this.tail.prev = this.head;
	this.nCount = 0;																					// keep track of count
}

bwinHash.prototype.iterator = function(node,bForward)
{
	if ( arguments.length == 1 ) bForward = true;
	return new bwinLinkIterator(this,node,bForward,this.type);
}

bwinHash.prototype.isIterator = bwin.prototype.isIterator;

bwinHash.prototype.createNode = function(item)
{
	return {item:item,key:item,next:null,prev:null};						// default behaviour; the item is the key
}

bwinHash.prototype.insertNode = function(node, prev,next)
{
	node.prev = prev;														// insert a node into the linked list
	prev.next = node;
	node.next = next;
	next.prev = node;
	this.nCount++;															// increment the count
}

bwinHash.prototype.removeNode = function(node)
{
	node.prev.next = node.next;												// remove the node from the list
	node.next.prev = node.prev;
	this.nCount--;															// decrement the count
}

bwinHash.prototype.begin = function()
{
	return this.iterator(this.head.next);									// return iterator at start of collection
}

bwinHash.prototype.clear = function()
{
	this.bucket = new Array();												// remove all items from collection
	this.head.next = this.tail;												// and empty the list
	this.tail.prev = this.head;
	this.nCount = 0;														// reset the count
}

bwinHash.prototype.count = function(key)
{
	var node = this.lower_bound(key).node;									// count the number of items that match key
	var nCount = 0;
	var nHash = this.hash.fn(key);
	while ( !node.bSentinel &&
			(this.hash.fn(node.key) == nHash) &&
			!this.less.fn(key,node.key) )
	{
		nCount++;
		node = node.next;
	}
	return nCount;
}

bwinHash.prototype.empty = function()
{
	return this.nCount == 0;												// return true if no items contained.
}

bwinHash.prototype.end = function()
{
	return this.iterator(this.tail);										// return iterator one step beyond the last item
}

bwinHash.prototype.equal_range = function(key)
{
	var lb = this.lower_bound(key);											// return lower and upper bounds of key
	var ub = this.upper_bound(key);
	return {first:lb,second:ub};
}

bwinHash.prototype.eraseImpl = function(node)
{
	var next = node.next;
	var h = this.hash.fn(node.key);											// find the array index
	if ( this.bucket[h] === node )											// if node is at head of bucket
	{
		if ( this.hash.fn(next.key) == h )
		{
			this.bucket[h] = next;											// put the next one in this bucket
		}
		else
		{
			delete this.bucket[h];											// empty the bucket
		}
	}

	this.removeNode(node);													// remove node from linked list
	return next;															// return the next node in the list
}

bwinHash.prototype.erase = function(a,b)
{
	var iNode, nCount;
	if ( arguments.length == 0 ) return;											// erase items from the collection

	if ( !this.isIterator(a,true,true) )
	{
		iNode = this.lower_bound(a).node;												// a is a key
		nCount = 0;
		while ( !this.less.fn(a, iNode.key) )
		{
			iNode = this.eraseImpl(iNode);
			nCount++;
		}
		return nCount;
	}

	if ( arguments.length == 1 )															// if b not specified, erase just a
	{
		if ( !a.node.bSentinel )
		{
			return this.iterator(this.eraseImpl(a.node));
		}
		else return this.end();
	}
	else
	{
		iNode = a.node;
		while ( iNode !== b.node )
		{
			iNode = this.eraseImpl(iNode);
		}
		return this.iterator(iNode);
	}
}

bwinHash.prototype.find = function(key)
{
	var nIndex = this.hash.fn(key);
	var node = this.bucket[nIndex];
	if ( !node ) return this.end();
	while ( !node.bSentinel &&
			(this.hash.fn(node.key) == nIndex) &&
			this.less.fn(node.key,key) )
	{
		node = node.next;
	}
	if ( (this.hash.fn(node.key) == nIndex) &&
		 !this.less.fn(key, node.key) ) return this.iterator(node);
	else return this.end();
}

bwinHash.prototype.insertImpl = function(value)
{
	var node = this.createNode(value);
	var nIndex = this.hash.fn(node.key);
	if ( this.bucket[nIndex] )
	{
		var pNode = this.bucket[nIndex];								// find the first item in this bin not less than value
		while ( (this.hash.fn(pNode.key) == nIndex) &&
				this.less.fn(pNode.key,node.key) )
		{
			pNode = pNode.next;
		}
																		// if not multi container and key exists already, return it
		if ( !this.bMultiContainer && !this.less.fn(node.key,pNode.key) ) return {first:pNode,second:false};
		if ( pNode === this.bucket[nIndex] ) this.bucket[nIndex] = node;// if head of bin, adjust bin
		this.insertNode(node, pNode.prev, pNode);						// insert in list just before pNode
	}
	else
	{
		this.bucket[nIndex] = node;
		this.insertNode(node, this.tail.prev,this.tail);				// insert at tail of list
	}
	return {first:node,second:true};									// return new node.
}

bwinHash.prototype.insertReturn = function(pair)
{
	if ( this.bMultiContainer ) return this.iterator(pair.first);	// pair: first:node, second:bInserted
	else return {first:this.iterator(pair.first),second:pair.second};
}

bwinHash.prototype.insert = function(a,b)
{
	if ( arguments.length == 0 ) return;							// insert item(s) into collection
	var pair = null;
	var hint;
	if ( arguments.length == 1 )
	{
		return this.insertReturn(this.insertImpl(a));				// case 1: a is value type
	}

	if ( this.isIterator(a) && this.isIterator(b) )
	{
		node = a.node;												// case 2: a and b are input iterators. Insert [a,b)
		while ( node !== b.node )
		{
			this.insertImpl(node.item);
			node = node.next;
		}
		return;
	}

	if ( this.isIterator(a,true,true) )
	{
		if ( !a.node.bSentinel )									// case 3: a is a hint. Test and insert
		{
			node = this.createNode(b);
			var next = a.node.next;
			var nHint = this.hash.fn(a.node.key);
			var nIndex = this.hash.fn(node.key);
			if ( nHint == nIndex )
			{
				if ( this.bMultiContainer )
				{
					if ( !this.less.fn(node.key,a.node.key) &&
							(next.bSentinel ||
							(this.hash.fn(next.key) != nIndex) ||
							!this.less.fn(next.key,node.key)) )
					{
						this.insertNode(node,a.node,next);			// next is end or in a different hash or not less than b so insert here
						return this.iterator(node);
					}
				}
				else
				{
					if ( this.less.fn(a.node.key, node.key) &&
							(next.bSentinel ||
							(this.hash.fn(next.key) != nIndex) ||
							this.less.fn(node.key,next.key)) )
					{
						this.insertNode(node,a.node,next);			// next is end or in a different hash or not less than b so insert here
						return this.iterator(node);
					}
				}
			}
		}
		return this.iterator(this.insertImpl(b).first);				// if the attempt to use the hint failed, fall back on normal insert
	}
}

bwinHash.prototype.key_comp = function()
{
	return this.less;
}

bwinHash.prototype.lower_bound = function(key)
{
	var nIndex = this.hash.fn(key);
	var node = this.bucket[nIndex];
	if ( !node ) return this.end();
	while ( !node.bSentinel &&
			(this.hash.fn(node.key) == nIndex) &&
			this.less.fn(node.key,key) )
	{
		node = node.next;
	}
	return this.iterator(node);
}

bwinHash.prototype.rbegin = function()
{
	return this.iterator(this.tail.prev, false);
}

bwinHash.prototype.rend = function()
{
	return this.iterator(this.head, false);
}

bwinHash.prototype.size = function()
{
	return this.nCount;
}

bwinHash.prototype.swap = function(other)
{
	var begin = this.head.next;																// save the first element for insertion into other.
	this.clear();																							// insert the contents of other into this
	this.insert(other.begin(), other.end());
	other.clear();																						// insert the old contents of this into other. Note: still terminated by this.end()
	other.insert(this.iterator(begin), this.end());
}

bwinHash.prototype.upper_bound = function(key)
{
	var nIndex = this.hash.fn(key);														// first element greater than key
	var node = this.bucket[nIndex];
	if ( !node ) return this.end();
	while ( !node.bSentinel &&
			(this.hash.fn(node.key) == nIndex) &&
			!this.less.fn(key, node.key) )
	{
		node = node.next;
	}
	return this.iterator(node);
}

//=============================================================================
function bwinHashMap(hash,less)															// bwinHashMap
{
	this.createNode = bwinHashMap_createNode;									// add special map behaviour
	this.type = "hash_map";																		// initialise hash_map settings
	this.bMultiContainer = false;
	this.initialise(hash,less);																// initialise bwinHash settings
}

bwinHashMap.prototype = bwinHash.prototype;									// inherit behaviour from bwinHash

bwinHashMap_createNode = function(item)
{
	return {item:item,key:item.first,next:null,prev:null};		// in a map, the key is item.first
}

//=============================================================================
function bwinHashMultiMap(hash,less)												// bwinHashMultiMap
{
	this.createNode = bwinHashMap_createNode;									// add special map behaviour
	this.type = "hash_multimap";															// initialise hash_multimap settings
	this.bMultiContainer = true;
	this.initialise(hash,less);																// initialise bwinHash settings
}

bwinHashMultiMap.prototype = bwinHash.prototype;						// inherit behaviour from bwinHash

//=============================================================================
function bwinHashSet(hash,less)															// bwinHashSet
{
	this.type = "hash_set";																		// initialise hash_set settings
	this.bMultiContainer = false;
	this.initialise(hash,less);																// initialise bwinHash settings
}

bwinHashSet.prototype = bwinHash.prototype;									// inherit behaviour from bwinHash

//=============================================================================
function bwinHashMultiSet(hash,less)												// bwinHashMultiSet
{
	this.type = "hash_multiset";															// initialise map settings
	this.bMultiContainer = true;
	this.initialise(hash,less);																// initialise bwinHash settings
}

bwinHashMultiSet.prototype = bwinHash.prototype;						// inherit behaviour from bwinHash

//=============================================================================
// RBTree.js - implementation of a red black tree

function xor(b1,b2)																					// logical xor of b1 and b2
{
	return (b1 && !b2) || (!b1 && b2);
}

//=============================================================================
function RBTree(less)
{
	this.less = less;
	this.clear();
}

RBTree.prototype.clear = function()
{
	this.root = null;
	this.nSize = 0;
	this.head = {item:"head",prev:null,bSentinel:true};				// head and tail are sentinel nodes not stored in the tree
	this.tail = {item:"tail",tail:null,bSentinel:true};
	this.head.next = this.tail;
	this.tail.prev = this.head;
}

RBTree.prototype.insert = function(value,hint)
{
	var node = new RBTreeNode(value,this);

	if ( !this.nSize++ )																			// account for size
	{
		this.root = node;
		node.listInsert(this.head,this.tail);
		node.parent = null;
		return node;
	}

	var pos = this.root;

	if ( hint && hint.bSentinel )															// if hint exists, assume upper bound - 1
	{
		if ( hint === this.head ) hint = hint.next;
		else if ( hint === this.tail ) hint = hint.prev;
		else hint = null;
	}
	if ( hint && (hint.tree === this) ) pos = hint;
	pos.insert(node, this.less);
	node.balance();
	this.root.bBlack = 1;																			// make root node black
	return node;
}

RBTree.prototype.remove = function(node)
{
	if ( node.tree !== this ) return this.tail;								// remove the node from the tree returning the node that follows. protect and serve
	if ( --this.nSize == 0 )																	// account for size
	{
		this.root = null;
		node.listRemove();
		return this.tail;
	}

	var next = node.next;

	if ( !node.parent || (node.left.bNode && node.right.bNode) )	// case 1: node has two children or is root
	{
		var sub = node.prev;																		// find inorder predecessor (or successor) and swap values after deletion, value order will be preserved
		if ( !sub )
		{
			sub = node.next;
			next = node;
		}
		node.item = sub.item;
		node = sub;
	}

	node.listRemove();																				// node now has at most one child node remove node from linked list
	var p = node.parent;																			// p is parent of node
	var bLeft = (node === p.left);
	var c = node.left.bNode ? node.left : node.right;					// c is child of node
	c.parent = node.parent;																		// move c into place
	if ( bLeft ) p.left = c; else p.right = c;
	if ( !node.bBlack )																				// node is red
	{
		c.bBlack = 1;																						// this is easy, colour c black and return
		return next;
	}

	c.bBlack++;																								// node is black, add to c and fix

	if ( c.bBlack > 1 ) c.fix();

	return next;
}

RBTree.prototype.upper_bound = function(value)							//Returns an iterator to the first element in a set that with a key that is greater than a specified key.
{
	if ( !this.root ) return this.tail;
	return this.root.upper_bound(value,this.less);
}

RBTree.prototype.lower_bound = function(value)							//Returns an iterator to the first element in a map that with a key value that is equal to or greater than that of a specified key.
{
	if ( !this.root ) return this.tail;
	else return this.root.lower_bound(value, this.less);
}

//=============================================================================
function RBTreeNode(value,tree)
{
	this.item = value;
	this.tree = tree;
	this.bBlack = 0; 																					// default
	this.bNode = true;
	this.left = {parent:this,bBlack:1,bLeft:true,fix:RBTreeNode.prototype.fix};		// add left and right sentinel nodes
	this.right = {parent:this,bBlack:1,bLeft:false,fix:RBTreeNode.prototype.fix};
}

RBTreeNode.prototype.rightmost = function()
{
	if ( this.right.bNode ) return this.right.rightmost();
	else return this;
}

RBTreeNode.prototype.leftmost = function()
{
	if ( this.left.bNode ) return this.left.leftmost();
	else return this;
}

RBTreeNode.prototype.listInsert = function(prev,next)
{
	this.prev = prev;
	prev.next = this;

	this.next = next;
	next.prev = this;
}

RBTreeNode.prototype.listRemove = function()
{
	this.next.prev = this.prev;
	this.prev.next = this.next;
}

RBTreeNode.prototype.insertChild = function(prev,next,node)
{
	node.parent = this;
	node.listInsert(prev,next);
}

RBTreeNode.prototype.insert = function(node, less)
{
	if ( less.fn(node.item,this.item) )												// simple binary insertion
	{
		if ( this.left.bNode ) this.left.insert(node,less);
		else this.insertChild(this.prev,this,this.left = node);
	}
	else
	{
		if ( this.right.bNode ) this.right.insert(node,less);
		else this.insertChild(this,this.next,this.right = node);
	}
}

RBTreeNode.prototype.balance = function()
{
	var p = this.parent;															// walk up the tree preserving the red-black rules - p is parent
	if ( !p || (p.bBlack != 0) ) return;											// case 1: this is root node or parent is black
	var g = p.parent;																// g is grand parent
	if ( !g ) return;																// case 1b: p is root node
	var bLeft = (this === p.left);													// record whether we are the left child
	var bPLeft = (p === g.left);													// and whether parent is a left child
	var u = (bPLeft ? g.right : g.left);											// u is uncle
	if ( u.bBlack != 0 )															// case 2: parent is red, uncle is black
	{
		if ( xor(bLeft,bPLeft) )
		{
			this.rotate();															// case 2a: parent is different handed to this
			this.rotate();
		}
		else
		{
			p.rotate();																// case 2b: parent is same handed as this
		}
		return;
	}
	p.bBlack = 1;																	// case 3: parent is red, uncle is red
	u.bBlack = 1;
	g.bBlack = 0;
	g.balance();
}

RBTreeNode.prototype.rotate = function()
{
	var p = this.parent;															// p is parent
	if ( !p ) return;																// if this is root node, we can't rotate
	var g = p.parent;																// g is grand parent
	var bLeft = (this === p.left);
	if ( bLeft )
	{
		p.left = this.right;
		this.right.parent = p;
		this.right = p;
	}
	else
	{
		p.right= this.left;
		this.left.parent = p;
		this.left = p;
	}

	p.parent = this;																// set parents
	this.parent = g;
	if ( g ) { if ( g.left === p ) g.left = this; else g.right = this; }
	else this.tree.root = this;

	var bBlack = p.bBlack;															// swap colours
	p.bBlack = this.bBlack;
	this.bBlack = bBlack;
}

RBTreeNode.prototype.fix = function()
{
	var p = this.parent;															// fix any colour inconsistancy - p is parent
	if ( !p )
	{
		this.bBlack = 1;
		return;
	}
	var s = (this === p.left) ? p.right : p.left;									// s is sibling
	if ( s.bBlack && s.bNode )														// case 1: black sibling with red child
	{
		var n = null;
		if ( !s.left.bBlack ) n = s.left;
		else if ( !s.right.bBlack ) n = s.right;
		if ( n )
		{
			this.bBlack = 1;														// restructure
			n.bBlack = 1;
			if ( !xor((s===p.left),(n===s.left)) )
			{
				s.rotate();															// s and n same handed
			}
			else
			{
				n.rotate();															// s and n different handed
				n.rotate();
			}
			return;
		}
	}

	if ( s.bBlack )																	// case 2: black sibling without (red) children
	{
		this.bBlack = 1;															// recolour
		s.bBlack = 0;
		if ( ++p.bBlack > 1 ) p.fix();
		return;
	}

	s.rotate();																		// case 3: red sibling --> adjustment
	this.fix();
}

RBTreeNode.prototype.upper_bound = function(value,less)			//Returns node of the first element in a set that with a key that is greater than a specified key.
{
	if ( !less.fn(value,this.item) )
	{
		if ( this.right.bNode ) return this.right.upper_bound(value,less);			// value >= this.item
		else return this.next;
	}
	else
	{
		if ( this.left.bNode ) return this.left.upper_bound(value,less);			// value < this.item
		else return this;
	}
}

RBTreeNode.prototype.lower_bound = function(value,less)			//Returns node of the first element in a map that with a key value that is equal to or greater than that of a specified key.
{
	if ( less.fn(this.item,value) )
	{
		if ( this.right.bNode ) return this.right.lower_bound(value,less);			// value > this.item
		else return this.next;
	}
	else
	{
		if ( this.left.bNode ) return this.left.lower_bound(value,less);				// value <= this.item
		else return this;
	}
}


//</script>