// Library of useful functions
// Version 1.0

// Written by David J. Taylor
// © djtSoft
// Web site: http://www.djtsoft.com/

Math.sign = function(v) {
	if (v == 0) return 0;
	return v / Math.abs(v);
};

Math.rnd = function(min, max) {
	return Math.floor(Math.random() * (max - min + 1) + min);
};

function round(x, n) {
	if (n == null) n = 0;
	return Math.round(x * Math.pow(10, n)) / Math.pow(10, n);
}

function random(b, c, n) {
	if (n == null) n = 0;
	return round((c - b) * Math.random() + b, n);
}

ln=Math.log;
arcsin=Math.asin;
arccos=Math.acos;
arctan=Math.atan;
function sq(x) {return Math.pow(x, 2)}
function csc(x) {return 1/Math.sin(x)}
function sec(x) {return 1/Math.cos(x)}
function cot(x) {return 1/Math.tan(x)}
function arccsc(x) {return arcsin(1/x)}
function arcsec(x) {return arccos(1/x)}
function arccot(x) {return arctan(1/x)}
function sinh(x) {return (Math.exp(x)-Math.exp(-x))/2}
function cosh(x) {return (Math.exp(x)+Math.exp(-x))/2}
function tanh(x) {return sinh(x)/cosh(x)}
function csch(x) {return 1/sinh(x)}
function sech(x) {return 1/cosh(x)}
function coth(x) {return 1/tanh(x)}
function arcsinh(x) {return ln(x+Math.sqrt(x*x+1))}
function arccosh(x) {if(x>=1) return ln(x+Math.sqrt(x*x-1))}
function arctanh(x) {if(x>1) return ln((1+x)/(1-x))/2}
function arccsch(x) {return arcsinh(1/x)}
function arcsech(x) {return arccosh(1/x)}
function arccoth(x) {return arctanh(1/x)}
function base(x,a,b) {
	if (b == null) {
		b=a;
		a=10;
	}
	if (typeof x == "number") {
		j=new Array(Math.floor(log(x,10))+1);
		for (i=j.length;i>0;i--) {
			j[j.length-i]=Math.floor(x/Math.pow(10,i-1));
			x%=Math.pow(10,i-1);
		}
		x=j;
	}
	k=0;
	for (i=x.length;i>0;i--) k+=x[x.length-i]*Math.pow(a,i-1);
	x=k;
	j = new Array(Math.floor(log(x,b))+1);
	for (i=j.length;i>0;i--) {
		j[j.length-i] = Math.floor(x/Math.pow(b,i-1));
		x%=Math.pow(b,i-1);
	}
	x=j;
	k=1;
	for (i=0;i<x.length;i++) k*=(x[i]<10);
	if (k) {
		k=0;
		for (i=x.length;i>0;i--) k+=x[x.length-i]*Math.pow(10,i-1);
		x=k;
	}
	return x;
}
function factor(x) {
	k=0;
	d=new Array();
	for (i=2;i<=Math.sqrt(x);i+=k) {
		if (k<2) k++;
		for (j=0;x%i==0;j++)  {
			x/=i;
			d[d.length]=i;
		}
	}
	if(x!=1||d.length==0) d[d.length]=x;
	return d;
}
function factorial(x,n) {
	if(n==null) n=1;
	for(i=x-n;i>0;i-=n) x*=i;
	return x;
}
function fibonacci(x) {return round((Math.pow((1+Math.sqrt(5))/2,x)-Math.pow((1-Math.sqrt(5))/2,x))/Math.sqrt(5))}
function gcd(a) {
	r=a[0];
	for(i=1;i<a.length;i++) {
		c=a[i];
		while(c!=0) {
			r-=c*Math.floor(r/c);
			k=c;
			c=r;
			r=k;
		}
	}
	return r;
}
function isprime(x) {
	if(x==2) return true;
	else if(x%2==0) return false;
	for(i=3;i<=Math.sqrt(x);i+=2) if(x%i==0) return false;
	return true;
}
function lcm(a) {
	s=a[0];
	for(j=1;j<a.length;j++) {
		s*=a[j]/gcd([s,a[j]]);
	}
	return s;
}
function log(x,b) {
	if (b == null) b = Math.E;
	return ln(x)/ln(b);
}
function max(a) {return a.sort(function(b,c) {return c-b})[0]}
function min(a) {return a.sort(function(b,c) {return b-c})[0]}
function pfactorial(x) {
	k=1;
	for(j=3;j<=x;j+=2) if(isprime(j)) k*=j;
	if(x>2) k*=2;
	return k;
}
function product(a) {
	k=1;
	for(i=0;i<a.length;i++) k*=a[i];
	return k;
}
function sum(a) {
	k=0;
	for(i=0;i<a.length;i++) k+=a[i];
	return k;
}
function totient(x) {
	k=1;
	for(j=2;j<x;j++) if(gcd([x,j])==1) k++;
	return k;
}
function primepi(x) {
	k=1;
	if(x%2==0) j++;
	for(j=3;j<=x;j+=2) if(isprime(j)) k++;
	return k;
}

