<cffunction name="deleteCFML" access="private" output="false"
	hint="Helper function to delete all non-opensource CFML files from a folder (used in Railo deployment)">
	<cfargument name="folder" type="string" required="true">
	<cfargument name="lstOpenSource" type="string" required="true">
	<cfargument name="qryManifest" type="any" required="true">
	<cfargument name="startFolder" type="string" required="false" default="#arguments.folder#">
	
	<cfset var dirList = "">
	<cfset var exts = "*.cfm,*.cfml,*.cfc,*.cfr">
	<cfset var ext = "">
	<cfset var sName = "">
	<cfset var qryManifestCheck = "">
	<!--- the list of open source files now contains "\Intranet" in the path, remove that from the path for deleteCFML compatibility  --->
	<cfset arguments.lstOpenSource = ReplaceNoCase(arguments.lstOpenSource,"\Intranet","","all")>
	<!--- ignore product updates folder --->
	<cfif arguments.folder NEQ "#arguments.startFolder#\Updates">
	
		<!--- delete all cfm, cfml, cfr, and cfc files in the folder (not open source and in manifest) --->
		<cfloop list="#exts#" index="ext">
			<cfdirectory action="list" type="file" filter="#ext#" directory="#arguments.folder#" name="dirList">
			<cfloop query="dirList">
				
				<!--- convert file name to compiled class name --->
				<cfset sName = dirList.name>
				<cfif IsNumeric(Left(sName, 1))>
					<cfset sName = "_" & sName>
				</cfif>
				<cfset sName = LCase("#ReplaceNoCase(ReplaceNoCase(arguments.folder, arguments.startFolder, ''), '\', '/', 'all')#/#sName#")>
				<cfset sName = ReplaceNoCase(sName, ".cfm", "_cfm$cf.class")>
				<cfset sName = ReplaceNoCase(sName, ".cfml", "_cfml$cf.class")>
				<cfset sName = ReplaceNoCase(sName, ".cfr", "_cfr$cf.class")>
				<cfset sName = ReplaceNoCase(sName, ".cfc", "_cfc$cf.class")>
				<cfset sName = Right(sName, Len(sName) - 1)>
					
				<!--- check if file is in manifest --->				
				<cfquery name="qryManifestCheck" dbtype="query">
					SELECT		*
					FROM		qryManifest
					WHERE		name = '#sName#'
				</cfquery>
				
				<!--- delete file --->
				<cfif NOT ListFindNoCase(arguments.lstOpenSource, "#ReplaceNoCase(arguments.folder, arguments.startFolder, '')#\#dirList.name#")
					AND qryManifestCheck.RecordCount
					AND NOT FindNoCase("cfregdn.cfm", dirList.name)>
					<cffile action="delete" file="#arguments.folder#\#dirList.name#">
				</cfif>
			</cfloop>
		</cfloop>
		
		<!--- do the same for any sub folders --->
		<cfdirectory action="list" type="dir" directory="#arguments.folder#" name="dirList">
		<cfloop query="dirList">
			<cfset deleteCFML(folder = "#arguments.folder#\#dirList.name#", 
				lstOpenSource = arguments.lstOpenSource, 
				qryManifest = arguments.qryManifest, 
				startFolder = arguments.startFolder)>
		</cfloop>
		
	</cfif>
	
</cffunction>

<cffunction name="deployPackage" access="private" output="false">
	<cfargument name="packagePath" type="string" required="true">
	<cfargument name="intranetRoot" type="string" required="true">
	<cfargument name="installRoot" type="string" required="true">
	<cfargument name="intranetFolder" type="string" required="true">
	
	<cfset var tempLocation = "#intranetRoot#\Updates\package">
	
	<!--- unzip package to temp location --->
	<cfif NOT DirectoryExists("#intranetRoot#\Updates\package")>
		<cfdirectory action="create" directory="#tempLocation#">
	</cfif>
	<cfzip action="unzip" 
		file="#intranetRoot#\Updates\package.zip"
		destination="#tempLocation#" 
		overwrite="yes" />
	
	<!--- rename "Intranet" folder if different --->
	<cfif intranetFolder NEQ "Intranet">
		<cfdirectory action="rename" 
			directory="#intranetRoot#\Updates\package\Intranet" 
			newdirectory="#intranetRoot#\Updates\package\#intranetFolder#">
	</cfif>
	
	<!--- copy from temp location to installation locations --->
	<cfdirectory action="copy"
		destination="#installRoot#" 
		directory="#tempLocation#"
		nameconflict="overwrite"
		recurse="true">
	
	<!--- delete temp location --->
	<cfdirectory action="delete"
		directory="#tempLocation#"
		recurse="true">
	
	<cfreturn />
