function ansGetHexLinear(start, stop, length, options)
{
	if(length < 2 || isNaN(length) || isNaN(options))
		return false;
	if(typeof(start) != 'number')
		parseInt(start, 16);
	if(typeof(stop) != 'number')
		parseInt(stop, 16);
	if(isNaN(start) || isNaN(stop))
		return false;
	var out = new Array(length);
	var range = start > stop ? start - stop : stop - start;

	for(var c = 0; c < length; c++)
	{
		out[c] = start > stop ? start - range / (length - 1) * c : start + range / (length - 1) * c;
		out[c] = ansApplyHexFormatting(0, 0, out[c], options);
	}
	return out;
}

function ansGetHexColorLinear(start, stop, length, options)
{
	if(length < 2 || typeof(start) != 'string' || typeof(stop) != 'string')
		return false;
	if(start.length < 3 || stop.length < 3)
		return false;
	var out = [new Array(length), 0, 0, 0];
	var startRed, startGreen, startBlue, stopRed, stopGreen, stopBlue;
	var rangeRed, rangeGreen, rangeBlue;

	if(start.substr(0, 1) == '#')
		start = start.substr(1, start.length - 1);
	if(start.substr(0, 2) == '0x' || start.substr(0, 2) == '0X')
		start = start.substr(2, start.length - 2);
	if(stop.substr(0, 1) == '#')
		stop = stop.substr(1, stop.length - 1);
	if(stop.substr(0, 2) == '0x' || stop.substr(0, 2) == '0X')
		stop = stop.substr(2, stop.length - 2);

	if((start.length != 3 && start.length != 6) || (stop.length != 3 && stop.length != 6))
		return false;

	if(start.length == 3)
	{
		startRed   = parseInt(start.substr(0, 1) + start.substr(0, 1), 16);
		startGreen = parseInt(start.substr(1, 1) + start.substr(1, 1), 16);
		startBlue  = parseInt(start.substr(2, 1) + start.substr(2, 1), 16);
	}
	else
	{
		startRed   = parseInt(start.substr(0, 2), 16);
		startGreen = parseInt(start.substr(2, 2), 16);
		startBlue  = parseInt(start.substr(4, 2), 16);
	}
	if(stop.length == 3)
	{
		stopRed   = parseInt(stop.substr(0, 1) + stop.substr(0, 1), 16);
		stopGreen = parseInt(stop.substr(1, 1) + stop.substr(1, 1), 16);
		stopBlue  = parseInt(stop.substr(2, 1) + stop.substr(2, 1), 16);
	}
	else
	{
		stopRed   = parseInt(stop.substr(0, 2), 16);
		stopGreen = parseInt(stop.substr(2, 2), 16);
		stopBlue  = parseInt(stop.substr(4, 2), 16);
	}

	if(isNaN(startRed) || isNaN(startGreen) || isNaN(startBlue) ||
		isNaN(stopRed) || isNaN(stopGreen) || isNaN(stopBlue))
		return false;

	out[1] = ansGetHexLinear(startRed, stopRed, length, 4);
	out[2] = ansGetHexLinear(startGreen, stopGreen, length, 4);
	out[3] = ansGetHexLinear(startBlue, stopBlue, length, 4);
	if(!out[1] || !out[2] || !out[3])
		return false;

	for(var c = 0; c < length; c++)
	{
		out[1][c] = out[1][c] < 16 ? '0' + out[1][c].toString(16) : out[1][c].toString(16);
		out[2][c] = out[2][c] < 16 ? '0' + out[2][c].toString(16) : out[2][c].toString(16);
		out[3][c] = out[3][c] < 16 ? '0' + out[3][c].toString(16) : out[3][c].toString(16);
		out[0][c] = options & HSIGN ? '#' : '';
		out[0][c] = out[0][c] + out[1][c] + out[2][c] + out[3][c];
	}
	return out[0];
}