String.prototype.trimLeft = function() {
	return this.replace(/^[\s\xA0]+/, "");
};

String.prototype.trimRight = function() {
	return this.replace(/[\s\xA0]+$/, "");
};

if (!String.prototype.trim) {
	String.prototype.trim = function() {
		return this.trimLeft().trimRight();
	};
}

String.prototype.repeat = function(n) {
	return new Array(Math.max(parseInt(n, 10), 0) + 1).join(this);
};

String.prototype.padLeft = function(n, str) {
	if (!str) str = " ";
	return str.repeat(n - this.length).substr(0, n - this.length) + this;
};

String.prototype.padRight = function(n, str) {
	if (!str) str = " ";
	return this + str.repeat(n - this.length).substr(0, n - this.length);
};

String.prototype.pad = function(n, str) {
	return this.padLeft(Math.floor(n / 2)).padRight(n);
};

String.prototype.toSentenceCase = function() {
	var str = this, match;
	while (match = str.match(/^([a-z])/)) {
		str = str.substr(0, match.index) + match[1].toUpperCase() + str.substr(match.index + 1);
	}
	while (match = str.match(/([\.\?\!] +|\r|\n)([a-z])/)) {
		i = match.index + match[1].length;
		str = str.substr(0, i) + match[2].toUpperCase() + str.substr(i + 1);
	}
	return str;
};

String.prototype.toTitleCase = function() {
	var str = this, match;
	while (match = str.match(/\b([a-z])/)) {
		str = str.substr(0, match.index) + match[1].toUpperCase() + str.substr(match.index + 1);
	}
	return str;
};

Date.prototype.getDayOfWeek = function() {
	return (this.getDay() + 6) % 7;
};

Date.prototype.getDayOfYear = function() {
	return Math.floor((new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0) - new Date(this.getFullYear(), 0, 1, 0, 0, 0) + 1) / 86400000);
};

Date.prototype.getWeekOfYear = function() {
	var date = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	date.setDate(date.getDate() - date.getDayOfWeek() + 3);
	var D = date.valueOf();
	date.setMonth(0);
	date.setDate(4);
	return Math.round((D - date.valueOf()) / 7 / 86400000) + 1;
};

Date.getDaysInMonth = function(month, year) {
	switch (month) {
		case 2:
			return (year % 4 > 0) ? 28 : 29;
		case 4:
		case 6:
		case 9:
		case 11:
			return 30;
	}

	return 31;
};

Date.prototype.getDaysInMonth = function() {
	return Date.getDaysInMonth(this.getMonth() + 1, this.getFullYear());
};

Number.prototype.format = function(dp, trim) {
	var str;
	dp = Math.max(parseInt(dp, 10), 0);

	if (this.toFixed) {
		str = this.toFixed(dp);
	} else {
		str = this.toString();
		var i = str.indexOf(".");
		if (i < 0) {
			if (dp > 0) str += "." + "0".repeat(dp);
		} else {
			str = (this + ((parseInt(str.charAt(i + dp + 1), 10) >= 5) ? Math.pow(10, -dp) : 0)).toString().substr(0, (dp > 0) ? i + dp + 1 : i);
		}
	}

	if (trim) return str.replace(/\.?0+$/, "");

	return str;
};

Number.prototype.toBase = function(b, nd) {
	nd = parseInt(nd, 10);
	var str = this.toString(parseInt(b, 10)).padLeft(nd, "0");
	return str.substr(Math.max(str.length - nd, 0));
};

if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(val, start) {
		var len = this.length;

		var i = parseInt(start, 10) || 0;
		if (i < 0) i += len;

		for (; i < len; ++i) {
			if (i in this && this[i] === val) return i;
		}

		return -1;
	};
}

if (!Array.prototype.lastIndexOf) {
	Array.prototype.lastIndexOf = function(val, start) {
		var len = this.length;

		var i = Math.min(parseInt(start, 10) || -1, len);
		if (i < 0) i += len;

		for (; i >= 0; --i) {
			if (i in this && this[i] === val) return i;
		}

		return -1;
	};
}

if (!Array.prototype.each) {
	Array.prototype.each = function(callback) {
		for (var i = 0, len = this.length; i < len && callback.call(this[i], i) !== false; ++i) {}
	};
}

