PageSourceSearch

https://calvertcountymd.gov/Common/GlobalJSFunctionsDetail.js

js calvertcountymd.gov collected 2026-09-24 19:46:51 UTC 121,687 bytes, 3,550 lines download raw bytes

1/// <reference name="MicrosoftAjax.js" />
2/// <reference name="Util.js" />
3/// <reference path="GlobalJSFunctionsDetail.js" />
4
5//Callback global variables for Slideshow.
6var callbackfnDocumentCenter = null;
7var callbackfnSlideshowSave = null;
8var $popUp_Slideshow = null;
9var parentID_Slideshow = null;
10var slideshowFolderDefault = '';
11var numbersOnly = new RegExp('^[0-9]*$');
12//Global variable for ThemeProperties modal
13var $popup_ThemeProperties = null;
14//Callback variables for Slideshow.
15var SetCursorPosition = null;
16
17// Prevents errors for Internet Explorer (modes prior to 9).
18// They will occur unless the developer tools are open.
19if (!window.console) {
20	var noop = function () { };
21
22	// Note: MSIE will override this once the dev. tools are open.
23	window.console = {
24		log: noop, clear: noop, warn: noop, error: noop, assert: noop,
25		dir: noop, count: noop, profile: noop, profileEnd: noop,
26		trace: noop, info: noop, memoryProfile: noop, memoryProfileEnd: noop,
27		exception: noop, debug: noop, dirxml: noop, group: noop, groupEnd: noop,
28		markTimeline: noop, time: noop, timeEnd: noop, groupCollapsed: noop
29	};
30}
31
32// User-agent sniffing for functions that rely on the user-agent
33// to determine version of Safari. Avoid using this variable and
34// check for the presence of features instead (best-practice).
35var isWebKit = (navigator.userAgent.toLowerCase().indexOf('webkit') > -1);
36
37// Determines if an array contains an object.
38// Uses == equality, case-sensitive. a containsExact() could do === equality.
39if (!Array.prototype.contains) {
40	Array.prototype.contains = function (item) {
41		for (var i = 0; i < this.length; i++) {
42			if (this[i] == item)
43				return true;
44		}
45		return false;
46	}
47}
48
49// Gets index of an item if it is present in the array, else returns -1.
50if (!Array.prototype.indexOf) {
51	Array.prototype.indexOf = function (item) {
52		for (var i = 0; i < this.length; i++) {
53			if (this[i] == item)
54				return i;
55		}
56		return -1;
57	}
58}
59
60// Implement ECMAScript 5 String.trim() and friends for browsers that
61// don't have it (e.g. Firefox prior to 3.5, Internet Explorer 6, 7, 8).
62if (!String.prototype.trim) {
63	String.prototype.trim = function () {
64		return this.replace(/^\s+/g, "").replace(/\s+$/g, "");
65	}
66	String.prototype.trimLeft = function () {
67		return this.replace(/^\s+/g, "");
68	}
69	String.prototype.trimRight = function () {
70		return this.replace(/\s+$/g, "");
71	}
72}
73
74// Implement .NET-style left-padding method.
75String.prototype.padLeft = function (desiredLength, paddingChar) {
76	paddingChar += '';
77	desiredLength = parseInt(desiredLength);
78
79	if (paddingChar.length > 1)
80		paddingChar = paddingChar.charAt(0);
81	else if (paddingChar.length < 1)
82		return this;
83
84	if (this.length >= desiredLength)
85		return this;
86	else {
87		var arr = new Array();
88		var padNum = desiredLength - this.length;
89
90		for (var i = 0; i < padNum; i++)
91			arr.push(paddingChar);
92
93		return arr.join('') + this;
94	}
95}
96
97// Implement .NET-style right-padding method.
98String.prototype.padRight = function (desiredLength, paddingChar) {
99	paddingChar += '';
100	desiredLength = parseInt(desiredLength);
101
102	if (paddingChar.length > 1)
103		paddingChar = paddingChar.charAt(0);
104	else if (paddingChar.length < 1)
105		return this;
106
107	if (this.length >= desiredLength)
108		return this;
109	else {
110		var arr = new Array();
111		var padNum = desiredLength - this.length;
112
113		for (var i = 0; i < padNum; i++)
114			arr.push(paddingChar);
115
116		return this + arr.join('');
117	}
118}
119
120String.isNullOrEmpty = function (text) {
121	return (text == null || text == '');
122}
123
124// Adds static method to regular expressions that escapes meta-characters.
125if (!RegExp.metaEscape) {
126	RegExp.metaEscape = function (text) {
127		if (text == null)
128			return null;
129		else if (typeof (text) != "string")
130			text += '';
131
132		return text.replace(/(\\|\/|\<|\>|\:|\.|\*|\+|\?|\$|\[|\]|\(|\)|\{|\}|\||\&)/g, '\\$1');
133	};
134}
135
136// Copies text data to clipboard in WebKit browsers (Chrome/Safari).
137function toWebkitClipboard(text) {
138	// Create element in DOM with text to copy.
139	var tmp = document.createElement('div');
140	tmp.textContent = text;
141	document.body.appendChild(tmp);
142
143	// Get current user selection, and remove selection current ranges.
144	var curSelection = window.getSelection();
145	curSelection.removeAllRanges();
146
147	// Create new selection range with DOM element containing text to copy.
148	var textRange = document.createRange();
149	textRange.selectNode(tmp);
150	curSelection.addRange(textRange);
151
152	// Execute COPY DHTML command.
153	document.execCommand("Copy");
154
155	// Clean-up.
156	document.body.removeChild(tmp);
157}
158
159// Copies value in stringVal to the clipboard, displaying the successMessage if hideAlert is false.
160// NOTE: Replace this with something like toWebkitClipboard() at some point.
161function toClipboardEx(stringVal, hideAlert, successMessage) {
162	if (window.clipboardData) {		// Internet Explorer
163		if (!window.clipboardData.setData("Text", stringVal) && !hideAlert)
164			hideAlert = true;
165	}
166	else if ((window.WebKitPoint || !window.netscape) && !window.opera) {
167		toWebkitClipboard(stringVal);
168	}
169	else if (window.netscape) {	// Mozilla Firefox and derivitives (Netscape, Seamonkey)...
170		try {
171			// Request full access to the XPCOM (Cross-Platform COM) API.
172			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
173		}
174		catch (e) {
175			// Unable to obtain access, user rejected or setting in about:config not set right.
176			alert('Please type "about:config" in your browser and press enter. Type "signed.applets.codebase_principal_support" in Filter. Double click to change the value to "true". Then come back and click on the link again.\n\nIf you have already performed this action, make sure when you are asked whether to allow or deny the browser permission, that you are allowing it.');
177			return;
178		}
179
180		// Create an instance of the clipboard class.
181		var clipBoard = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard);
182
183		// Create an instance of the Transferable class (used to talk to the clipboard).
184		var clipTrans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
185
186		// Set clipboard format for text only.
187		clipTrans.addDataFlavor('text/unicode');
188
189		// Create XPCOM string, set data to copy of stringVal.
190		var clipString = Components.classes["@mozilla.org/supports-string;1"].createInstance(Components.interfaces.nsISupportsString);
191		var copyText = stringVal;
192		clipString.data = copyText;
193
194		// Note: This code may be bugged in some scenarios! 1 char does not always equal 2 bytes in UTF-16!
195		// Set data to transfer to the clipboard (length * 2, since 1 char is usually 2 bytes in UTF-16).
196		clipTrans.setTransferData("text/unicode", clipString, copyText.length * 2);
197
198		// Transfer data to the global clipboard.
199		clipBoard.setData(clipTrans, null, clipBoard.kGlobalClipboard);
200	}
201
202	if (!hideAlert)
203		alert(successMessage);
204
205	return true;
206}
207
208function toClipboard(stringVal, hideAlert) {
209	return toClipboardEx(stringVal, hideAlert, "The link has been copied to your clipboard.");
210}
211
212function getClipboard() {
213	if (window.clipboardData) {
214		return window.clipboardData.getData('Text');
215	} else if (window.netscape) {
216		try {
217			netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
218		}
219		catch (e) {
220			alert('Please type "about:config" in your browser and press enter. Type "signed.applets.codebase_principal_support" in Filter. Double click to change the value to "true". Then come back and click on the link again.\n\nIf you have already performed this action, make sure when you are asked whether to allow or deny the browser permission, that you are allowing it.');
221			return;
222		}
223
224		// Create instances of the Clipboard and Transferable objects.
225		var clipBoard = Components.classes['@mozilla.org/widget/clipboard;1'].createInstance(Components.interfaces.nsIClipboard);
226		var clipTrans = Components.classes['@mozilla.org/widget/transferable;1'].createInstance(Components.interfaces.nsITransferable);
227
228		// Get data from global clipboard, place in clipTrans object.
229		clipTrans.addDataFlavor('text/unicode');
230		clipBoard.getData(clipTrans, clipBoard.kGlobalClipboard);
231
232		// Create objects to pass to getTransferData, which uses XPCOM String
233		// and Integer classes instead of those normally used by JavaScript.
234		var objStr = new Object(); var objNumBytes = new Object();
235		try {
236			clipTrans.getTransferData('text/unicode', objStr, objNumBytes);
237		}
238		catch (error) {
239			return '';
240		}
241
242		// Query whichever interface is available, opting to use nsISupportsWString.
243		if (objStr) {
244			if (Components.interfaces.nsISupportsWString)
245				objStr = objStr.value.QueryInterface(Components.interfaces.nsISupportsWString);
246			else if (Components.interfaces.nsISupportsString)
247				objStr = objStr.value.QueryInterface(Components.interfaces.nsISupportsString);
248			else
249				objStr = null;
250		}
251
252		// Note: This code may be bugged in some scenarios! 1 char does not always equal 2 bytes in UTF-16!
253		// Get data out of the XPCOM string and into a normal JS string.
254		if (objStr)
255			return (objStr.data.substring(0, objNumBytes.value / 2));
256	}
257	return;
258}
259
260// Gets the computed style of an element (browser-independent).
261var getCurrentStyle = (document.defaultView ?
262	function (elem) {
263		return document.defaultView.getComputedStyle(elem, '');
264	} :
265	function (elem) {
266		return elem.currentStyle;
267	}
268);
269
270// Gets children nodes of an HTML DOM element matching the tag name specified.
271function getChildNodesByTag(domElement, tagName) {
272	var cn = domElement.childNodes;
273	var nodesPresent = 0, retVal = new Array();
274	retVal.length = cn.length;
275
276	tagName = tagName.toUpperCase();
277	for (var cv = 0;
277 cv < cn.length; cv++) {
278		if (cn[cv].nodeType == 1 && cn[cv].nodeName == tagName)
279			retVal[nodesPresent++] = cn[cv];
280	}
281
282	return retVal.slice(0, nodesPresent);
283}
284
285// Returns true on Safari browsers 1.3.4 and older (bad date object behavior in old Safari).
286// Check does not work properly if user-agent has been modified by user.
287var isSafariVersion13OrOlder = (isWebKit ?
288	function () {
289		var navAppVersion = navigator.appVersion;
290		var phraseToFind = 'AppleWebKit/';
291		var foundStartAt = navAppVersion.indexOf(phraseToFind) + phraseToFind.length;
292		var foundEndAt = navAppVersion.indexOf(' ', foundStartAt + 1);
293		return (parseInt(navAppVersion.substring(foundStartAt, foundEndAt)) < 320);
294	} :
295	function () {
296		return false;
297	}
298);
299
300// Returns true on Safari browsers 2.0.4 and older (textbox/button not stylable before 3.x).
301// Check does not work properly if user-agent has been modified by user.
302var isSafariVersion20OrOlder = (isWebKit ?
303	function () {
304		var navAppVersion = navigator.appVersion;
305		var phraseToFind = 'AppleWebKit/';
306		var foundStartAt = navAppVersion.indexOf(phraseToFind) + phraseToFind.length;
307		var foundEndAt = navAppVersion.indexOf(' ', foundStartAt + 1);
308		return (parseInt(navAppVersion.substring(foundStartAt, foundEndAt)) < 525);
309	} :
310	function () {
311		return false;
312	}
313);
314
315// Returns true if an event fired too soon after another event.
316// Mechanism used on older Safari browsers to prevent
317// double-fire problems (especially with key presses).
318function safariEventRateLimitBlock() {
319	if (isWebKit && isSafariVersion13OrOlder()) {
320		if (safariRateLimited != 0)
321			return true;
322		else {
323			safariRateLimited = setTimeout('safariRateLimited = 0;', 10);
324			return false;
325		}
326	}
327}
328
329// Get coordinates relative to document (works out container issues).
330// Wrote this so it works in quirks or standards mode.
331function getDocumentCoordinates(element) {
332	var htmlElem = document.body.parentNode;
333	var bodyElem = document.body;
334	var pos = { "x": 0, "y": 0 };
335	pos.toString = function () { return this.x + ', ' + this.y; }
336	while (element != null) {
337		pos.x += element.offsetLeft;
338		pos.y += element.offsetTop;
339		switch (element.offsetParent) {
340			case htmlElem:
341			case bodyElem:
342			case null:
343				return pos;
344		}
345		element = element.offsetParent;
346	}
347}
348
349// Attach an event handler to an object (browser-independent).
350// First clause is W3C DOM method, second is DHTML (IE).
351var addEvent = (window.addEventListener ?
352	function (obj, evType, fn, useCapture) {
353		try {
354			obj.addEventListener(evType, fn, useCapture);
355		} catch (e) { }
356		return true;
357	} :
358	function (obj, evType, fn, useCapture) {
359		try {
360			return obj.attachEvent('on' + evType, fn);
361		} catch (e) { }
362	}
363);
364
365// Release an event handler from an object (browser-independent).
366// First clause is W3C DOM method, second is DHTML (IE).
367var removeEvent = (window.removeEventListener ?
368	function (obj, evType, fn, useCapture) {
369		try {
370			obj.removeEventListener(evType, fn, useCapture);
371		} catch (e) { }
372		return true;
373	} :
374	function (obj, evType, fn, useCapture) {
375		try {
376			obj.detachEvent('on' + evType, fn);
377		} catch (e) { }
378		return true;
379	}
380);
381
382// Stops a DOM event from propagating further than the current handler.
383// Note: Returning false from event handlers in IE 6/7/8 does the same thing.
384function stopEventPropagation(evObj) {
385	if (evObj.preventDefault)
386		evObj.preventDefault();
387
388	// Calling cancelButton after stopPropagation
389	// may negate the stopPropagation so do not do it. -KB
390	if (evObj.stopPropagation)
391		evObj.stopPropagation();
392	else if (evObj.cancelBubble)
393		evObj.cancelBubble();
394}
395
396// These functions assists in obscuring email addresses:
397function mailTo(obj) {
398	//alert('mailto:'+eval(obj.getAttribute('id')));
399	obj.setAttribute('href', 'mailto:' + eval(obj.getAttribute('id')));
400}
401
402function js_mail(obj, Emails) {
403	var mail_link = Emails[0];
404	for (var email = 1; email < Emails.length; email++)
405		if (Emails[email] != null && Emails[email] != '' && Emails[email].substr(1, 4) != 'href') mail_link = mail_link + Emails[email];
406
407	obj.setAttribute('href', 'mailto:' + mail_link);
408}
409
410// Used to prevent right-click menu from appearing for some clients that wanted this ability.
411function antiContextMenuHook() {
412	// Note: Opera is not hookable.
413	var showAlert = function () { alert('All images are protected by Copyright. Do not use without permission.'); }
414	var mdClick = function (e) {
415		if (!document.all) {
416			if (e.button == 2 || e.button == 3)
417				showAlert();
418		}
419		else if (event && event.button == 2)
420			showAlert();
421	}
422	var cmClick = function (e) {
423		if (navigator.userAgent.toLowerCase().indexOf('khtml') > -1) {
424			// Safari, Konquerer
425			if (e.preventDefault)
426				e.preventDefault();
427			showAlert();
428		}
429		if (e.stopPropagation)
430			e.stopPropagation(); // Mozilla Firefox 2.0
431		return false; // IE 6.0 and 7.0
432	}
433	document.onmousedown = mdClick;
434	document.oncontextmenu = cmClick;
435}
436
437// Form validation functions:
438function RegExValidate(expression, value, param) {
439    var re = new RegExp(expression, param);
440    if (value != '' && value != undefined) {
441        if (value.match(re)) return true;
442        else return false;
443    }
444    else return true;
445}
446
447// Used for validating emailaddress for special scenarios like continuous periods. - VB
448function checkSpecialScenarios(s) {
449    var bugchars = '!#$^&*()|}{[]?><~%:;/,=`"'; 
450	var i;
451	var lchar = "";
452	// Search through string's characters one by one.
453	// If character is not in bag.
454	for (i = 0; i < s.length; i++) {
455		// Check that current character isn't whitespace.
456		var c = s.charAt(i);
457		if (i > 0) lchar = s.charAt(i - 1)
458		if (bugchars.indexOf(c) != -1 || (lchar == "." && c == ".")) return false;
459	}
460	return true;
461}
462
463// JavaScript version of CivicPlus.CMS.Site.Validation.IsValidEmailAddress();
464function emailValidate(emailAddress) {
465	var emailAddressTrimmed = TrimString(emailAddress + "");
466	if (emailAddressTrimmed != "") {
467		if (checkSpecialScenarios(emailAddressTrimmed) == false)
468			return false;
469		if (emailAddressTrimmed.replace(/[^@]/g, '').length > 1)
470			return false;
471		var parts = emailAddressTrimmed.splitRemoveEmpties('@');
472		if (emailAddressTrimmed.substr(emailAddressTrimmed.length - 1) == '@')
473			return false;
474		if (parts.length == 2) {
475			for (var i = 0; i < parts.length; i++) {
476				if (((!RegExValidate('^[A-Z0-9]$', parts[i].substr(0, 1), 'i') || !RegExValidate('^[A-Z0-9]$', parts[i].substr(parts[i].length - 1), 'i')) && i == 1) || (!RegExValidate('^[A-Z0-9_%-\\.]+$', parts[i].substr(0, parts[i].length - 1), 'i')))
477					return false;
478			}
479			var lastDotPos = parts[1].lastIndexOf('.');
480			if (lastDotPos < 0 || parts[1].substr(lastDotPos).length < 3 || (!RegExValidate('^[A-Z]+$', parts[1].substr(lastDotPos + 1), 'i')))
481				return false;
482			else
483				return true;
484		}
485		else
486			return false;
487	}
488	else
489		return false;
490}
491
492// Returns: 0 - success, 1 - illegal value, 2 - too large, 3 - too small, 4 - blank.
493function intValidateWithRange(value, min, max) {
494	if (value == '' || value == null) return 4;
495	if (RegExValidate('^(-|)[0-9]*$', value, 'i')) {
496		try { var pint = parseInt(value); } catch (ex) { return 1; }
497		if (pint < min) return 3; else if (pint > max) return 2; return 0;
498	} else
499		return 1;
500}
501
502// Split function that remotes empty entries.
503String.prototype.splitRemoveEmpties = function (separator, howmany) {
504	var splitArr;
505	var returnArr = new Array();
506
507	if (arguments.length == 2)
508		splitArr = this.split(separator, howmany);
509	else
510		splitArr = this.split(separator);
511
512	for (var i = 0; i < splitArr.length; i++) {
513		if (splitArr[i] != '')
514			returnArr.push(splitArr[i]);
515	}
516
517	return returnArr;
518}
519
520// JavaScript equivalent of a function in GlobalFunctionsDetail.aspx.
521// Do not use this function unless you have a good reason (e.g. textarea length on client must match size on server).
522// KNOWN: Does not do entities properly, matches server behavior (where's the semi-colon?).
523function SQLSafe(strInput) {
524	return strInput.replace(/\'/g, "&#39").replace(/\"/g, "&#34");
525}
526
527// Returns true if the string is empty. Will blow up on NULLs.
528function FieldIsEmpty(strInput) {
529	if (strInput == undefined)
530		return true;
531	return TrimString(strInput).length == 0;
532}
533
534// Removes leading and trailing white space from a string. Will blow up on NULLs.
535function TrimString(strInput) {
536	return strInput.replace(/^\s+/g, "").replace(/\s+$/g, "");
537}
538
539// Returns true if the value is an integer value.
540function isInteger(strInput) {
541	var leadingZeros = calculateLeadingZeroStrings(strInput);
542
543	return leadingZeros == strInput || (strInput == leadingZeros + parseInt(strInput).toString());
544}
545
546// Returns true if the value is a real number.
547function isRealNumber(strInput) {
548	var leadingZeros = calculateLeadingZeroStrings(strInput);
549
550	return leadingZeros == strInput || (strInput == leadingZeros + parseFloat(strInput));
551}
552
553function calculateLeadingZeroStrings(strInput) {
554	var leadingZeros = "";
555
556	if (strInput != null) {
557	for (var i = 0; i < strInput.length; i++) {
558		if (strInput[i] == "0") {
559			leadingZeros += "0";
560		}
561		else {
562			break;
563		}
564	}
565	}
566
567	return leadingZeros;
568}
569
570// Date validator class.
571function dateValidator() {
572	this.firstValidDate = new Date('01/01/1753');
573	this.lastValidDate = new Date('01/01/3000');
574	this.strStartDateID = 'Start/Begin Date';
575	this.strEndDateID = 'End/Stop/Expiration Date';
576	this.strStartTimeID = 'Start Time';
577	this.strEndTimeID = 'End Time';
578	this.ysnRequireStartDateIfEndSpecified = false;
579	this.ysnStartDateRequired = false;
580	this.ysnEndDateRequired = false;
581	this.ysnStartTimeRequired = false;
582	this.ysnEndTimeRequired = false;
583	this.ysnAllowEqualDates = false;
584	this.ysnAllowTimeOnly = false;
585	this.ysnCent = false; //Allow only four digit years
586	var dtiEndDate;
587	var dtiStartDate;
588	var dtiStartTime;
589	var dtiEndTime;
590	this.timesAlreadyValidated = false;
591	this.datesAlreadyValidated = false;
592
593	this.setStartDate = function (date) {
594		dtiStartDate = this.cleanDate(date);
595	}
596
597	this.setEndDate = function (date) {
598		dtiEndDate = this.cleanDate(date);
599	}
600
601	this.setStartDateRequired = function (required) {
602		this.ysnStartDateRequired = required;
603	}
604
605	this.setEndDateRequired = function (required) {
606		this.ysnEndDateRequired = required;
607	}
608
609	this.setRequireStartDateIfEndSpecified = function (required) {
610		this.ysnRequireStartDateIfEndSpecified = required;
611	}
612
613	this.cleanDate = function (date) {
614		if (date) {
615			if (typeof isMobileView != 'undefined' && isMobileView) {
616				date = this.ChangeDateFormatForMobileView(date);
617			}
618			else if (RegExValidate('^([0-9-\\/]*?)([0-9]{2,4})$', date, 'i')) {
619				var year = RegExp.$2;
620				if (year.length == 2) {
621					if (year >= 50) date = RegExp.$1 + "19" + year;
622					else date = RegExp.$1 + "20" + year;
623				}
624				date = date.replace('\-', '/', 'g');
625			}
626		}
627		return date;
628	}
629
630	this.ChangeDateFormatForMobileView = function (date) {
631		var rxDatePattern = /^\d{4}\-\d{1,2}\-\d{1,2}$/; //Regex for yyyy-mm-dd format
632		var match = date.match(rxDatePattern);
633		if (match != null) {
634			var dateArray = date.split('-');
635			var dateFormat = getDateFormat().toLowerCase();
636			if (dateFormat == "mm/dd/yyyy")
637				date = dateArray[1] + '/' + dateArray[2] + '/' + dateArray[0];
638			else if (dateFormat == "dd/mm/yyyy")
639				date = dateArray[2] + '/' + dateArray[1] + '/' + dateArray[0];
640		}
641		return date;
642	}
643
644	this.dateValidate = function (dtiDate, ysnRequired, strID) {
645		if (!ysnRequired && (dtiDate == null || dtiDate == '')) return true;
646		else if (ysnRequired && (dtiDate == null || dtiDate == '')) {
647			if (strID) this.error = strID + ' cannot be blank.';
648			else this.error = ' cannot be blank';
649			this.errorNumber = 1;
650			return false;
651		}
652		else if (RegExValidate('^(1[0-2]|0?[1-9])(/|-)(0?[1-9]|[1-2][0-9]|3[0-1])\\2([0-9]{4}|[0-9]{2})$', dtiDate, 'i')) {
653			var month = RegExp.$1;
654			var day = RegExp.$3;
655			var year = RegExp.$4;
656
657			if (year.length == 2 && this.ysnCent == true) {
658				if (strID) this.error = strID + ' requires a four digit year';
659				else this.error = 'Please use a four digit year';
660				return false;
661			}
662			if (year.length == 4 && (year > 3000 || year < 1753)) {
663				this.error = dtiDate + '\nis outside of the date range.';
664				this.errorNumber = 2;
665				return false;
666			}
667			if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) {
668				this.error = 'This month doesn\'t have 31 days';
669				this.errorNumber = 3;
670				return false;
671			}
672			if (day >= 30 && month == 2) {
673				this.error = 'February doesn\'t have ' + day + ' days';
674				this.errorNumber = 4;
675				return false;
676			}
677			if (month == 2 && day == 29 && !(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) {
678				this.error = 'This is not a leap year\nFebruary doesn\'t have 29 days.';
679				this.errorNumber = 5;
680				return false;
681			}
682			return true;
683		} else {
684			if (strID) this.error = strID + ' is not a valid date format.\nPlease use ' + getDateFormat().toUpperCase() + '.';
685			else this.error = dtiDate + '\n is an invalid date format.\nPlease use ' + getDateFormat().toUpperCase() + '.';
686			this.errorNumber = 6;
687			return false;
688		}
689		return false;
690	}
691
692	this.dateOrderValidate = function () {
693		if (this.dateValidate(dtiStartDate, this.ysnStartDateRequired, this.strStartDateID) && this.dateValidate(dtiEndDate, this.ysnEndDateRequired, this.strEndDateID)) {
694			if (this.ysnRequireStartDateIfEndSpecified && !dtiStartDate && dtiEndDate) {
695				this.error = 'A Start Date must be specified if an End Date was entered.';
696				this.errorNumber = 9;
697				return false;
698			}
699			if (!dtiStartDate || !dtiEndDate) return true;
700			else {
701				var StartDate = new Date(dtiStartDate);
702				var EndDate = new Date(dtiEndDate);
703			}
704			if (StartDate.getTime() < EndDate.getTime()) return true;
705			else if (StartDate.getTime() == EndDate.getTime() && this.ysnAllowEqualDates == true) {
706				this.ysnDatesAreEqual = true;
707				return true;
708			} else {
709				this.error = 'The End Date must be after the Start Date.';
710				this.errorNumber = 7;
711				return false;
712			}
713		}
714		else return false;
715	}
716
717	this.dateValidateNew = function (dtiDate, ysnRequired, strID) {
718		var month;
719		var day;
720		var year;
721		if (dtiDate === undefined)
722			dtiDate = '';
723
724        if (!ysnRequired && (dtiDate == '' || !dtiDate)) return true;
725
726		if (ysnRequired && dtiDate == '') {
727			if (strID) this.error = strID + ' is required';
728			else this.error = ' is required';
729			this.errorNumber = 1;
730			return false;
731		}
732
733		var dateFormat = getDateFormat().toLowerCase();
734
735		if (typeof isMobileView != 'undefined' && isMobileView) {
736			dtiDate = this.ChangeDateFormatForMobileView(dtiDate);
737		}
738
739		if ((dateFormat == "mm/dd/yyyy") && (RegExValidate('^(1[0-2]|0?[1-9])(/|-)(0?[1-9]|[1-2][0-9]|3[0-1])\\2([0-9]{4}|[0-9]{2})$', dtiDate, 'i'))) {
740			month = RegExp.$1;
741			day = RegExp.$3;
742			year = RegExp.$4;
743
744			return this.validDateParts(month, day, year);
745		}
746
747		if ((dateFormat == "dd/mm/yyyy") && (RegExValidate('^(0?[1-9]|[1-2][0-9]|3[0-1])(/|-)(1[0-2]|0?[1-9])\\2([0-9]{4}|[0-9]{2})$', dtiDate, 'i'))) {
748			month = RegExp.$3;
749			day = RegExp.$1;
750			year = RegExp.$4;
751
752			return this.validDateParts(month, day, year);
753		}
754
755		if (strID) this.error = strID + ' is not a valid date format.\nPlease use ' + dateFormat.toUpperCase() + '.';
756		else this.error = dtiDate + '\n is an invalid date format.\nPlease use ' + dateFormat.toUpperCase() + '.';
757		this.errorNumber = 6;
758
759		return false;
760	}
761
762	this.validDateParts = function (month, day, year) {
763		if (year.length == 2 && this.ysnCent == true) {
764			if (strID) this.error = strID + ' requires a four digit year';
765			else this.error = 'Please use a four digit year';
766			return false;
767		}
768		if (year.length == 4 && (year > 3000 || year < 1753)) {
769			this.error = dtiDate + '\nis outside of the date range.';
770			this.errorNumber = 2;
771			return false;
772		}
773		if (day == 31 && (month == 4 || month == 6 || month == 9 || month == 11)) {
774			this.error = 'This month doesn\'t have 31 days';
775			this.errorNumber = 3;
776			return false;
777		}
778		if (day >= 30 && month == 2) {
779			this.error = 'February doesn\'t have ' + day + ' days';
780			this.errorNumber = 4;
781			return false;
782		}
783		if (month == 2 && day == 29 && !(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))) {
784			this.error = 'This is not a leap year\nFebruary doesn\'t have 29 days.';
785			this.errorNumber = 5;
786			return false;
787		}
788		return true;
789	}
790
791	this.dateOrderValidateNew = function () {
792		//If sending in US format run dateValidateNew first becuase it expects dates in daybeforemonth format
793		if (this.datesAlreadyValidated || (this.dateValidateNew(dtiStartDate, this.ysnStartDateRequired, this.strStartDateID) && this.dateValidateNew(dtiEndDate, this.ysnEndDateRequired, this.strEndDateID))) {
794			if (this.ysnRequireStartDateIfEndSpecified && !dtiStartDate && dtiEndDate) {
795				this.error = 'A Start Date must be specified if an End Date was entered.'
796				this.errorNumber = 9; return false;
797			}
798			if (!dtiStartDate || !dtiEndDate || dtiEndDate == "NaN/NaN/NaN" || dtiStartDate == "NaN/NaN/NaN") return true;
799			else {
800				//Expects dates in US format 
801				var StartDate = new Date(dtiStartDate);
802				var EndDate = new Date(dtiEndDate);
803			}
804			if (StartDate.getTime() < EndDate.getTime()) return true;
805			else if (StartDate.getTime() == EndDate.getTime() && this.ysnAllowEqualDates == true) {
806				this.ysnDatesAreEqual = true;
807				return true;
808			}
809			else {
810				this.error = 'The End Date must be after the Start Date.';
811				this.errorNumber = 7; return false;
812			}
813		}
814		else return false;
815	}
816
817	this.getStandardDate = function (dateText) {
818		$.ajax({
819			url: '/Utility/GetDate?dateText=' + dateText,
820			async: false,
821			type: 'GET',
822			dataType: 'json',
823			success: function (data) {
824				dateText = data.date;
825			},
826			error: function (jqXHR, textStatus, errorThrown) {
827			}
828		});
829
830		return dateText;
831	}
832
833	this.smallDateTimeMaxValueValidate = function () {
834		var StartDate = new Date(dtiStartDate);
835		var EndDate = new Date(dtiEndDate);
836		var MaxDate = new Date('05/06/2079 23:59:59');
837		var result = true;
838		if (StartDate <= MaxDate && EndDate <= MaxDate) {
839			result = true;
840		}
841		else if (StartDate > MaxDate) {
842			this.error = "The Start Date must be less than '5/6/2079'.";
843			this.errorNumber = 2;
844			result = false;
845		}
846		else if (EndDate > MaxDate) {
847			this.error = "The End Date must be less than '5/6/2079'.";
848			this.errorNumber = 3;
849			result = false;
850		}
851		return result;
852	}
853
854	this.format = function (format, date) {
855		if (!date) date = new Date();
856		var day = date.getDate();
857		var month = date.getMonth() + 1;
858		var year = date.getFullYear();
859		return format.toLowerCase().replace(/dd/g, day).replace(/mm/g, month).replace(/y{1,4}/g, year)
860	}
861
862	this.timeValidate = function (ditTime, ysnRequired, strID) {
863		if (!ysnRequired && ditTime == '') return true;
864		else if (ysnRequired && ditTime == '') {
865			if (strID) this.error = strID + ' is required';
866			else this.error = 'Time is required';
867			this.errorNumber = 1;
868			return false;
869		}
870		else if (RegExValidate('^(1[0-2]|0?[1-9]):([0-5]?[0-9])(:([0-5][0-9]))?$', ditTime, 'i')) return true;
871		else {
872			if (strID) this.error = strID + ' is not a valid time format. Please use H
872H:MM.';
873			else this.error = ' is not a valid time format. Please use HH:MM.';
874			this.errorNumber = 8;
875			return false;
876		}
877	}
878
879	this.timeValidate24Hour = function (ditTime, ysnRequired, strID) {
880		if (!ysnRequired && ditTime == '') return true;
881		else if (ysnRequired && ditTime == '') {
882			if (strID) this.error = strID + ' is required';
883			else this.error = 'Time is required';
884			this.errorNumber = 1;
885			return false;
886		}
887		else if (RegExValidate('^([01]?[0-9]|2[0-3]):([0-5]?[0-9])(:([0-5][0-9]))?$', ditTime, 'i')) return true;
888		else {
889			if (strID) this.error = strID + ' is not valid.';
890			else this.error = ' is not valid.';
891			this.errorNumber = 8;
892			return false;
893		}
894	}
895	this.timeOrderValidate = function () {
896		if (!this.ysnAllowTimeOnly && ((!dtiStartDate && this.dtiStartTime) || (!dtiEndDate && this.dtiEndTime))) {
897			this.error = 'You only submited a time.\nPlease provide a day as well.';
898			this.errorNumber = 10;
899			this.startDateBlank = (!dtiStartDate && this.dtiStartTime);
900			this.endDateBlank = (!dtiEndDate && this.dtiEndTime);
901			return false;
902		}
903		if (this.timesAlreadyValidated || (this.timeValidate(this.dtiStartTime, this.ysnStartTimeRequired, this.strStartTimeID) && this.timeValidate(this.dtiEndTime, this.ysnEndTimeRequired, this.strEndTimeID))) {
904			if (!this.ysnDatesAreEqual) return true;
905
906			if (!this.dtiStartTime && !this.ysnStartTimeRequired) return true;
907			if (!this.dtiEndTime && !this.ysnEndTimeRequired) return true;
908			
909			var dtiStartTime = this.convertTo24Hour(this.dtiStartTime, this.strStartAMPM, dtiStartDate);
910			var dtiEndTime = this.convertTo24Hour(this.dtiEndTime, this.strEndAMPM, dtiEndDate);
911
912			if (dtiStartTime.getTime() < dtiEndTime.getTime()) return true;
913			else if (dtiStartTime.getTime() == dtiEndTime.getTime() && this.ysnAllowEqualTimes == true) {
914				this.ysnTimesAreEqual = true;
915				return true;
916			}
917			else {
918				this.error = 'The End Time must be after the Start Time if the Start and End Dates are the same.'
919				this.errorNumber = 9;
920				return false;
921			}
922		}
923		return false;
924	}
925
926	this.convertTo24Hour = function (time, AMPM, date) {
927		if (!date) date = "1/1/70";
928
929		var dtTime = time.indexOf(AMPM) == -1 ? new Date(date + " " + time + " " + AMPM) : new Date(date + " " + time);
930		if (dtTime == 'Invalid Date') {
931			var dayBeforeMonthOn = getDateFormat().toLocaleLowerCase() == "dd/mm/yyyy" ? true : false;
932			if (dayBeforeMonthOn) {
933				var dateArray = date.split('/');
934				date = dateArray[1] + '/' + dateArray[0] + '/' + dateArray[2];
935				dtTime = time.indexOf(AMPM) == -1 ? new Date(date + " " + time + " " + AMPM) : new Date(date + " " + time);
936			}
937		}
938		return dtTime;
939	}
940}
941
942// Helper function for inputAlert().
943function inputEmailValidate(obj, required) {
944	if (required == null || required == false)
945		return (obj.value == '' || emailValidate(obj.value) == true)
946	else
947		return (obj.value != '' && emailValidate(obj.value) == true)
948}
949
950// Note: This function does not match standard validation behavior! Users are supposed to see
951// a summary of problems with their inputs and not be alerted multiple times!
952// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
953// Calls another validation routine, and determines success/failure on result of call (true/false).
954// Displays error message on validation failure. Returns result of call.
955function inputAlert(call, obj, required, errorMessage) {
956	call = eval('input' + call + 'Validate');
957	if (call(obj, required) == false) {
958		if (errorMessage == null)
959			errorMessage = 'Please enter a single valid email address without any extra body, subject, etc. information (ie [email protected]).';
960		obj.setAttribute('autocomplete', 'off');
961		obj.focus();
962		obj.setAttribute('autocomplete', 'on');
963		alert(errorMessage);
964		return false;
965	}
966	else
967		return true;
968}
969
970// Takes array of required fields and checks whether they have a value or not
971// If empty fields found, formats a javascript alert to inform the user and returns true
972function checkRequiredFieldsEmpty(requiredFieldList) {
973	var badList = new Array();
974	for (var i = 0, len = requiredFieldList.length; i < len; i++) {
975		var $this = requiredFieldList[i];
976		var $fieldId = $('#' + $this);
977		if (($fieldId.length > 0) && (FieldIsEmpty($fieldId.val()))) {
978			var $label = $('label[for=' + $this + ']');
979			if ($label.length > 0)
980				badList.push($label.text().trim());
981			else
982				badList.push($this);
983		}
984	}
985	if (badList.length > 0) {
986		var msg = badList.join(" cannot be blank.\r\n");
987		msg += " cannot be blank.";
988		msg = msg.replace(/\*/g, '');
989		alert(msg);
990		return true;
991	}
992	return false;
993}
994// End Form Validation functions.
995
996// Begin AJAX functions:
997// See http://blogs.msdn.com/xmlteam/archive/2006/10/23/using-the-right-version-of-msxml-in-internet-explorer.aspx
998// If you are curious why the XMLHTTP versions specified are and why others are not.
999function makeErrorRequest(url, status) {
1000	var http_error_request = false;
1001	var origin = location.pathname;
1002
1003	if (window.XMLHttpRequest) { // Mozilla, Safari, IE7
1004		http_error_request = new XMLHttpRequest();
1005		if (http_error_request.overrideMimeType)
1006			http_error_request.overrideMimeType("text/html");
1007	} else if (window.ActiveXObject) { // IE6
1008		try {
1009			http_error_request = new ActiveXObject("Msxml2.XMLHTTP.6.0");
1010		} catch (e) {
1011			try {
1012				http_error_request = new ActiveXObject("Msxml2.XMLHTTP"); // Version 3.0
1013			} catch (e) { }
1014		}
1015	}
1016
1017	http_error_request.onreadystatechange = function () { }
1018	http_error_request.open("GET", "/AJAX-error.ashx?url=" + escape(url) + "&status=" + status + "&origin=" + escape(origin), true);
1019	http_error_request.send(null);
1020	//if(status == 403)
1021	//window.location = '/admin/AccessDenied.aspx?fromURL=' + window.location.pathname.substr(7);
1022}
1023
1024// Makes AJAX request, additionally supporting POST data (makeHttpRequest doesn't).
1025// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1026// Note: It's YOUR responsibility as a developer to make sure data
1027// placed in formData is formatted as it should be. Form data should be
1028// in Query String format with the value portions escape()'d. -KB
1029function makeHttpRequestEx(URL, formData, callbackFunc, ysnReturnXML) {
1030
1031	URL = window.location.origin + URL;
1032
1033	if (formData != null) {
1034		$.ajax({
1035			type: 'POST',
1036			url: URL,
1037			data: formData,
1038			success: callbackFunc
1039		});
1040	}
1041	else {
1042		$.ajax({
1043			type: 'GET',
1044			url: URL,
1045			success: callbackFunc
1046		});
1047}
1048}
1049
1050// NOTE: Do not use this in new code, use $.ajax() instead.
1051// Makes AJAX request. Used in n-menu code.
1052function makeHttpRequest(url, callback_function, return_xml) {
1053	var http_request = false;
1054
1055	if (window.XMLHttpRequest) { // Mozilla, Safari, IE7
1056		http_request = new XMLHttpRequest();
1057		if (http_request.overrideMimeType && !return_xml)
1058			http_request.overrideMimeType("text/html");
1059	} else if (window.ActiveXObject) { // IE6
1060		try {
1061			http_request = new ActiveXObject("Msxml2.XMLHTTP.6.0");
1062		} catch (e) {
1063			try {
1064				http_request = new ActiveXObject("MSxml2.XMLHTTP"); // Version 3
1065			} catch (e) { }
1066		}
1067	}
1068
1069	if (!http_request) {
1070		alert("Unfortunately, your browser doesn't support this feature.");
1071		return false;
1072	}
1073
1074	http_request.onreadystatechange = function () {
1075		if (http_request.readyState == 4) {
1076			--ajax_call_counter;
1077
1078			//try {
1079			if (http_request.status == 200) {
1080				if (return_xml)
1081					eval(callback_function + ', http_request.responseXML)');
1082				else {
1083					if (http_request.responseText.search(/<form action='error.asp' method=post>/i) < 0)
1084						eval(callback_function + ', http_request.responseText)');
1085					else
1086						makeErrorRequest(url, http_request.status);
1087				}
1088			}
1089			else if (http_request.status)
1090				makeErrorRequest(url, http_request.status);
1091			//} catch (e) {
1092			// If this happens, there is no way to notify anyone
1093			// of the previous error. It might be their connection died,
1094			// or failed in some other way.
1095
1096			//alert('An error occured while reporting the previous error.');
1097			//var USER_EXPLAIN_ERR_EN = '\n\nTechnical Details:\n' + e.name + ' - ';
1098			// IE 6 & 7: No Line Number, No Filename
1099			//if (document.all && !window.opera) {
1100			//	alert(USER_EXPLAIN_ERR_EN + e.description + ' (line unavailable, code: ' + e.number + ')' + '\n\nJavaScript Callback:\n' + callback_function + ', <responseData>);');
1101			//}
1102			// Opera and Firefox 1.5+: Line Number + Filename
1103			//else {
1104			//	alert(USER_EXPLAIN_ERR_EN + e.message + '\n' + e.fileName + ', line ' + e.lineNumber + '\n\nJavaScript Callback:\n' + callback_function + ', <responseData>);');
1105			//}
1106			//}
1107
1108			http_request = null;
1109		}
1110	}
1111
1112	http_request.open("GET", url, true);
1113	http_request.send(null);
1114}
1115// Invoked on window.onunload for pages using synchronous AHAH.
1116// Catches switches to different pages and window closes.
1117// -=-=-=-=-
1118// Note: It is synchronous instead of asynchronous to ensure
1119// the operation completes before a close. This is SHAH.
1120//
1121function destroyAHAH(e) {
1122	var http_request;
1123
1124	if (window.XMLHttpRequest) { // Mozilla, Safari, IE7
1125		http_request = new XMLHttpRequest();
1126		if (http_request.overrideMimeType) {
1127			http_request.overrideMimeType("text/html");
1128		}
1129	} else if (window.ActiveXObject) { // IE6
1130		try {
1131			http_request = new ActiveXObject("MSXML2.XMLHTTP.6.0");
1132		} catch (e) {
1133			try {
1134				http_request = new ActiveXObject("MSXML2.XMLHTTP"); // Version 3
1135			} catch (e) { }
1136		}
1137	}
1138
1139	if (!http_request) return;
1140	http_request.open("GET", 'http://' + window.location.host + '/AJAX-NMenuLoader.ashx?clearCache=1', false);
1141	http_request.send(null);
1142	//alert(http_request.status + ': if 200, the session cache object was term\'d where needed be.');
1143}
1144// End AJAX functions.
1145
1146//
1147//  slideShow class
1148//  vars:
1149//  slideShowId						constructor param for the id of the image that will have the Slide Show
1150//  slideShowLink					constructor param for the id of the link that will be around the image that has Slide Show, use '' for no link
1151//  slideShowSpeed					optional constructor param for the speed of the slide show, default = 5000
1152//  filterName						optional constructor param for the IE filter, default = blendTrans
1153//  filterAttr1						optional constructor param for the IE filter, default = duration=3
1154//  filterAttr2						optional constructor param for the IE filter
1155//  filterAttr3						optional constructor param for the IE filter
1156//  j								counter for the object
1157//  picArr							array of pictures
1158//  altArr							array of alt text
1159//  linkArr							array of links
1160//  methods:
1161//  addImage(n, img, alt, caption, lngCaption, link)	add an image with alt text and a link, n specifies which postion in the arrays
1162//  runSlideShow()					continually calls nextSlide to run the Slide Show
1163//  nextSlide()						applies the transition and advances the Slide Show image 1 spot in the arrays
1164//  mouseOver()						detects and loads that image to the Main Image Display & draws border around the slected 
1164image & removed border from the Other small image icons
1165function slideShow(slideShowId, slideShowLink, slideShowSpeed, filterName, filterAttr1, filterAttr2, filterAttr3, slideShowLinkTarget, layout, externalLink) {
1166	if (!slideShowLinkTarget || slideShowLinkTarget == null || slideShowLinkTarget == "undefined" || slideShowLinkTarget == "")
1167		slideShowLinkTarget = "_self";
1168	if (!layout || layout == null || layout == "undefined")
1169		layout = 1;
1170
1171	this.slideShowId = document.getElementById(slideShowId);
1172
1173	this.picArr = new Array();
1174	this.altArr = new Array();
1175	this.captionArr = new Array();
1176	this.lngCaptionArr = new Array();
1177	this.linkArr = new Array();
1178	this.linkTargetArr = new Array();
1179	var useStyle = false;
1180	var captionFilter = "";
1181	var cssRule = false;
1182	var pos = 0;
1183
1184	//Get The filter for IE.//
1185	for (i = 0; i < document.styleSheets.length; i++) {
1186		var styles = document.styleSheets[i];
1187		do {
1188			if (styles.href && styles.href.indexOf("style.css") > -1) {
1189				if (styles.cssRules) {
1190					cssRule = styles.cssRules[pos];
1191				}
1192				else if (styles.rules) {
1193					cssRule = styles.rules[pos];
1194				}
1195			}
1196			if (cssRule && cssRule.selectorText != undefined && cssRule.selectorText.indexOf('slideCaption') != -1) {
1197				useStyle = true;
1198				captionFilter = cssRule.style.filter;
1199				break;
1200			}
1201			pos++;
1202		} while (cssRule && !useStyle)
1203		if (useStyle) break;
1204	}
1205	var useStyle = $('.slideCaption').attr('class') == 'slideCaption';
1206
1207	// If junk data causes one slideshow to fail the others should not.
1208	if (this.slideShowId == null) {
1209		this.addImage = function (n, img, alt, link, linkTarget, caption, lngCaption, externalLink) { }
1210		this.runSlideShow = function () { }
1211		this.nextSlide = function () { }
1212		this.mouseOver = function (elem, imgPath, altText) { }
1213		return;
1214	}
1215
1216	var tmpElem = document.createElement('a');
1217	if (slideShowLink && slideShowLink != '') {
1218		do {
1219			slideShowLink = (slideShowLink).replace("%38", "&");
1220		} while ((slideShowLink).indexOf("%38") != -1)
1221		tmpElem.href = slideShowLink;
1222		if (slideShowLinkTarget && slideShowLinkTarget != '')
1223			tmpElem.target = slideShowLinkTarget;
1224
1225		var ssID = this.slideShowId.id.replace("cvpSlideShowImage", "");
1226		var capt = document.getElementById('slideCaption' + ssID);
1227		tmpElem.onclick = "";
1228		if (capt && capt.children && capt.children.length > 0)
1229			capt.children[0].removeAttribute("onclick");
1230	}
1231	else
1232		tmpElem.removeAttribute('href');
1233
1234	this.j = 1;
1235	if (slideShowSpeed == null || slideShowSpeed == '')
1236		this.slideShowSpeed = 4000;
1237	else
1238		this.slideShowSpeed = slideShowSpeed * 1000;
1239	if (filterAttr1 == null || filterAttr1 == '')
1240		filterAttr1 = 2;
1241	if (filterName == null || filterName == '' || filterName.toLowerCase() == 'blendtrans')
1242		this.filterName = 'BlendTrans(duration=' + filterAttr1;
1243	else if (filterName.toLowerCase() != 'none')
1244		this.filterName = 'progid:DXImageTransform.Microsoft.' + filterName + ', duration=' + filterAttr1;
1245	if (filterAttr2 != null && filterAttr2 != '' && filterAttr2 != 'null')
1246		this.filterName = this.filterName + ',' + filterAttr2;
1247	if (filterAttr3 != null && filterAttr3 != '' && filterAttr3 != 'null')
1248		this.filterName = this.filterName + ',' + filterAttr3;
1249	if (filterName.toLowerCase() == 'none')
1250		this.filterName = filterName;
1251	else
1252		this.filterName = this.filterName + ')';
1253
1254	switch (layout) {
1255		case 1: // Standard
1256			tmpElem.style.border = 'none';
1257			tmpElem.style.background = 'transparent';
1258			//tmpElem.style.border = 'medium none';
1259			//tmpElem.style.background = 'transparent none repeat scroll 0% 0%';
1260			tmpElem.id = slideShowId + '_link';
1261			this.slideShowLink = tmpElem;
1262			this.slideShowId.parentNode.insertBefore(tmpElem, this.slideShowId);
1263			this.slideShowId.parentNode.removeChild(this.slideShowId);
1264			this.slideShowLink.appendChild(this.slideShowId);
1265			break;
1266		case 5: // StandardFiveBottom
1267			//DO NOT COPY for this case - follow 12 for a better code.
1268			//tmpElem.style.border = 'none';
1269			//tmpElem.style.background = 'transparent';
1270			tmpElem.style.border = 'medium none';
1271			tmpElem.style.background = 'transparent none repeat scroll 0% 0%';
1272			tmpElem.id = slideShowId + '_link';
1273			this.slideShowLink = tmpElem;
1274			this.slideShowId.parentNode.insertBefore(tmpElem, this.slideShowId);
1275			//this.slideShowId.parentNode.removeChild(this.slideShowId);
1276			this.slideShowLink.appendChild(this.slideShowId);
1277			var tmpElemHTML = this.slideShowLink.innerHTML;
1278
1279			var td = this.slideShowId.parentNode.parentNode;
1280			this.slideShowId.parentNode.parentNode.removeChild(this.slideShowId.parentNode);
1281
1282			var newSection = document.createElement("div");
1283			newSection.setAttribute("id", "SubSection1");
1284
1285			var cpSlideShowWrapper1 = document.createElement("div");
1286			cpSlideShowWrapper1.setAttribute("id", "cpSlideShowWrapper1");
1287			cpSlideShowWrapper1.style.padding = "5px";
1288			cpSlideShowWrapper1.style.background = "rgb(70, 43, 16) none repeat scroll 0% 0%";
1289			cpSlideShowWrapper1.style.position = "relative";
1290			cpSlideShowWrapper1.style.width = "416px";
1291			//cpSlideShowWrapper1.style.-moz-background-clip = "border";
1292			//cpSlideShowWrapper1.style.-moz-background-origin = "padding";
1293			//cpSlideShowWrapper1.style.-moz-background-inline-policy = "continuous";
1294			cpSlideShowWrapper1.style.height = "254px";
1295
1296			var imageHead = document.createElement("div");
1297			imageHead.style.padding = "4px";
1298			imageHead.style.background = "rgb(241, 239, 234) none repeat scroll 0% 0%";
1299			imageHead.style.align = "left";
1300			imageHead.style.width = "406px";
1301			//-moz-background-clip: border;
1302			//-moz-background-origin: padding;
1303			//-moz-background-inline-policy: continuous;
1304			imageHead.style.float = "left";
1305			imageHead.style.height = "198px";
1306			imageHead.style.align = "left";
1307
1308			imageHead.innerHTML = tmpElemHTML;
1309			cpSlideShowWrapper1.appendChild(imageHead);
1310
1311			var imageRows = document.createElement("div");
1312			imageRows.setAttribute("id", "imageRows");
1313			imageRows.style.position = "relative";
1314			imageRows.style.align = "left";
1315			imageRows.style.margin = "5px 0px 0px 0px";
1316			imageRows.style.width = "416px";
1317			imageRows.style.float = "left";
1318			imageRows.style.height = "42px";
1319			imageRows.style.clear = "both";
1320
1321			cpSlideShowWrapper1.appendChild(imageRows);
1322			newSection.appendChild(cpSlideShowWrapper1);
1323			td.appendChild(newSection);
1324
1325			this.slideShowId = document.getElementById(slideShowId);
1326			if (isie) {
1327				this.slideShowId.style.height = "100%";
1328				this.slideShowId.style.width = "100%";
1329			}
1330			else {
1331				this.slideShowId.setAttribute("height", "100%");
1332				this.slideShowId.setAttribute("width", "100%");
1333			}
1334			break;
1335		case 12: //This case would handle the new 12 image slideshow without Rotation. & with mouseover
1336			tmpElem.id = slideShowId + '_link';
1337			this.slideShowLink = tmpElem;
1338			this.slideShowId.parentNode.insertBefore(tmpElem, this.slideShowId);
1339			this.slideShowLink.appendChild(this.slideShowId);
1340			var tmpElemHTML = this.slideShowLink.innerHTML;
1341
1342			var td = this.slideShowId.parentNode.parentNode;
1343
1344			// If the slideshow is in the middle of the page's content, we
1345			// have to keep track of its next sibling, so we put the 12-thumbnail
1346			// content in the new location.
1347			var nextSibling = this.slideShowLink.nextSibling;
1348
1349			this.slideShowId.parentNode.parentNode.removeChild(this.slideShowId.parentNode);
1350
1351			var newSection = document.createElement("div");
1352			newSection.setAttribute("id", "SubSectionFor" + slideShowId);
1353
1354			var cpSlideShowWrapper1 = document.createElement("div");
1355			cpSlideShowWrapper1.setAttribute("id", "cpSlideShowWrapper" + slideShowId);
1356
1357			//Remove these in-line style Height and Width after CSS changes
1358			cpSlideShowWrapper1.style.width = "441px";
1359			cpSlideShowWrapper1.style.height = "190px";
1360			cpSlideShowWrapper1.style.padding = "5px";
1361			cpSlideShowWrapper1.style.position = "relative";
1362			cpSlideShowWrapper1.style.clear = "both";
1363
1364			var imageHead = document.createElement("div");
1365			imageHead.setAttribute("id", "imageHead");
1366			//Remove these in-line style Height and Width after CSS changes
1367			imageHead.style.width = "201px"; //185 px
1368			imageHead.style.height = "168px";
1369			imageHead.style.padding = "8px";
1370			imageHead.style.align = "left";
1371			imageHead.style.styleFloat = "left";
1372			imageHead.style.cssFloat = "left";
1373			imageHead.innerHTML = tmpElemHTML;
1374			cpSlideShowWrapper1.appendChild(imageHead);
1375
1376			var imageRowsHeader = document.createElement("div");
1377			imageRowsHeader.setAttribute("id", "imageRowsHeader");
1378			imageRowsHeader.style.position = "relative";
1379			imageRowsHeader.style.align = "right";
1380			imageRowsHeader.style.styleFloat = "right";
1381			imageRowsHeader.style.cssFloat = "right";
1382			imageRowsHeader.style.width = "216px"; //247px
1383			imageRowsHeader.style.height = "18px";
1384
1385			//Image Link
1386			var slideImageHeaderLink = document.createElement("a");
1387			slideImageHeaderLink.setAttribute("href", "/gallery.aspx");
1388
1389			//Image Header
1390			var slideImageHeader = document.createElement("img");
1391			slideImageHeader.setAttribute("id", slideShowId + "Header");
1392			slideImageHeader.setAttribute("src", "/images/pages/ImageHeader.jpg");
1393			slideImageHeader.setAttribute("target", "_blank");
1394			slideImageHeader.style.width = "198px"; //247px
1395			slideImageHeader.style.height = "18px";
1396			slideImageHeader.setAttribute("border", "0");
1397
1398			slideImageHeaderLink.appendChild(slideImageHeader);
1399			imageRowsHeader.appendChild(slideImageHeaderLink);
1400
1401			cpSlideShowWrapper1.appendChild(imageRowsHeader);
1402
1403			var imageRows = document.createElement("div");
1404			imageRows.setAttribute("id", "imageRows");
1405			imageRows.style.position = "relative";
1406			imageRows.style.align = "right";
1407			//imageRows.style.margin = "28px 0px 0px 0px";
1408			imageRows.style.styleFloat = "right";
1409			imageRows.style.cssFloat = "right";
1410			imageRows.style.width = "216px"; //247px
1411			imageRows.style.height = "145px";
1412			imageRows.style.padding = "4px";
1413
1414			cpSlideShowWrapper1.appendChild(imageRows);
1415			newSection.appendChild(cpSlideShowWrapper1);
1416
1417			var scriptTag = td.firstChild;
1418			while (scriptTag) {
1419				if (scriptTag.nodeType == 1 && scriptTag.tagName == 'SCRIPT')
1420					break;
1421				scriptTag = scriptTag.nextSibling;
1422			}
1423			if (nextSibling != null)
1424				td.insertBefore(newSection, nextSibling);
1425			else
1426				td.insertBefore(newSection, scriptTag);
1427
1428			this.slideShowId = document.getElementById(slideShowId);
1429			//Remove these in-line style Height and Width after CSS changes
1430			if (isie) {
1431				this.slideShowId.style.height = "100%";
1432				this.slideShowId.style.width = "100%";
1433			}
1434			else {
1435				this.slideShowId.setAttribute("height", "100%");
1436				this.slideShowId.setAttribute("width", "100%");
1437			}
1438			break;
1439		default:
1440			break;
1441	}
1442
1443	this.addImage = function (n, img, alt, link, linkTarget, caption, lngCaption, isExternal) {
1444		if (layout == 12 && n > 11)
1445			return; // Allow only upto 12 thumbnail images for Standard 12 Bottom layout
1446
1447		if (!linkTarget || linkTarget == null || linkTarget == "undefined" || linkTarget == "")
1448			linkTarget = "_self";
1449
1450		this.picArr[n] = new Image();
1451		this.picArr[n].src = img;
1452		do {
1453			alt = (alt).replace("%39", "'");
1454		} while ((alt).indexOf("%39") != -1)
1455		this.altArr[n] = alt;
1456		this.captionArr[n] = caption;
1457		this.lngCaptionArr[n] = lngCaption;
1458
1459		do {
1460			link = (link).replace("%38", "&");
1461		} while ((link).indexOf("%38") != -1)
1462		this.linkArr[n] = link;
1463
1464		this.linkTargetArr[n] = linkTarget;
1465
1466		switch (layout) {
1467			case 5:
1468				var slideImage = document.createElement("img");
1469				slideImage.setAttribute("id", slideShowId + n);
1470				if (isie) {
1471					slideImage.style.height = "40";
1472					slideImage.style.width = "40";
1473				}
1474				else {
1475					slideImage.setAttribute("height", "40");
1476					slideImage.setAttribute("width", "40");
1477				}
1478				if (n == 0)
1479					slideImage.setAttribute("border", "1");
1480				else
1481					slideImage.setAttribute("border", "0");
1482				slideImage.style.borderStyle = "solid";
1483				slideImage.style.borderColor = "#FFFF00";
1484				slideImage.setAttribute("src", img);
1485				slideImage.setAttribute("alt", alt);
1486				slideImage.setAttribute("link", link);
1487				slideImage.setAttribute("target", linkTarget);
1488				slideImage.setAttribute("class", "photoGalleryImgArray");
1489
1490				if (n == 0)
1491					slideImage.style.margin = "0px 0px 0px 0px";
1492				else
1493					slideImage.style.margin = "0px 0px 0px 6px";
1494				this.imageRows = document.getElementById("imageRows");
1495				this.imageRows.appendChild(slideImage);
1496				break;
1497			case 12: //This case would handle the new 12 image slideshow without Rotation. & with mouseover
1498				var slideImage = document.createElement("img");
1499				slideImage.setAttribute("id", slideShowId + n);
1500				//Remove these in-line style 'Padding' after CSS changes
1501				if (n == 0) {
1502					if (isie)
1503						slideImage.style.cssText = "margin:6px 6px; border: 2px solid transparent; background-color: lightblue; padding: 3px; height:30px; width:30px;";
1504					else
1505						slideImage.setAttribute('style', 'margin:6px 6px; border: 2px solid transparent; background-color: lightblue; padding: 3px; height:30px; width:30px;');
1506				}
1507				else {
1508					if (isie)
1509						slideImage.style.cssText = "margin:6px 6px; border: 2px solid transparent ; background-color: white; padding: 3px; height:30px; width:30px;";
1510					else
1511						slideImage.setAttribute('style', 'margin:6px 6px; border: 2px solid transparent ; background-color: white; padding: 3px;height:30px; width:30px;');
1512				}
1513				slideImage.setAttribute("src", img);
1514				slideImage.setAttribute("alt", alt);
1515				slideImage.setAttribute("link", link);
1516				slideImage.setAttribute("target", linkTarget);
1517				slideImage.setAttribute("class", "photoGalleryImgArray");
1518				var siObj = eval(slideShowId.replace("Image", ""));
1519				slideImage.onmouseover = function () { siObj.mouseOver(slideShowId + n, img, alt); };
1520
1521				this.imageRows = document.getElementById("imageRows");
1522				this.imageRows.appendChild(slideImage);
1523				break;
1524			default:
1525				break;
1526		}
1527	}
1528
1529	this.mouseOver = function (elem, imgPath, altText) {
1530		//Set the Main Display image to mouseOver Image
1531		this.slideShowId.setAttribute("src", imgPath);
1532		this.slideShowId.alt = altText;
1533
1534		//Loop through all other images and set the border to 1
1535		this.ImageRows = document.getElementById("imageRows");
1536		this.ImageRows.Images = this.ImageRows.getElementsByTagName("img");
1537		var j = 0;
1538		while (j < this.ImageRows.Images.length) {
1539			if (this.ImageRows.Images[j] == document.getElementById(elem)) {
1540				if (isie)
1541					this.ImageRows.Images[j].style.cssText = "margin:6px 6px; border: 2px solid transparent; background-color: lightblue; padding: 3px; height:30px; width:30px;";
1542				else
1543					this.ImageRows.Images[j].setAttribute('style', 'margin:6px 6px; border: 2px solid transparent; background-color: lightblue; padding: 3px;height:30px; width:30px;');
1544			}
1545			else {
1546				if (isie)
1547					this.ImageRows.Images[j].style.cssText = "margin:6px 6px; border: 2px solid transparent; background-color:white; padding: 3px;height:30px; width:30px;";
1548				else
1549					this.ImageRows.Images[j].setAttribute('style', 'margin:6px 6px; border: 2px solid transparent; background-color:white; padding: 3px;height:30px; width:30px;');
1550			}
1551			j++;
1552		}
1553	}
1554
1555	this.runSlideShow = function () {
1556		switch (layout) {
1557			case 12:
1558			case 5:
1559				//Do nothing, do not run a slideshow
1560				break;
1561			default:
1562				if (this.picArr.length > 1) {
1563					var self = this; 					//  reference to get around context loss of this during setTimeout()
1564					this.timeoutId = setTimeout(function () { self.nextSlide(); self.runSlideShow(); }, this.slideShowSpeed);
1565				}
1566				break;
1567		}
1568	}
1569
1570	this.nextSlide = function () {
1571		var ssID = this.slideShowId.id.replace("cvpSlideShowImage", "");
1572		var capt = document.getElementById('slideCaption' + ssID);
1573		var lngCapt = document.getElementById('slideCaptionLng' + ssID);
1574		if (document.all && this.slideShowId.filters && this.slideShowId.filters.length > 0 && this.filterName.toLowerCase() != 'none') {
1575			this.slideShowId.style.filter = this.filterName;
1576			this.slideShowId.filters.item(0).apply();
1577			if (capt) {
1578				capt.style.filter = captionFilter + " " + this.filterName;
1579				capt.filters.item(capt.filters.length - 1).apply();
1580				if (lngCapt) {
1581					lngCapt.style.filter = captionFilter + " " + this.filterName;
1582					lngCapt.filters.item(lngCapt.filters.length - 1).apply();
1583				}
1584			}
1585		}
1586		this.slideShowId.setAttribute('src', this.picArr[this.j].src);
1587		this.slideShowId.setAttribute('alt', this.altArr[this.j]);
1588		this.slideShowId.setAttribute('title', this.altArr[this.j]);
1589
1590		var height = '';
1591		var marginTop = useStyle ? "-61px" : "0px";
1592		var paddingTop = "3px";
1593		if (this.captionArr[this.j] == "") {
1594			height = "0px";
1595		}
1596		else if (this.lngCaptionArr[this.j] == "") {
1597			height = "31px";
1598			marginTop = useStyle ? "-35px" : "0px";
1599			paddingTop = useStyle ? "-4px" : "0px";
1600		}
1601		else
1602			height = useStyle ? "55px" : "";
1603
1604		if (capt) {
1605			capt.innerHTML = useStyle ? this.captionArr[this.j] : "<strong>" + this.captionArr[this.j] + "</strong>";
1606			capt.style.marginTop = marginTop;
1607			capt.style.height = height;
1608			capt.style.paddingLeft = useStyle ? "15px" : "5px";
1609			capt.style.paddingRight = useStyle ? "10px" : "5px";
1610			capt.style.paddingTop = paddingTop;
1611
1612			if (height != "0px" && lngCapt != null) {
1613				lngCapt.innerHTML = this.lngCaptionArr[this.j];
1614				lngCapt.style.marginTop = useStyle ? "-38px" : "0px";
1615				lngCapt.style.paddingLeft = useStyle ? "15px" : "5px";
1616				lngCapt.style.paddingRight = useStyle ? "10px" : "5px";
1617				lngCapt.style.paddingTop = paddingTop;
1618				lngCapt.style.overflow = 'hidden';
1619			}
1620			else if (lngCapt != null) {
1621				lngCapt.style.marginTop = "0px";
1622				lngCapt.innerHTML = "";
1623				lngCapt.height = "0px";
1624			}
1625		}
1626
1627		var slideLink = this.linkArr[this.j]
1628		var slideLinkTarget = this.linkTargetArr[this.j]
1629		if (slideLink && slideLink != '') {
1630			tmpElem.href = slideLink;
1631			this.slideShowLink.removeAttribute("onclick");
1632			tmpElem.onclick = "";
1633			if (capt)
1634				capt.innerHTML = useStyle ? "<a class = 'slideCaptionHyperlink' href=" + slideLink + " target = " + slideLinkTarget + ">" + this.captionArr[this.j] + "</a>" :
1635                                             "<a class = 'Hyperlink' href=" + slideLink + " target = " + slideLinkTarget + ">" + this.captionArr[this.j] + "</a>";
1636			if (slideLinkTarget && slideLinkTarget != '')
1637				tmpElem.target = slideLinkTarget;
1638		}
1639		else {
1640			tmpElem.removeAttribute('href');
1641			if (capt)
1642				capt.removeAttribute('href');
1643		}
1644		if (document.all && this.slideShowId.filters && this.slideShowId.filters.length > 0 && filterName.toLowerCase() != 'none') {
1645			this.slideShowId.filters.item(0).play();
1646			if (capt) {
1647				capt.filters.item(capt.filters.length - 1).play();
1648				lngCapt.filters.item(lngCapt.filters.length - 1).play();
1649			}
1650		}
1651
1652		var slideImageId, slideImage;
1653		if (layout == 5) {
1654			// Set the selected image's border
1655			if (this.j == 0)
1656				slideImageId = slideShowId + (this.picArr.length - 1);
1657			else
1658				slideImageId = slideShowId + (this.j - 1);
1659			slideImage = document.getElementById(slideImageId);
1660			slideImage.setAttribute("border", "0");
1661
1662			slideImageId = slideShowId + this.j;
1663			slideImage = document.getElementById(slideImageId);
1664			slideImage.setAttribute("border", "1");
1665		}
1666
1667		this.j++;
1668		if (this.j >= this.picArr.length)
1669			this.j = 0;
1670	}
1671}
1672
1673function validateMultiFileUpload(el, useWhiteList) {
1674	try {
1675		const fileNames = [...el.files].map(file => file.name);
1676		const xhr = new XMLHttpRequest();
1677		xhr.open('POST', '/Utility/AreValidFileNames', false);
1678		xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
1679		const data = new FormData();
1680		fileNames.forEach(fileName => {
1681			data.append("paths[]", fileName);
1682		})
1683
1684		xhr.send(data);
1685		const response = JSON.parse(xhr.responseText);
1686		const isValid = response.every(x => x === true);
1687
1688		for (const fileName of fileNames) {
1689			if (!isAllowedFileExtension(fileName, useWhiteList) || !isValid) {
1690				return false;
1691			}
1692		}
1693		return true;
1694	} catch (e) {
1695		console.error(e);
1696		return false;
1697	}
1698}
1699
1700//el is the pointer to the input type="file"
1701//example usage: <input type="file" size="38" name="txtFile" onChange="validateFileUpload(this);">
1702function validateFileUpload(el, useWhiteList) {
1703	var val = el.value;
1704	var cbox = document.getElementById(el.name + "_pdf");
1705	if (cbox) {
1706		cbox.disabled = true;
1707		cbox.checked = false;
1708	}
1709	if (val.length > 0) {
1710		var isValid = false;
1711		if (val.indexOf(':\\fakepath\\') > -1)
1712			val = val.substring(12);
1713		$.ajax({
1714			async: false,
1715			type: "POST",
1716			url: '/Utility/IsValidFileName',
1717			data: { path: val },
1718			dataType: "json",
1719			success: function (response) {
1720				if (typeof (response.d) != "undefined") {
1721					response = response.d;
1722				}
1723				if (response.result == "True")
1724					isValid = true;
1725			}
1726		});
1727		if (!isAllowedFileExtension(val, useWhiteList) || !isValid) {
1728			alert("The file you are trying to upload is not an allowed file type or has an invalid file name. These are the accepted characters: A-z 0-9 ~ ! ( ) - + = [ ] { } , . _");
1729			var tempElem = el.cloneNode(false);
1730			tempElem.value = "";
1731			el.parentNode.replaceChild(tempElem, el);
1732			el.focus();
1733			return false;
1734		}
1735		if (cbox) {
1736			cbox.disabled = !isAllowedFileExtensionPDF(val);
1737			if (cbox.disabled) cbox.checked = false;
1738		}
1739	}
1740	return true;
1741}
1742
1743// Recommended you use isAllowedFileExtensionWhiteList() instead. Do not use this method
1744// where useWhiteList is false or null, that is not secure (uses blacklist rather than whitelist).
1745function isAllowedFileExtension(filename, useWhiteList) {
1746	if (filename + '' == '')
1747		return true;
1748
1749	// Cut out the path portion (why not use lastIndexOf()?).
1750	while (filename.indexOf("/", 0) > 0)
1751		filename = filename.substr(filename.indexOf("/", 0) + 1, filename.length - filename.indexOf("/", 0))
1752	while (filename.indexOf("\\", 0) > 0)
1753		filename = filename.substr(filename.indexOf("\\", 0) + 1, filename.length - filename.indexOf("\\", 0))
1754
1755	var lastPeriod = filename.indexOf(".", 0);
1756	var i = lastPeriod;
1757
1758	while (lastPeriod > 0) {
1759		i = lastPeriod;
1760		lastPeriod = filename.indexOf(".", i + 1);
1761	}
1762
1763	var fileExtension = (i > 0 ? filename.substr(i + 1, filename.length - i) : "");
1764
1765	if (useWhiteList)
1766		return isAllowedFileExtensionWhiteList('.' + fileExtension)
1767	else {
1768		switch (fileExtension.toUpperCase()) {
1769			case "ASA":
1770			case "ASAX":
1771			case "ASBX":
1772			case "ASCX":
1773			case "ASP":
1774			case "ASPX":
1775			case "BAT":
1776			case "CAB":
1777			case "CF":
1778			case "CFM":
1779			case "CGI":
1780			case "COM":
1781			case "CONFIG":
1782			case "DLL":
1783			case "EXE":
1784			case "HTA":
1785			case "LHA":
1786			case "LHZ":
1787			case "MIM":
1788			case "PIF":
1789			case "PL":
1790			case "SYS":
1791			case "UUE":
1792			case "VBS":
1793			case "VXD":
1794			case "WEBINFO":
1795			case "WIZ":
1796			case "WSH":
1797				{
1798					return false;
1799					break;
1800				}
1801			default:
1802				{
1803					return true;
1804					break;
1805				}
1806		}
1807	}
1808}
1809
1810// Makes sure a file being uploaded for PDF conversion is supported.
1811// Note: Server logic should additionally chop out paths and other evil things (e.g. Windows Device Names like 'CON', 'AUX', etc).
1812function isAllowedFileExtensionPDF(filename) {
1813	//cut out the path portion
1814	while (filename.indexOf("/", 0) > 0)
1815		filename = filename.substr(filename.indexOf("/", 0) + 1, filename.length - filename.indexOf("/", 0))
1816	while (filename.indexOf("\\", 0) > 0)
1817		filename = filename.substr(filename.indexOf("\\", 0) + 1, filename.length - filename.indexOf("\\", 0))
1818
1819	var lastPeriod, i, fileExtension;
1820	lastPeriod = filename.indexOf(".", 0);
1821	i = lastPeriod;
1822	while (lastPeriod > 0) {
1823		i = lastPeriod;
1824		lastPeriod = filename.indexOf(".", i + 1);
1825	}
1826
1827	if (i > 0)
1828		fileExtension = filename.substr(i + 1, filename.length - i).toUpperCase();
1829	else
1830		fileExtension = "";
1831
1832	switch (fileExtension) {
1833		case "HTM":
1834		case "HTML":
1835		case "DOC":
1836		case "DOCX":
1837		case "XLS":
1838		case "XLSX":
1839		case "TXT":
1840			{
1841				return true;
1842				break;
1843			}
1844		default:
1845			{
1846				return false;
1847				break;
1848			}
1849	}
1850}
1851
1852// returns true if it is a valid US or Canadian zip code.
1853// supports ZIP, ZIP+4 and Canadian zip code format
1854// * intCountryCode is a ISO 3166-1 numeric value.
1855function isZipCode(strInput, intCountryCode) {
1856	var countryCodeRe = {
1857		840: /^\d{5}([\-]\d{4})?$/, // USA
1858		124: /^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ -]?\d[ABCEGHJ-NPRSTV-Z]\d$/i, //Canada
1859		36: /^(?:(?:[2-8]\d|9[0-7]|0?[28]|0?9(?=09))(?:\d{2}))$/ //Australia
1860	};
1861	if (intCountryCode in countryCodeRe) {
1862		return countryCodeRe[intCountryCode].test(strInput);
1863	}
1864	return strInput.length > 0;
1865}
1866
1867// returns name to assign postal/zip code.
1868function getZipCodeName(intCountryCode) {
1869	if (intCountryCode == 840) // USA
1870		return 'Zip';
1871	else// if (intCountryCode == 124) // Canada
1872		return 'Postal';
1873}
1874
1875function updateAddressPlaceholdersForCanadinaClients(zipElementId, stateElementId) {
1876	document.getElementById(stateElementId).setAttribute('placeholder', 'Province');
1877	document.getElementById(stateElementId).style.width = '5em';
1878	document.getElementById(zipElementId).setAttribute('placeholder', 'Postal Code');
1879}
1880
1881function getLowerCaseStateString() {
1882	if (intCountryCode == 124)
1883		return "province";
1884	else// if (intCountryCode == 840) <- neutral setting (en-US).
1885		return "state";
1886}
1887
1888// Gets card type. Will return one of the following values (or an empty string for unknown/invalid cards):
1889// * Master = M
1890// * Visa = V
1891// * Discover = D
1892// * American Express = A
1893function getCreditCardType(cardNumber) {
1894	switch (cardNumber.substr(0, 2)) {
1895		case "50":
1896		case "51":
1897		case "52":
1898		case "53":
1899		case "54":
1900		case "55":
1901			return "M";
1902		case "65":
1903			return "D";
1904	}
1905	switch (cardNumber.substr(0, 1)) {
1906		case "4":
1907			return "V";
1908	}
1909	switch (cardNumber.substr(0, 4)) {
1910		case "6011":
1911			return "D";
1912	}
1913	switch (cardNumber.substr(0, 2)) {
1914		case "34":
1915		case "37":
1916			return "A";
1917	}
1918
1919	// Card unknown/invalid.
1920	return '';
1921}
1922
1923// Validates credit card numbers. cardType is an optional argument.
1924function isValidCreditCardNumber(cardNumber, cardType) {
1925	var isValid = false;
1926	var ccCheckRegExp = /[^\d ]/;
1927
1928	isValid = !ccCheckRegExp.test(cardNumber);
1929
1930	if (isValid) {
1931		// Get card type if not explicitly specified.
1932		if (cardType == null)
1933			cardType = getCreditCardType(cardNumber);
1934
1935		// If unknown/unsupported/invalid card type, abort/fail.
1936		if (cardType == '')
1937			return false;
1938
1939		var cardNumbersOnly = cardNumber.replace(/ /g, "");
1940		var cardNumberLength = cardNumbersOnly.length;
1941		var lengthIsValid = false;
1942		var patternIsValid = false;
1943		var patternRegExp;
1944
1945		switch (cardType) {
1946			case "V":
1947				{ // visa
1948					lengthIsValid = (cardNumberLength == 13 || cardNumberLength == 16);
1949					patternRegExp = /^4/;
1950					break;
1951				}
1952			case "M":
1953				{ // mastercard
1954					lengthIsValid = (cardNumberLength == 16);
1955					patternRegExp = /^5[0-5]/;
1956					break;
1957				}
1958			case "A":
1959				{ // amercian express
1960					lengthIsValid = (cardNumberLength == 15);
1961					patternRegExp = /^3[4,7]/;
1962					break;
1963				}
1964			case "D":
1965				{ // discover
1966					lengthIsValid = (cardNumberLength == 16);
1967					patternRegExp = /^6011/;
1968					break;
1969				}
1970				/*case "J":
1971				{ // jcb
1972				lengthIsValid = (cardNumberLength == 15) || (cardNumberLength == 16);
1973				patternRegExp = /^[3,1800,2131]/;
1974				break;
1975				}
1976				case "C":
1977				{ // diner's club
1978				lengthIsValid = (cardNumberLength == 14);
1979				patternRegExp = /^3[0,6,8]/;
1980				break;
1981				}*/
1982			default:
1983				patternRegExp = /^$/;
1984		}
1985
1986		patternIsValid = patternRegExp.test(cardNumbersOnly);
1987		isValid = patternIsValid && lengthIsValid;
1988	}
1989
1990	if (isValid) {
1991		var numberProduct;
1992		var numberProductDigitIndex;
1993		var checkSumTotal = 0;
1994
1995		for (digitCounter = cardNumberLength - 1; digitCounter >= 0; digitCounter--) {
1996			checkSumTotal += parseInt(cardNumbersOnly.charAt(digitCounter));
1997			digitCounter--;
1998			numberProduct = String((cardNumbersOnly.charAt(digitCounter) * 2));
1999			for (var productDigitCounter = 0; productDigitCounter < numberProduct.length; productDigitCounter++)
2000				checkSumTotal += parseInt(numberProduct.charAt(productDigitCounter));
2001		}
2002
2003		isValid = (checkSumTotal % 10 == 0);
2004	}
2005
2006	return isValid;
2007}
2008
2009// Confirms data given is legal.
2010function isDate(varDateToCheck) {
2011	var objDate = new dateValidator();
2012	return objDate.dateValidate(varDateToCheck, true, 'Date');
2013}
2014
2015// Confirms data given is legal.
2016function isDateNew(varDateToCheck) {
2017	var objDate = new dateValidator();
2018	return objDate.dateValidateNew(varDateToCheck, true, 'Date');
2019}
2020
2021// TODO: JavaScript - Remove this function. Better ways to handle this.
2022// Date comparison function.
2023function dateDiff(dtiDateEntered, dtiDateToday) {
2024	var date1 = new Date();
2025	var date2 = new Date();
2026	var diff = new Date();
2027	// Initialize the first date
2028	var date1temp = new Date(dtiDateEntered);
2029	date1.setTime(date1temp.getTime());
2030	// Initialize the second date
2031	var date2temp = new Date(dtiDateToday);
2032	date2.setTime(date2temp.getTime());
2033	// sets difference date to difference of first date and second date
2034	diff.setTime(date1.getTime() - date2.getTime());
2035	timediff = diff.getTime();
2036	days = Math.floor(timediff / (86400000)); // 1000 * 60 * 60 * 24
2037	timediff -= days * (86400000);
2038	return days;
2039}
2040
2041// .NET JavaScript debugging function.
2042// TO-DO: Add sections for 'add_' and 'remove_' event prefixes.
2043function debugDisplayMembers(obj) {
2044	var getters = new Array();
2045	var setters = new Array();
2046	var others = new Array();
2047	var sKey;
2048
2049	for (var key in obj) {
2050		sKey = key + "";
2051		if (!((sKey.length > 0) && (sKey[0] == '_'))) {
2052			switch (sKey.substr(0, 4)) {
2053				case 'get_':
2054					getters.push(key);
2055					break;
2056				case 'set_':
2057					setters.push(key);
2058					break;
2059				default:
2060					others.push(key);
2061			}
2062		}
2063	}
2064
2065	getters.sort();
2066	setters.sort();
2067	others.sort();
2068
2069	alert(others.join(", ") + "\r\n\r\n" +
2070		getters.join(", ") + "\r\n\r\n" +
2071		setters.join(", "));
2072}
2073
2074// BEGIN PSEUDO-FORMS CODE
2075// Do not call any of these methods directly in your application code.
2076// Pseudo-forms are transparent, you shouldn't need to use these methods.
2077addEvent(window, 'load', initializePseudoForms, false);
2078
2079// Allows IE to recognize tag "subform". You cannot legally nest
2080// FORM tags inside FORM tags and at least Firefox pretends they're not
2081// in the DOM period. This is problematic, so the tag was renamed.
2082// Done for FORMS inside of FORMs trick to get around ASP.NET form limitations
2083// for content we cannot control (User Pages, Info Advanced HTML, etc).
2084document.createElement('subform');
2085
2086// Initialize pseudo-forms. Called on window load.
2087function initializePseudoForms() {
2088	// Make sure we're in an HTML document (not XUL).
2089	if (document.body) {
2090		var subForms = document.body.getElementsByTagName('subform');
2091		for (var i = 0; i < subForms.length; i++)
2092			setupPseudoForm(subForms[i]);
2093	}
2094}
2095
2096// Sets up pseudo-form.
2097function setupPseudoForm(pseudoFormElement) {
2098	// Re-routes form submission elements (no javascript used/necessary).
2099	// (those being input.type=submit, button.type=submit, and input.type=image)
2100	var rerouteElement = function (input, pseudoFormElement, newTagName, newType, copyInnerHTML) {
2101		var replacement = document.createElement(newTagName);
2102		replacement.setAttribute('type', newType);
2103		var onClickDest, onClickSrc = replacement.getAttribute('onclick');
2104		if (onClickSrc != null)
2105			replacement.removeAttribute('onclick');
2106		cloneAttributes(input, replacement);
2107		if (onClickSrc != null) {
2108			eval("window.tmp = function(event) { " + onClick + " }");
2109			onClickSrc = window.tmp;
2110			window.tmp = null;
2111			onClickDest = function (ev) {
2112				ev = (window.event ? window.event : ev);
2113				if (onClickSrc(ev) == false)
2114					return;
2115				pseudoFormElement._submitter = replacement;
2116				pseudoFormElement._submevent = ev;
2117				pseudoFormElement.submit();
2118			}
2119		}
2120		else {
2121			onClickDest = function (ev) {
2122				ev = (window.event ? window.event : ev);
2123				pseudoFormElement._submitter = replacement;
2124				pseudoFormElement._submevent = ev;
2125				pseudoFormElement.submit();
2126			}
2127		}
2128
2129		// Return replacement routine.
2130		var fn = function () {
2131			var inputParent = input.parentNode;
2132			var inputRightAfter = input.nextSibling;
2133			var inputDisabled = input.disabled; // For Internet Explorer (it forgets).
2134			var inputHTML = (copyInnerHTML ? input.innerHTML : null);
2135			inputParent.removeChild(input); input = null;
2136			if (copyInnerHTML)
2137				replacement.innerHTML = inputHTML;
2138			inputParent.insertBefore(replacement, inputRightAfter);
2139			replacement.disabled = inputDisabled;
2140			addEvent(replacement, 'click', onClickDest, false);
2141		}
2142		return fn;
2143	}
2144
2145	// Re-route submits (needs to be done early on).
2146	var inputs, input, inc, repls;
2147	repls = new Array();
2148	inputs = pseudoFormElement.getElementsByTagName('input');
2149	for (var i = 0; i < inputs.length; i++) {
2150		input = inputs[i];
2151		switch (input.type.toLowerCase()) {
2152			case 'submit':
2153				repls.push(rerouteElement(input, pseudoFormElement, 'input', 'button', false));
2154				break;
2155			case 'image':
2156				repls.push(rerouteElement(input, pseudoFormElement, 'img', 'image', false));
2157				break;
2158		}
2159	}
2160	inputs = pseudoFormElement.getElementsByTagName('button');
2161	for (var i = 0; i < inputs.length; i++) {
2162		input = inputs[i];
2163		switch (input.type.toLowerCase()) {
2164			case 'submit':
2165				repls.push(rerouteElement(input, pseudoFormElement, 'button', 'button', true));
2166				break;
2167		}
2168	}
2169	for (var i = 0; i < repls.length; i++)
2170		repls[i]();
2171
2172	// Implement properties for pseudo-form.
2173	var name = pseudoFormElement.getAttribute('name');
2174	if (name && name != '') {
2175		document[name] = pseudoFormElement;
2176		document.forms[name] = pseudoFormElement;
2177	}
2178	pseudoFormElement.method = pseudoFormElement.getAttribute('method');
2179	if (pseudoFormElement.method == null || pseudoFormElement.method == '')
2180		pseudoFormElement.method = 'get';
2181	pseudoFormElement.enctype = pseudoFormElement.getAttribute('enctype');
2182	if (pseudoFormElement.enctype == null || pseudoFormElement.enctype == '')
2183		pseudoFormElement.enctype = 'application/x-www-form-urlencoded';
2184	pseudoFormElement.target = pseudoFormElement.getAttribute('target');
2185	pseudoFormElement.action = pseudoFormElement.getAttribute('action');
2186	pseudoFormElement.acceptCharset = pseudoFormElement.getAttribute('accept-charset');
2187
2188	// Initialize.
2189	var elements = new Array(); // elements in pseudo-form (for form.elements).
2190	var simpleInputs = new Array(); // simple value inputs and textareas, no additional logic.
2191	var stateInputs = new Array(); // checkboxes and radiobuttons.
2192	var dropdowns = new Array(); // drop-downs and lists.
2193	pseudoFormElement.elements = elements;
2194	pseudoFormElement._simple = simpleInputs;
2195	pseudoFormElement._state = stateInputs;
2196	pseudoFormElement._dropdown = dropdowns;
2197
2198	// Registers element for the pseudo-form.
2199	var registerElement = function (input) {
2200		// Add to elements array.
2201		elements.push(input);
2202		// Add as property.
2203		if (input.name != '' && input.name != null) {
2204			obj = pseudoFormElement[input.name];
2205			if (obj == null)
2206				pseudoFormElement[input.name] = input;
2207			else if (obj instanceof Array)
2208				obj.push(input);
2209			else {
2210				var arr = new Array();
2211				arr.push(obj);
2212				arr.push(input);
2213				pseudoFormElement[input.name] = arr;
2214			}
2215		}
2216	}
2217
2218	// Add methods (can be overridden by form elements /w same names, just like real forms).
2219	pseudoFormElement.submit = function () { submitPseudoForm(this, false); }
2220	pseudoFormElement.reset = document.aspnetForm.reset; // HACK (we'll fix it if someone complains)
2221
2222	// Register elements, and categorize them for form submission.
2223	inputs = pseudoFormElement.getElementsByTagName('input');
2224	for (var i = 0; i < inputs.length; i++) {
2225		input = inputs[i];
2226		switch (input.type.toLowerCase()) {
2227			case 'checkbox':
2228			case 'radio':
2229				stateInputs.push(input);
2230				registerElement(input);
2231				break;
2232			case 'text':
2233			case 'hidden':
2234			case 'password':
2235				simpleInputs.push(input);
2236				registerElement(input);
2237				break;
2238			default:
2239				registerElement(input);
2240		}
2241	}
2242	inputs = pseudoFormElement.getElementsByTagName('textarea');
2243	for (var i = 0; i < inputs.length; i++) {
2244		input = inputs[i];
2245		simpleInputs.push(input);
2246		registerElement(input);
2247	}
2248	inputs = pseudoFormElement.getElementsByTagName('select');
2249	for (var i = 0; i < inputs.length; i++) {
2250		input = inputs[i];
2251		dropdowns.push(input);
2252		registerElement(input);
2253	}
2254	inputs = pseudoFormElement.getElementsByTagName('button');
2255	for (var i = 0; i < inputs.length; i++)
2256		registerElement(inputs[i]);
2257}
2258
2259// Copies attributes from one element to another. Copy should occur
2260// before destElement is added to the DOM, as some things become read-only.
2261// ID and CLASS need to be handled specially for compatiblity reasons.
2262// Warning: TYPE is not supported (blame IE)!
2263function cloneAttributes(srcElement, destElement) {
2264	var attr;
2265	for (var i = 0; i < srcElement.attributes.length; i++) {
2266		attr = srcElement.attributes[i];
2267		switch (attr.name.toLowerCase()) {
2268			case 'name':
2269				if ((attr.value + '').toLowerCase() == 'submit')
2270					destElement.setAttribute('name', 'submit_button');
2271				else
2272					destElement.setAttribute('name', attr.value);
2273				break;
2274			case 'class':
2275				destElement.className = attr.value;
2276				break;
2277			case 'id':
2278				destElement.id = attr.value;
2279				break;
2280			case 'type':
2281			case 'form':
2282				break;
2283			default:
2284						try { destElement.setAttribute(attr.name, attr.value); }
2285						catch (e) { }
2286		}
2287	}
2288}
2289
2290// Called by pseudo-form when submit() is invoked.
2291function submitPseudoForm(pseudoFormElement, debugMode) {
2292	var inputs, input;
2293	var spawner = pseudoFormElement._submitter;
2294	var spawnerEvent = pseudoFormElement._submevent;
2295	pseudoFormElement._submitter = null;
2296	pseudoFormElement._submevent = null;
2297
2298	// Destroy form if it already exists (possible if target not implicit/explicit "_self").
2299	if (pseudoFormElement._form != null)
2300		document.body.removeChild(pseudoFormElement._form);
2301	pseudoFormElement._form = null;
2302
2303	// Fire pseudo-onsubmit event (remember that just like in real forms, only fires on non-J/S submits).
2304	var onsubmit = pseudoFormElement.getAttribute('onsubmit');
2305	if (onsubmit != null && onsubmit != '' && spawnerEvent) {
2306		eval("window.tmp = function(event) { " + onsubmit + " }");
2307		onsubmit = window.tmp;
2308		window.tmp = null;
2309		if (onsubmit(spawnerEvent) == false)
2310			return false;
2311	}
2312
2313	// Create actual form to forward submission to.
2314	var newForm = document.createElement('form');
2315	pseudoFormElement._form = newForm;
2316
2317	// Transfer some standard HTML/XHTML attributes.
2318	newForm.dir = pseudoFormElement.dir;
2319	newForm.lang = pseudoFormElement.lang;
2320	newForm.title = pseudoFormElement.title;
2321
2322	// Setup actual form action, accept, accept-charset, encoding, method, and target.
2323	var action = pseudoFormElement.getAttribute('action');
2324	var method = pseudoFormElement.getAttribute('method');
2325	var target = pseudoFormElement.getAttribute('target');
2326	var enctype = pseudoFormElement.getAttribute('enctype');
2327	var accept = pseudoFormElement.getAttribute('accept');
2328	var acceptCharset = pseudoFormElement.getAttribute('accept-charset');
2329	if (action)
2330		newForm.action = action;
2331	if (method)
2332		newForm.method = method;
2333	if (target)
2334		newForm.target = target;
2335	if (enctype)
2336		newForm.enctype = enctype;
2337	if (accept)
2338		newForm.accept = accept;
2339	if (acceptCharset)
2340		newForm.acceptCharset = acceptCharset;
2341
2342	// Method used to create hidden input copies.
2343	var newHiddenInput = function (name, value) {
2344		var ret = document.createElement('input');
2345		ret.type = 'hidden';
2346		ret.value = value;
2347		ret.name = name;
2348		newForm.appendChild(ret);
2349	}
2350
2351	// Create element for spawner if one exists (submitted w/o JS, e.g. input.type=submit).
2352	if (spawner && spawner.name != null && spawner.name != '')
2353		newHiddenInput(spawner.name, spawner.value);
2354
2355	// Forward text, textarea, hidden, and password input values.
2356	inputs = pseudoFormElement._simple;
2357	for (var i = 0; i < inputs.length; i++) {
2358		input = inputs[i];
2359		if ((!input.disabled) && (input.style.display != 'none'))
2360			newHiddenInput(input.name, input.value);
2361	}
2362
2363	// Forward checkbox and radio-button values.
2364	inputs = pseudoFormElement._state;
2365	for (var i = 0; i < inputs.length; i++) {
2366		input = inputs[i];
2367		if ((!input.disabled) && (input.style.display != 'none')) {
2368			if (input.checked)
2369				newHiddenInput(input.name, input.value);
2370		}
2371	}
2372
2373	// Forward drop-down/list selections.
2374	// Blame for text/value condition and necessity of options loop lies with IE.
2375	// 1) Specifically, IE 7  and IE 7 mode don't give the implicit value if it's left off.
2376	// 2) IE 8 should support retrieval of all values from the select.value prop, but doesn't.
2377	inputs = pseudoFormElement._dropdown;
2378	for (var i = 0; i < inputs.length; i++) {
2379		input = inputs[i];
2380		if ((!input.disabled) && (input.style.display != 'none')) {
2381			for (var j = 0; j < input.options.length; j++) {
2382				if (input.options[j].selected) {
2383					if (input.options[j].value == '')
2384						newHiddenInput(input.name, input.options[j].text);
2385					else
2386						newHiddenInput(input.name, input.options[j].value);
2387				}
2388			}
2389		}
2390	}
2391
2392	document.body.appendChild(newForm);
2393	if (debugMode)
2394		alert(newForm.innerHTML);
2395	newForm.submit();
2396}
2397// END PSEUDO-FORMS CODE
2398
2399function phoneStripFormatting(value) {
2400	/// <summary>Strips formatting characters (for display purposes only) from the NANP phone number given.</summary>
2401	/// <param name="value" type="String">Phone number.</summary>
2402	/// <returns type="String">Phone number with formatting cahracter removed.</returns>
2403	return (value + '').replace(/\(/g, '').replace(/\)/g, '').replace(/\s/g, '').replace(/\-/g, '');
2404}
2405
2406function phoneReformat(value, delim) {
2407	/// <summary>Reformats a number for display purposes using delimiter specified.</summary>
2408	/// <param name="value" type="String">The phone number.</summary>
2409	/// <param name="delim" type="String">The delimiter used. If argument is not passed, a hyphen is used.</summary>
2410	/// <returns type="String">Reformatted phone number.</returns>
2411	value = phoneStripFormatting(value);
2412
2413	if (delim == null)
2414		delim = '-';
2415
2416	return value.substr(0, 3) + delim + value.substr(3, 3) + delim + value.substr(6)
2417}
2418
2419function phoneObfuscate(value, secret, delim) {
2420	/// <summary>Reformats a number for display purposes, obfuscating the first 6 digits.</summary>
2421	/// <param name="value" type="String">The phone number.</summary>
2422	/// <param name="secret" type="String">The obfuscation character or string to use in place of a digit in the number. If argument is not pased, a asterisk is used.</summary>
2423	/// <param name="delim" type="String">The delimiter used. If argument is not passed, a hyphen is used.</summary>
2424	/// <returns type="String">Reformatted, obfuscated phone number.</returns>
2425	value = phoneStripFormatting(value);
2426
2427	if (secret == null)
2428		secret = '*';
2429
2430	if (delim == null)
2431		delim = '-';
2432
2433	secret = secret + secret + secret + delim;
2434	return secret + secret + value.substr(6);
2435}
2436
2437function phoneValidate(value, intCountryCode) {
2438	/// <summary>Validates that phone numbers appear to adhere to the NANP format (North American Numbering Plan).</summary>
2439	/// <remarks>
2440	/// Expects area code to be present, and no country code (e.g. 555-555-0123 is valid, 1-555-555-0123 is not).
2441	/// Does not validate that numbers are legal (e.g. area code 123 is invalid, area codes cannot begin with 1).
2442	/// </remarks>
2443	/// <param name="value" type="String">Phone number.</summary>
2444	/// <returns type="Boolean">Whether or not number passed a basic format validation.</returns>
2445	value = phoneStripFormatting(value);
2446	if (value.length == 10)
2447		return numbersOnly.test(value);
2448	else if (value.length == 8 && intCountryCode == 36) //For Australia
2449		return numbersOnly.test(value);
2450	else
2451		return false;
2452}
2453
2454//gets the cookie, if it exists
2455function getCookieValue(cookiename) {
2456	var ck = document.cookie;
2457	var cn = cookiename + "=";
2458	var pos = ck.indexOf(cn);
2459
2460	if (pos != -1) {
2461		var start = pos + cn.length;
2462		var end = ck.indexOf(";", start);
2463		if (end == -1) end = ck.length;
2464		var cookieValue = ck.substring(start, end);
2465		return (cookieValue);
2466	}
2467
2468	return (null);
2469}
2470
2471window['getCookieValue'] = getCookieValue;
2472
2473function setCookieValue(cname, cvalue, exdays) {
2474    var d = new Date();
2475    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
2476    var expires = "expires=" + d.toUTCString();
2477    document.cookie = cname + "=" + cvalue + "; " + expires + "; path=/";
2478}
2479
2480//Gets no of days between 2 dates provided in a string format('mm/dd/yyyy')
2481function dayDifference(first, second) {
2482	return Math.floor((Date.parse(first) - Date.parse(second)) / 86400000);
2483}
2484
2485// Returns whether or not file extension given is acceptable.
2486// Client-side version of FileSystemSafety.IsAllowedFileExtension().
2487function isAllowedFileExtensionWhiteList(ext) {
2488
2489	// Check if the URL contains the string "Admin"
2490	const allowed = window.location.pathname.toLowerCase().startsWith("/admin") ? 1 : 0;
2491
2492	if (!window.acceptedFileExtensions) {
2493		window.acceptedFileExtensions =
2494		{
2495			'.123': 1, '.3g2': 1, '.3gp': 1, '.3gp2': 1, '.7z': allowed, '.aac': 1, '.abw': 1, '.abx': 1, '.accdb': 1, '.accde': 1,
2496			'.accdr': 1, '.accdt': 1, '.accfl': 1, '.ace': allowed, '.ade': 1, '.adp': 1, '.aeh': 1, '.ai': 1, '.aif': 1, '.aiff': 1,
2497			'.amr': 1, '.apng': 1, '.arc': allowed, '.art': 1, '.asc': 1, '.asf': 1, '.asx': 1, '.atom': 1, '.au': 1, '.avi': 1,
2498			'.awt': 1, '.azw': 1, '.azw1': 1, '.b64': 1, '.backup': 1, '.bin': 1, '.bmp': 1, '.bz': 1, '.bz2': 1, '.bzip': 1,
2499			'.bzip2': allowed, '.cab': allowed, '.cad': 1, '.caf': 1, '.cal': 1, '.cgm': 1, '.crtx': 1, '.css': 1, '.csv': 1, '.cwk': 1, '.dap': 1, '.db': 1,
2500			'.dbf': 1, '.dcr': 1, '.dds': 1, '.dex': 1, '.dib': 1, '.dif': 1, '.diz': 1, '.dmg': 1, '.doc': 1, '.docm': 1,
2501			'.docx': 1, '.dot': 1, '.dotm': 1, '.dotx': 1, '.drw': 1, '.ds_store': 1, '.dv': 1, '.dvr-ms': 1, '.dwf': 1, '.dwg': 1,
2502			'.dxf': 1, '.emf': 1, '.eml': 1, '.emlx': 1, '.emz': 1, '.eot': 1, '.eps': 1, '.fbp': 1, '.fdp': 1, '.fhtml': 1,
2503			'.file': 1, '.flac': 1, '.flc': 1, '.fli': 1, '.flp': 1, '.flv': 1, '.fm': 1, '.fm2': 1, '.fm3': 1, '.fm5': 1,
2504			'.fmp': 1, '.fnt': 1, '.fon': 1, '.fp': 1, '.fp3': 1, '.fp5': 1, '.fp7': 1, '.fphtml': 1, '.fpt': 1, '.fpweb': 1,
2505			'.fpx': 1, '.gg': 1, '.gif': 1, '.gnumeric': 1, '.gra': 1, '.gsm': 1, '.gz': allowed, '.hdmov': 1, '.hdp': 1, '.hqx': 1,
2506			'.htm': 1, '.html': 1, '.ical': 1, '.icns': 1, '.ico': 1, '.ics': 1, '.ifo': 1, '.indd': 1, '.isf': 1, '.isu': 1,
2507			'.ivs': 1, '.jbf': 1, '.jfif': 1, '.jpe': 1, '.jpeg': 1, '.jpf': 1, '.jpg': 1, '.jxr': 1, '.key': 1, '.kml': 1, '.kmz': 1,
2508			'.knt': 1, '.kth': 1, '.lhz': 1, '.lit': 1, '.log': 1, '.lrc': 1, '.lrf': 1, '.lrx': 1, '.lst': 1, '.lyr': 1,
2509			'.m4a': 1, '.m4b': 1, '.m4p': 1, '.m4r': 1, '.mdb': 1, '.mde': 1, '.mht': 1, '.mhtml': 1, '.mid': 1, '.midi': 1,
2510			'.mim': 1, '.mix': 1, '.mng': 1, '.mobi': 1, '.mod': 1, '.moi': 1, '.mov': 1, '.movie': 1, '.mp3': 1, '.mp4': 1,
2511			'.mpa': 1, '.mpc': 1, '.mpe': 1, '.mpeg': 1, '.mpg': 1, '.mpv2': 1, '.msg': 1, '.mswmm': 1, '.mxd': 1, '.numbers': 1,
2512			'.odb': 1, '.odf': 1, '.odg': 1, '.ods': 1, '.odx': 1, '.ofm': 1, '.oft': 1, '.ogg': 1, '.ogm': 1, '.ogv': 1,
2513			'.one': 1, '.onepkg': 1, '.opx': 1, '.osis': 1, '.ost': 1, '.otf': 1, '.oth': 1, '.p65': 1, '.p7b': 1, '.pages': 1,
2514			'.pbm': 1, '.pcast': 1, '.pcf': 1, '.pcm': 1, '.pct': 1, '.pcx': 1, '.pdc': 1, '.pdd': 1, '.pdf': 1, '.pdp': 1,
2515			'.pfx': 1, '.pgf': 1, '.pic': 1, '.pict': 1, '.pkg': 1, '.pmd': 1, '.pmf': 1, '.png': 1, '.pot': 1, '.pothtml': 1,
2516			'.potm': 1, '.potx': 1, '.ppam': 1, '.pps': 1, '.ppsm': 1, '.ppsx': 1, '.ppt': 1, '.ppthtml': 1, '.pptm': 1, '.pptx': 1,
2517			'.prc': 1, '.ps': 1, '.psd': 1, '.psp': 1, '.pspimage': 1, '.pst': 1, '.pub': 1, '.pubhtml': 1, '.pubmhtml': 1, '.qbb': 1,
2518			'.qcp': 1, '.qt': 1, '.qxd': 1, '.qxp': 1, '.ra': 1, '.ram': 1, '.ramm': 1, '.rar': allowed, '.raw': 1, '.rax': 1,
2519			'.rm': 1, '.rmh': 1, '.rmi': 1, '.rmm': 1, '.rmvb': 1, '.rmx': 1, '.rp': 1, '.rss': 1, '.rt': 1, '.rtf': 1,
2520			'.rts': 1, '.rv': 1, '.sbx': 1, '.sdf': 1, '.sea': 1, '.shs': 1, '.sit': 1, '.sitx': 1, '.smil': 1, '.snapfireshow': 1,
2521			'.snp': 1, '.stc': 1, '.svg': 1, '.svgz': 1, '.swf': 1, '.sxc': 1, '.sxi': 1, '.tab': 1, '.tar': allowed, '.tex': 1,
2522			'.tga': 1, '.thmx': 1, '.tif': 1, '.tiff': 1, '.tpz': 1, '.tr': 1, '.trm': 1, '.tsv': 1, '.ttf': 1, '.txt': 1,
2523			'.uue': 1, '.vcf': 1, '.vob': 1, '.vrml': 1, '.vsc': 1, '.vsd': 1, '.wab': 1, '.wav': 1, '.wax': 1, '.wbk': 1,
2524			'.wbmp': 1, '.wdp': 1, '.webarchive': 1, '.webloc': 1, '.wk1': 1, '.wk3': 1, '.wm': 1, '.wma': 1, '.wmf': 1, '.wmmp': 1,
2525			'.wmv': 1, '.wmx': 1, '.wpd': 1, '.wps': 1, '.wri': 1, '.wvx': 1, '.xbm': 1, '.xcf': 1, '.xg0': 1, '.xg1': 1,
2526			'.xg2': 1, '.xg3': 1, '.xg4': 1, '.xht': 1, '.xhtm': 1, '.xhtml': 1, '.xif': 1, '.xlam': 1, '.xlb': 1, '.xlc': 1,
2527			'.xld': 1, '.xlk': 1, '.xlm': 1, '.xls': 1, '.xlsb': 1, '.xlshtml': 1, '.xlsm': 1, '.xlsmhtml': 1, '.xlsx': 1, '.xlt': 1,
2528			'.xlthtml': 1, '.xltm': 1, '.xltx': 1, '.xlv': 1, '.xlw': 1, '.xml': 1, '.xpi': 1, '.xps': 1, '.xsf': 1, '.xsn': 1,
2529			'.xtp': 1, '.zabw': 1, '.zip': allowed, '.zipx': allowed
2530		};
2531	}
2532
2533	return (window.acceptedFileExtensions[(ext + '').toLowerCase()] === 1);
2534}
2535
2536function handleServiceMethodError(error) {
2537	throw new Error('A server-side error occurred during the execution of an AJAX request (' +
2538		error.get_exceptionType() +
2539		')!\r\n\r\nAdditional Information:\r\n' +
2540		error.get_message() +
2541		'\r\n\r\nStack Trace:\r\n' +
2542		error.get_stackTrace().trim());
2543}
2544
2545function toggleDisplay(elem) {
2546	elem.style.display =
2547		(elem.style.display == 'none' ? '' : 'none');
2548}
2549
2550// BEGIN Old Character Counter
2551var APENDED_TEXT_LEN = typeof intCountryCode !== 'undefined' && intCountryCode === 840 && typeof FeatureToggles !== 'undefined' ? 9 : 0;
2552var MAX_MESSAGE_SIZE_SMS = 160 - APENDED_TEXT_LEN;
2553var trackLengths = new Array();
2554
2555function registerCharCounter(input, outputElemID, maxMessageSize) {
2556	var outputElem = document.getElementById(outputElemID);
2557	var id = input.id;
2558	var tracker;
2559
2560	tracker = new Object();
2561	tracker.oldLength = -1;
2562	tracker.outputElem = outputElem;
2563	tracker.input = input;
2564	trackLengths[id] = tracker;
2565
2566	setInterval(
2567		'var tracker = trackLengths[\'' + id + '\'];\r\n' +
2568		'var newLength = (tracker.input.value + \'\').length;\r\n' +
2569		'if (newLength != tracker.oldLength) {\r\n' +
2570		'	if (newLength > ' + maxMessageSize + ')' +
2571		'		tracker.outputElem.innerHTML = (newLength - ' + maxMessageSize + ') + " Characters Over";\r\n' +
2572		'	else\r\n' +
2573		'		tracker.outputElem.innerHTML = (' + maxMessageSize + ' - newLength) + " Characters Remaining";\r\n' +
2574		'	\r\n' +
2575		'	tracker.oldLength = newLength;\r\n' +
2576		'}\r\n', 100);
2577}
2578// END Old Character Counter
2579
2580function elemInsideOrEq(elemFirst, elemSecond) {
2581	/// <summary>Gets whether or not second element specified is inside or is equal to first element.</summary>
2582	/// <param name="elemFirst" type="domElement">First element.</param>
2583	/// <param name="elemSecond" type="domElement">Second element.</param>
2584	if (elemFirst == elemSecond)
2585		return true;
2586
2587	if (elemFirst && elemSecond) {
2588		elemSecond = elemSecond.parentNode;
2589
2590		while (elemSecond != null) {
2591			if (elemSecond == elemFirst)
2592				return true;
2593
2594			elemSecond = elemSecond.parentNode;
2595		}
2596	}
2597
2598	return false;
2599}
2600
2601// Do not use in new code. Use jQuery with event.preventDefault().
2602function hookAnchorClick(anchor, fn) {
2603	/// <summary>Hooks an anchor onclick and prevents default HREF behavior.</summary>
2604	/// <param name="anchor" type="domElement">The DOM element to attach the event handler for.</param>
2605	/// <param name="fn" type="Function">Function to be called when anchor is clicked. Should have sender and event argument, in that order.</param>
2606	var clickHandler = function (event) {
2607		var sender;
2608
2609		if (window.event) {
2610			event = window.event;
2611			sender = event.srcElement;
2612		}
2613		else
2614			sender = event.target;
2615
2616		fn(sender, event);
2617
2618		if (event.stopPropagation)
2619			event.stopPropagation();
2620		else
2621			event.cancelBubble = true;
2622
2623		return false;
2624	}
2625
2626	// HACK: MSIE/Opera onclick fails to operate correctly.
2627	if (isie || isie8 || isie7 || isie6 || (document.documentMode < 8) || window.opera)
2628		anchor.onmousedown = clickHandler;
2629	else
2630		anchor.onclick = clickHandler;
2631}
2632
2633// For ClientCharacterCounter control.
2634var registeredCounters = null;
2635function registerCounter(assocElem, counterElem, fmtStandard, fmtOver, maxChars) {
2636	if (assocElem == null || counterElem == null || maxChars == null || fmtStandard == null || fmtOver == null)
2637		return;
2638
2639	if (registeredCounters == null) {
2640		registeredCounters = [];
2641
2642		setInterval(function () {
2643			for (var i = 0, l = registeredCounters.length; i < l; i++) {
2644				if (registeredCounters[i].counter && registeredCounters[i].input) {
2645					var len;
2646					if (typeof registeredCounters[i].input.value === 'undefined')
2647						len = registeredCounters[i].input.val().length;
2648					else
2649						len = registeredCounters[i].input.value.length;
2650					var prevLen = registeredCounters[i].prevLen;
2651
2652					if (len == prevLen)
2653						continue;
2654					else {
2655						registeredCounters[i].prevLen = len;
2656
2657						var max = registeredCounters[i].maxChars;
2658						var numToDisplay = max - len;
2659
2660						var fmtToUse = (numToDisplay >= 0
2661							? registeredCounters[i].fmtStandard
2662							: registeredCounters[i].fmtOver);
2663
2664						if (numToDisplay >= 0)
2665							registeredCounters[i].counter.className = 'counterUnderLimit';
2666						else
2667							registeredCounters[i].counter.className = 'counterOverLimit';
2668
2669						numToDisplay = Math.abs(numToDisplay);
2670
2671						registeredCounters[i].counter.innerHTML = fmtToUse
2672							.replace(/\{0\}/g, numToDisplay)
2673							.replace(/\{1\}/g, (numToDisplay == 1 ? '' : 's'));
2674					}
2675				}
2676			}
2677		}, 100);
2678	}
2679
2680	registeredCounters.push({
2681		"fmtStandard": fmtStandard,
2682		"fmtOver": fmtOver,
2683		"counter": counterElem,
2684		"input": assocElem,
2685		"prevLen": -1,
2686		"maxChars": maxChars
2687	});
2688}
2689
2690// Detects if nextElementSibling/previousElementSibling are present.
2691function detectElementSiblingSupport() {
2692	var p = document.createElement('div');
2693	var c1 = document.createElement('div');
2694	var c2 = document.createElement('div');
2695
2696	p.appendChild(c1);
2697	p.appendChild(c2);
2698
2699	return (c1.nextElementSibling != null);
2700}
2701
2702// Gets next sibling element. Version for browsers missing nextElementSibling DOM property.
2703function nextElementSibling(elem) {
2704	elem = elem.nextSibling;
2705
2706	while (elem != null) {
2707		if (elem.nodeType == 1)
2708			return elem;
2709
2710		elem = elem.nextSibling;
2711	}
2712
2713	return null;
2714}
2715
2716// Gets previous sibling element. Version for browsers missing previousElementSibling DOM property.
2717function previousElementSibling(elem) {
2718	elem = elem.previousSibling;
2719
2720	while (elem != null) {
2721		if (elem.nodeType == 1)
2722			return elem;
2723
2724		elem = elem.previousSibling;
2725	}
2726
2727	return null;
2728}
2729
2730// Gets first child element. Version for browsers missing firstElementChild DOM property.
2731function firstElementChild(elem) {
2732	elem = elem.firstChild;
2733
2734	while (elem != null) {
2735		if (elem.nodeType == 1)
2736			return elem;
2737
2738		elem = elem.nextSibling;
2739	}
2740
2741	return null;
2742}
2743
2744if (detectElementSiblingSupport()) {
2745	// If browsers support built-in DOM properties, just use those.
2746	nextElementSibling = function (elem) { return elem.nextElementSibling; }
2747	previousElementSibling = function (elem) { return elem.previousElementSibling; }
2748	firstElementChild = function (elem) { return elem.firstElementChild; }
2749}
2750
2751function haltEvent(event, windowEvent) {
2752	if (windowEvent & !window.opera)
2753		windowEvent.cancelBubble();
2754	else {
2755		if (event.stopPropagation)
2756			event.stopPropagation();
2757
2758		if (event.preventDefault)
2759			event.preventDefault();
2760	}
2761}
2762
2763// Gets absolute left offset.
2764function absoluteOffsetLeft(oElem) {
2765	var oLeft = 0;
2766
2767	while (oElem != null) {
2768		oLeft += oElem.offsetLeft;
2769		oElem = oElem.offsetParent;
2770	}
2771
2772	return oLeft;
2773}
2774
2775function imposeMaxLength(e, Object, MaxLen) {
2776	//Truncate to maximum length
2777	if (Object.value.length > MaxLen)
2778		Object.value = Object.value.substring(0, MaxLen);
2779
2780	//ALLOW:        BACKSPACE           DELETE                  LEFT ARROW              UP ARROW            RIGHT ARROW             DOWN ARROW
2781	if ((e.keyCode == '8') || (e.keyCode == '46') || (e.keyCode == '37') || (e.keyCode == '38') || (e.keyCode == '39') || (e.keyCode == '40'))
2782		return true;
2783
2784	return (Object.value.length <= MaxLen);
2785}
2786
2787function checkURL(val, showAlert) {
2788	val = TrimString(val);
2789	if (val != '' && (val.substr(0, 7) != 'http://' && val.substr(0, 8) != 'https://' && val.substr(0, 6) != 'ftp://' && val.substr(0, 1) != '/')) {
2790		if (arguments.length == 1 || showAlert)
2791			alert('All URLs must begin with http:// or https:// or ftp://.\nAll internal links must start with a /.');
2792
2793		return false;
2794	}
2795	return true;
2796}
2797
2798function toSQLSafe(formvar) {
2799	var s = String(formvar);
2800	s = (s.replace(/'/gi, "&#39")).replace(/"/gi, "&#34");
2801	return s;
2802}
2803
2804function cancelFE(needsConfirm) {
2805	if (needsConfirm) {
2806		if (!confirm("You will discard any unsaved changes. Do you want to proceed?"))
2807			return;
2808	}
2809	window.parent.closeModalDialog('editItemBehavior');
2810	return false;
2811}
2812
2813function getThumbNailPath(path, width, height) {
2814	var lastSlashPos = path.lastIndexOf('/');
2815	var filename = path.substr(lastSlashPos + 1);
2816	var directory = path.substr(0, lastSlashPos);
2817	var lastDotPos = filename.lastIndexOf('.');
2818	var filenameWithOutExtension = filename.substr(0, lastDotPos)
2819	var fileExtension = filename.substr(lastDotPos)
2820	return directory + "/ThumbNails/" + filenameWithOutExtension + "_" + width + "x" + height + "_thumb" + fileExtension;
2821}
2822
2823function measureHtml(html, fontStyle) {
2824	var tmp = document.createElement('span');
2825	tmp.style.display = 'inline';
2826	tmp.style.position = 'absolute';
2827	tmp.style.top = '-1000px';
2828	tmp.style.left = '-1000px';
2829	tmp.style.font = fontStyle;
2830	tmp.innerHTML = html;
2831
2832	document.body.appendChild(tmp);
2833	var retVal = { width: tmp.clientWidth, height: tmp.clientHeight };
2834	document.body.removeChild(tmp);
2835
2836	return retVal;
2837}
2838
2839function fileValidateError(errorType) {
2840	if (errorType == 1)
2841		alert("A file you tried to upload was not of a permitted type. Only *.jpeg, *.jpg, *.gif, *.png, *.bmp are allowed");
2842	else
2843		alert("You have an invalid character in your filename. These are the accepted characters: a-z 0-9 ~ !( ) - + = [ ] { } , . $");
2844}
2845
2846function getNumericThousandsSeparator() {
2847	var dummy = new Number(11111111);
2848	var thousandSep = dummy.toLocaleString().replace(/1/g, '');
2849	return (thousandSep.length > 0 ? thousandSep.charAt(0) : ',');
2850}
2851
2852function getNumericDecimalSeparator() {
2853	var dummy = new Number(1.1);
2854	var thousandSep = dummy.toLocaleString().replace(/1/g, '');
2855	return (thousandSep.length > 0 ? thousandSep.charAt(0) : '.');
2856}
2857
2858function ChangeDateFormat(elem) {
2859	if (elem.value != "") {
2860		var Error = false;
2861		var dateSplit = (elem.value).split("/");
2862
2863		if (dateSplit.length == 3) {
2864			if (dateSplit[0] <= 12 && dateSplit[1] <= 31) {
2865				var d = new Date(elem.value);
2866				var currentDate = new Date();
2867
2868				var selectedDate = d.getDate();
2869				var selectedMonth = d.getMonth();
2870				var SelectedYear = d.getFullYear();
2871
2872				if (isNaN(selectedDate))
2873					Error = true;
2874				else if (isNaN(selectedDate))
2875					Error = true;
2876				else if (isNaN(selectedDate))
2877					Error = true;
2878				if (Error == false) {
2879					if (selectedDate.toString().length == 1)
2880						selectedDate = '0' + selectedDate;
2881
2882					selectedMonth++;
2883
2884					if (selectedMonth.toString().length == 1)
2885						selectedMonth = '0' + selectedMonth;
2886
2887					currentYear = currentDate.getFullYear();
2888
2889					if (SelectedYear.toString().substr(0, 2) < 20)
2890						SelectedYear = currentYear;
2891					elem.value = selectedMonth + '/' + selectedDate + '/' + SelectedYear;
2892				}
2893			}
2894			else
2895				Error = true;
2896		}
2897		else
2898			Error = true;
2899
2900		if (Error == true) {
2901			alert('Date should be in the format MM/DD/YYY');
2902			elem.value = "";
2903		}
2904	}
2905}
2906
2907function ChangeDateFormatNew(elem) {
2908	return isDateNew(elem.value);
2909}
2910
2911function isSilverlightInstalled() {
2912	var isSilverlightInstalled = false;
2913	try {
2914		//check on IE
2915		try {
2916			var slControl = new ActiveXObject('AgControl.AgControl');
2917			isSilverlightInstalled = true;
2918			isSilverlightInstalled = true;
2919		}
2920		catch (e) {
2921			//either not installed or not IE. Check Firefox.
2922			if (navigator.plugins["Silverlight Plug-In"]) {
2923				isSilverlightInstalled = true;
2924			}
2925		}
2926	}
2927	catch (e) {
2928		//we don't want to leak exceptions. However, you may want
2929		//to add exception tracking code here.
2930	}
2931	return isSilverlightInstalled;
2932}
2933
2934function setModalClass(cssClass, behaviorID) {
2935	var modalContainer = document.getElementById(behaviorID._PopupControlID);
2936
2937	if (modalContainer)
2938		modalContainer.className = 'modalContainer modalContainerCP ' + cssClass;
2939}
2940
2941function setModalClassFE(cssClass, behaviorID) {
2942	var modalContainer = document.getElementById(behaviorID._PopupControlID);
2943
2944	if (modalContainer)
2945		modalContainer.className = 'modalContainer ' + cssClass;
2946}
2947
2948//------------------- Copy Link ---------------------//
2949function showCopyLinkWindow(relatedLink, absoluteAddress, behavior, ifrID) {
2950	if (behavior) {
2951		setModalClass('modalCopyLink', behavior);
2952		var iFrame = document.getElementById(ifrID);
2953		iFrame.src = '/common/admin/CopyLink.aspx?relatedLink=' + encodeURIComponent(relatedLink) + '&absoluteAddress=' + encodeURIComponent(absoluteAddress);
2954		iFrame.style.display = 'block';
2955		behavior.show();
2956	} else {
2957		openCpModal({
2958			title: 'Copy Link',
2959			className: 'modalCopyLink',
2960			isFrontEnd: false,
2961			useIframe: true,
2962			url: '/common/admin/CopyLink.aspx?relatedLink=' + encodeURIComponent(relatedLink) + '&absoluteAddress=' + encodeURIComponent(absoluteAddress)
2963		});
2964	}
2965}
2966
2967function showCopyLinkWindowUsingAddress(absoluteAddress) {
2968	var relatedUrl = absoluteAddress.replace(window.location.host, '');
2969	relatedUrl = relatedUrl.replace(window.location.protocol + '//', '');
2970
2971	var behavior = $find('copyLinkBehavior');
2972	if (behavior)
2973		showCopyLinkWindow(relatedUrl, absoluteAddress, behavior, 'copyLinkDialog');
2974	else
2975		showCopyLinkWindow(relatedUrl, absoluteAddress, $find('editItemBehavior'), 'liveEditDialog');
2976}
2977
2978function showCopyLinkWindowUsingRelatedLink(relatedUrl) {
2979	var absoluteUrl = window.location.protocol + '//' + window.location.host + relatedUrl;
2980
2981	var behavior = $find('copyLinkBehavior');
2982	if (behavior)
2983		showCopyLinkWindow(relatedUrl, absoluteUrl, behavior, 'copyLinkDialog');
2984	else
2985		showCopyLinkWindow(relatedUrl, absoluteUrl, $find('editItemBehavior'), 'liveEditDialog');
2986}
2987
2988function closeCopyModal() {
2989	var behavior = $find('copyLinkBehavior');
2990	if (behavior)
2991		behavior.hide();
2992	else {
2993		behavior = $find('editItemBehavior');
2994		if (behavior)
2995			behavior.hide();
2996		else
2997			closeCpModal();
2998	}
2999}
3000//------------------- Copy Link End---------------------//
3001
3002//Parses the query string for the specified paramter and returns the value
3003//Returns "" if the parameter is not found
3004function GetQueryStringParameter(name) {
3005	name = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
3006	var regexS = "[\\?&]" + name + "=([^&#]*)";
3007	var regex = new RegExp(regexS);
3008	var results = regex.exec(window.location.href);
3009	if (results == null)
3010		return "";
3011	else
3012		return results[1];
3013}
3014
3015function setModalTitle(title, behaviorID) {
3016	if (behaviorID) {
3017		$('#' + behaviorID._PopupControlID).find('.modalTitle').text(title);
3018	}
3019	else {
3020		//if behaviorID is not provided, do the same as setModalTitle on FrontEnd.js
3021		var titleElem = document.getElementById('ctl00_LiveEditModalTitle');
3022
3023		if (titleElem == null)
3024			titleElem = document.getElementById('ctl00_ct100_LiveEditModalTitle');
3025
3026		if (titleElem == null)
3027			titleElem = document.getElementById('ctl00_ctl00_NotifyMeModalTitle');
3028
3029		if (titleElem)
3030			titleElem.innerHTML = title;
3031	}
3032}
3033
3034//------------------- Copy Link End---------------------//
3035
3036function isNull(object, replacement) {
3037	return object == null ? replacement : object;
3038}
3039
3040// Validates domain of email with service (ensures MX record present, DNS name valid, acceptable format).
3041// The callbacks object should contain the following methods:
3042// * badFormat - Email format invalid. Will also be thrown for null/empty email addresses.
3043// * mxMissing - MX record missing for the domain.
3044// * dnsError - A DNS error occurred (domain invalid, invalid characters in domain, etc).
3045// * success - The email appears to be valid.
3046function validateEmailDomain(emailAddress, callbacks) {
3047	$.ajax({
3048		type: "POST",
3049		url: "/Services/ValidateEmail.ashx",
3050		data: { email: emailAddress },
3051		success: function (data, textStatus, jqXHR) {
3052			switch (data.d) {
3053				case 1:
3054					callbacks.badFormat(emailAddress);
3055					break;
3056				case 2:
3057					callbacks.mxMissing(emailAddress);
3058					break;
3059				case 3:
3060					callbacks.dnsError(emailAddress);
3061					break;
3062				case 0:
3063				default:
3064					callbacks.success(emailAddress);
3065					break;
3066			}
3067		}
3068	});
3069}
3070
3071//Called when opening action menu.
3072function openPopUp(id, event) {
3073	var $popUp = $(document.getElementById(id));
3074
3075	if ($popUp.hasClass('popped')) {
3076		//do not do anything if popup is already open.
3077		return false;
3078	}
3079
3080	//Hide all popups already open if nesessary.
3081	$('.popUp').fadeOut(200).removeClass('popped');
3082	$('.popUpParent').removeClass('popped');
3083
3084	//Open popup
3085	$popUp.fadeIn(200);
3086	$popUp.addClass('popped');
3087	$popUp.parents('.popUpParent').addClass('popped');
3088
3089	//prevent triggering any other event.
3090	if (window.event)
3091		window.event.cancelBubble = true;
3092	else
3093		event.stopPropagation();
3094}
3095
3096function SignIn() {
3097	window.location.href = '/MyAccount?from=url&url=' + window.location.pathname + window.location.search;
3098}
3099
3100function SignOut() {
3101	window.location.href = '/publiclogin.aspx?out=true&txtRedirect=' + window.location.pathname.substring(1) + window.location.search;
3102}
3103
3104function removeIEParagraphs(editor) {
3105	editor.attachEventHandler("onkeyup", function (e) {
3106		if (e.keyCode == 8 || e.keyCode == 46 || e.keyCode == 13) {
3107			var result = '';
3108			var re = new RegExp("<[P]>&nbsp;<\\/[P]>", "gi");
3109
3110			var m = re.exec(editor.get_html(true));
3111
3112			if (m == null) {
3113				return;
3114			} else {
3115				result = editor.get_html(true).replace(re, '<BR>');
3116				editor.set_html(result);
3117			}
3118		}
3119	});
3120}
3121
3122//To toggle the slide show and image manger menu items based on if the img is a from a slide show or not.
3123function setMenuItems(editor) {
3124	var contextMenu = editor.getContextMenuByTagName("IMG");
3125	if (!contextMenu) return;
3126
3127	//Attach to the context menu show event, obtain editor selection and determine which tools to show
3128	contextMenu.add_show(function () {
3129		//Must be an image, the context menu would not fire
3130		var sel = editor.getSelectedElement();
3131
3132		//An array of menu item objects
3133		var menuItems = contextMenu.get_items();
3134		var menuItem = null;
3135
3136		//reset to show all and then disable the menu item based on currently selection
3137		for (i = 0; i < menuItems.length; i++) {
3138			menuItems[i].get_element().style.display = "";
3139			menuItems[i].get_element().parentNode.style.display = "";
3140		} //end for
3141
3142		if (sel.getAttribute("slideshowimage")) {
3143			menuItem = menuItems[menuItems.length - 3];
3144			menuItem.get_element().style.display = "none";
3145			menuItem.get_element().parentNode.style.display = "none";
3146
3147			menuItem = menuItems[menuItems.length - 2];
3148			menuItem.get_element().style.display = "none";
3149			menuItem.get_element().parentNode.style.display = "none";
3150		} else {
3151			menuItem = menuItems[menuItems.length - 1];
3152			menuItem.get_element().style.display = "none";
3153			menuItem.get_element().parentNode.style.display = "none";
3154		}
3155	});
3156}
3157
3158function integersOnly(e, input) {
3159	var charCode = (e.which) ? e.which : e.keyCode;
3160
3161	var keyChar = String.fromCharCode(charCode);
3162	var currentValue = $(input).val();
3163	var allowNegativeSign = !$(input).hasClass("positive") && currentValue.indexOf('-') == -1 && (currentValue.length == 0 || currentValue == window.getSelection().toString());
3164	if (keyChar == '-' && allowNegativeSign)
3165		return true;
3166
3167	if (charCode > 31 && (charCode < 48 || charCode > 57))
3168		return false;
3169
3170	return true;
3171}
3172
3173function decimalOnly(e, input, skipSelected) {
3174	skipSelected = (skipSelected == undefined || skipSelected == null) ? false : skipSelected;
3175
3176	var charCode = (e.which) ? e.which : e.keyCode;
3177
3178	var keyChar = String.fromCharCode(charCode);
3179	var currentValue = $(input).val();
3180	var hasDecimalPoint = currentValue.indexOf('.') != -1;
3181	if ((keyChar == '.' && !hasDecimalPoint))
3182		return true;
3183
3184	if (!skipSelected && isTextSelected(input))
3185		return true;
3186
3187	return integersOnly(e, input);
3188}
3189
3190function isTextSelected(input) {
3191	if (typeof input.selectionStart == "number") {
3192		return input.selectionStart == 0 && input.selectionEnd == input.value.length;
3193	} else if (typeof document.selection != "undefined") {
3194		input.focus();
3195		return document.selection.createRange().text == input.value;
3196	}
3197}
3198
3199function validFileName(e) {
3200	var charCode = (e.which) ? e.which : e.keyCode;
3201	var keyChar = String.fromCharCode(charCode);
3202	var invalidCharacters = "\\/:*?\"<>|',";
3203
3204	return invalidCharacters.indexOf(keyChar) < 0;
3205}
3206
3207function isValidURL(value) {
3208	return /^(https?:\/\/|ftp:\/\/|\/).+/i.test(value);
3209}
3210function isValidAbsoluteURL(value) {
3211	try {
3212		var parsedUrl = new URL(value, window.location.href);
3213	} catch (e) {
3214		return false;
3215	}
3216	return /^(https?|ftp):\/\//i.test(value) && /^(https?|ftp):$/.test(parsedUrl.protocol) && parsedUrl.host != '';
3217}
3218
3219function validateLink(link) {
3220	if (link != '') {
3221		if ((link.indexOf('http://') == -1) &&
3222		 (link.indexOf('https://') == -1) &&
3223		 (link.substr(0, 1) != '/')) {
3224			return false;
3225		}
3226	}
3227	return true;
3228}
3229
3230// Check if string is a whole number(digits only).
3231function isWholeNumber(val) {
3232	return String(val).search(/^(([1-9]{1}\d{0,2},(\d{3},)*\d{3})|([1-9]{1}\d{0,}))$/) != -1;
3233}
3234
3235// Checks that an input string is a decimal number
3236function isDecimalOrZero(val) {
3237	isDecimal_re = /^\d{1,5}(\.\d{1,2})?$/;
3238	return String(val).search(isDecimal_re) != -1;
3239}
3240
3241//Allows login to CPC
3242function RebuildCSS(menu) {
3243	if (confirm('This will take some time\nand the site may look funny during the process.\nAre you sure?')) {
3244		var frmARC = document.forms.frmAdminRebuldCSS;
3245		frmARC.ysnNeedInclude.value = '1';
3246		frmARC.intMenu.value = menu;
3247		frmARC.submit();
3248	}
3249}
3250
3251//Allows login to CPC
3252function adminGetHelp(helpUrl, newWindow) {
3253	document.cpconnect.action = document.cpconnect.action.split('?')[0] + '?from=url&url=' + encodeURIComponent(helpUrl);
3254	cpconnecttLogin();
3255}
3256
3257function connectCPC() {
3258	document.cpconnect.action = document.cpconnect.action.split('?')[0];
3259	var ifr = document.createElement('iframe');
3260	ifr.name = "submitCPCFrame";
3261	ifr.id = "submitCPCFrame";
3262	ifr.style.display = 'none';
3263	var frm = $(document.cpconnect).clone().get(0);
3264	frm.name = "iframeCPCConnect"
3265	frm.target = 'submitCPCFrame';
3266	ifr.appendChild(frm);
3267	document.body.appendChild(ifr);
3268	frm.submit();
3269}
3270
3271function showFeatureNotAvailablePopup(hypothesisID) {
3272	var data = {
3273		id: hypothesisID
3274	};
3275
3276	$('.emailPage').removeClass('emailPage');
3277
3278	$.ajax({
3279		url: '/FeatureNotAvailable/Popup',
3280		type: 'GET',
3281		data: {
3282			hypothesisID: hypothesisID
3283		},
3284		cache: false,
3285		success: function (response) {
3286			if (response.action == 'modal') {
3287				openCpModal({
3288					title: 'Feature Not Yet Available',
3289					className: 'featureNotAvailableModal moduleContentNew modalContainer',
3290					htmlContent: response.html,
3291					autoAdjust: true,
3292					isFrontEnd: true,
3293					elementID: 'featureNotAvailableModal'
3294				});
3295			} else {
3296				window.location = '/FeatureNotAvailable?hypothesisID='
3297                    + hypothesisID
3298                    + '&referrerUrl=' + window.location;
3299			}
3300		},
3301		beforeSend: function () {
3302			ajaxPostBackStart('Loading');
3303		},
3304		complete: function () {
3305			ajaxPostBackEnd();
3306		}
3307	});
3308}
3309
3310function getDateFormat() {
3311	if (!gDateFormat) {
3312		$.ajax({
3313			url: "/GetDateFormat",
3314			type: "GET",
3315			success: function (response) {
3316				if (response.DateFormat)
3317					gDateFormat = response.DateFormat;
3318			},
3319			error: function (xhr, textStatus, exception) {
3320				gDateFormat = "MM/dd/yyyy";
3321			},
3322			async: false
3323		});
3324	}
3325
3326	return gDateFormat == null ? "MM/dd/yyyy" : gDateFormat;	
3327
3328}
3329
3330function getdDateFormat() {
3331	var dateFormat;
3332
3333	$.ajax({
3334		url: '/Utility/GetdDateFormat',
3335		async: false,
3336		type: 'GET',
3337		dataType: 'json',
3338		success: function (data) {
3339			dateFormat = data.dateFormat;
3340		},
3341		error: function (jqXHR, textStatus, errorThrown) {
3342			dateFormat = "mm/dd/yyyy";
3343		}
3344	});
3345
3346	return dateFormat;
3347}
3348
3349function getDateFromInput(datePickerID, keepDayBeforeMonth) {
3350	var datePicker = $(datePickerID);
3351	var date;
3352	var dateFormat = keepDayBeforeMonth ? getDateFormat() : "mm/dd/yyyy";
3353	//See if datepicker if so becuase of UK format we cannot just grab the value
3354	if (!isNaN(datePicker.data('tDatePicker')) && datePicker.data('tDatePicker') && datePicker.data('tDatePicker').value()) {
3355	    var dateValTmp = new dateValidator();
3356		date = dateValTmp.format(dateFormat,new Date(datePicker.data('tDatePicker').value()));
3357	} else {
3358		if (datePicker.val()) {
3359			var dayBeforeMonthOn = getDateFormat().toLocaleLowerCase() == "dd/mm/yyyy" ? true : false;
3360			//Check if valid date before trying to format            			
3361			var dateString = checkDateFormatReturnUSString(datePicker.val(), dayBeforeMonthOn);
3362			var dateVal = new dateValidator();
3363			if (dateVal.dateValidateNew(dateString, false)) {
3364				date = dateVal.format(dateFormat,new Date(checkDateFormatReturnUSString(dateString, false)));
3365			} else {
3366				//Send the date string formatted eventhough invalid date. Allow date validation to return approiate error
3367				if (keepDayBeforeMonth) {
3368					date = dateString;
3369				} else {
3370					date = checkDateFormatReturnUSString(dateString, true);
3371				}
3372			}
3373		}
3374	}
3375	return date;
3376}
3377
3378function formatUkDateReturnUSString(dateStr, isForce) {
3379	var retVal;
3380	if (isForce || getDateFormat().toLocaleLowerCase() == "dd/mm/yyyy") {
3381		dateStr = dateStr.replace(/\-/g, '/');
3382		dateStr = dateStr.split("/");
3383		retVal = dateStr[1] + "/" + dateStr[0] + "/" + dateStr[2];
3384	} else {
3385		retVal = dateStr;
3386	}
3387	return retVal;
3388}
3389
3390function formatRFC3339DateReturnString(dateStr, keepDayBeforeMonth) {
3391	var retVal;
3392	var dateStrMod = dateStr.replace(/\-/g, '/');
3393	dateStrMod = dateStr.split("/");
3394	if (dateStrMod.length == 3 && dateStrMod[0].length == 4) {
3395		if (keepDayBeforeMonth && getDateFormat().toLowerCase() == "dd/mm/yyyy") {
3396			retVal = dateStrMod[2] + "/" + dateStrMod[1] + "/" + dateStrMod[0];
3397        } else {
3398			retVal = dateStrMod[1] + "/" + dateStrMod[2] + "/" + dateStrMod[0];
3399		}
3400	} else {
3401		retVal = dateStr;
3402	}
3403	return retVal;
3404}
3405
3406function checkDateFormatReturnUSString(dateStr, keepDayBeforeMonth) {
3407	var retVal;
3408	if (dateStr) {
3409		var splitDate = dateStr;
3410		dateStr = dateStr.replace(/\-/g, '/');
3411		splitDate = dateStr.split("/");
3412		if (splitDate.length == 3) {
3413			if (splitDate[0].length == 4) {
3414				retVal = formatRFC3339DateReturnString(dateStr, keepDayBeforeMonth);
3415			} else if (keepDayBeforeMonth) {
3416				retVal = dateStr;
3417			} else {
3418				var dateVal = new dateValidator();
3419				retVal = formatUkDateReturnUSString(dateVal.cleanDate(dateStr));
3420			}
3421		} else {
3422			retVal = dateStr;
3423		}
3424	}
3425	return retVal;
3426}
3427
3428//IE no longer displays as IE by design code to determin if it is IE11
3429function isIE11() {
3430	var trident = !!navigator.userAgent.match(/Trident\/7.0/);
3431	var net = !!navigator.userAgent.match(/.NET4.0E/);
3432	return trident && net;
3433}
3434
3435function isValidUrl(url) {
3436	return url.match(/^(ht|f)tps?:\/\/[a-z0-9-\.]+\.[a-z]{2,4}\/?([^\s<>\#%"\,\{\}\\|\\\^\[\]`]+)?$/);
3437}
3438
3439function isValidAbsoluteUrl(value) {
3440	return isValidAbsoluteURL(value);
3441}
3442
3443//Replaces the given tag with the tag to replace inside the element for all occurences of the tag within the element.
3444//$element - The element to perform the replace to
3445//tagToReplace - Tag to be replaced replace provided as string, ex: "i", "b", "strong" etc
3446//tagToReplaceWith - Tag to replace with, provided as string, ex: "i", "b", "strong" etc
3447function replaceTag($element, tagToReplace, tagToReplaceWith) {
3448    var $tagElemsToReplace = $element.find(tagToReplace);
3449    $tagElemsToReplace.each(function () {
3450        var $tagElem = $(this);
3451        var tagElemeHtml = $tagElem.html();
3452        $tagElem.replaceWith('<' + tagToReplaceWith + '>' + tagElemeHtml + '</' + tagToReplaceWith + '>');        
3453    });
3454}
3455
3456window.addEventListener("load", function () {
3457	if (MutationObserver != null) {
3458		if ($('.contentContainerOld').length > 0 && ($('.spellchecker').length > 0 || $('[id^="DialogOpener"]').length > 0)) {
3459			var observer = new MutationObserver(function moveTelerikModalOverlay(mutations) {
3460				mutations.forEach(function (mutation) {
3461					if (!mutation.addedNodes) return;
3462
3463					for (var i = 0; i < mutation.addedNodes.length; i++) {
3464						// do things to your newly added nodes here
3465						var node = mutation.addedNodes[i];
3466
3467						if (node.classList != null && node.classList.contains("TelerikModalOverlay")) {
3468							$('.contentContainerOld').after(node);
3469						}
3470					}
3471				});
3472			});
3473
3474			observer.observe(document.getElementsByClassName('contentContainerOld')[0], {
3475				childList: true,
3476				subtree: true,
3477				attributes: false,
3478				characterData: false
3479			});
3480		}
3481	}
3482});
3483
3484if (!Array.prototype.includes) {
3485	Array.prototype.includes = function (searchElement) {
3486		'use strict';
3487		if (this == null) {
3488			throw new TypeError('Array.prototype.includes called on null or undefined');
3489		}
3490
3491		var O = Object(this);
3492		var len = parseInt(O.length, 10) || 0;
3493		if (len === 0) {
3494			return false;
3495		}
3496		var n = parseInt(arguments[1], 10) || 0;
3497		var k;
3498		if (n >= 0) {
3499			k = n;
3500		} else {
3501			k = len + n;
3502			if (k < 0) { k = 0; }
3503		}
3504		var currentElement;
3505		while (k < len) {
3506			currentElement = O[k];
3507			if (searchElement === currentElement ||
3508			   (searchElement !== searchElement && currentElement !== currentElement)) { // NaN !== NaN
3509				return true;
3510			}
3511			k++;
3512		}
3513		return false;
3514	};
3515}
3516
3517function isMsie() {
3518	ua = navigator.userAgent;
3519	/* MSIE used to detect old browsers and Trident used to newer ones*/
3520	var is_ie = ua.indexOf("MSIE ") > -1 || ua.indexOf("Trident/") > -1;
3521
3522	return is_ie;
3523}
3524
3525function isMozilla() {
3526	return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
3527}
3528
3529function browserVersion() {
3530	ua = navigator.userAgent;
3531	var browserVersion = null;
3532	var verOffset = null;
3533	if (isMsie()) {
3534		verOffset = ua.indexOf("rv:");
3535		browserVersion = ua.slice(verOffset + 3).slice(0, 4);
3536	}
3537	else if (isMozilla()) {
3538		verOffset = ua.indexOf("Firefox")
3539		browserVersion=  ua.substring(verOffset + 8)
3540	}
3541	return browserVersion;
3542}
3543
3544function setDatepickerHighlightedDate(date, datePickerId) {
3545	var dateFormat = getdDateFormat();
3546	var momentDate = moment(date, dateFormat.toUpperCase()).format('MM/DD/YYYY');
3547	if (momentDate.toLowerCase() !== "invalid date") {
3548		$('#' + datePickerId).pickadate('picker').set('highlight', date, { format: dateFormat });
3549	}
3550}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.