function ansApplyHexFormatting(start, stop, val, options)
{
	if(options & ROUND)
		val = Math.round(val);
	if(options & STRNG)
		val = val.toString(16);
	return val;
}

function ansGetDecLinear(start, stop, length, options, points)
{
	if(length < 2 || typeof(start) != 'number' || typeof(stop) != 'number')
		return false;
	var out = new Array(length);
	var range = start > stop ? start - stop : stop - start;

	for(var c = 0; c < length; c++)
	{
		out[c] = start > stop ? start - range / (length - 1) * c : start + range / (length - 1) * c;
		out[c] = ansApplyDecFormatting(start, stop, out[c], options, points);
	}
	return out;
}

function ansGetDecHill(start, stop, length, options, points)
{
	if(length < 2 || typeof(start) != 'number' || typeof(stop) != 'number')
		return false;
	var out = new Array(length);
	if(length == 2)
	{
		out[0] = ansApplyDecFormatting(start, stop, 0, options, points);
		out[1] = ansApplyDecFormatting(start, stop, 1, options, points);
		return out;
	}
	var mid = Math.ceil(length / 2);
	var avg = length % 2 == 0 ? 100 / length : 100 / (length - 1);
	var prev = 0.0;

	for(var c = 0; c < length; c++)
	{
		if(length % 2 == 0)
			out[c] = +(prev += avg * Math.cos((mid - c) * Math.PI / mid) + avg).toFixed(2) * 0.01;
		else
			out[c] = +(prev += c < mid ? avg * Math.cos((mid - c) * Math.PI / mid) + avg : avg * Math.cos((c - mid + 1) * Math.PI / mid) + avg).toFixed(2) * 0.01;
		out[c] = ansApplyDecFormatting(start, stop, out[c], options, points);
	}
	return out;
}

function ansGetDecLadder(start, stop, length, options, points)
{
	if(length < 2 || typeof(start) != 'number' || typeof(stop) != 'number')
		return false;
	var out = new Array(length);
	if(length == 2)
	{
		out[0] = ansApplyDecFormatting(start, stop, 0, options, points);
		out[1] = ansApplyDecFormatting(start, stop, 1, options, points);
		return out;
	}
	var mid = Math.ceil(length / 2);
	var avg = length % 2 == 0 ? 100 / length : 100 / (length - 1);
	var prev = 0.0;

	for(var c = 0; c < length; c++)
	{
		if(length % 2 == 0)
		{
			if(c < mid)
				out[c] = +(prev += avg * (c * 2) / mid).toFixed(2) * 0.01;
			else if(c == mid)
				out[c] = +(prev += 100 / length * 2).toFixed(2) * 0.01;
			else
				out[c] = +(prev += avg * ((length - c) * 2) / mid).toFixed(2) * 0.01;
		}
		else
			out[c] = +(prev += c < mid ? avg * (c * 2) / mid : avg * ((length - c) * 2) / mid).toFixed(2) * 0.01;
		out[c] = ansApplyDecFormatting(start, stop, out[c], options, points);
	}
	return out;
}

function ansApplyDecFormatting(start, stop, val, options, points)
{
	var range = start > stop ? start - stop : stop - start;

	if(options & PCTOV)
		val = start > stop ? start - val * range : start + val * range;
	if(options & PERCT)
		val *= 100;
	if(options & TCREP)
		val *= 0.01;
	if(options & ROUND)
		val = Math.round(val);
	if(options & POINT)
		val = val.toFixed(points);
	if(+val == 0 && (options & PSIGN || options & PXSTR || options & STRNG))
		val = isNaN(val) ? val : val.toString();
	else
	{
		if(options & PSIGN)
			val = isNaN(val) ? val + '%' : val.toString() + '%';
		else if(options & PXSTR)
			val = isNaN(val) ? val + 'px' : val.toString() + 'px';
		if(options & STRNG)
			val = isNaN(val) ? val : val.toString();
	}
	return val;
}