if (!Array.prototype.eachRev) {
	Array.prototype.eachRev = function(callback) {
		for (var i = this.length - 1; i >= 0 && callback.call(this[i], i) !== false; --i) {}
	};
}

if (!Array.prototype.every) {
	Array.prototype.every = function(callback) {
		var len = this.length;
		for (var i = 0; i < len; ++i) {
			if (callback.call(this[i], i) === false) return false;
		}
		return true;
	};
}

if (!Array.prototype.some) {
	Array.prototype.some = function(callback) {
		var len = this.length;
		for (var i = 0; i < len; ++i) {
			if (callback.call(this[i], i) === true) return true;
		}
		return false;
	};
}

if (!Array.prototype.map) {
	Array.prototype.map = function(callback) {
		var ar = [];
		for (var i = 0, len = this.length; i < len; ++i) {
			ar[i] = callback.call(this[i], i);
		}
		return ar;
	};
}

if (!Array.prototype.filter) {
	Array.prototype.filter = function(callback) {
		var len = this.length, ar = [];
		for (var i = 0, val = this[0]; i < len; val = this[++i]) {
			if (callback.call(val, i)) ar.push(val);
		}
		return ar;
	};
}

if (!Array.prototype.reduce) {
	Array.prototype.reduce = function(callback, initialValue) {
		var i = 0;
		if (initialValue === null) {
			initialValue = this[0];
			i++;
		}
		for (var len = this.length; i < len; ++i) {
			initialValue = callback.call(this[i], i, initialValue);
		}
		return initialValue;
	};
}

if (!Array.prototype.reduceRight) {
	Array.prototype.reduceRight = function(callback, initialValue) {
		var i = this.length - 1;
		if (initialValue === null) {
			initialValue = this[i];
			i--;
		}
		for (; i >= 0; --i) {
			initialValue = callback.call(this[i], i, initialValue);
		}
		return initialValue;
	};
}

if (!window.XMLHttpRequest) {
	XMLHttpRequest = function() {
		var web_req = null;
		["Microsoft.XMLHTTP.1.0", "Microsoft.XMLHTTP", "MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0", "MSXML2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP"].each(function() {
			try {
				web_req = new ActiveXObject(this);
				return false;
			}
			catch (ex) {
			}
		});
		return web_req;
	};
}

function clipboardCopy(text) {
	if (window.clipboardData && window.clipboardData.setData) window.clipboardData.setData("Text", text);
}

// Colours

