function PasswordGenerator(pstrPattern, pintMin, pintMax, pblnAllowDup)
{
	var LOWER_CASE = "abcdefghijklmnopqrstuvwzyz";
	var UPPER_CASE = "ABCDEFGHIJKLMNOPQRSTUVWZYZ";
	var NUMBERS    = "0123456789";
	var SYMBOLS    = "~!@#$%^&*()-_+={}[]|\:;?/,.<>";

	var intMin = 0;
	var intMax = 0;
	var blnAllowDup = pblnAllowDup;
	var strPattern = "";

	if (isNaN(pintMin))
		intMin = 8;
	else if (pintMin <= 0)
		intMin = 8;
	else
		intMin = pintMin;

	if (isNaN(pintMax))
		intMax = 15;
	else if (pintMax <= 0)
		intMax = 15;
	else
		intMax = pintMax;

	if (intMax < intMin) intMax = 2 * intMin;
	if (pstrPattern == null || pstrPattern == undefined || pstrPattern == "")
		strPattern = genPattern(intMax);
	else if (pstrPattern.length < intMax)
		strPattern = genPattern(intMax);
	else
		strPattern = pstrPattern.toUpperCase();

	checkPattern(strPattern);

	this.Pattern = function() {return strPattern;};
	this.Password = function() {
		var strRet = "";
		var iCntr  = 0;
		var chrTmp = "";

		for (iCntr = 0; iCntr < intMax; iCntr++)
		{
			chrTmp = strPattern.charAt(iCntr);
			switch (chrTmp)
			{
				case "9":
					chrTmp = getRandomChar(NUMBERS, strRet, blnAllowDup);
					strRet += chrTmp;
					break;					
				case "L":
					chrTmp = getRandomChar(LOWER_CASE, strRet, blnAllowDup);
					strRet += chrTmp;
					break;					
				case "U":
					chrTmp = getRandomChar(UPPER_CASE, strRet, blnAllowDup);
					strRet += chrTmp;
					break;					
				case "S":
					chrTmp = getRandomChar(NUMBERS, strRet, blnAllowDup);
					//chrTmp = getRandomChar(SYMBOLS, strRet, blnAllowDup);
					strRet += chrTmp;
					break;					
				default:
					throw "Unsupported pattern character [" + chtTmp + "] at " + iCntr;
			}
		}
		return strRet;
	}

	function checkPattern(pstrPattern, pblnAllowDup)
	{
		var totLower = 0;
		var totUpper = 0;
		var totSym   = 0;
		var totNum   = 0;
		var arrTmp = null;

		arrTmp = pstrPattern.match("L", "g");
		if (arrTmp) totLower = arrTmp.length;
		arrTmp = pstrPattern.match("U", "g");
		if (arrTmp) totUpper = arrTmp.length;
		arrTmp = pstrPattern.match("S", "g");
		if (arrTmp) totSym = arrTmp.length;
		arrTmp = pstrPattern.match("9", "g");
		if (arrTmp) totNum = arrTmp.length;
	
		if (totLower > LOWER_CASE.length && !pblnAllowDup)
			throw "Lower case pattern exceeds avaliable charset length!";
		if (totUpper > UPPER_CASE.length && !pblnAllowDup)
			throw "Upper case pattern exceeds avaliable charset length!";
		if (totSym > SYMBOLS.length && !pblnAllowDup)
			throw "Symbol pattern exceeds avaliable charset length!";
		if (totNum > NUMBERS.length && !pblnAllowDup)
			throw "Numeric pattern exceeds avaliable charset length!";
	}
}

function genPattern(pintLen)
{
	var strRet = "";
	var iCntr  = 0;
	var rndNo  = 0;

	for (iCntr = 0; iCntr < pintLen; iCntr++)
	{
		rndNo = Math.floor((4 - 1 + 1) * Math.random() + 1)
		switch (rndNo)
		{
			case 1:
				strRet += "9";
				break;
			case 2:
				strRet += "U";
				break;
			case 3:
				strRet += "S";
				break;
			case 4:
				strRet += "L";
				break;
		}
	}
	return strRet;
}

function getRandomChar(pstrSet, pstrProcessed, pblnAllowDup)
{
	var intRnd = 0;
	var chrRet = "";
	var intLimit = pstrSet.length;

	intRnd = Math.floor((intLimit - 0 + 1) * Math.random() + 1);
	if (pblnAllowDup)
		chrRet = pstrSet.charAt(intRnd);
	else
	{
		chrRet = pstrSet.charAt(intRnd);
		while (pstrProcessed.indexOf(chrRet) >= 0)
		{
			intRnd = Math.floor((intLimit - 0 + 1) * Math.random() + 1);
			chrRet = pstrSet.charAt(intRnd);
		}
	}
	return chrRet;
}