function ansSetupAniElement(name, status, current, length, delay, option, reserve)
{
	var out = {'info':[], 'actv':[], 'anim':[], 'long':length, 'dlay':delay};

	out.info.push({'name':name, 'hand':document.getElementById(name), 'stat':status, 'curr':current, 'optn':option, 'resv':reserve});
	return out;
}

function ansSetupAniElements(name, status, current, length, delay, option, reserve, mode, total, digits)
{
	var out = {'info':[], 'actv':[], 'anim':[], 'long':length, 'dlay':delay, 'mode':mode};
	var id  = '';
	digits -= 1;

	for(var c = 0; c < total; c++)
	{
		id = name;
		for(var d = Math.pow(10, digits); d != 1; d /= 10)
			if(c < d)
				id = id + '0';
		id = id + c.toString();
		out.info.push({'name':id, 'hand':document.getElementById(id), 'stat':status, 'curr':current, 'optn':option, 'resv':reserve});
	}

	return out;
}

function ansSetupAniElementsListener(ani, event, next, type)
{
	if(type == 'standard')
		ani.info[next].hand.addEventListener(event, function() {ansChangeAniElements(ani, next);}, false);
	else if(type =='ie')
		ani.info[next].hand.attachEvent(event, function() {ansChangeAniElements(ani, next);});
}

function ansSetupAniElementsListeners(ani, event)
{
	var type = 'unknown';
	var obj = document.createElement('obj');
	if(obj.addEventListener)
		type = 'standard';
	else if(obj.attachEvent)
	{
		type = 'ie';
		event = 'on' + event;
	}
	for(var c = 0; c < ani.info.length; c++)
		ansSetupAniElementsListener(ani, event, c, type);
}

function ansChangeAniElements(ani, next)
{
	for(var c = 0; c < ani.info.length; c++)
	{
		if((ani.mode == 1 && c != next && ani.info[c].stat == 3) ||
			(ani.mode == 2 && c >  next && ani.info[c].stat == 3))
		{
			ani.info[c].stat = 1;
			ani.actv.push(c);
		}
		else if((ani.mode == 1 && c != next && ani.info[c].stat == 2 && ani.info[c].curr != 0) ||
				(ani.mode == 2 && c >  next && ani.info[c].stat == 2 && ani.info[c].curr != 0))
			ani.info[c].stat = 1;
		else if((ani.mode == 1 && c != next && ani.info[c].stat == 2 && ani.info[c].curr == 0) ||
				(ani.mode == 2 && c >  next && ani.info[c].stat == 2 && ani.info[c].curr == 0))
		{
			ani.info[c].stat = 0;
			for(var d = 0; d > -1; d++)
				if(ani.actv[d] == c)
				{
					ani.actv.splice(d, 1);
					d = -1;
				}
		}
		else if((ani.mode == 1 && c == next && ani.info[c].stat == 0) ||
				(ani.mode == 2 && c <= next && ani.info[c].stat == 0))
		{
			ani.info[c].stat = 2;
			ani.actv.push(c);
		}
		else if((ani.mode == 1 && c == next && ani.info[c].stat == 1 && ani.info[c].curr != ani.long - 1) ||
				(ani.mode == 2 && c <= next && ani.info[c].stat == 1 && ani.info[c].curr != ani.long - 1))
			ani.info[c].stat = 2;
		else if((ani.mode == 1 && c == next && ani.info[c].stat == 1 && ani.info[c].curr == ani.long - 1) ||
				(ani.mode == 2 && c <= next && ani.info[c].stat == 1 && ani.info[c].curr == ani.long - 1))
		{
			ani.info[c].stat = 3;
			for(var d = 0; d > -1; d++)
				if(ani.actv[d] == c)
				{
					ani.actv.splice(d, 1);
					d = -1;
				}
		}
	}
	return ani;
}