function hex2rgb(c) {
	if (typeof c == "string") {
		var match = c.match(/^#*([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i);
		if (match) {
			return {
				r: parseInt(match[1], 16),
				g: parseInt(match[2], 16),
				b: parseInt(match[3], 16)
			};
		}

		match = c.match(/^rgb\(([0-9]{1,3}), *([0-9]{1,3}), *([0-9]{1,3})\)$/i);
		if (match) {
			return {
				r: parseInt(match[1], 10),
				g: parseInt(match[2], 10),
				b: parseInt(match[3], 10)
			};
		}
	}
}

function rgb2hex(c) {
	if (c instanceof Object && c.hasOwnProperty("r") && c.hasOwnProperty("g") && c.hasOwnProperty("b")) {
		return "#" + parseInt(c.r, 10).toBase(16, 2) + parseInt(c.g, 10).toBase(16, 2) + parseInt(c.b, 10).toBase(16, 2);
	}
}

// Cookies

function setCookie(name, value, expires, path, domain, secure) {
	var str = name + "=" + escape(value);
	if (expires instanceof Date) {
		str += "; expires=" + expires.toGMTString();
	} else if (typeof expires == "number") {
		var date = new Date();
		date.setTime(date.getTime() + expires * 24 * 60 * 60 * 1000);
		str += "; expires=" + date.toGMTString();
	} else if (typeof expires == "string") {
		str += "; expires=" + expires;
	}
	if (path) str += "; path=" + escape(path);
	if (domain) str += "; domain=" + escape(domain);
	if (secure) str += "; secure";
	document.cookie = str;
}

function getCookie(name) {
	name += "=";
	var ca = document.cookie.split("; ");
	for (var i = 0; i < ca.length; ++i) {
		if (ca[i].substr(0, name.length) == name) return unescape(ca[i].substr(name.length));
	}
}

function deleteCookie(name) {
	setCookie(name, "", new Date());
}

// VML objects

function line(ar, flg, linecolr) {
	if (typeof ar == "string") ar = ar.split("|");
	if (!(ar instanceof Array)) return;
	var i, x1 = parseInt(ar[0], 10), y1 = parseInt(ar[1], 10), x2, y2, str = "<v:polyline points='" + x1 + "," + y1;
	if (flg) {
		ar.push(x1);
		ar.push(y1);
	}
	for (i = 2; i < ar.length; i += 2) {
		x2 = ar[i];
		y2 = ar[i + 1];
		if (typeof x2 == "string" && (x2.charAt(0) == "+" || x2.charAt(0) == "-")) x2 = x1 + parseInt(x2, 10);
		if (typeof y2 == "string" && (y2.charAt(0) == "+" || y2.charAt(0) == "-")) y2 = y1 + parseInt(y2, 10);
		str += " " + x2 + "," + y2;
		x1 = x2;
		y1 = y2;
	}
	str += "'" + ((linecolr) ? (" strokecolor='" + linecolr + "'") : "") + " filled='false'/>";
	return str;
}

function rect(x, y, w, h, linecolr, fillcolr, fillcolr2, ang, foc) {
	return "<v:rect style='margin-left: " + x + "px; margin-top: " + y + "px; width: " + w + "px; height: " + h + "px;'" + shapecolr(linecolr, fillcolr, fillcolr2, ang, foc) + "</v:rect>";
}

function ellipse(x, y, w, h, linecolr, fillcolr, fillcolr2, ang, foc) {
	return "<v:oval style='margin-left: " + (x - (w - 1) / 2) + "px; margin-top: " + (y - (h - 1) / 2) + "px; width: " + w + "px; height: " + h + "px;'" + shapecolr(linecolr, fillcolr, fillcolr2, ang, foc) + "</v:oval>";
}

function polygon(ar, linecolr, fillcolr, fillcolr2, ang, foc) {
	if (typeof ar == "string") ar = ar.split("|");
	if (!(ar instanceof Array)) return;
	var i, x1 = parseInt(ar[0], 10), y1 = parseInt(ar[1], 10), x2, y2, lx = x1, hx = x1, ly = y1, hy = y1;
	for (i = 2; i < ar.length; i += 2) {
		x2 = ar[i];
		y2 = ar[i + 1];
		if (typeof x2 == "string" && (x2.charAt(0) == "+" || x2.charAt(0) == "-")) x2 = x1 + parseInt(x2, 10);
		if (typeof y2 == "string" && (y2.charAt(0) == "+" || y2.charAt(0) == "-")) y2 = y1 + parseInt(y2, 10);
		ar[i] = x2;
		ar[i + 1] = y2;

		lx = Math.min(lx, x2);
		hx = Math.max(hx, x2);
		ly = Math.min(ly, y2);
		hy = Math.max(hy, y2);

		x1 = x2;
		y1 = y2;
	}

	var str = "<v:shape style='margin-left: " + lx + "px; margin-top: " + ly + "px; width: " + (hx - lx + 1) + "px; height: " + (hy - ly + 1) + "px;' coordsize='" + (hx - lx + 1) + "," + (hy - ly + 1) + "' path='m " + (ar[0] - lx) + "," + (ar[1] - ly) + " l";
	for (i = 2; i < ar.length; i += 2) str += " " + (ar[i] - lx) + "," + (ar[i + 1] - ly);
	str += " x e'" + shapecolr(linecolr, fillcolr, fillcolr2, ang, foc) + "</v:shape>";
	return str;
}

function shapecolr(linecolr, fillcolr, fillcolr2, ang, foc) {
	return ((linecolr && linecolr != 0) ? " strokecolor='" + linecolr + "'" : "") +
	((linecolr == 0) ? " stroked='false'" : "") +
	((fillcolr) ? " fillcolor='" + fillcolr + "'" : " filled='false'") + ">" +
	((fillcolr2) ? "<v:fill type='gradient' method='linear' color2='" + fillcolr2 + "'" + ((ang) ? " angle='" + ang + "'" : "")  + ((foc) ? " focus='" + foc + "%'" : "") + " />" : "");
}

// Basic functions for DHTML positioned elements that will work on
// both Netscape Navigator and Internet Explorer (version 4.0 and above)

function getObj(name) {
	if (name instanceof Object) return name;
	if (typeof name != "string") return;
	if (document.getElementById) return document.getElementById(name);
	if (document.all) return document.all[name];
	if (document.layers) return findObj(name);
}

function findObj(name, obj) {
	if (obj == null) obj = document;
	var layer;
	for (var i in obj.layers) {
		layer = obj.layers[i];
		if (layer.name == name) return layer;
		if (layer.document.layers.length > 0) {
			layer = findObj(name, layer.document);
			if (layer) return layer;
		}
	}
}