</cffunction>

<!--- date/time string parsing functions --->
<cfscript>
function stringToDate(sDate, dateformat)
{
	var iYrFutr = 30;
	var iMhFutr = 5;
	var MONTH_NAMES = ListToArray(ValueList(application.cache.qryDateMonth.ShortFormat));
	var LONG_MONTH_NAMES = ListToArray(ValueList(application.cache.qryDateMonth.DisplayFormat));
	var dDate = '';
	var dToday = Now();
	var bBad = false;
	var i = 0;
		
	// Handle Empty String
	sDate = Trim(sDate);
	if (sDate == '')
		return dDate;
	
	// Remove day names from date format and ensure no stray separators at beginning or end of string
	dateformat = Trim(Replace(Replace(dateformat, "dddd", ""), "ddd", ""));
	dateformat = ReMatchNoCase("[dmy]+.*[dmy]+", dateformat);
	dateformat = dateformat[1];
		
	// Initialize
	iYr = Find('y', dateformat);
	iMh = Find('m', dateformat);
	iDay = Find('d', dateformat);
	if (iYr < iMh && iMh < iDay) order = 'ymd';
	else if (iMh < iDay && iDay < iYr) order = 'mdy';
	else order = 'dmy';
	
	// Handle spelled out months
	sDate = LCase(sDate);
	for (i = 1; i <= ArrayLen(MONTH_NAMES); i++)
	{
		sMth = '' & (i);
		if (Len(sMth) == 1) sMth = '0' & sMth;
		if (Find(LCase(LONG_MONTH_NAMES[i]), sDate) != 0 || Find(LCase(MONTH_NAMES[i]), sDate) != 0)
		{
			switch (order)
			{
				case "ymd":
					// YMD Example: 1996Jan24 -> 1996/1/24
					sDate = Replace(Replace(sDate, LCase(LONG_MONTH_NAMES[i]), '/' & sMth & '/'), LCase(MONTH_NAMES[i]), '/' & sMth & '/');
					break;
				case "mdy":
					// MDY Example: Jan24,1996 -> 1/24,1996
					sDate = Replace(Replace(sDate, LCase(LONG_MONTH_NAMES[i]), sMth & '/'), LCase(MONTH_NAMES[i]), sMth & '/');
					break;
				case "dmy":
					// DMY Example: 24Jan1996 -> 24/1/1996
					sDate = Replace(Replace(sDate, LCase(LONG_MONTH_NAMES[i]), '/' & sMth & '/'), LCase(MONTH_NAMES[i]), '/' & sMth & '/');
					break;
			}
		}
	}
	
	// Change all separators to slashes for easier manipulation, remove duplicate slashes
	// and insert separators if needed
	sDate = Replace(sDate, ' ', '/', 'All');
	sDate = REReplace(sDate, '\.+|,+|-+', '/', 'All');
	sDate = Replace(Replace(sDate, '//', '/', 'All'), '//', '/', 'All');
	
	if (Find('/', sDate) == 0)
	{
		iLen = Len(sDate);
		if (iLen <= 2)
		{
			// OK, just the day, handled later
		}
		else if (iLen == 4)
		{
			sDate = Left(sDate, 2) & '/' & Right(sDate, 2);
		}
		else if (iLen == 6)
		{
			sDate = Left(sDate, 2) & '/' & Mid(sDate, 3, 2) & '/' & Right(sDate, 2);
		}
		else if (iLen == 8)
		{
			if (order == 'ymd')
				sDate = Left(sDate, 4) & '/' & Mid(sDate, 5, 2) & '/' & Right(sDate, 2);
			else
				sDate = Left(sDate, 2) & '/' & Mid(sDate, 3, 2) & '/' & Right(sDate, 4);
		}
		else
		{
			// Bad string
			bBad = true; 
		}
	}
	
	if (!bBad)
	{
		// At this point, a valid string would only contain digits and slashes.
		// Here's a quick way to make sure that's the case.  Also, make sure 
		// there are no more than two slashes.
		if (Len(REReplace(sDate, '[0-9]+|/', '', 'All')) != 0)
			bBad = true;
		iSlashCount = 0;
		for (i = 1; i <= Len(sDate); i++)
		{
			if(Mid(sDate, i, 1) == '/') iSlashCount += 1;
		}
		if (iSlashCount > 2)
			bBad = true;
	}	
	
	if (!bBad)
	{
		// Acquire the 3 numbers (if they exist) that are separated by slashes
		iYr = -1;
		iMh = -1;
		iDay = -1;
		aNums = ListToArray(sDate, '/');
		if (ArrayLen(aNums) < 1 || aNums[1] == '') aNums[1] = -1;
		if (ArrayLen(aNums) < 2 || aNums[2] == '') aNums[2] = -1;
		if (ArrayLen(aNums) < 3 || aNums[3] == '') aNums[3] = -1;
		
		// Populate the month, day, year from the 3 numbers
		if (sDate == '/')
		{
			// Today
			iMh = Month(dToday);
			iDay = Day(dToday);
			iYr = Year(dToday);
		}
		else if (Find('/', sDate) == 0)
		{
			// Day Only
			iMh = Month(dToday);
			iDay = aNums[1];
			iYr = Year(dToday);
		}
		else if (order == 'mdy')
		{
			// MM/DD/YYYY
			iMh = aNums[1];
			iDay = aNums[2];
			iYr = aNums[3];
		}
		else if (order == 'dmy')
		{
			// DD/MM/YYYY
			iDay = aNums[1];
			iMh = aNums[2];
			iYr = aNums[3];
		}
		else if (order == 'ymd')
		{
			// YYYY/MM/DD
			if (ArrayLen(ListToArray(sDate, '/')) == 2)
			{
				iYr = -1;
				iMh = aNums[1];
				iDay = aNums[2];
			}
			else
			{
				iYr = aNums[1];
				iMh = aNums[2];
				iDay = aNums[3];
			}
		}
				
		// Fill in pieces that were not input
		if (iDay == -1) iDay = 1;
		if (iMh == -1) iMh = Month(dToday);
		if (iYr == -1)
		{
			if (iMhFutr == 0) iYr = Year(dToday);
			else 
			{
				iYr = Year(dToday)-1;
				dTmp = DateAdd('m', Month(dToday)+(iMhFutr-12), dToday);
				sYmBarrier = '' & Year(dTmp) & IIf(Month(dTmp) < 10, '0' & Month(dTmp), Month(dTmp));
				while ('' & (iYr * 100 + iMh) < sYmBarrier)
				{
					iYr += 1;
				}
			}
			
		}
				
		// Handle 2-digit year assumptions
		if (iYr < 100)
		{
			if (iYrFutr == 0) iYr = Fix(Year(dToday)/100) * 100 + iYr;
			else
			{
				iYr += 1800;
				while (iYr < (Year(dToday) + iYrFutr - 99))
				{
					iYr += 100;
				}
			}
		}
		
		// Check if day and month are valid.
		if (iMh > 12 or iMh <= 0) return dDate;
		if (iDay > DaysInMonth(CreateDate(iYr, iMh, 1))) return dDate;
				
		// Construct the date
		dDate = CreateDate(iYr, iMh, iDay);
	}

	return dDate;
}
function stringToTime(sTime, timeformat)
{
	var dTime = '';
	var dNow = Now();
	var ampm = '';
	var bBad = false;
	var i = 0;
	
	// Handle Empty String
	sTime = Trim(sTime);
	if (sTime == '')
		return dTime;
	
	if(len(sTime) lt 4 and not Find(":", sTime))
	{
		sTime = "#RepeatString("0", 4-len(sTime))##sTime#";
	}
	
	// Initialize
	format = '';
	if (Find('HH', timeformat) != 0) format = '24';
	else format = '12';
	sTime = Replace(LCase(sTime), ' ', '', 'All');
	
	// Determine am/pm if possible
	if (format == '12')
	{
		if (Mid(sTime, Len(sTime)-1, 1) == 'a' || Mid(sTime, Len(sTime)-2, 2) == 'am')
		{
			ampm = 'AM';
			sTime = Replace(Replace(sTime, 'am', '', 'All'), 'a', '', 'All');
		}
		else if (Mid(sTime, Len(sTime)-1, 1) == 'p' || Mid(sTime, Len(sTime)-2, 2) == 'pm')
		{
			ampm = 'PM';
			sTime = Replace(Replace(sTime, 'pm', '', 'All'), 'p', '', 'All');
		}
	}
		
	// Change all separators to colons for easier manipulation, remove duplicate colons
	// and insert separators if needed
	sTime = REReplace(sTime, '\.+|,+|:+', ':', 'All');
	sTime = Replace(Replace(sTime, '::', ':', 'All'), '::', ':', 'All');
	
	if (Find(':', sTime) == 0)
	{
		iLen = Len(sTime);
		if (iLen <= 2)
		{
			// OK, just the hour, handled later
		}
		else if (iLen == 3)
		{
			sTime = Left(sTime, 1) & ':' & Right(sTime, 2);
		}
		else if (iLen == 4)
		{
			sTime = Left(sTime, 2) & ':' & Right(sTime, 2);
		}
		else if (iLen == 5)
		{
			sTime = Left(sTime, 1) & ':' & Mid(sTime, 2, 2) & ':' & Right(sTime, 2);
		}
		else if (iLen == 6)
		{
			sTime = Left(sTime, 2) & ':' & Mid(sTime, 3, 2) & ':' & Right(sTime, 2);
		}
		else
		{
			// Bad string
			bBad = true; 
		}
	}

	if (!bBad)
	{
		// At this point, a valid string would only contain digits and colons.
		// Here's a quick way to make sure that's the case.  Also, make sure 
		// there are no more than two colons.
		if (Len(REReplace(sTime, '[0-9]+|:', '', 'All')) != 0)
			bBad = true;
		iColonCount = 0;
		for (i = 1; i <= Len(sTime); i++)
		{
			if(Mid(sTime, i, 1) == ':') iColonCount += 1;
		}
		if (iColonCount > 2)
			bBad = true;
	}	
	
	if (!bBad)
	{
		// Acquire the 3 numbers (if they exist) that are separated by colons
		iH = 0;
		iM = 0;
		iSS = 0;
		aNums = ListToArray(sTime & '::', ':');
		if (ArrayLen(aNums) < 1 || aNums[1] == '') aNums[1] = 0;
		if (ArrayLen(aNums) < 2 || aNums[2] == '') aNums[2] = 0;
		if (ArrayLen(aNums) < 3 || aNums[3] == '') aNums[3] = 0;
		
		// Populate the hours, minutes, seconds from the 3 numbers
		if (sTime == ':')
		{
			// Now
			iH = Hour(dNow);
			iM = Minute(dNow);
			iSS = Second(dNow);
		}
		else if (Find(':', sTime) == -1)
		{
			// Hour Only
			iH = aNums[1];
			iM = 0;
			iSS = 0;
		}
		else if (format == '24')
		{
			// HH:mm:ss
			iH = aNums[1];
			iM = aNums[2];
			iSS = aNums[3];
		}
		else if (format == '12')
		{
			// h:mm:ss tt
			iH = aNums[1];
			iM = aNums[2];
			iSS = aNums[3];
		}
		
		// Handle the am/pm
		if (format == '12' && ampm == 'AM' && iH == 12)
			iH = iH - 12;
		else if (format == '12' && ampm == 'PM' && iH > 0 && iH < 12)
			iH = iH + 12;
		else if (format == '12' && ampm == '' && iH > 0 && iH < 7 )
			iH = iH + 12;
		
		if(iH eq 24)
		{
			iH = 0;
			dNow = DateAdd("d", 1, dNow);
		}
		
		// Construct the time
		dTime = CreateDateTime(Year(dNow), Month(dNow), Day(dNow), iH, iM, iSS);
	}
	
	return dTime;
}
function utcStringToDateTime(sUTC)
{
	var sTemp = ListRest(Replace(arguments.sUTC, ' UTC', ''), ' ');
	var sTime = Right(sTemp, 8);
	var sDate = Replace(sTemp, ' ' & sTime, '');
	var dDate = stringToDate(sDate, 'dddd mmmm d, yyyy');
	var dTime = stringToTime(sTime, 'HH:mm:ss');
	return CreateDateTime(Year(dDate), Month(dDate), Day(dDate), Hour(dTime), Minute(dTime), Second(dTime));
}
</cfscript>