// Compare two strings - null values get sorted BEFORE non-null values
function strComp( s1, s2 )
{
	if (s1 == null) 
	{
		if ( s2 == null ) return 0
		else return -1
	}
	else if ( s2 == null )
		return 1

	if ( s1 > s2 )
		return 1
	else if ( s1 < s2 )
		return -1

	return 0
}

// Compare two numbers - null values get sorted BEFORE non-null values
function numComp( n1, n2 )
{
	var nN1 = (n1 == null) ? Number.NEGATIVE_INFINITY : parseFloat(n1)
	var nN2 = (n2 == null) ? Number.NEGATIVE_INFINITY : parseFloat(n2)

	if ( nN1 > nN2 )
		return 1
	else if ( nN1 < nN2 )
		return -1

	return 0
}

// Compare two dates - null values get sorted BEFORE non-null values
function dateComp( d1, d2 )
{
	var nD1 = (d1 == null) ? Number.NEGATIVE_INFINITY : d1.getTime()
	var nD2 = (d2 == null) ? Number.NEGATIVE_INFINITY : d2.getTime()

	if ( nD1 > nD2 )
		return 1
	else if ( nD1 < nD2 )
		return -1

	return 0
}

function swapitem(items, i1, i2)
{
	var temp;
	temp=items[i1];
	items[i1]=items[i2];
	items[i2]=temp;
}

function quicksort( items, compare )
{
	if ( items ) items.sort( compare )
}

function quicksortEx( items, compareObject )
{
	if ( items ) qsortEx(items, 0, items.length-1, compareObject);
}

function qsortEx( items, low, high, compareObject )
{
	var pivot, ri, i, j;
	if (low < high)
	{
		ri = low + Math.floor(Math.random() * (high-low));
		swapitem( items, ri, high );
		pivot = items[high];
		i = low;
		j = high;
		while (i < j)
		{
			while ((i < j) && compareObject.compare(items[i], pivot) <= 0)
			i++;
			while ((j > i) && compareObject.compare(items[j], pivot) >= 0)
			j--;
			if (i < j)
			swapitem( items, i, j );
		}

		swapitem( items, i, high);
		qsortEx( items, low, i-1, compareObject );
		qsortEx( items, i+1, high, compareObject );
	}
}


// Merge sort the part of array a from start to end-1
function mergeSort(items, start, end, compareObject)
	{
	var a = items;
	if (end-start > 1)  // Recursively merge sort
		{
		// Merge sort each half of a
		var mid=parseInt((start+end)/2);
		mergeSort(a, start, mid, compareObject);
		mergeSort(a, mid, end, compareObject);

		// Merge the two halves
		var b=new Array();  // Temporary array
		var j1=start;
		var j2=mid;
		for (var i=0; i<end-start; ++i)
			{
			if (j1>=mid)
				b[i]=a[j2++];
			else if (j2>=end)
				b[i]=a[j1++];
			else if (compareObject.compare(a[j1],a[j2]) <= 0)
				b[i]=a[j1++];
			else
				b[i]=a[j2++];
			}
			for (i=0; i<end-start; ++i)
				{
				a[i+start]=b[i];     
				}
		}
	}

// Merge sort setup and reporting
function mergeSortEx(items, compareObject)
	{
	if ( items ) mergeSort(items, 0, items.length, compareObject);
	}
