PageSourceSearch

https://site.tourmyhome.com/js/main.js?v=573

js tourmyhome.com collected 2026-09-30 16:09:26 UTC 138,483 bytes, 3,200 lines download raw bytes

1
2var hd = {
3
4	host: 'media.hd.pics',
5
6	addFont: function (f) {
7		var fl = this.addFontList || '|';
8		var fa = f.split('|');
9		for (var a = 0; a < fa.length; a++) {
10			if ((fa[a] != '') && (fl.indexOf('|' + fa[a] + '|') == -1)) {
11				$('<link href="https://fonts.googleapis.com/css?family=' + fa[a] + '" rel="stylesheet" />').appendTo('head');
12				this.addFontList = fl + fa[a] + '|';
13			}
14		}
15	},
16
17	allowtabs: function (s) {
18		$(s).bind('keydown', function (e) {
19			var keyCode = e.keyCode || e.which;
20			if (keyCode == 9) {
21				e.preventDefault();
22				var start = $(this).get(0).selectionStart;
23				var end = $(this).get(0).selectionEnd;
24				$(this).val($(this).val().substring(0, start) + "\t" + $(this).val().substring(end));
25				$(this).get(0).selectionStart = $(this).get(0).selectionEnd = start + 1;
26			}
27		});
28	},
29
30	appMessage: function (v) {
31		if (window.ReactNativeWebView) {
32			window.ReactNativeWebView.postMessage(v);
33		}
34	},
35
36	brEncode: function (v) {
37		return v.replace(/\r/g, '').replace(/\n/g, '<br />');
38	},
39
40	cloudflareKey: function (u) {
41		return (u + 'videodelivery.net/').split('videodelivery.net/')[1].replace('?', '/').split('/')[0];
42	},
43
44	confirm: function (t, m, y, n) {
45		hd.dialog({
46			buttonAlign: 'center',
47			buttonOK: y,
48			buttonCancel: n,
49			content: '<h2 class="fheader">' + t + '</h2>' + m,
50			padding: hd.isMobile() ? '20px' : '30px 40px',
51			width: 400
52		});
53	},
54
55	cookieGotIt: function () {
56		document.cookie = 'hdph_consent=1; max-age=31536000; path=/; SameSite=Lax; Secure';
57		$('.cookie-notification').animate({ bottom: -$('.cookie-notification').outerHeight(), opacity: 0 }, 200, function () { $(this).hide(); });
58	},
59
60	cookieDecline: function () {
61		document.cookie = 'hdph_consent=0; max-age=31536000; path=/; SameSite=Lax; Secure';
62		$('.cookie-notification').animate({ bottom: -$('.cookie-notification').outerHeight(), opacity: 0 }, 200, function () { $(this).hide(); });
63	},
64
65	cookieManage: function () {
66		document.cookie = 'hdph_consent=; max-age=0; path=/; SameSite=Lax; Secure';
67		$('.cookie-notification').css({ display: 'flex', bottom: 0, opacity: 0 }).animate({ opacity: 1 }, 400);
68	},
69
70	cookieNotification: function () {
71		var hasDecision = document.cookie.split(';').some(function (c) { var t = c.trim(); return t === 'hdph_consent=1' || t === 'hdph_consent=0'; });
72		if (!hasDecision) {
73			$('.cookie-notification').css({ display: 'flex', opacity: 0 }).animate({ opacity: 1 }, 400);
74		}
75	},
76
77	copyToClipboard: function (u, t) {
78		var c2c = $('<textarea>').css({ position: 'absolute', top: 0, left: 0 }).appendTo(document.body).val(u).select();
79		document.execCommand('copy');
80		$(c2c).remove();
81		if (t) { $(t).html(''); $('<div style="position: absolute; bottom: 1.7em; left: -3.8em; background: #ffa; border: 1px solid #bb9; border-radius: 4px; box-shadow: 0 0.07em 0.3em rgba(0,0,0,0.3); color: #000; font-family: sans-serif; font-size: 0.75em; font-weight: 400; padding: 0.3em 0.7em; white-space: nowrap;">Copied to Clipboard</div>').appendTo(t).delay(2000).animate({ opacity: 0 }, 300, function () { $(this).remove(); }); }
82	},
83
84	chatOpen: function () {
85		console.log('chatOpen');
86		window.fcWidget.open();
87	},
88
89    cubiCasaTourKey: function (u) {
90        var tmp = u.replace("https://", "").replace("http://", "");
91        var parts = tmp.split('/');
92        var parts = parts[1].split('?');
93        return parts[0];
94    },
95
96    designload: function () {
97		var st = $(document).scrollTop() + $(window).height();
98		$('.designloading').each(function (i, o) {
99			if ($(o).css('display') != 'none') {
100				var ot = $(o).offset().top;
101				if (st > ot) {
102					$(o).removeClass('designloading').bind('load error', hd.designload).attr('src', $(o).attr('hd-src')).addClass('designloaded');
103					i = 99999;
104					return false;
105				}
106			}
107		});
108	},
109
110	designload_init: function () {
111		var d = $('.designload:not(".designloaded")').addClass('designloading');
112		if (d.length) {
113			var f = function () { window.clearTimeout(hd.designload_tmr); hd.designload_tmr = window.setTimeout(hd.designload, 150); }
114			$(window).resize(f).scroll(f);
115			hd.designload();
116		}
117	},
118
119	designload_tmr: null,
120
121	dialog: function (o) {
122		hd.dialog_object = o;
123		var bo = $('.hd-dialog-container');
124		var up = false;
125		if (bo.length == 0) {
126			bo = $('<div class="hd-dialog-container" style="position: relative; z-index: 999;"><div class="blackout"><div class="dialog"></div></div></div>').appendTo('body');
127			$('.blackout', bo).mousedown(function (e) { hd.dialog_blackoutclose.call(this, e); });
128		}
129		else {
130			bo.finish();
131			up = bo.is(':visible');
132		}
133		bo.css('z-index', (o.overchat) ? '2147483600' : '999');
134		var $d = $('.dialog', bo);
135		var c = o.content || '';
136		var buttons = '';
137		if (o.closer) { c = '<div class="dialog-closer"><div class="fas fa-times-circle" onclick="hd.dialog_close();"></div></div>' + c; }
138		if (o.buttonOK) { buttons += '<button class="btn btn-ok required" style="min-width: 7em; margin: 0 1em;" onclick="if(typeof hd.dialog_object.buttonOK === \'function\') { if (hd.dialog_object.buttonOK() != false) { hd.dialog_close(); } } else { hd.dialog_close(); }">' + (o.buttonOKText || 'OK') + '</button>'; }
139		if (o.buttonCancel) { buttons += '<button class="btn btn-cancel" style="min-width: 7em; margin: 0 1em;" onclick="if(typeof hd.dialog_object.buttonCancel === \'function\') { if (hd.dialog_object.buttonCancel() != false) { hd.dialog_close(); } } else { hd.dialog_close(); }">' + (o.buttonCancelText || 'Cancel') + '</button>'; }
140		if (o.buttonClose) { buttons += '<button class="btn btn-close" style="min-width: 7em; margin: 0 1em;" onclick="if(typeof hd.dialog_object.buttonClose === \'function\') { hd.dialog_object.buttonClose(); }; hd.dialog_close();">' + (o.buttonCloseText || 'Close') + '</button>'; }
141		$d.css({ padding: ((o.padding) ? o.padding : '') });
142		$d.css({ maxWidth: 'calc(100vw - ' + (20 + parseInt($d.css('padding-left').replace('px', '')) + parseInt($d.css('padding-right').replace('px', ''))) + 'px)' });
143		$d.height((o.height) ? o.height : '');
144		$d.width((o.width) ? o.width : '');
145		if (o.minWidth) { $d.css({ minWidth: o.minWidth }); }
146		if (o.maxWidth) { $d.css({ maxWidth: o.maxWidth }); }
147		if (o.maxHeight) { $d.css({ maxHeight: o.maxHeight, overflowY: 'auto' }); }
148		if (buttons.length) { c += '<div style="margin: 20px -1em 0 -1em;"><div style="display: flex; margin: 0 auto; max-width: calc(100vw - 80px); justify-content: ' + ((o.buttonAlign) ? o.buttonAlign : 'flex-end') + ';">' + buttons + '</div></div>'; }
149		if (up) { $d.html(c); } else { $d.html(c).css({ marginTop: -250 }).stop(true, false).animate({ marginTop: 0 }, 200); }
150		if (hd.isEdge() || up) { $(bo).show().css({ opacity: 1 }) } else { $(bo).show().css({ opacity: 0 }).stop(true, false).animate({ opacity: 1 }, 200); }
151		if (!(o.keepscroll)) { window.addEventListener('wheel', hd.dialog_scroll, { passive: false }); }
152		if (!(o.nofocus)) { window.setTimeout(function () { $('input, button, select, textarea', bo).first().focus(); }, 100); }
153		$('#chat-widget-container').css({ zIndex: 500 });
154	},
155
156	dialog_blackoutclose: function (e) {
157		if (hd.dialog_object == undefined) { return false; }
158		var t = (e ? (e.target == this) : true);
159		if (t && !hd.dialog_object.modal) { hd.dialog_close(); }
160	},
161
162	dialog_close: function () {
163		if (hd.dialog_object && hd.dialog_object.beforeClose) { hd.dialog_object.beforeClose(); }
164		$('.hd-dialog-container .dialog').css({ marginTop: 0 }).stop(true, false).animate({ marginTop: -250 }, 200, function () { $('.hd-dialog-container .dialog').html(''); });
165		$('.hd-dialog-container').css({ opacity: 1 }).stop(true, false).animate({ opacity: 0 }, 200, function () {
166			$('.hd-dialog-container').hide();
167			if (hd.dialog_object && hd.dialog_object.afterClose) {
168				hd.dialog_object.afterClose();
169			}
170			hd.dialog_object = undefined;
171		})
172		window.removeEventListener('wheel', hd.dialog_scroll);
173	},
174
175	dialog_height: function (h) {
176		$('.hd-dialog-container .dialog, .hd-dialog-container .dialog iframe').height(h);
177	},
178
179	dialog_scroll: function (e) {
180		var as = $(e.target).closest('.allow-scroll');
181		if (as.length == 0) {
182			hd.nope(e);
183		}
184		else {
185			if (e.originalEvent.wheelDelta > 0) {
186				if (as.scrollTop() == 0) { hd.nope(e); }
187			}
188			else {
189				if (as.scrollTop() == (as[0].scrollHeight - as.innerHeight())) { hd.nope(e); }
190			}
191		}
192	},
193
194	dialog_width: function (w) {
195		$('.hd-dialog-container .dialog, .hd-dialog-container .dialog iframe').width(w);
196	},
197
198	embedCode: function (u) {
199		if (u.toLowerCase().indexOf('iguide') > -1) {
200			return 'https://manage.youriguide.com/embed/' + hd.iGuideKey(u);
201		}
202		else if (u.toLowerCase().indexOf('matterport') > -1 || u.toLowerCase().indexOf('mpembed') > -1) {
203			return '<iframe src="' + u + '" frameborder="0" width="853" height="480" allowfullscreen allow="xr-spatial
203-tracking"></iframe>';
204		}
205		else if (u.toLowerCase().indexOf('videodelivery') > -1) {
206			return '<iframe src="' + u + '" style="border: none;" width="640" height="360" frameborder="0" allow="accelerometer; gyroscope; autoplay; encrypted-media; picture-in-picture;" allowfullscreen="true"></iframe>';
207		}
208		else if (u.toLowerCase().indexOf('vimeo') > -1) {
209			return '<iframe src="' + u + (u.indexOf('?') > -1 ? '&' : '?') + 'title=0&byline=0&portrait=0" width="640" height="360" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
210		}
211		else if (u.toLowerCase().indexOf('youtube') > -1 || u.toLowerCase().indexOf('youtu.be') > -1) {
212			return '<iframe src="https://www.youtube.com/embed/' + hd.youTubeKey(u) + '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" width="560" height="315" allowfullscreen></iframe>';
213		}
214		else if (u.toLowerCase().indexOf('zillow.com') > -1) {
215			return '<iframe src="' + u + '" width="640" height="360" frameborder="0" allow="autoplay; fullscreen" allowfullscreen></iframe>';
216        }
217		else {
218			return '';
219		}
220	},
221
222	embedThumb: function (u) {
223		return hd.embedThumbEx(u, '');
224	},
225
226	embedThumbEx: function (u, parm1) {
227		return hd.embedThumbEx2(u, parm1, '', '');
228	},
229
230	embedThumbEx2: function (u, parm1, parm2, parm3) {
231		if (u.indexOf('<') > -1) { u = ''; }
232        return 'src="https://thumb.hd.pics/thumbnail?url=' + encodeURIComponent(u) + (u ? '&time=' + parm1 : '') + '"';
233		// if (u.toLowerCase().indexOf('youtube.com/') > -1) {
234		// 	return 'src="//img.youtube.com/vi/' + hd.youTubeKey(u) + '/0.jpg"';
235		// }
236		// else if (u.toLowerCase().indexOf('videodelivery.net/') > -1) {
237		// 	return 'src="//videodelivery.net/' + hd.cloudflareKey(u) + '/thumbnails/thumbnail.jpg?fit=crop&time=' + ((parm1 != undefined && parm1.length) ? parm1 : '5s') + '&width=' + ((parm2 != undefined && parm2.toString().length) ? parm2 : '220') + '&height=' + ((parm3 != undefined && parm3.toString().length) ? parm3 : '147') + '"';
238		// }
239		// else if (u.toLowerCase().indexOf('vimeo.com/') > -1) {
240		// 	var vk = hd.vimeoKey(u);
241		// 	if (vk.length) {
242		// 		return 'class="vimeosrc" hd-vimeo="' + vk + '"';
243		// 	}
244		// 	else {
245		// 		return 'src="' + u + '" class="vimeosrc"';
246		// 	}
247		// }
248		// else if (u.toLowerCase().indexOf('matterport.com/') > -1) {
249		// 	return 'src="//my.matterport.com/api/v2/player/models/' + hd.matterportKey(u) + '/thumb/"';
250		// }
251		// else if ( (u.toLowerCase().indexOf('youriguide.com/') > -1) || (u.toLowerCase().indexOf('plntr.dev') > -1 ) ) {
252		// 	return 'src="' + u + '?'.split('?')[0] + '/doc/page_preview.jpg"';
253		// }
254		// else if (u.toLowerCase().indexOf('zillow.com/view-') > -1) {
255		// 	//return 'src="/media/zillowthumb.aspx?i=' + (u.split('/view-')[1] + '/').split('/')[1] + '"';
256		// 	return 'src="/art/social/zillow3d.png"';
257		// }
258		// else if (u.toLowerCase().indexOf('cloudpano/') > -1) {
259		// 	return 'src="/art/social/cloudpano.jpg"';
260		// }
261		// else if (u.toLowerCase().indexOf('kuula/') > -1) {
262		// 	return 'src="/art/social/kuula.jpg"';
263		// }
264        // else if (u.toLowerCase().indexOf('tour.cubi.casa') > -1) {
265        //     return `src="//tourcli.cubi.casa/${hd.cubiCasaTourKey(u)}/latest/images/cover_image.webp"`;
266        // }
267        // else {
268		// 	return 'src="//' + hd.justDomain(u) + '/favicon.ico"';
269		// }
270	},
271
272	error: function (t, m, f) {
273		if (f == undefined) { f = true; }
274		hd.dialog({
275			buttonAlign: 'center',
276			buttonOK: f,
277			content: '<h2 class="fheader">' + t + '</h2>' + m,
278			padding: '30px 40px',
279			width: 400
280		});
281	},
282
283	errornoclear: false,
284
285	errors_clear: function (o) {
286		$('.error-' + $(o).attr('name')).animate({ height: 0 }, 200, function () { $(this).hide(); hd.resize(); });
287	},
288
289	errors_init: function (el) {
290		$(el).each(function (i, o) {
291			var f = $('input[name=' + o.field + '], textarea[name=' + o.field + '], select[name=' + o.field + ']');
292			var e = $('.error-' + o.field);
293			if (e.length == 0) {
294				$(f).closest('.f').before($('<div class="error error-' + o.field + '">' + o.message + '</div>'));
295			}
296			else {
297				$(e).stop(false, false).html(o.message).css({ height: '' }).show();
298			}
299			if (i == 0) {
300				f.focus();
301				if (f.length && f.closest('.dialog').length == 0) { $('html, body').animate({ scrollTop: f.offset().top - ($(window).height() * 0.4) }); }
302			}
303		});
304	},
305
306	facialRecognition: function (o) {
307		if (!window.cv) {
308			console.log('Loading OpenCV');
309			$('<script src="/js/opencv.js"></script>').appendTo('head');
310			cv.onRuntimeInitialized = function () { hd.facialRecognition(o); }
311			$('<script src="/js/utils.js"></script>').appendTo('head');
312		}
313		else if (!window.utils) {
314			window.utils = new Utils();
315			window.utils.createFileFromUrl('haarcascade_frontalface_default.xml', '/js/haarcascade_frontalface_default.xml', function () {
316				hd.facialRecognition(o);
317			});
318		}
319		else {
320			var ms = hd.getMediaSize($(o).attr('hd-media'), 400, 400);
321			let img = document.createElement('img');
322			img.o = o;
323			img.crossOrigin = 'Anonymous';
324			img.onload = hd.facialRecognitionProcess;
325			img.src = '/media/sized.aspx?k=' + ms.s + '&e=' + $(o).attr('hd-mediaext') + '&w=' + Math.min(ms.w, 700);
326		}
327	},
328
329	facialRecognitionProcess: function () {
330		let src = cv.imread(this);
331		let gray = new cv.Mat();
332		cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY, 0);
333		let faces = new cv.RectVector();
334		let faceCascade = new cv.CascadeClassifier();
335		faceCascade.load('haarcascade_frontalface_default.xml');
336		let msize = new cv.Size(0, 0);
337		faceCascade.detectMultiScale(gray, faces, 1.2, 3, 0, msize, msize);
338		var f = '';
339		var iw = this.width;
340		var ih = this.height;
341		for (let i = 0; i < faces.size(); ++i) {
342			f += (f == '' ? '' : '|') +
343				Math.round(100 * (faces.get(i).x / iw)) + '`' +
344				Math.round(100 * (faces.get(i).y / ih)) + '`' +
345				Math.round(100 * ((faces.get(i).x + faces.get(i).width) / iw)) + '`' +
346				Math.round(100 * ((faces.get(i).y + faces.get(i).height) / ih));
347		}
348		if (f == '') { f = '`'; }
349		var m = $(this.o).attr('hd-media').split(','); var m0 = m[0].split(':'); m0[3] = f; m[0] = m0.join(':');
350		var s = m.join(',');
351		$(this.o).attr('hd-media', s);
352		var mid = $(this.o).attr('hd-mid');
353		if (mid) {
354			$.ajax('/admin/server/facial.asp?nMediaID=' + mid + '&sSizes=' + s);
355			$('.m' + mid).attr('hd-media', s).each(function (i, o) { o.picboxprocessed = false; hd.picbox_process(o); });
356		}
357		hd.facialShow(this.o);
358		src.delete(); gray.delete(); faceCascade.delete(); faces.delete();
359		if (this.o.callback) { this.o.callback(); }
360		$(this).remove();
361	},
362
363	facialShow: function (o) {
364		var m = $(o).attr('hd-media');
365		$('.facialshow', o).remove();
366		if (m) {
367			var f = m.split(',')[0].split(':')[3];
368			if (f && (f.length > 1)) {
369				$(f.split('|')).each(function (i, ff) {
370					var fff = ff.split('`');
371					var ii = $('img', o);
372					var iip = ii.position();
373					$('<div class="facialshow" style="box-shadow: 0 0 1px 1px #fff, 0 0 30px #000; position: absolute; left: ' + ((fff[0] * ii.width() * 0.01) + iip.left) + 'px; top: ' + ((fff[1] * ii.height() * 0.01) + iip.top) + 'px; width: ' + ((fff[2] - fff[0]) * ii.width() * 0.01) + 'px; height: ' + ((fff[3] - fff[1]) * ii.height() * 0.01) + 'px;"></div>').appendTo(ii.parent());
374				});
375			}
376		}
377	},
378
379	fileSize: function (f) {
380		var main;
381		f = Number(f);
382
383		if (f != NaN) {
384			if (f > 999999999999999) {
385				main = f / (Math.pow(1024, 5));
386				main = Math.round((main + Number.EPSILON) * 100) / 100; //round to nearest 2 digits
387				return new Intl.NumberFormat((hd.moneyCulture.length > 1 ? hd.moneyCulture : 'en-US')).format(main).toString() + ' PB';
388			}
389			if (f > 999999999999) {
390				main = f / (Math.pow(1024, 4));
391				main = Math.round((main + Number.EPSILON) * 100) / 100; //round to nearest 2 digits
392				return new Intl.NumberFormat((hd.moneyCulture.length > 1 ? hd.moneyCulture : 'en-US')).format(main).toString() + ' TB';
393			}
394			if (f > 999999999) {
395				main = f / (Math.pow(1024, 3));
396				main = Math.round((main + Number.EPSILON) * 100) / 100; //round to nearest 2 digits
397				return new Intl.NumberFormat((hd.moneyCulture.length > 1 ? hd.moneyCulture : 'en-US')).format(main).toString() + ' GB';
398			}
399			if (f > 999999) {
400				main = f / (Math.pow(1024, 2));
401				main = Math.round((main + Number.EPSILON) * 100) / 100; //round to nearest 2 digits
402				return new Intl.NumberFormat((hd.moneyCulture.length > 1 ? hd.moneyCulture : 'en-US')).format(main).toString() + ' MB';
403			}
404			if (f > 999) {
405				main = f / 1024;
406				main = Math.round((main + Number.EPSILON) * 100) / 100; //round to nearest 2 digits
407				return new Intl.NumberFormat((hd.moneyCulture.length > 1 ? hd.moneyCulture : 'en-US')).format(main).toString() + ' KB';
408			}
409		}
410
411		return f.toString() + ' bytes';
412	},
413
414    fixDate: function (f) {
415        var v = $(f).val();
416        if (v == '') { return true; }
417        var d = new Date(v);
418        if (d.toString() == 'Invalid Date') {
419            $(f).focus();
420            window.setTimeout(function () { hd.errors_init([{ field: f.name, message: 'Invalid Date' }]); }, 1);
421            return false;
422        }
423        else {
424            $(f).val((d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear());
425            return true;
426        }
427    },
428
429    fixEmail: function (f) {
430        var v = $(f).val();
431        if (v == '') { return true; }
432
433        if (!hd.isValidEmail(v)) {
434            $(f).focus();
435            window.setTimeout(function () { hd.errors_init([{ field: f.name, message: 'Invalid Email Address' }]); }, 1);
436            return false;
437        }
438        else {
439            return true;
440        }
441    },
442
443    fixEmbedUrl: function (t) {
444        var v = $(t).val();
445        if (v.indexOf('<') > -1) {
446            v = v.replace(/'/g, '"');
447            if ((v.indexOf('cloudpano') > -1) && (v.indexOf('data-short="') > -1)) {
448                v = 'https://app.cloudpano.com/tours/' + v.split('data-short="')[1].split('"')[0];
449            }
450            else if (v.indexOf('src="') > -1) {
451                v = v.split('src="')[1].split('"')[0];
452            }
453            else if (v.indexOf('href="') > -1) {
454                v = v.split('href="')[1].split('"')[0];
455            }
456            else {
457                v = '';
458            }
459            if (v.substr(0, 2) == '//') { v = 'https:' + v; }
460            $(t).val(v);
461        }
462    },
463
464    fixMoney: function (f) {
465        var v = $(f).val();
466        if (v == '') { return true; }
467        var n = Number(hd.moneyStripComma(v));
468        if (isNaN(n)) {
469            $(f).focus();
470            window.setTimeout(function () { hd.errors_init([{ field: f.name, message: 'Invalid Amount' }]); }, 1);
471            return false;
472        }
473        else {
474            $(f).val(hd.moneySimple(n));
475            return true;
476        }
477    },
478
479	fixPercentage: function (f, d) {
480		hd.fixPercentageEx(f, (d || 1));
481	},
482
483	//extension function to allow for no decimal points
484	fixPercentageEx: function (f, d) {
485		var v = $(f).val().replace(/%/g, '');
486		if (v == '') { return true; }
487		var n = Number(v);
488		if (isNaN(n)) {
489			$(f).focus();
490			window.setTimeout(function () { hd.errors_init([{ field: f.name, message: 'Invalid Percentage' }]); }, 1);
491			return false;
492		}
493		else {
494			$(f).val(hd.number(n, (d || 0)) + '%');
495			return true;
496		}
497	},
498
499    fixTime: function (f) {
500        var v = $(f).val().trim();
501        if (v == '') { return true; }
502        v = v.replace(/pm/i, ' pm').replace(/am/i, ' am');
503        if (v.indexOf(':') == -1) { v = v.replace(/ /, ':00 '); }
504        if (v.indexOf(':') == -1) { v += ':00'; }
505        var d = new Date('1/1/2000 ' + v);
506        if (d.toString() == 'Invalid Date') {
507            $(f).focus();
508            window.setTimeout(function () { hd.errors_init([{ field: f.name, message: 'Invalid Time' }]); }, 1);
509            return false;
510        }
511        else {
512            invaliddata = false;
513            var h = d.getHours();
514            var m = d.getMinutes();
515            if (h < 9 && v.toLowerCase().indexOf('am') == -1) { h += 12; }
516            $(f).val((((h + 11) % 12) + 1) + ':' + (m < 10 ? '0' : '') + d.getMinutes() + ((h < 12) ? ' AM' : ' PM'));
517            return true;
518        }
519    },
520
521    fixUrl: function (f, s, d) {
522        var v = $(f).val();
523        if (v == '') { return true; }
524        if (s == undefined) { s = true; }
525        if (s && v.substr(0, 7).toLowerCase() == 'http://') {
526            v = 'https' + v.substr(4);
527            $(f).val(v);
528        }
529        else if (v.substr(0, 7).toLowerCase() != 'http://' && v.substr(0, 8).toLowerCase() != 'https://') {
530            v = (s ? 'https://' : 'http://') + v;
531            $(f).val(v);
532        }
533        if (d) {
534            var dp = v.split('/');
535            var vd = dp[2].toLowerCase();
536            var p = false;
537            console.log(vd);
538            $(d).each(function (i, o) {
539                if (o.toLowerCase() == vd) {
540                    p = true;
541                }
542                else if (vd.length > o.length && vd.substr(-o.length) == o.toLowerCase() && vd.substr(-1 - o.length, 1)) {
543                    p = true;
544                }
545            });
546            if (!p) {
547                window.setTimeout(function () { hd.errors_init([{ field: f.name, message: 'The link must be at the ' + d.join(' or ') + ' domain.' }]); }, 1);
548                return false;
549            }
550            if (dp.length < 4 || dp[3] == '') {
551                window.setTimeout(function () { hd.errors_init([{ field: f.name, message: 'The URL must be the link to your page.' }]); }, 1);
552                return false;
553            }
554        }
555        return true;
556	},
557
558	fixVideoUrl: function (u) {
559		if (u == undefined || u == null) {
560			return '';
561		}
562		if (u.toLowerCase().substring(0, 7) != 'http://' && u.toLowerCase().substring(0, 8) != 'https://') {
563			u = 'http://' + u;
564		}
565		if (u.toLowerCase().indexOf('youtu.be') > -1) {
566			u = 'https://www.youtube.com/embed/' + (u.toLowerCase().split('youtu.be', 2)[1] + '?').split('?')[0];
567		}
568
569		if (u.toLowerCase().indexOf('vimeo.com/') > -1) {
570			var hash = hd.vimeoHash(u);
571			return 'https://player.vimeo.com/video/' + hd.vimeoKey(u) + (hash.length ? '?h=' + hash : '');
572		}
573		else if (u.toLowerCase().indexOf('youtube.com/') > -1) {
574			var key = hd.youTubeKey(u);
575			if (key.length) {
576				return 'https://www.youtube.com/embed/' + key;
577			}
578		}
579		return u;
580	},
581
582    fullDate: function (d) {
583        return String(d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear() + ' ' + (((d.getHours() + 11) % 12) + 1) + ':' + ('0' + d.getMinutes()).slice(-2) + ':' + ('0' + d.getSeconds()).slice(-2) + (d.getHours() < 12 ? ' AM' : ' PM');
584    },
585
586    fullMonth: function (i) {
587        return ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'][Math.min(Math.max(parseInt(i), 0), 11)];
588    },
589
590    geocode: function (adr, fn, f) { //address, optional result functionName, optional passthrough variable/function
591        //this function calls a local (on the page that calls hd.geocode) geocodeResult function, if exists, when the results have been retreived.
592        var funcName = 'geocodeResult';
593        if (fn != undefined) //override the name of the function if provided
594            funcName = fn;
595
596        $.ajax({
597            url: '/Admin/Map/Geocode.asp?sAddress=' + encodeURIComponent(adr),
598            error: function (jqXHR, s, e) {
599                if (typeof self[funcName] === 'function') //using self[funcName] compares the string name as the function name
600                    return self[funcName]({ 'error': e }, f);
601                else
602                    return { 'error': e };
603            },
604            success: function (d) {
605                //console.log(d);
606                if (d && d.error == undefined) {
607                    var l = { 'lat': d.lat, 'lng': d.lng, 'resultTypeAcceptable': d.resultTypeAcceptable, 'resultTypeAccurate': d.resultTypeAccurate, 'queryScore': d.queryScore };
608                    if (typeof self[funcName] === 'function')
609                        return self[funcName](l, f);
610                    else
611                        return { l };
612                } else {
613                    if (typeof self[funcName] === 'function')
614                        //return self[funcName]({ 'error': 'There was a problem retrieving Lat/Lng.' }, f);
615                        return self[funcName]({ 'error': d.error }, f);
616                    else
617                        //return { 'error': 'There was a problem retrieving Lat/Lng.' }
618                        return { 'error': d.error }
619                }
620            }
621        });
622    },
623
624    getMediaSize: function (s, w, h) {
625        var l = s.split(',');
626        var p;
627        for (var a = 0; a < l.length; a++) {
628            p = l[a].split(':');
629            if ((p[1] > w) && (p[2] > h)) {
630                return { s: p[0], w: p[1], h: p[2] };
631            }
632        }
633        return { s: p[0], w: p[1], h: p[2] };
634    },
635
636    staticIcons: { dwg: { u: '/art/IconDWG.png', w: 512, h: 532 } },
637
638    getMediaUrl: function (s, w, h, e, f, b, nrc) {
639        if (s == '-') { return { u: '/art/pixel.gif', s: s, w: 1, h: 1 }; }
640        if (s.split(':')[0] == 'z') { return { u: '/art/z.jpg', s: s, w: 1000, h: 750 }; }
641        if (s.substr(0, 1) == '*') { return { u: '/art/pixel.gif', s: s, w: 1, h: 1, v: s.substr(1) }; }
642        if (e == undefined || e == '') { e = 'jpg'; }
643        var ic = hd.staticIcons[e.toLowerCase()];
644        if (ic && ic.u) { return { u: ic.u, s: s, w: ic.w, h: ic.h }; }
645        if (e == 'pdf') {
646            return {
647                u: '//gfx.hd.pics/pdf?k=' + s.split(':')[0],
648                s: s,
649                w: 256,
650                h: 336,
651                l: function () {
652                    var tt = $(this).css({ width: 'auto', height: 'auto' }), iw = tt.width(), ih = tt.height();
653                    var pb = tt.parent(), bw = parseFloat(pb.attr('hd-picboxborder') || -1), cw = pb.width(), ch = pb.height();
654                    var ir = iw / ih, cr = (cw - (bw * 2)) / (ch - (bw * 2));
655                    if (ir < cr) {
656                        tt.css({ height: ch - (bw * 2), top: bw, left: bw + (((cw - (bw * 2)) - ((ch 
656- (bw * 2)) * ir)) * 0.5) });
657                    }
658                    else {
659                        tt.css({ width: cw - (bw * 2), top: bw + (((ch - (bw * 2)) - ((cw - (bw * 2)) / ir)) * 0.5), left: bw });
660                    }
661                }
662            };
663        }
664        else {
665            var pr = window.devicePixelRatio;
666            if (pr) { w *= pr; h *= pr; }
667            if (s.substr(0, 1) == '@') {
668                return { u: 'https://videodelivery.net/' + s.substr(1).split('/')[0] + '/thumbnails/thumbnail.jpg?fit=crop&time=' + ((s.substr(1) + '/').split('/')[1] || '5s') + ((w) ? '&width=' + parseInt(Math.min(2000, w)) : '') + ((h) ? '&height=' + parseInt(Math.round(h / 2) * 2) : ''), s: s, w: w, h: h };
669            }
670            var o = hd.getMediaSize(s, w, h);
671            if (o.s.substr(0, 1) == '~') {
672                return { u: 'https://i.vimeocdn.com/video/' + o.s.substr(1) + '.jpg?r=pad', s: o.s, w: o.w, h: o.h };
673            }
674            if ((o.w > (w * 2)) && (o.w > 500) && (o.h > (h * 2)) && (o.h > 500) && (nrc !== true) && (window.noresizepicbox !== true)) {
675                return { u: '/media/sized.aspx?k=' + o.s + '&e=' + e + '&w=' + w + '&h=' + h + ((f != undefined) ? '&f=' + (f || 'c') : '') + ((b) ? '&b=' + b : ''), s: o.s, w: w, h: h };
676            }
677            return { u: '//' + hd.host + '/' + o.s + '.' + e, s: o.s, w: o.w, h: o.h };
678        }
679    },
680
681    gridsort: function () {
682        var t = $(this).closest('table');
683        var totalsrows = parseInt(t.attr('hd-totalrows') ?? '0'); //skip this many rows that contain totals
684        var i = parseInt($(this).attr('hd-sortcol') || $(this).index());
685        var r = t.find('tbody tr');
686        var inv = ($(this).find('.sortdown').length > 0);
687        var num = $(this).hasClass('sortnum');
688        var s = t.attr('hd-sort');
689        if (s) { window.localStorage['sort-' + s] = (inv ? (-1 - i) : (i + 1)); }
690        $(t).find('.sortdown, .sortup').remove();
691        if (!inv) {
692            $(this).append('<span class="sortdown fas fa-long-arrow-down" style="margin-left: 0.3em;"></span>');
693        }
694        else {
695            $(this).append('<span class="sortup fas fa-long-arrow-up" style="margin-left: 0.3em;"></span>');
696        }
697        var l = [];
698        for (var a = 0; a < r.length; a++) {
699            var c = $(r[a]).find('td')[i];
700            var v = $(c).attr('hd-sortkey'); if (!v) { v = $(c).text(); }
701            if (num) { v = parseFloat(v.replaceAll(/[^\d.-]/g, '')); } else { v = v.toLowerCase(); }
702            l[a] = { v: v, r: r[a] };
703        }
704        for (var a = 0; a < r.length - 1 - totalsrows; a++) {
705            var t1 = l[a].v;
706            var t2 = l[a + 1].v;
707            if ((!inv && (t1 > t2)) || (inv && (t1 < t2))) {
708                var ll = l[a];
709                l[a] = l[a + 1];
710                l[a + 1] = ll;
711                if (a == 0) { a--; } else { a -= 2; }
712            }
713        }
714        for (var a = 0; a < r.length - 1; a++) {
715            $(l[a].r).after(l[a + 1].r);
716        }
717        hd.maxrows(t);
718    },
719
720    gridsort_init: function () {
721        $('.grid th.sortcol').css({ cursor: 'pointer', userSelect: 'none' }).click(hd.gridsort);
722        $('.grid').each(function (i, o) {
723            var s = $(o).attr('hd-sort');
724            if (s) {
725                var v = window.localStorage['sort-' + s];
726                if (v) {
727                    var h = $(o).find('thead th')[Math.abs(Number(v)) - 1];
728                    if (Number(v) < 0) { $(h).append('<span class="sortdown"></span>'); }
729                    window.setTimeout(function () { hd.gridsort.apply(h); }, 10);
730                }
731            }
732        });
733    },
734
735	guid: function (s) {
736		if (s == undefined) { s = ''; }
737		s = hd.onlyHex(hd.iD(s));
738		if (s.length == 32) {
739			s = '{' + s.substr(0, 8) + '-' + s.substr(8, 4) + '-' + s.substr(12, 4) + '-' + s.substr(16, 4) + '-' + s.substr(20) + '}';
740		}
741		else {
742			s = '';
743		}
744		return s;
745	},
746
747    hasTime: function (v) {
748        var d = new Date(v);
749        return (d.getHours() > 0) || (d.getMinutes() > 0) || (d.getSeconds() > 0);
750    },
751
752    hero: function (s, l) {
753        hd.hero_apply(s, l);
754        hd.hero_data.push({ s: s, l: l });
755    },
756
757    hero_apply: function (s, l) {
758        var ww = $(window).width();
759        var o = $(s)[0];
760        if (o) {
761            var i = l.length - 1;
762            for (var a = 0; a < l.length; a++) {
763                if (l[a].w > ww) {
764                    i = a; a = l.length;
765                }
766            }
767            if (i > (o.heroindex !== undefined ? o.heroindex : -1)) {
768                $(o).css({ background: 'url(' + l[i].u + ')', backgroundSize: 'cover', backgroundPosition: 'center center' });
769                o.heroindex = i;
770            }
771        }
772    },
773
774    hero_data: [],
775
776    hero_resize: function () {
777        $(hd.hero_data).each(function (i, o) {
778            hd.hero_apply(o.s, o.l);
779        });
780	},
781
782	hexToRgb: function(hex) {
783	  // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
784	  var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
785	  hex = hex.replace(shorthandRegex, function(m, r, g, b) {
786		return r + r + g + g + b + b;
787	  });
788
789	  var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
790	  return result ? {
791		r: parseInt(result[1], 16),
792		g: parseInt(result[2], 16),
793		b: parseInt(result[3], 16)
794	  } : null;
795	},
796
797    htmlDecode: function (v) {
798        return $('<div/>').html(v).text();
799    },
800
801    htmlEncode: function (v) {
802        return $('<div/>').text(v).html().replace(/"/g, '&quot;');
803    },
804
805	iGuideKey: function(u) {
806		if (u.toLowerCase().indexOf('youriguide.com/') > -1) {
807			return (((u.replace('/embed/', '/') + 'youriguide.com/').split('youriguide.com/')[1] + '/').split('/')[0] + '?').split('?')[0];
808		}
809		return '';
810	},
811
812	iD: function (s) { //we can worry about case if we want. I made it cap "D" to make it more intentional to use. (function should match ASP function)
813		if (s == undefined) { s = ''; }
814		return s.replace(/[{}-]+$/, '');
815	},
816
817    invoiceSend: function (s, o) {
818        var e = $('.dialog input[name=sInvoiceEmail]').focus().val().trim();
819        if (e == '') { return false; }
820        $('.dialog input[name=sInvoiceEmail], .dialog .email-send').prop('disabled', true);
821        $.ajax({
822            url: '/Sites/invoice.asp?nSiteID=' + (s || '') + '&nOrderID=' + (o || '') + '&sEmail=' + encodeURIComponent(e),
823            complete: function () {
824                $('.dialog .emailenter').hide();
825                $('.dialog .sent').show();
826                $('.dialog .emailbox').delay(3000).animate({ opacity: 0 }, function () {
827                    $(this).animate({ height: 0 }, function () { $('.dialog .btn-cancel').prop('disabled', false); })
828                    $('.dialog input[name=sInvoiceEmail], .dialog .email-send').prop('disabled', false);
829                    $('.dialog .emailenter').show();
830                    $('.dialog .sent').hide();
831                });
832            }
833        });
834    },
835
836    invoiceView: function (s, o, e) {
837        hd.dialog({
838            buttonAlign: 'center',
839            buttonOK: function () { var p = $('.invoiceframe')[0].contentWindow.printMe; if (p) { p(); } return false; },
840            buttonOKText: 'Print',
841            buttonCancel: function () { $('.dialog .btn-cancel').prop('disabled', true); $('.dialog .ithumb').animate({ height: 600 }); $('.dialog .emailbox').animate({ height: 70 }).animate({ opacity: 1 }, function () { $('.dialog input[name=sInvoiceEmail]').focus(); }); return false; },
842            buttonCancelText: 'Email',
843            buttonClose: function () { },
844            content: '<div style="display: flex; flex-direction: column; height: 460px; max-height: calc(100vh - 180px);">' +
845                '   <div style="flex-grow: 1;"><iframe class="invoiceframe" src="/Sites/invoice.asp?nSiteID=' + (s || '') + '&nOrderID=' + (o || '') + '" frameborder="0" style="width: 798px; height: 100%; box-shadow: 0 0 2px 1px #555, 0 0 7px #aaa, 0 50px 50px -50px #ccc;"></iframe></div>' +
846                '   <div class="emailbox" style="overflow: hidden; height: 0; margin: 20px 0 -20px 0; opacity: 0; text-align: center;">' +
847                '       <div class="emailenter">' +
848                '           <div style="display: flex; justify-content: center; margin: 0 auto; max-width: calc(100vw - 70px);">' +
849                '               <div class="f" style="flex-basis: 400px; flex-shrink: 1;"><input type="text" name="sInvoiceEmail" value="' + hd.htmlEncode(e) + '" hd-hint="Email Address(es)" hd-hint-noshrink style="width: calc(100% - 15px); vertical-align: bottom; border-top-right-radius: 0; border-bottom-right-radius: 0; " /></div>' +
850                '               <button class="btn email-send" style="height: 42px; vertical-align: bottom; border-top-left-radius: 0; border-bottom-left-radius: 0; border-left: 0;" onclick="hd.invoiceSend(' + String(s) + ',' + String(o) + ');">Send</button>' +
851                '           </div>' +
852                '       </div>' +
853                '       <div class="sent" style="display: none; margin-top: 0.9em;">Email Sent</div>' +
854                '   </div>' +
855                '</div>',
856            padding: '0',
857            height: 'min(calc(100vh - 110px), 530px)',
858            width: 800,
859            nofocus: true
860        });
861        var d = $('.dialog');
862        hd.texthint_init(d);
863        if (hd.isMobile()) {
864            var s = d.width() / 798;
865            d.find('iframe').css({ transform: 'scale(' + s.toFixed(3) + ')', transformOrigin: '0 0', height: 'calc(100% / ' + s.toFixed(3) + ')' });
866        }
867    },
868
869    isAdvancedUpload: function () {
870        var div = document.createElement('div');
871        return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && 'FormData' in window && 'FileReader' in window;
872    },
873
874    isEdge: function () {
875        return /Edge/.test(navigator.userAgent);
876    },
877
878    isIOS: function() {
879        return (/iPhone|iPod|iPad/).test(navigator.userAgent);
880    },
881
882    isMac: function () {
883        return (/Macintosh/).test(navigator.userAgent);
884    },
885
886    isMobile: function () {
887        return (/Mobile|iPhone|iPod|iPad|Android|BlackBerry/).test(navigator.userAgent);
888    },
889
890    isSafari: function () {
891        return /^((?!chrome|android).)*safari/i.test(navigator.userAgent) || hd.pretendToBeSafari;
892    },
893
894	isValidDate: function (s) {
895		s += '//'; //split protection
896		var bits = s.replace(/-/g, '/').split('/'); //in the event that the date was written with dashes ex: 2-14-2024, change them to slashes.
897		var d = new Date(bits[0] + '/' + bits[1] + '/' + bits[2]);
898        var y = (bits[2].indexOf(' ') > -1 ? bits[2].split(' ')[0] : bits[2]);
899        //return !!(d && (d.getMonth() + 1) == bits[0] && d.getDate() == Number(bits[1]) && hd.isValidYear(y)); //this will be retried for the date validation Card
900        return !!(d && (d.getMonth() + 1) == bits[0] && d.getDate() == Number(bits[1]));
901    },
902
903    isValidDomain: function (e) {
904        var re = /^(?!:\/\/)([a-zA-Z0-9-_]+\.)*[a-z0-9][a-z0-9-_]+\.[a-zA-Z]{2,11}?$/;
905        return re.test(String(e).toLowerCase());
906    },
907
908    isValidEmail: function (e) {
909        var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
910        return re.test(String(e).toLowerCase());
911    },
912
913    isValidYear: function (y) {
914        return (y && '24'.indexOf(String(y).length) > -1);
915    },
916
917    isVideo: function (e) {
918        e = e.replace('.', '');
919        return (e == 'avi') || (e == 'm4v') || (e == 'mp4') || (e == 'mov') || (e == 'wmv');
920    },
921
922	justDomain: function(u) {
923		if (u == undefined || !u.length) {
924			return '';
925		}
926		if (u.toLowerCase().substring(0, 7) == 'http://') {
927			return u.substring(8).split('/')[0];
928		}
929		else if (u.toLowerCase().substring(0, 8) == 'https://') {
930			return u.substring(9).split('/')[0];
931		}
932	},
933
934    justNumbers: function (v) {
935        var n = v.match(/\d+/gi);
936        if (n) { return parseInt(n.join('')); }
937        return '';
938    },
939
940    keydown: function (e) {
941        var keyCode = e.keyCode || e.which;
942        if (keyCode == 27) {
943            if (window.parent == window) {
944                return hd.dialog_blackoutclose();
945            }
946            else {
947                return window.parent.hd.dialog_blackoutclose();
948            }
949        }
950    },
951
952    list: function (o) {
953        o.tableObject = $(o.table);
954        o.tableBody = $('tbody', o.table);
955        hd.listprop = o;
956
957        if (o.search) {
958            $(o.search).change(hd.list_search).keyup(hd.list_search).keypress(function (e) { if (e && e.keyCode && e.keyCode == 13) { return false; } });
959            if (o.searchText) {
960                $(o.search).val(hd.trim(o.searchText));
961            }
962            else {
963                if (o.searchStore) { $(o.search).val(window.localStorage[o.searchStore] || ''); }
964            }
965            if ($(o.search).parent().find('.fa-times').length == 0) {
966                $('<button class="btn-lite" style="position: absolute; font-size: 0.75em; top: 0.5em; right: 0.5em; padding: 0.15em 0.5em;"' + ($(o.search).val() == '' ? ' disabled' : '') + '><i class="fas fa-times"></i></button>').click(hd.list_clear).appendTo($(o.search).parent());
967            }
968        }
969        if (o.view) {
970            $(o.view).change(hd.list_view).html('');
971            if (o.tiles) { $('<option value="tiles" hd-icon="fad fa-th">Grid</option>').appendTo(o.view); }
972            if (o.table) { $('<option value="table" hd-icon="fad fa-list">List</option>').appendTo(o.view); }
973            if (o.viewStore) { $(o.view)[0].selectedIndex = Number(window.localStorage[o.viewStore] || 0); }
974            $(o.view).parent().find('.viewicon').attr('class', 'viewicon ' + $('option:selected', o.view).attr('hd-icon'));
975        }
976        if (o.dropdown) {
977            var dd = {};
978            if (o.dropdownStore) { dd = JSON.parse(window.localStorage[o.dropdownStore] || '{}'); }
979            $(Object.keys(o.dropdown)).each(function (i, k) {
980                var ko = o.dropdown[k];
981                var s = $('select[name="' + k + '"]').change(hd.list_search).html('');
982                $(ko).each(function (i, d) { $('<option value="' + (d.value || d.name) + '" hd-search="' + d.search + '"' + ((dd[k] == (d.value || d.name)) ? ' selected' : '') + '>
982' + d.name + '</option>').appendTo(s); });
983            });
984        }
985        if (o.sort) {
986            $(o.sort).change(hd.list_sort).html('');
987            for (var a = 0; a < o.sortOptions.length; a++) {
988                var opt = $('<option>' + o.sortOptions[a].name + '</option>').appendTo(o.sort)[0];
989                opt.compare = o.sortOptions[a].compare;
990                opt.field = o.sortOptions[a].field;
991                opt.order = o.sortOptions[a].order;
992            }
993            if (o.sortStore) { $(o.sort)[0].selectedIndex = Number(window.localStorage[o.sortStore] || 0); }
994        }
995        if (o.listClear) {
996            $(o.listClear).hide().html('');
997            $('<button class="btn-medium">Clear Search and Show All Results</button>').click(hd.list_clear).appendTo(o.listClear);
998        }
999        var m = (o.view) ? $(o.view).val() : '';
1000        if (hd.listprop.table) { if (m == '' || m == 'table') { $(hd.listprop.table).show(); } else { $(hd.listprop.table).hide(); } }
1001		if (hd.listprop.tiles) { if (m == '' || m == 'tiles') { $(hd.listprop.tiles).show(); } else { $(hd.listprop.tiles).hide(); } }
1002		$(hd.listprop.tiles).html('<div style="padding: 2em; text-align: center; width: 100%;">Loading...<div class="loadbar"></div></div>');
1003		$(o.tableBody).html('<tr><td colspan="' + ($('th', o.tableObject).length) + '" style="padding: 2em; text-align: center;">Loading...<div class="loadbar"></div></td></tr>');
1004		hd.listprop.loadbar = $('.loadbar', hd.listprop.tiles + ', ' + o.table);
1005        hd.resize();
1006
1007        var sq = hd.listprop.lastsearch = hd.list_searchquery();
1008        var ajx = {
1009            url: o.url + sq,
1010            dataType: 'json',
1011            error: function (e) { console.log('list loading error: ' + this.url); console.log(e); $('> tr > td', o.tableBody).html('Error loading list'); },
1012            success: hd.list_load
1013        };
1014
1015        $('.websql').hide();
1016        hd.listprop.serverFilter = 1;
1017
1018		if (hd.isSafari()) {
1019			$('.loadbar').html('<img src="/art/spinner.gif" style="width: 64px; height: 64px;" />');
1020            $.ajax(ajx);
1021        }
1022        else if (hd.listprop.dataDB) {
1023            try {
1024                var db = hd.listprop.db = window.openDatabase(hd.listprop.dataDB, '1.0', hd.listprop.dataDB, hd.listprop.dataStoreSize * 1024 * 1024);
1025                if (o.urlDB) { ajx.url = o.urlDB; }
1026                hd.listprop.serverFilter = 0;
1027                $('.websql').show();
1028                if ($(o.search).parent().find('.fa-sync').length == 0) {
1029                    $('<button title="Perform a full reload of the list" class="btn-lite" style="position: absolute; font-size: 0.75em; top: 0.5em; right: 2.8em; padding: 0.15em 0.5em;"><i class="far fa-sync"></i></button>').click(hd.list_refresh).appendTo($(o.search).parent());
1030                }
1031                db.transaction(function (tx) {
1032                    tx.executeSql('select max([_lu]) as lu from ' + hd.listprop.dataTable, [], function (tx2, r) {
1033                        if (!hd.listprop.refresh) {
1034                            ajx.url = (o.urlDB || o.url) + (o.url.indexOf('?') > -1 ? '&' : '?') + '_lu=' + r.rows[0].lu + '&_v=1';
1035                            $.ajax(ajx);
1036                        }
1037                        else {
1038                            hd.listprop.refresh = false;
1039                            console.log('refresh cache table');
1040                            tx.executeSql('drop table ' + hd.listprop.dataTable, [], function (tx3, r) {
1041                                $.ajax(ajx);
1042                            }, function () {
1043                                $.ajax(ajx);
1044                            });
1045                        }
1046                    }, function () {
1047                        $.ajax(ajx);
1048                    });
1049                });
1050            }
1051			catch (e) {
1052				$('.loadbar').html('<img src="/art/spinner.gif" style="width: 64px; height: 64px;" />');
1053                $.ajax(ajx);
1054            }
1055        }
1056		else {
1057			$('.loadbar').html('<img src="/art/spinner.gif" style="width: 64px; height: 64px;" />');
1058            $.ajax(ajx);
1059        }
1060
1061        $(window).scroll(hd.list_show).resize(hd.list_show);
1062    },
1063
1064    list_clear: function () {
1065        if (hd.listprop.search) {
1066            $(hd.listprop.search).val('').focus();
1067            if (hd.listprop.dropdown) {
1068                $(Object.keys(hd.listprop.dropdown)).each(function (i, k) {
1069                    var ko = $('select[name="' + k + '"] option:selected').removeProp('selected');
1070                });
1071            }
1072            hd.list_search();
1073        }
1074    },
1075
1076    list_load: function (d) {
1077        if (hd.listprop.db) {
1078            hd.listprop.loadbar.css({ background: '#f8f8f8', border: '1px solid #000', height: 12, width: '80%', margin: '0.7em auto 0 auto', opacity: 0 }).html('<div style="background: #aaa; height: 12px; width: 0%;"></div>').animate({ opacity: 1 });
1079            hd.resize();
1080            db = hd.listprop.db;
1081            console.log('Records to add/update: ' + d.length);
1082            if (d.length == 0) {
1083                hd.listprop.dbFields = [];
1084                db.transaction(function (tx) {
1085                    tx.executeSql('select * from ' + hd.listprop.dataTable + ' limit 1', [], function (tx2, r) {
1086                        var k = hd.listprop.dbFields = Object.keys(r.rows[0]);
1087                        hd.list_loadrecord(d, db, k, '', 0);
1088                    }, function () {
1089                        hd.list_loadrecord(d, db, [], '', 0);
1090                    });
1091                });
1092            }
1093            else {
1094                var k = hd.listprop.dbFields = Object.keys(d[0]);
1095                var fl = '[' + k.join('], [') + ']';
1096                db.transaction(function (tx) {
1097                    var ct = 'CREATE TABLE IF NOT EXISTS ' + hd.listprop.dataTable + ' ([' + k.join('], [').replace(', ', ' unique, ').replace('[_lu],', '[_lu] int,') + '])';
1098                    tx.executeSql('select * from ' + hd.listprop.dataTable + ' limit 1', [], function (tx2, r) {
1099                        try {
1100                            if (Object.keys(r.rows[0]).join(',') != k.join(',')) {
1101                                console.log('schema change - replace cache table');
1102                                tx.executeSql('drop table ' + hd.listprop.dataTable, [], function (tx3, r) {
1103                                    hd.list_refresh();
1104                                });
1105                            }
1106                            else {
1107                                tx.executeSql(ct, [], function () { hd.list_loadrecord(d, db, k, fl, 0); });
1108                            }
1109                        }
1110                        catch (e) {
1111                            tx.executeSql(ct, [], function () { hd.list_loadrecord(d, db, k, fl, 0); });
1112                        }
1113                    }, function () {
1114                        tx.executeSql(ct, [], function () { hd.list_loadrecord(d, db, k, fl, 0); });
1115                    });
1116                });
1117            }
1118        }
1119        else {
1120            if (d.length == 0) {
1121                if (hd.listprop.moreUrl) {
1122                    hd.listprop.moreUrl = null;
1123                }
1124                else {
1125                    hd.listprop.list = hd.listprop.data = [];
1126                    hd.list_show();
1127                }
1128            }
1129            else if (d[0] && d[0]._row) {
1130                if (d[0]._row == 0) {
1131                    hd.listprop.moreUrl = this.url;
1132                    hd.listprop.serverFilter = 2;
1133                    hd.listprop.data = hd.listprop.list = d;
1134                    hd.list_reset();
1135                }
1136                else {
1137                    $(d).each(function (i, o) {
1138                        hd.listprop.data[o._row] = o;
1139                    });
1140                }
1141                hd.listprop.moreLoading = false;
1142                hd.list_show();
1143            }
1144            else {
1145                hd.listprop.serverFilter = 0;
1146                hd.listprop.data = d;
1147                hd.list_search();
1148            }
1149        }
1150    },
1151
1152    list_loadrecord: function (d, db, k, fl, i) {
1153        var rows = 500;
1154        hd.listprop.loadbar.find('div').css({ width: Number(100 * Math.min(1, (i / d.length))).toFixed(1) + '%' });
1155        if (!d[i]) {
1156            $(hd.listprop.search).parent().find('.fa-sync').parent().prop('disabled', false);
1157            if (d.length) {
1158                db.transaction(function (tx) {
1159                    tx.executeSql('DELETE FROM ' + hd.listprop.dataTable + ' WHERE [_s]=\'-1\'');
1160                    hd.list_search();
1161                }, hd.list_search, hd.list_search);
1162            }
1163            else {
1164                hd.list_search();
1165            }
1166            return false;
1167        }
1168        var s = 'REPLACE INTO ' + hd.listprop.dataTable + '(' + fl + ') VALUES(';
1169        for (a = i; a < Math.min(i + rows, d.length); a++) {
1170            s += ((a == i) ? '' : ', (');
1171            for (var b = 0; b < k.length; b++) {
1172                var v = d[a][k[b]];
1173                s += (v ? '\'' + v.replace(/'/g, '\'\'') + '\'' : 'NULL') + ((b < (k.length - 1)) ? ', ' : ')');
1174            }
1175        }
1176        db.transaction(function (tx) {
1177            tx.executeSql(s);
1178        }, function (tx) {
1179            console.log(tx);
1180            hd.list_loadrecord(d, db, k, fl, i + rows);
1181        }, function (tx) {
1182            hd.list_loadrecord(d, db, k, fl, i + rows);
1183        });
1184    },
1185
1186    list_more: function () {
1187        if ((hd.listprop.moreUrl) && (!hd.listprop.moreLoading)) {
1188            hd.listprop.moreLoading = true;
1189            $.ajax({
1190                url: hd.listprop.moreUrl + '&o=' + (hd.listprop.list.length),
1191                dataType: 'json',
1192                complete: function () { hd.listprop.moreLoading = false; },
1193                error: function (e) { console.log('list loading error: ' + this.url); console.log(e); $('> tr > td', hd.listprop.tableBody).html('Error loading list'); },
1194                success: hd.list_load
1195            });
1196        }
1197    },
1198
1199    list_refresh: function () {
1200        $(hd.listprop.search).parent().find('.fa-sync').parent().prop('disabled', true);
1201        hd.listprop.refresh = true;
1202        hd.listprop.lastsearch = null;
1203        hd.list(hd.listprop);
1204    },
1205
1206    list_reset: function () {
1207        if (hd.listprop.table) { hd.listprop.tableBody.html(''); }
1208        if (hd.listprop.tiles) { $(hd.listprop.tiles).html(''); }
1209        hd.listprop.show = 10;
1210    },
1211
1212    list_search: function (e) {
1213        // console.log('list_search');
1214        if (!hd.listprop.data && !hd.listprop.db) { return false; }
1215        var s = hd.trim($(hd.listprop.search).val() || '').toLowerCase();
1216        if (hd.listprop.searchStore) { window.localStorage[hd.listprop.searchStore] = s; }
1217        if (hd.listprop.hiddenSearch) { s += ' ' + hd.listprop.hiddenSearch };
1218        s = hd.list_searchdropdown(s);
1219
1220        if (hd.listprop.serverFilter) {
1221            var sq = hd.list_searchquery();
1222            if (sq == hd.listprop.lastsearch) { return false; }
1223            hd.listprop.lastsearch = sq;
1224
1225            hd.list_reset();
1226            hd.resize();
1227            window.clearTimeout(hd.listprop.searchDelay);
1228            hd.listprop.searchDelay = window.setTimeout(function () {
1229                $.ajax({
1230                    url: hd.listprop.url + sq,
1231                    dataType: 'json',
1232                    error: function (e) { console.log('list loading error: ' + this.url); console.log(e); $('> tr > td', hd.listprop.tableBody).html('Error loading list'); },
1233                    success: hd.list_load
1234                });
1235            }, 1000);
1236            return false;
1237        }
1238
1239        if (s == hd.listprop.lastsearch && (!hd.listprop.db)) { return; }
1240        hd.listprop.lastsearch = s;
1241
1242        var so = [];
1243        if (s != '') {
1244            var ss = s;
1245            var i = ss.replace(/"/g, ' ').indexOf(' ');
1246            while (i > -1) {
1247                if (i == 0) {
1248                    if (ss.substr(0, 1) == ' ') {
1249                        ss = ss.substr(1, ss.length);
1250                    }
1251                    else {
1252                        var ii = (ss.substr(1, ss.length) + '"').indexOf('"');
1253                        so.push({ text: ss.substr(1, ii).toLowerCase() });
1254                        ss = ss.substr(ii + 2, ss.length);
1255                    }
1256                }
1257                else {
1258                    if (ss.substr(i, 1) == ' ') {
1259                        so.push({ text: ss.substr(0, i).toLowerCase() });
1260                        ss = ss.substr(i + 1, s.length);
1261                    }
1262                    else {
1263                        so.push({ text: ss.substr(0, i).toLowerCase() });
1264                        ss = ss.substr(i, ss.length);
1265                    }
1266                }
1267                i = ss.replace(/"/g, ' ').indexOf(' ');
1268            }
1269            if (ss != '') {
1270                so.push({ text: ss });
1271            }
1272        }
1273
1274        if (hd.listprop.db) {
1275            hd.listprop.db.transaction(function (tx) {
1276                var w = ''
1277                var df = hd.listprop.dbFields;
1278                for (var a = 0; a < so.length; a++) {
1279                    var sf;
1280                    var fl = [];
1281                    if (so[a].text.indexOf(':') > -1) {
1282                        fl = [so[a].text.substr(0, so[a].text.indexOf(':'))];
1283                        sf = so[a].text.substr(so[a].text.indexOf(':') + 1);
1284                    }
1285                    else {
1286                        fl = df;
1287                        sf = so[a].text;
1288                    }
1289                    if (!Array.isArray(fl)) fl = []; 
1290                    var ss;
1291                    if (sf.substr(0, 1) == '=') {
1292                        ss = '=\'' + sf.substr(1).replace(/'/g, '\'\'') + '\'';
1293                    }
1294                    else if (sf.substr(0, 2) == '!=') {
1295                        ss = '!=\'' + sf.substr(2).replace(/'/g, '\'\'') + '\'';
1296                    }
1297                    else if (sf.substr(0, 1) == '~') {
1298                        ss = ' is null';
1299                    }
1300                    else if ((fl.length == 1) && ('<>').indexOf(sf.substr(0, 1)) > -1) {
1301                        fl[0] = 'Cast([' + fl[0] + '] as decimal)';
1302                        ss = sf.substr(0, 1) + sf.substr(1).replace(/'/g, '\'\'');
1303                    }
1304                    else {
1305                        ss = ' like \'%' + sf.replace(/'/g, '\'\'') + '%\'';
1306                    }
1307                    w += (w == '' ? '' : ' and ') + ('(([' + fl.join(']' + ss + ') or ([') + ']' + ss + '))').replace(/\[Cast/g, 'Cast').replace(/decimal\)\]/g, 'decimal)');
1308                }
1309                var sql = 'select *' + (hd.listprop.extrafields || '') + ' from ' + hd.listprop.dataTable + (w != '' ? ' where ' + w : '');
1310                if (hd.listprop.sort) {
1311                    var srt = $(hd.listprop.sort)[0];
1312                    sql += ' order by ' + srt.options[srt.selectedIndex].field + ' limit 1000';
1313                }
1314                // console.log(sql);
1315                tx.executeSql(sql, [], function (tx2, r) {
1316                    var l = [];
1317                    for (var a = 0; a < r.rows.length; a++) { l[a] = r.rows[a]; }
1318                    //console.log('results: ' + l.length);
1319                    hd.listprop.list = l;
1320                    hd.list_reset();
1321                    hd.list_show();
1322                }, function (tx2, r) {
1323                    console.log(r);
1324                    hd.listprop.list = [];
1325                    hd.list_show();
1326                    return false;
1327                });
1328            });
1329        }
1330        else {
1331            if (hd.listprop.data.length == 0) {
1332                hd.listprop.list = [];
1333                hd.list_show();
1334                return false;
1335            }
1336            else if (s == '') {
1337                hd.listprop.list = hd.listprop.data.slice(0);
1338            }
1339            else {
1340                var d = hd.listprop.data
1341                var df = [];
1342                var k = Object.keys(d[0]);
1343                for (var a = 0; a < k.length; a++) { df.push(a); k[a] = k[a].toLowerCase(); }
1344                for (var a = 0; a < so.length; a++) {
1345                    var i = so[a].text.indexOf(':');
1346                    if (i == -1) {
1347                        so[a].fields = df;
1348                    }
1349                    else {
1350                        so[a].fields = [];
1351                        var fn = so[a].text.substr(0, i).toLowerCase();
1352                        for (var b = 0; b < k.length; b++) {
1353                            if (k[b] == fn) { so[a].fields.push(b); }
1354                        }
1355                        so[a].text = so[a].text.substr(i + 1, so[a].text.length);
1356                    }
1357                }
1358
1359                var l = [];
1360                var k = Object.keys(d[0]);
1361                for (var a = 0; a < d.length; a++) {
1362                    var f1 = true;
1363                    for (var b = 0; b < so.length; b++) {
1364                        var f2 = false;
1365                        var t = so[b].text;
1366                        var tp = t.substr(0, 1);
1367                        var tt = t.substr(1, t.length);
1368                        var fl = so[b].fields
1369                        if (tp == '<' || tp == '>') { if (!isNaN(tt)) { tt = Number(tt); } else { f1 = false; break; } }
1370                        for (var c = 0; c < fl.length; c++) {
1371                            v = d[a][k[fl[c]]] || '';
1372                            if (tp == '=') {
1373                                if (v.toLowerCase() == tt) { f2 = true; break; }
1374                            }
1375                            else if (tp == '<') {
1376                                if ((v != '') && !isNaN(v) && Number(v) < tt) { f2 = true; break; }
1377                            }
1378                            else if (tp == '>') {
1379                                if ((v != '') && !isNaN(v) && Number(v) > tt) { f2 = true; break; }
1380                            }
1381                            else {
1382                                if (v.toLowerCase().indexOf(t) > -1) { f2 = true; break; }
1383                            }
1384                        }
1385                        f1 = f1 && f2;
1386                    }
1387                    if (f1) { l.push(d[a]); }
1388                }
1389                hd.listprop.list = l;
1390            }
1391            hd.list_sort();
1392        }
1393    },
1394
1395    list_searchdropdown: function (s) {
1396        var dv = (s != '');
1397        if (hd.listprop.dropdown) {
1398            var dd = {};
1399            $(Object.keys(hd.listprop.dropdown)).each(function (i, k) {
1400                var ko = $('select[name="' + k + '"] option:selected');
1401                if (ko.length) {
1402                    dv = dv || (ko.index() > 0);
1403                    var ks = ko.attr('hd-search');
1404                    if ((ks || '') != '') {
1405                        s += (s == '' ? '' : ' ') + ks;
1406                        dd[k] = ko.val();
1407                    }
1408                }
1409            });
1410            if (hd.listprop.dropdownStore) { window.localStorage[hd.listprop.dropdownStore] = JSON.stringify(dd); }
1411        }
1412        $(hd.listprop.search).parent().find('.fa-times').parent().prop('disabled', !dv);
1413        if (hd.listprop.listClear) {
1414            if (!dv) {
1415                $(hd.listprop.listClear).hide();
1416            }
1417            else {
1418                $(hd.listprop.listClear).show();
1419            }
1420            hd.resize();
1421        }
1422        return s;
1423    },
1424
1425    list_searchquery: function () {
1426        var s = hd.trim($(hd.listprop.search).val() || '').toLowerCase();
1427        if (hd.listprop.searchStore) { window.localStorage[hd.listprop.searchStore] = s; }
1428        var srt = $(hd.listprop.sort)[0];
1429		var sf = (srt ? srt.options[srt.selectedIndex].order : '');
1430        return '&q=' + encodeURIComponent(hd.list_searchdropdown(s)) + (sf ? '&s=' + encodeURIComponent(srt.options[srt.selectedIndex].order) : '');
1431    },
1432
1433    list_show: function () {
1434        if (hd.listprop.list == undefined) { return false; }
1435        var m = (hd.listprop.view) ? $(hd.listprop.view).val() : '';
1436        if (hd.listprop.table) {
1437            if (m == '' || m == 'table') {
1438                $(hd.listprop.table).show();
1439                hd.list_show_table();
1440            }
1441            else {
1442                $(hd.listprop.table).hide();
1443                hd.listprop.tableBody.html('')
1444            }
1445        }
1446        if (hd.listprop.tiles) {
1447            if (m == '' || m == 'tiles') {
1448                $(hd.listprop.tiles).show();
1449                hd.list_show_tiles();
1450            }
1451            else {
1452                $(hd.listprop.tiles).html('').hide();
1453            }
1454        }
1455    },
1456
1457    list_show_table: function () {
1458        var l = hd.listprop.list;
1459        var c = hd.listprop.columns;
1460        var m = Math.min(l.length, hd.listprop.show);
1461        var rc = $('tr', hd.listprop.tableBody).length;
1462        if (l.length == 0) {
1463            $(hd.listprop.tableBody).html('<tr><td colspan="' + ($('th', hd.listprop.tableObject).length) + '" style="padding: 2em; text-align: center;">No results found.</td></tr>');
1464            hd.resize();
1465        }
1466        else {
1467            for (var a = rc; a < m; a++) {
1468                var li = l[a];
1469                var r = '';
1470                for (var b = 0; b < c.length; b++) {
1471                    var v = '';
1472                    var v2 = '';
1473                    var s = '';
1474                    if (c[b].name) { v = (l[a][c[b].name] || ''); }
1475                    if (c[b].name2) { v2 = (l[a][c[b].name2] || ''); }
1476                    if (c[b].padding) { s += 'padding: ' + c[b].padding + ';'; }
1477                    if (c[b].position) { s += 'position: ' + c[b].position + ';'; }
1478                    if (c[b].textAlign) { s += 'text-align: ' + c[b].textAlign + ';'; }
1479                    if (c[b].value) { v = c[b].value(l[a]); }
1480                    if (c[b].value2) { v2 = c[b].value2(l[a]); }
1481                    if (c[b].width) {
1482                        v = '<div class="truncate" style="display: inline-block; vertical-align: middle; width: ' + c[b].width + 'px;">' + v + '</div>';
1483                        if (v2 || (v2 != '')) { v2 = '<div class="truncate" style="display: inline-block; vertical-align: middle; width: ' + c[b].width + 'px;">' + v2 + '</div>'; }
1484                    }
1485                    if (c[b].media) {
1486                        v = '<div class="picbox" style="display: inline-block; width: ' + (c[b].media.w || 40) + 'px; height: ' + (c[b].media.h || 40) + 'px; margin: 2px 9px 2px -8px; vertical-align: middle;" hd-media="' + (l[a][c[b].media.m] || '') + '" hd-mediaext="' + (l[a][c[b].media.e] || '') + '" ' + (c[b].media.f ? ' hd-mediafit="' + c[b].media.f + '"' : '') + '></div>' + v;
1487                    }
1488                    if (c[b].media2 && (v2 || (v2 != ''))) { v2 = '<div class="picbox" style="display: inline-block; width: ' + (c[b].media2.w || 40) + 'px; height: ' + (c[b].media2.h || 40) + 'px; margin: 2px 9px 2px -8px; vertical-align: middle;" hd-media="' + (l[a][c[b].media2.m] || '') + '" hd-mediaext="' + (l[a][c[b].media2.e] || '') + '"></div>' + v2; }
1489                    if (v2 || (v2 != '')) { v2 = '<div>' + v2 + '</div>'; }
1490                    r += '<td' + (s == '' ? '' : ' style="' + s + '"') + '>
1490' + v + v2 + '</td>';
1491                }
1492                var s = '';
1493                if (hd.listprop.rowColor) { rc = hd.listprop.rowColor(l[a], a); if ((rc || '') != '') { s += 'background: ' + rc; } }
1494                if (hd.listprop.rowBreak) { rc = hd.listprop.rowBreak(l[a], a); if ((rc || '') != '') { s += 'border-top: ' + rc; } }
1495                $('<tr' + ((s) ? ' style="' + s + '"' : '') + '>' + r + '</tr>').appendTo(hd.listprop.tableBody);
1496            }
1497            hd.resize();
1498            for (var a = 0; a < c.length; a++) { if (c[a].media) { hd.picbox_init(); break; } }
1499
1500            if (($(hd.listprop.tableObject).offset().top + $(hd.listprop.tableObject).height()) < ($(document).scrollTop() + ($(window).height() * 2))) {
1501                if ($('tr', hd.listprop.tableBody).length < l.length) {
1502                    hd.listprop.show += 10;
1503                    hd.list_show();
1504                }
1505                else if (hd.listprop.moreUrl) {
1506                    hd.list_more();
1507                }
1508            }
1509        }
1510    },
1511
1512    list_show_tiles: function () {
1513        var l = hd.listprop.list;
1514        var m = Math.min(l.length, hd.listprop.show);
1515        var rc = $('.tile-site', hd.listprop.tiles).length;
1516        if (l.length == 0) {
1517            $(hd.listprop.tiles).html('<div style="padding: 2em; text-align: center; width: 100%;">No results found.</div>');
1518            hd.resize();
1519        }
1520        else {
1521            for (var a = rc; a < m; a++) {
1522                $(hd.listprop.tileObject(l[a])).appendTo(hd.listprop.tiles);
1523            }
1524            hd.resize();
1525            hd.picbox_init();
1526            hd.truncate_init();
1527
1528            if (($(hd.listprop.tiles).offset().top + $(hd.listprop.tiles).height()) < ($(document).scrollTop() + ($(window).height() * 2))) {
1529                if ($('.tile-site', hd.listprop.tiles).length < l.length) {
1530                    hd.listprop.show += 10;
1531                    hd.list_show();
1532                }
1533                else if (hd.listprop.moreUrl) {
1534                    hd.list_more();
1535                }
1536            }
1537        }
1538    },
1539
1540    list_sort: function () {
1541        if (hd.listprop.sort) {
1542            var srt = $(hd.listprop.sort)[0];
1543            var comp = srt.options[srt.selectedIndex].compare;
1544            if (hd.listprop.sortStore) {
1545                window.localStorage[hd.listprop.sortStore] = srt.selectedIndex;
1546            }
1547            if ((hd.listprop.db) || (hd.listprop.serverFilter)) {
1548                hd.list_search();
1549                return false;
1550            }
1551            var l = hd.listprop.list;
1552            for (var a = 0; a < l.length - 1; a++) {
1553                if (comp(l[a], l[a + 1])) {
1554                    var tmp = l[a];
1555                    l[a] = l[a + 1];
1556                    l[a + 1] = tmp;
1557                    if (a == 0) { a--; } else { a -= 2; }
1558                }
1559            }
1560        }
1561        hd.list_reset();
1562        hd.list_show();
1563    },
1564
1565    list_view: function () {
1566        if (hd.listprop.viewStore) {
1567            window.localStorage[hd.listprop.viewStore] = $(hd.listprop.view)[0].selectedIndex;
1568        }
1569        $(hd.listprop.view).parent().find('.viewicon').attr('class', 'viewicon ' + $('option:selected', hd.listprop.view).attr('hd-icon'));
1570        hd.list_reset();
1571        hd.list_show();
1572    },
1573
1574    listprop: {},
1575
1576    login_close: function () {
1577        $('.auth .loginform').animate({ marginTop: -32 });
1578        $('.auth .loginform-container').animate({ height: 0 }, function () { $('.header .login .logintab').removeClass('logintab-sel'); $('.auth').hide(); });
1579    },
1580
1581    login_open: function () {
1582        if ($('.auth .loginform-container').height() > 1) { hd.login_close(); return false; }
1583        $('.auth .loginform-container').height(1);
1584        $('.auth').show();
1585        $('.header .login .logintab').addClass('logintab-sel');
1586        $('.auth .loginform').animate({ marginTop: 0 });
1587        $('.auth .loginform-container').animate({ height: $('.auth .loginform').outerHeight() + 24 });
1588	},
1589
1590	maphost: '',
1591
1592	matterportKey: function(u) {
1593		if (u.indexOf('m=') > -1) {
1594			return ((u + 'm=').split('m=')[1] + '&').split('&')[0];
1595		}
1596		return '';
1597	},
1598
1599    maxrows: function (o) {
1600        if (o == undefined) { o = $('.maxrows'); } else if (!$(o).hasClass('maxrows')) { o = $('.maxrows', $(o)); }
1601        $(o).each(function (i, t) {
1602            var m = Number($(t).attr('hd-maxrows') || 10);
1603            var r = $('tbody tr', t);
1604            if (r.length > m) {
1605                r.each(function (ii, oo) { if (ii <= m) { $(oo).show(); } else { $(oo).hide(); } });
1606                $(t.maxrows).remove();
1607                t.maxrows = $('<div class="hoverlink" style="font-size: 0.8em; margin-top: 0.3em;"><a href="#" onclick="var d = $(this).parent(); d.prev().find(\'tr\').show(); d.remove(); return false;">See ' + (r.length - m) + ' More</a></div>').insertAfter(t)[0];
1608            }
1609        });
1610    },
1611
1612    mediaNames: function () {
1613        return '360 Back,360 Front,360 Master,3D Floor Plan,Aerial,Aerial Back,Aerial Front,Aerial Tour,Aerial Video,Aerial View,Back,Back Aerial,Back of Home,Back of House,Back Panorama,Back Patio,Back Patio & Yard,Back to House,Back View,Backyard,Backyard 2,Backyard Panorama,Backyard Patio,Backyard to Home,Backyard View,Balcony,Balcony Vie
1613w,Bar,Basketball Court,Bath,Bath 1,Bath 2,Bath 3,Bath 4,Bathroom,Bathroom 1,Bathroom 2,Bathroom 3,BBQ,Bedroom,Bedroom 1,Bedroom 2,Bedroom 2 Bath,Bedroom 3,Bedroom 3 Bath,Bedroom 4,Bedroom 5,Bonus Room,Breakfast Area,Breakfast Bar,Breakfast Nook,Built in BBQ,Butler\'s Pantry,Cabana,Casita,Casual Dining,Closet,Club house,Clubhouse,Common Area,Community Center,Community Entrance,Community Park,Community Playground,Community Pool,Conservatory,Corner Lot,Courtyard,Covered Patio,Deck,Deck View,Den,Dining,Dining & Living Room,Dining Area,Dining Room,Dining Room to Kitchen,Dining to Kitchen,Dining to Living,Dining to Living Room,Dock,Downstairs Bath,Downstairs Bathroom,Downstairs Bedroom,Driveway,Drone Photography,Eating Area,Entrance,Entry,Entry Courtyard,Entryway,Exterior,Exterior Back,Exterior Front,Family,Family Room,Family Room 2,Family Room to Kitchen,Family Room/Kitchen,Family to Back,Family to Dining,Family to Kitchen,Finished Lower Level,Fireplace,Floor Plan,Formal Dining,Formal Dining Room,Formal Living,Formal Living Room,Foyer,Front,Front 2,Front Aerial,Front Bedroom,Front Courtyard,Front Door,Front Entrance,Front Entry,Front Exterior,Front of Home,Front patio,Front Porch,Front Porch View,Front View,Front Yard,Full Bath,Game Room,Garage,Garden,Gated Community,Gated Entrance,Gated Entry,Gazebo,Golf,Golf Course,Great Room,Grounds,Guest,Guest Bath,Guest Bathroom,Guest Bedroom,Guest House,Guest Room,Gym,Half Bath,Hall,Hall Bath,Hall Bathroom,Hallway,Hot Tub,Jack & Jill Bedroom,Jack & Jill Bath,Kitchen,Kitchen & Dining,Kitchen & Family Room,kitchen 1,Kitchen 2,Kitchen 3,Kitchen Area,Kitchen Dining,Kitchen Dining Area,Kitchen to Dining,Kitchen to Family,Kitchen to Family Room,Kitchen to Laundry,Kitchen to Living,Kitchen View,Kitchen/Dining,Koi Pond,Lake View,Landing,Laundry,Laundry Area,Laundry Room,Library,Living,Living & Dining,Living & Dining Room,Living Area,Living from Dining,Living Panorama,Living Room,Living Room & Dining Room,Living Room 2,Living Room to Dining,Living Room to Kitchen,Living to Back,Living to Dining,Living to Entry,Living to Foyer,Living to Kitchen,Living to Landing,Living to Stairs,Lobby,Loft,Lower Bath,Lower Bedroom,Lower Level,Main,Main Bath,Main Exterior,Main Level Bedroom,Main Living Area,Master,Master Balcony,Master Balcony View,Master Bath,Master Bath 2,Master Bathroom,Master Bathroom 2,Master Bedroom,Master Bedroom 2,Master Bedroom Closet,Master Bedroom to Bath,Master Closet,Master Panorama,Master Retreat,Master Shower,Master Suite,Master Suite to Balcony,Master Suite to Bath,Master Suite to Retreat,Master Suite View,Master to Bath,Master View,Morning Room,Mudroom,Neighborhood,Nook,Office,Office/Bedroom,Open Floor Plan,Outdoor Kitchen,Overhead,Pantry,Park,Parking,Patio,Patio Area,Playground,Pool,Pool & Spa,Pool Area,Pool Bath,Porch,Powder,Powder Room,Primary Bathroom,Primary Bedroom,Princess Suite,Property Aerial,Rear of Home,Rear View,Rear Yard,RV Parking,Screened Porch,Side,Side Patio,Side Yard,Sideyard,Sitting Room,Spa,Sports Court,Staircase,Stairs,Storage,Street View,Study,Summer Kitchen,Sun Room,Sunset,Tennis,Tennis Court,Terrace,Three Seasons Room,Twilight,Twilight Photos,Upper Level,Upstairs,Upstairs Bathroom,Upstairs Bedroom,Upstairs Down,Upstairs Landing,Upstairs Laundry Room,Upstairs Living,Utility Room,View,View From Balcony,Virtually Staged,Welcome Home,Welcome,Wet Bar,Yard'.split(',');
1614    },
1615
1616    mediaselect_init: function () {
1617        $('.mediaselect').each(function (i, o) {
1618			var fit = ($(o).hasClass('mediaselectfit'));
1619			var mh = (($(o).attr('hd-maxheight') && $.isNumeric(($(o).attr('hd-maxheight')))) ? $(o).attr('hd-maxheight') : 400);
1620            var sm = $(o).selectmenu({
1621                change: function () { $(o).trigger('change'); },
1622                open: function (e) {
1623                    var button = $(o).selectmenu('instance').button[0];
1624					$(o).selectmenu('menuWidget').css({ maxHeight: Math.min(mh, Math.round($(window).height() - ($(button).position().top + $(button).outerHeight()) - 15)) });
1625                },
1626                width: $(o).width() + 14
1627            });
1628            sm.selectmenu('instance')._renderItem = function (ul, item) {
1629                var li = $('<li>').css({ display: 'block' });
1630                var span = $('<span>').css({ display: 'block', height: 48 }
1630).appendTo(li);
1631                $('<div>').addClass('truncate').css({ position: 'absolute', top: 14, left: 77, right: 8 }).html(item.label).appendTo(span);
1632                var pb = $('<div>').attr('hd-media', item.element.attr('hd-media')).attr('hd-mediaext', item.element.attr('hd-mediaext')).addClass('picbox').css({ border: '1px solid #fff', position: 'absolute', top: 5, left: 5, width: 60, height: 42 }).appendTo(span);
1633                if (fit) { pb.attr('hd-mediafit', true); }
1634                return li.appendTo(ul);
1635            };
1636            sm.selectmenu('instance')._renderButtonItem = function (item) {
1637                var hnt = ($(o).attr('hd-hint') != undefined);
1638                var span = $('<span>').css({ display: 'block', height: 41 });
1639                $('<div>').addClass('truncate').css({ position: 'absolute', top: (hnt ? 19 : 14), left: 77, right: 18 }).html(item.label).appendTo(span);
1640                if (item.element) {
1641                    var pb = $('<div>').attr('hd-media', item.element.attr('hd-media')).attr('hd-mediaext', item.element.attr('hd-mediaext')).addClass('picbox').css({ border: '1px solid #fff', position: 'absolute', top: 5, left: 5, width: 60, height: 42 }).appendTo(span);
1642                    if (fit) { pb.attr('hd-mediafit', true); }
1643                }
1644                hd.picbox_init(span[0]);
1645                return span;
1646            }
1647            sm.selectmenu('refresh');
1648            var button = sm.selectmenu('instance').button[0];
1649            var menu = sm.selectmenu('instance').menu[0]
1650            $('.ui-selectmenu-icon.ui-icon', button).css({ marginTop: '14px', marginRight: '-13px' });
1651			$(menu).css({ maxHeight: mh });
1652            $(button).css({ zIndex: 2 });
1653            $('.texthint', $(o).parent()).css({ marginLeft: 71 }).find('> div').each(function (i, o) { $(o).css('max-width', Number($(o).css('max-width').replace('px', '')) - 71); });
1654            hd.picbox_init(sm);
1655            $(o.selectBackground).height($(button).outerHeight());
1656            if ($(o).attr('hd-default')) {
1657                $(o).val($(o).attr('hd-default'));
1658                $(o).selectmenu('refresh');
1659            }
1660        });
1661    },
1662
1663    meldload: function () {
1664        var st = $(document).scrollTop() + $(window).height();
1665		$('.meldloading').each(function (i, o) {
1666			if ($(o).css('display') != 'none') {
1667				var ot = $(o).offset().top;
1668				if (st > ot) {
1669					$(o).removeClass('meldloading').bind('load error', hd.meldload).attr('src', $(o).attr('hd-src'));
1670					i = 99999;
1671					return false;
1672				}
1673			 }
1674        });
1675    },
1676
1677	meldload_init: function () {
1678        var m = $('.meldload').addClass('meldloading');
1679        if (m.length) {
1680            var f = function () { window.clearTimeout(hd.meldload_tmr); hd.meldload_tmr = window.setTimeout(hd.meldload, 150); }
1681            $(window).resize(f).scroll(f);
1682            hd.meldload();
1683        }
1684    },
1685
1686    meldload_tmr: null,
1687
1688	metricDisplay: false,
1689
1690    mobileGrid: function () {
1691        var mm = ($(window).width() < 770);
1692        if (mm) { $('body').addClass('mobile'); } else { $('body').removeClass('mobile'); }
1693        $('table.grid').not('.mobilegriddone').each(function (i, o) {
1694            var mt = $(o).addClass('mobilegriddone').attr('hd-mobile');
1695            if (mt) {
1696                if (mm) {
1697                    $(o).hide();
1698                    if (o.maxrows) { $(o.maxrows).hide(); }
1699                    if (o.gridmobile) {
1700                        $(o.gridmobile).show();
1701                        if (o.maxrowsmobile) { $(o.maxrowsmobile).show(); }
1702                    }
1703                    else {
1704                        var mr = Math.ceil((parseInt($(o).attr('hd-maxrows')) || 1000000) / 5);
1705                        o.gridmobile = $('<div class="gridmobile"' + ($(o).attr('hd-mobilegrid') ? ' style="' + $(o).attr('hd-mobilegrid') + '"' : '') + '>').insertAfter(o)[0];
1706                        var r = $('tbody tr', o);
1707                        r.each(function (tri, tr) {
1708                            var mc = mt.replace(/`/g, '"');
1709                            var i1 = mc.indexOf('{#');
1710                            while (i1 > -1) {
1711                                var i2 = (mc + '#}').indexOf('#}', i1);
1712                                mc = mc.substring(0, i1) + ($('.' + mc.substring(i1 + 2, i2), tr).html() || '') + mc.substring(i2 + 2);
1713                                i1 = mc.indexOf('{#');
1714                            }
1715                            var c = $('<div class="card">' + mc + '</div>').appendTo(o.gridmobile);
1716                            if (tri >= mr) { c.hide(); }
1717                        });
1718                        if (r.length > mr) {
1719                            o.maxrowsmobile = $('<div class="hoverlink" style="font-size: 0.8em; margin-top: 0.3em;"><a href="#" onclick="var d = $(this).parent(); d.prev().find(\'.card\').show(); d.remove(); return false;">See ' + (r.length - mr) + ' More</a></div>').insertAfter(o.gridmobile)[0];
1720                            console.log('more');
1721                        }
1722                        hd.maxrows(o);
1723                    }
1724                }
1725                else {
1726                    $(o).show();
1727                    if (o.maxrows) { $(o.maxrows).show(); }
1728                    hd.maxrows(o);
1729                    if (o.gridmobile) { $(o.gridmobile).hide(); }
1730                    if (o.maxrowsmobile) { $(o.maxrowsmobile).hide(); }
1731                }
1732            }
1733        });
1734    },
1735
1736	money: function (n, d) {
1737		if (d == undefined) { d = 0; }
1738		n = hd.round(Number(n), d);
1739		return (n < 0 ? '-' : '') + new Intl.NumberFormat((hd.moneyCulture.length > 1 ? hd.moneyCulture : 'en-US'), { minimumFractionDigits: d, style: 'currency', currency: (hd.moneyCurrency.length > 1 ? hd.moneyCurrency : 'USD') }).format(Math.abs(n));
1740	},
1741
1742	moneyCleanEx: function (v, stripComma = false, outputNumeric = false) {
1743		if (v != undefined) {
1744			v = hd.moneySimple(hd.moneyStripComma(hd.moneyStripSymbol(v))); //handle 123.45, 1234.56, '1,234.56', '$1234.56', '$1,234.56' (returns '123.45' or '1,234.56')
1745			if (stripComma) {
1746				v = hd.moneyStripComma(v);
1747			}
1748			if (outputNumeric) {
1749				return Number(v); //it will trim any trailing zeroes after the decimal point.  Use something like hd.moneySimple (or don't outputNumeric) on the page if wanting trailing zeroes in decimals (will be a string)
1750			}
1751			else { //legacy support
1752				return v;
1753			}
1754		}
1755		else {
1756			if (outputNumeric) {
1757				return NaN;
1758			}
1759			else { //legacy support
1760				return '';
1761			}
1762		}
1763	},
1764
1765	moneyClean: function (v, stripComma = false) {
1766		if (v != undefined) {
1767			v = hd.moneyStripSymbol(v);
1768			if (stripComma) {
1769				v = hd.moneyStripComma(v);
1770			}
1771			return v;
1772		}
1773		else {
1774			return '';
1775		}
1776	},
1777
1778	moneyCulture: 'en-US',
1779
1780	moneyCurrency: 'USD',
1781
1782	moneySimple: function (n, d = 2) {
1783		return hd.moneyStripSymbol(hd.money(n, d));
1784	},
1785
1786	moneyStripComma: function (v) {
1787		if (v != undefined) {
1788			v = v.toString(); //make sure we have a string
1789			v = v.trim();
1790			var swapped = false;
1791			var thousandDelimiter = '';
1792
1793			//Euro (non-English countries)
1794			if (hd.moneyCulture.toLowerCase().substring(0, 2) != 'en' && hd.moneyCurrency.toUpperCase() == 'EUR') {
1795				swapped = true;
1796				thousandDelimiter = '.';
1797			} 
1798			//Canada (French)
1799			else if (hd.moneyCulture.toLowerCase().substring(0, 2) == 'fr' && hd.moneyCurrency.toUpperCase() == 'CAD') {
1800				swapped = true;
1801				thousandDelimiter = ' ';
1802			} 
1803			//Switzerland
1804			else if (hd.moneyCulture.toLowerCase().substring(0, 2) == 'fr' && hd.moneyCurrency.toUpperCase() == 'CHF') {
1805				thousandDelimiter = ' ';
1806			} 
1807
1808			if (swapped) {
1809				//if we have a comma to the right of a period, we have a comma that is in the proper decimal of the number, or we have a period to the left of a potential decimal location we should have an EUR format
1810				if (v.indexOf(',') > v.indexOf(thousandDelimiter) || (v.lastIndexOf(',') == v.length - 3) || (v.lastIndexOf(thousandDelimiter) < v.length - 3))
1811				{
1812					if(thousandDelimiter == '.')
1813						v = v.replace(/\./g, '').replace(/,/g, '.');
1814					else if (thousandDelimiter == ' ')
1815						v = v.replace(/\s/g, '').replace(/,/g, '.');
1816				}
1817			}
1818			else if (thousandDelimiter.length > 0) {
1819				v = v.replace(/\s/g, '');
1820			}
1821			v = v.replace(/,/g, '').replace(/\u00A0/g, ''); //remove any trailing commas (standard currency or otherwise)
1822
1823			if (v.length)
1824				v = hd.round(v, 2).toFixed(2); //protection for invalid decimal points
1825			return v.trim();
1826		}
1827		else {
1828			return '';
1829		}
1830	},
1831
1832	moneyStripSymbol: function (v) {
1833		//should be able to just add symbols here as we add more currencies (for js) [and in functions.asp - CleanMoney()]
1834		if (v != undefined) {
1835			v = v.toString() //make sure we have a string
1836			v = v.replace('$', '').replace('€', '').replace('£', '').replace('CHF', '').replace('CA', '').replace(/\&nbsp;/g, ' ').trim();
1837			return v;
1838		}
1839		else {
1840			return '';
1841		}
1842	},
1843
1844    moneySymbolStyle: function (v, s) {
1845		if (v != undefined) {
1846			v = v.toString(); //make sure we have a string
1847            $(['$', '€', '£', 'CHF', 'CA']).each(function(i, o) {
1848                v = v.replace(o, '<span style="' + s + '">' + o + '</span>');
1849            });
1850			return v;
1851		}
1852		else {
1853			return '';
1854		}
1855    },
1856
1857    miniTime: function (n) {
1858        if (n == -1) {
1859            return 'Twilight';
1860        }
1861        else if (n == 0) {
1862            return 'no appt';
1863        }
1864        else if (n < 60) {
1865            return n + ' min';
1866        }
1867        else {
1868            var h = Math.floor(n / 60);
1869            var m = n - (h * 60);
1870            if (m == 0) {
1871                return h + ' hr' + (h == 1 ? '' : 's');
1872            }
1873            else if (m == 15) {
1874                return h + '<span style="margin-left: 0.2em;">&frac14;</span> hrs';
1875            }
1876            else if (m == 30) {
1877                return h + '<span style="margin-left: 0.2em;">&frac12;</span> hrs';
1878            }
1879            else if (m == 45) {
1880                return h + '<span style="margin-left: 0.2em;">&frac34;</span> hrs';
1881            }
1882            else {
1883                return h + ' hrs ' + m + ' min';
1884            }
1885        }
1886    },
1887
1888    musicPath: function (f) {
1889        if (f.substr(0, 1) == '*') {
1890            return '//' + hd.host + '/' + f.substr(1) + '.mp3';
1891        }
1892        else {
1893            return '/music/mp3/' + f;
1894        }
1895    },
1896
1897    nope: function (e) {
1898        e.preventDefault();
1899        e.stopPropagation();
1900        return false;
1901	},
1902
1903	null2empty: function (v) {
1904		return v ?? '';
1905	},
1906
1907	null2zero: function (v) {
1908		return v ?? 0;
1909	},
1910
1911    number: function (n, d) {
1912        if (d == undefined) { d = 0; }
1913        return Number(n).toFixed(d).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
1914	},
1915
1916	numberLocal: function (n, d) {
1917		var r;
1918		if (d == undefined) { d = 0; }
1919		r = hd.round(Number(n), d).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
1920		if (hd.moneyCulture.toLowerCase().substring(0, 2) != 'en' && hd.moneyCurrency.toUpperCase() == 'EUR') {
1921			r = r.replace(/,/g, '.').replace(/\.([^\.]*)$/, ',$1'); //EUR (non-English): replace periods for commas, replace last period (decimal) to a comma
1922		}
1923		else if (hd.moneyCulture.toLowerCase().substring(0, 2) == 'fr' && hd.moneyCurrency.toUpperCase() == 'CAD') {
1924			r = r.replace(/,/g, ' ').replace(/\.([^\.]*)$/, ',$1'); //Canada (French): replace spaces for commas, replace last period (decimal) to a comma
1925		}
1926		else if (hd.moneyCulture.toLowerCase().substring(0, 2) == 'fr' && hd.moneyCurrency.toUpperCase() == 'CHF') {
1927			r = r.replace(/,/g, ' '); //Switzerland: replace spaces for commas
1928		}
1929		return r;
1930	},
1931
1932    nvpDecode: function (v) {
1933        return v.replace(/`5/g, String.fromCharCode(13)).replace(/`4/g, String.fromCharCode(10)).replace(/`3/g, String.fromCharCode(9)).replace(/`2/g, '|').replace(/`1/g, '~').replace(/`0/g, '`');
1934    },
1935
1936
1937    nvpDelete: function (p, n) {
1938        n = hd.nvpEncode(n);
1939        var i1 = ('|' + p).toLowerCase().indexOf('|' + n.toLowerCase() + '~');
1940        if (i1 > -1) {
1941            var i2 = (p + '|').indexOf('|', i1);
1942            if (i2 > -1) {
1943                if (i2 >= p.length) {
1944                    if (i1 == 0) {
1945                        p = '';
1946                    }
1947                    else {
1948                        p = p.substr(0, i1 - 1);
1949                    }
1950                }
1951                else {
1952                    p = p.substr(0, i1) + p.substr(i2 + 1);
1953                }
1954            }
1955        }
1956        return p;
1957    },
1958
1959    nvpEncode: function (v) {
1960        if (v == null)
1961            return '';
1962        else
1963            return v.replace(/`/g, '`0').replace(/~/g, '`1').replace(/\|/g, '`2').replace(/\t/g, '`3').replace(/\n/g, '`4').replace(/\r/g, '`5');
1964    },
1965
1966    nvpGet: function (p, n) {
1967        var t = '|' + p.toLowerCase() + '|';
1968        n = hd.nvpEncode(n).toLowerCase();
1969        var i1 = t.indexOf('|' + n + '~');
1970        if (i1 > -1) {
1971            i1 += n.length + 1;
1972            var i2 = t.indexOf('|', i1) - 1;
1973            return hd.nvpDecode(p.substr(i1, i2 - i1));
1974        }
1975        else {
1976            return '';
1977        }
1978    },
1979
1980    nvpSet: function (p, n, v) {
1981        p = hd.nvpDelete(p, n);
1982        if (p.length == 0) {
1983            p = hd.nvpEncode(n) + "~" + hd.nvpEncode(v);
1984        }
1985        else {
1986            p += '|' + hd.nvpEncode(n) + '~' + hd.nvpEncode(v);
1987        }
1988        return p;
1989    },
1990
1991	onlyHex: function (s) {
1992		if (s == undefined) { s = ''; }
1993		return s.replace(/^[^0-9a-fA-F]+$/, '').replace(/-/g, '');
1994	},
1995
1996    persistInterval: 300000,
1997
1998    // Shared three ways, all on the same origin: the inline script in /Login/persist.asp (which
1999    // stamps it when the keep-alive iframe reloads itself), and the React app, in
2000    // HDPhotoHub-UX/src/services/session-keepalive.ts. Change it in all three or the stacks stop
2001    // seeing each other and go back to pinging on top of one another.
2002    persistKey: 'hd-persist',
2003
2004    persistTmr: null,
2005
2006    persist_due: function () {
2007        var last = hd.persist_read();
2008        return (last === null) || ((last + hd.persistInterval) <= Date.now());
2009    },
2010
2011    // Keeps the ASP session alive across an idle stretch.
2012    //
2013    // The schedule hangs off a timestamp shared through localStorage rather than off page load.
2014    // It used to be a bare 5 minute setTimeout armed right here, which meant the clock restarted
2015    // on every navigation - a user clicking through pages faster than that never pinged at all -
2016    // and every open tab ran its own independent timer.
2017    //
2018    // The stored timestamp means "the session was last known to be renewed", and a page load is
2019    // itself a renewal: /inc/const.asp runs proc_GetSession, which moves dtLastAccessed forward.
2020    // So an actively browsing user correctly never needs the ping, and the ping fires only when
2021    // nothing has touched the session for a whole interval - in whichever tab notices first.
2022    persist_init: function () {
2023        if ($('.persist').length == 0) { return; }
2024        hd.persist_stamp();
2025        hd.persist_schedule();
2026        $(window).on('storage', function (e) {
2027            var oe = e.originalEvent || {};
2028            if (oe.key == hd.persistKey) { hd.persist_schedule(); }
2029        });
2030    },
2031
2032    persist_ping: function () {
2033        // Another tab may have loaded a page, or pinged, while this timer was pending.
2034        if (!hd.persist_due()) { hd.persist_schedule(); return; }
2035        // Claim the slot before the request goes out, so a sibling tab waking at the same moment
2036        // defers instead of pinging as well.
2037        hd.persist_stamp();
2038        $('.persist').attr('src', '/Login/persist.asp?' + String(Number(new Date())));
2039        hd.persist_schedule();
2040    },
2041
2042    persist_read: function () {
2043        // null means "unknown" - nothing stored yet, junk, a clock that moved backwards, or
2044        // storage unavailable (private browsing, cookies blocked). Callers fall back to the old
2045        // load-relative behaviour, so a browser without storage behaves exactly as before.
2046        try {
2047            var v = Number(window.localStorage.getItem(hd.persistKey));
2048            return ((v > 0) && (v <= Date.now())) ? v : null;
2049        }
2050        catch (e) { return null; }
2051    },
2052
2053    persist_schedule: function () {
2054        var last = hd.persist_read();
2055        if (last === null) { last = Date.now(); }
2056        window.clearTimeout(hd.persistTmr);
2057        hd.persistTmr = window.setTimeout(hd.persist_ping, Math.max((last + hd.persistInterval) - Date.now(), 0));
2058    },
2059
2060    persist_stamp: function () {
2061        try { window.localStorage.setItem(hd.persistKey, String(Date.now())); }
2062        catch (e) { }
2063    },
2064
2065    picbox_init: function (d) {
2066        if (d == undefined) { d = $('body'); }
2067        var wt = $(window).scrollTop();
2068        var wb = wt + $(window).height();
2069        $('.picbox', d).each(function (i, o) {
2070            if (!o.picboxprocessed) {
2071                var et = $(o).offset().top;
2072                var eb = et + $(o).height();
2073                if ((et == 0) || ((et <= wb) && (eb >= wt))) {
2074                    hd.picbox_process(o);
2075                }
2076            }
2077        });
2078    },
2079
2080    picbox_process: function (o) {
2081        if (o.picboxprocessed) { return false; }
2082        var img = $('> img', o);
2083        if (img.length == 0) { img = $('<img>').appendTo(o); }
2084        var s = $(o).attr('hd-media');
2085        if ((s == undefined) || (s == '')) {
2086            if ($(o).attr('hd-mediahideifempty') != undefined) {
2087                $(o).hide();
2088            }
2089            else if ($(o).attr('hd-medialoading') == undefined) {
2090                var pw = $(o).outerWidth();
2091                var ph = $(o).outerHeight();
2092                var m = Math.max(pw, ph) + 2;
2093                $(img).attr('src', '/art/nomedia.jpg').addClass('nomedia').css({ background: '#d7d3d0', width: m, height: m, left: Math.round((pw - m) * 0.5), top: Math.round((ph - m) * 0.5), padding: 0 });
2094            }
2095            $('.hidenomedia', o).hide();
2096        }
2097        else {
2098            var fit = $(o).attr('hd-mediafit');
2099            var ext = $(o).attr('hd-mediaext');
2100			var sdiv = $(o).attr('hd-mediashrinkdiv');
2101            var pbborder = $(o).attr('hd-picboxborder');
2102            var pw = $(o).innerWidth();
2103            var ph = $(o).innerHeight();
2104            var bg = (hd.rgb2hex($(img).css('background-color')) || hd.rgb2hex($(o).css('background-color'))).substr(1);
2105			var nrc = ($(o).attr('hd-medianoresizecrop') !== undefined);
2106            var m, x, y, iw, ih;
2107            if (fit == 'face') {
2108                var ss = s.split(',');
2109                if (ss && ss[0] && ss[0].split(':') && ss[0].split(':')[3] && ss[0].split(':')[3].length > 1) {
2110                    var x1, y1, x2, y2;
2111                    $(ss[0].split(':')[3].split('|')).each(function (i, o) {
2112                        var oo = o.split('`');
2113                        if (x1 == undefined || x1 > Number(oo[0])) { x1 = Number(oo[0]); }
2114                        if (y1 == undefined || y1 > Number(oo[1])) { y1 = Number(oo[1]); }
2115                        if (x2 == undefined || x2 < Number(oo[2])) { x2 = Number(oo[2]); }
2116                        if (y2 == undefined || y2 < Number(oo[3])) { y2 = Number(oo[3]); }
2117                    });
2118                    var fw = Math.min((x2 - x1) * 0.017, 1);
2119                    var fh = Math.min((y2 - y1) * 0.017, 1);
2120                    var pm = 1 / Math.max(fw, fh);
2121                    m = hd.getMediaUrl(s, pw * pm, ph * pm, ext, fit, bg, nrc);
2122                    var r = ((pw / ph) < (m.w / m.h));
2123                    iw = (r ? ph * (m.w / m.h) : pw) * pm;
2124                    ih = (r ? ph : pw / (m.w / m.h)) * pm;
2125                    x = Math.max(Math.min((((iw * ((x1 + x2) * 0.005)) - (pw * 0.5)) / (iw - pw)) || 0, 1), 0);
2126                    y = Math.max(Math.min((((ih * ((y1 + y2) * 0.005)) - (ph * 0.5)) / (ih - ph) || 0), 1), 0);
2127                }
2128                else {
2129                    fit = undefined;
2130                }
2131            }
2132            if (fit != 'face') {
2133                m = hd.getMediaUrl(s, pw, ph, ext, fit, bg, nrc);
2134                var r = ((pw / ph) < (m.w / m.h));
2135                x = 0.5;
2136                y = 0.5;
2137                if (fit != undefined) {
2138                    r = !r;
2139                    fit = ' ' + fit.toLowerCase() + ' ';
2140                    if (fit.indexOf(' left ') > -1) { x = 0; } else if (fit.indexOf(' right ') > -1) { x = 1; }
2141                    if (fit.indexOf(' top ') > -1) { y = 0; } else if (fit.indexOf(' bottom ') > -1) { y = 1; }
2142                }
2143                iw = r ? ph * (m.w / m.h) : pw;
2144                ih = r ? ph : pw / (m.w / m.h);
2145            }
2146            if (img[0]) { img[0].ratio = (m.w / m.h); }
2147            if (m.l) { if (!($(img).prop('onload'))) { $(img).bind('load', m.l); } }
2148            if (($(o).attr('hd-mediahideifempty') != undefined) && (!($(img).prop('onerror')))) { $(img).bind('error', function () { $(o).hide(); }); }
2149			$(img[0]).off('error', hd.picbox_error).on('error', hd.picbox_error).attr('alt', ($(o).closest('[role=img]').attr('aria-label') != undefined ? $(o).closest('[role=img]').attr('aria-label') : ''));
2150            if (sdiv == undefined) {
2151                if (pbborder) { iw -= parseFloat(pbborder * 2); ih -= parseFloat(pbborder * 2); } else { iw += 2; ih += 2; }
2152                $(img).attr('src', m.u).css({ left: ((pw - iw) * x), top: ((ph - ih) * y), width: iw, height: ih }).removeClass('nomedia');
2153            }
2154            else {
2155                $(img).attr('src', m.u).css({ left: 0, top: 0, width: iw, height: ih }).removeClass('nomedia');
2156                $(o).css({ width: iw, height: ih });
2157            }
2158            if (m.v) {
2159                $(img).attr('hd-vimeo', m.v).addClass('vimeolocal').removeClass('nomedia');
2160                $('.progress', o).width(0);
2161                hd.vimeo_init();
2162            }
2163            $(o).attr('hd-pbiw', iw).attr('hd-pbih', ih);
2164            $(o).closest('a').mouseover(hd.picbox_over).mouseout(hd.picbox_out);
2165            $('.hidenomedia', o).show();
2166        }
2167        if ($(o).hasClass('showface')) { hd.facialShow(o); }
2168        o.picboxprocessed = true;
2169    },
2170
2171    picbox_error: function () {
2172        $(this).off('error', hd.picbox_error);
2173        var src = $(this).attr('src');
2174        var s = src.split('/');
2175        if ((s[2] == 'videodelivery.net') && (s[4] == 'thumbnails')) {
2176            $(this).attr('src', src.split('&_jd=')[0] + '&_jd=' + Math.random());
2177            return false;
2178        }
2179        var f1 = 'vault01.hd.pics';
2180        var f2 = 'vault02.hd.pics';
2181        if (s[2] == hd.host) { 
2182            s[2] = f1; 
2183        } 
2184        else if (s[2] == f1) { 
2185            s[2] = f2; 
2186        } 
2187        else { 
2188            return false; 
2189        }
2190        $(this).attr('src', s.join('/'));
2191    },
2192
2193    picbox_over: function () {
2194        var t = this;
2195        window.clearTimeout(t.hover);
2196        t.hover = window.setTimeout(function () { hd.picbox_over_ex(t) }, 1);
2197    },
2198
2199    picbox_over_ex: function (t) {
2200        var m = 1.07;
2201        var tm = 150;
2202        if (t.hoverover) { return false; }
2203        var pb = $('.picbox', t);
2204        var pimg = $('> img', pb)[0];
2205        var iw = parseInt($(pb).attr('hd-pbiw'));
2206        var ih = parseInt($(pb).attr('hd-pbih'));
2207        $(pimg).stop(true, false).animate({ opacity: 100 }, { duration: tm, step: function (n) { $(this).css({ transform: 'scale(' + (1 + ((n / 100) * (m - 1))) + ')' }); } });
2208        t.hoverover = true;
2209    },
2210
2211    picbox_out: function () {
2212        var t = this;
2213        window.clearTimeout(t.hover);
2214        t.hover = window.setTimeout(function () { hd.picbox_out_ex(t) }, 1);
2215    },
2216
2217    picbox_out_ex: function (t) {
2218        var m = 1.07;
2219        var tm = 100;
2220        var pb = $('.picbox', t);
2221        var pimg = $('> img', pb)[0];
2222        var iw = parseInt($(pb).attr('hd-pbiw'));
2223        var ih = parseInt($(pb).attr('hd-pbih'));
2224        $(pimg).stop(true, false).animate({ opacity: 100 }, { duration: tm, step: function (n) { $(this).css({ transform: 'scale(' + (1 + ((1 - (n / 100)) * (m - 1))) + ')' }); } });
2225        t.hoverover = false;
2226    },
2227
2228    placeholderEdit: function (o) {
2229        o.focus(function () {
2230            if ($(this).val() == '') { $(this).val($(this).attr('placeholder')); }
2231        }).blur(function () {
2232            if ($(this).val() == $(this).attr('placeholder')) { $(this).val(''); }
2233        });
2234        return o;
2235    },
2236
2237    popup_init: function () {
2238        $('.popup').click(function () {
2239            var p;
2240            var s = $(this).attr('hd-popup');
2241            if (s != '') {
2242                var w = s.split(',')[0];
2243                var h = s.split(',')[1];
2244                p = (s == '' ? '' : 'width=' + w + ',height=' + h + ',left=' + ((screen.width - w) * 0.5) + ',top=' + ((screen.height - h) * 0.3) + ',menubar=0,status=0,titlebar=0');
2245            }
2246            window.open($(this).attr('href'), '_blank', p);
2247            return false;
2248        });
2249    },
2250
2251    pretendToBeSafari : false,
2252
2253    resize: function () {
2254        var hw = $('.headerlogo').width() || $('.headername').width();
2255        if (hw) {
2256            var bn = $('.bignav').width();
2257            var ww = $(window).width();
2258            if (ww < (hw + bn + 40)) {
2259                $('.mininav').show();
2260                $('.bignav').hide();
2261                hd.picbox_init($('.mininav'));
2262            }
2263            else {
2264                $('.bignav').show();
2265                $('.mininav').hide();
2266            }
2267            if (!$('.auth .loginform-container').is(':animated')) {
2268                if ($('.auth .loginform-container').height() > 1) {
2269                    $('.auth .loginform-container').css({ height: $('.auth .loginform').outerHeight() + 24 });
2270                }
2271            }
2272        }
2273		var f = $('.hd-footer');
2274		var e = $('.pgend');
2275		var s = $('.subnav');
2276		if (f.length) {
2277			if (f.offset().top) {
2278				for (var a = 0; a < 2; a++) {
2279					var fmt = Math.floor($(window).height() - (f.offset().top + f.outerHeight() - Number(f.css('marginTop').replace('px', ''))));
2280					if (fmt < 0) { fmt = 0; }
2281					f.css({ marginTop: fmt });
2282				}
2283				var s = $('.subnav');
2284				if (s.length == 1) {
2285					s.height(f.offset().top - s.offset().top);
2286				}
2287			}
2288			else {
2289				if (s.length == 1) {
2290					var eh = (((e.length ? e.offset().top : 0) < $(window).height()) ? $(window).height() - 21 : e.offset().top); //when page content is shorter than window height, adjust by 21. Not wasting more time tracking its source. But fixes pages from having a scrollbar when not needed.
2291					if (eh) {
2292						s.height(eh - s.offset().top);
2293					}
2294				}
2295			}
2296		}
2297		else {
2298			if (s.length == 1) {
2299				var eh = (((e.length ? e.offset().top : 0) < $(window).height()) ? $(window).height() - 21 : e.offset().top); //when page content is shorter than window height, adjust by 21. Not wasting more time tracking its source. But fixes pages from having a scrollbar when not needed.
2300				if (eh) {
2301					s.height(eh - s.offset().top);
2302				}
2303			}
2304		}
2305        hd.hero_resize();
2306        hd.mobileGrid();
2307    },
2308
2309    required_check: function (f) {
2310        var dis = false;
2311		$('input:visible, textarea:visible, select:visible', f).each(function (i, o) { if (($(o).attr('hd-required') != undefined) && (($(o).val().trim() == '') || (o.type == 'checkbox' && !o.checked))) { dis = true; } });
2312        $('input[type=submit], input[type=image], button.required', f).not('.norequired').each(function (i, o) {
2313            if (dis || $(o).hasClass('disabled')) {
2314                $(o).attr('disabled', true);
2315            }
2316            else {
2317                $(o).removeAttr('disabled');
2318            }
2319        });
2320    },
2321
2322    required_init: function () {
2323        $(document.forms).not('.requiredinit').each(function (i, o) { $(o).addClass('requiredinit'); hd.required_check(o); $('input, textarea, select', o).bind('change keyup', function () { hd.required_check(this.form); }) });
2324    },
2325
2326    rgb2hex: function (rgb) {
2327        if (!rgb) { return ''; }
2328        if (/^#[0-9A-F]{6}$/i.test(rgb)) return rgb;
2329        hex = function (x) { return ('0' + parseInt(x).toString(16)).slice(-2); };
2330        var p = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
2331        if (p) { return '#' + hex(p[1]) + hex(p[2]) + hex(p[3]); }
2332        p = rgb.match(/^rgba\((\d+),\s*(\d+),\s*(\d+),\s*(\d+)\)$/);
2333        if (p) {
2334            if (p[3] == 0) { return ''; }
2335            return '#' + hex(p[1]) + hex(p[2]) + hex(p[3]);
2336        }
2337        return '';
2338	},
2339
2340	round: function (number, precision) {
2341		var shift = function (number, exponent) {
2342			var numArray = ('' + number).split('e');
2343			return +(numArray[0] + 'e' + (numArray[1] ? (+numArray[1] + exponent) : exponent));
2344		};
2345		return shift(Math.round(shift(number, +precision)), -precision);
2346	},
2347
2348
2349    search: function(o) {
2350
2351		var state = {};
2352		var osort = {};
2353        var gettingmore = false;
2354        var atend = false;
2355        var tmrSearch;
2356        var running = false;
2357		var storeAllowed = ($(o.store).length == 0 || $(o.store).prop('checked') == true); //if identifier doesn't exist or it exists and is checked, then allow localStorage
2358
2359		var performSearch = async () => {
2360            var search = {};
2361            if (!running) {
2362                running = true;
2363                try {
2364                    atend = await o.method(Object.assign(search, state, osort));
2365                } catch { }
2366                running = false;
2367            }
2368		};
2369		var removeStore = () => {
2370			if (!storeAllowed)
2371				window.localStorage.removeItem(o.searchStore);
2372		};
2373		var saveSort = () => {
2374			if (o.sortStore) {
2375				if ($(o.sort).length) {
2376					osort.selectedIndex = $(o.sort)[0].selectedIndex;
2377				}
2378				window.localStorage[o.sortStore] = JSON.stringify(osort);
2379			}
2380		};
2381		var saveState = () => {
2382			if (o.searchStore && storeAllowed)
2383				window.localStorage[o.searchStore] = JSON.stringify(state);
2384			else
2385				removeStore();
2386		};
2387        if (o.state) {
2388            state = o.state;
2389        }
2390        else if (o.searchStore && storeAllowed) {
2391            state = JSON.parse(window.localStorage[o.searchStore] || '{}');
2392		}
2393		if (o.osort) {
2394			osort = o.osort;
2395		}
2396		else if (o.sortStore) { osort = JSON.parse(window.localStorage[o.sortStore] || '{}'); }
2397		osort.qty = o.qty || 50;
2398		osort.offset = o.offset || 0;
2399
2400        var changeEvent = (evt) => {
2401            var v = $(evt.currentTarget).val();
2402            state[evt.data.property] = v;
2403			osort.offset = 0;
2404			saveSort();
2405            saveState();
2406            window.clearTimeout(tmrSearch);
2407            tmrSearch = window.setTimeout(performSearch, 10);
2408        };
2409        o.searchControls.forEach(c => {
2410            $(c.selector).change(c, changeEvent);
2411            if (state[c.property]) $(c.selector).val(state[c.property]);
2412        });
2413
2414        if (o.moreSelector) {
2415            var moreDiv = $(o.moreSelector);
2416            $(document).bind('scroll', async (o) => {
2417                if (!gettingmore && !atend) {
2418                    var b = $(document).scrollTop() + $(window).innerHeight();
2419                    if (b > moreDiv.offset().top) {
2420						osort.offset += osort.qty;
2421                        gettingmore = true;
2422                        await performSearch();
2423                        gettingmore = false;
2424                    }
2425                }
2426            })
2427        }
2428
2429        if (o.sort) {
2430            var sortFunction = (evt) => {
2431				osort.sort = $(evt.currentTarget).val();
2432				osort.offset = 0;
2433				saveSort();
2434                performSearch();
2435            };
2436            $(o.sort).change(sortFunction);
2437			if (o.sortStore) {
2438				$(o.sort)[0].selectedIndex = Number((window.localStorage[o.sortStore] ? JSON.parse(window.localStorage[o.sortStore]).selectedIndex : 1) || 1);
2439			}
2440		}
2441
2442		if ($(o.store)) {
2443			var storeFunction = () => {
2444				storeAllowed = ($(o.store).prop('checked') == true);
2445				if (!storeAllowed)
2446					removeStore();
2447				else
2448					saveState();
2449			};
2450			$(o.store).change(storeFunction);
2451		}
2452
2453        performSearch();
2454    },
2455
2456    selectBackgroundResize: function (o) {
2457		if (o && o.selectBackground) {
2458            if ($(o).is(':visible')) {
2459                $(o.selectBackground).css({ width: $(o).outerWidth(), height: $(o).outerHeight() });
2460            }
2461            else if ($(o).hasClass('mediaselect')) {
2462                if ($(o).selectmenu('instance')) {
2463                    var s = $(o).selectmenu('instance').button[0];
2464                    $(o.selectBackground).css({ width: $(s).outerWidth(), height: $(s).outerHeight() });
2465                }
2466            }
2467        }
2468    },
2469
2470    selectFix: function () {
2471        if (document.fonts.status == 'loading') {
2472            window.setTimeout(hd.selectFix, 100);
2473            return false;
2474        }
2475        $('select').each(function (i, o) {
2476            var lh = $(o).css('lineHeight');
2477            $(o).css('lineHeight', '1em');
2478            window.setTimeout(function () { $(o).css('lineHeight', lh); }, 1);
2479        })
2480    },
2481
2482    sessionkey: function () {
2483        var cn = 'sid' + (document.location.hostname.split('.').length - 1) + '=';
2484        return (' ' + document.cookie + cn).split(cn)[1].split(';')[0];
2485    },
2486
2487    shortDate: function (v) {
2488        var d = new Date(v);
2489        return String(d.getMonth() + 1) + '/' + d.getDate() + '/' + String(d.getFullYear()).substr(2, 2);
2490    },
2491
2492    shortMonth: function (i) {
2493        return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][Math.min(Math.max(parseInt(i), 0), 11)];
2494    },
2495
2496    shortTime: function (v) {
2497        var d = new Date(v);
2498        var h = d.getHours();
2499        var m = d.getMinutes();
2500        return String(((h + 11) % 12) + 1) + ':' + (m < 10 ? '0' : '') + m + ' ' + (h < 12 ? ' AM' : ' PM');
2501    },
2502
2503    statusIndex: function (d) {
2504        if ((d.sid == 0) && ((d.ac || '') == '')) {
2505            return (d.dc && !d.lc) ? 3 : 2;
2506        }
2507        else if (d.sid == 1) {
2508            return (d.bid == 3 ? 5 : (d.bid == 4 ? 6 : 4));
2509        }
2510        else if (d.sid == 0) {
2511            return 7;
2512        }
2513        else if (d.sid == -1) {
2514            return 8;
2515        }
2516        return '???';
2517    },
2518
2519    statusName: function (s) {
2520        return {
2521            '-1': '<span style="color: #009; font-weight: 700;">DELETED</span>',
2522            '0': '<span style="color: #e00; font-weight: 700;">Inactive</span>',
2523            '1': '<span style="color: #0c0; font-weight: 700;">Active</span>',
2524            'deleted': '<span style="color: #009; font-weight: 700;">DELETED</span>',
2525            'inactive': '<span style="color: #e00; font-weight: 700;">Inactive</span>',
2526            'active': '<span style="color: #0c0; font-weight: 700;">Active</span>',
2527            'complete': '<span style="color: #0c0; font-weight: 700;">Complete</span>',
2528            'reserved': '<span style="color: #009; font-weight: 700;">Reserved</span>'
2529        }[String(s).toLowerCase()];
2530    },
2531
2532    statusNamePlain: function (s) {
2533        return {
2534            '-1': 'DELETED',
2535            '0': 'Inactive',
2536            '1': 'Active',
2537            'deleted': 'DELETED',
2538            'inactive': 'Inactive',
2539            'active': 'Active',
2540            'complete': 'Complete',
2541            'reserved': 'Reserved'
2542        }[String(s).toLowerCase()];
2543	},
2544
2545    stripPhone: function () {
2546        if (!hd.isMobile()) {
2547            $('a').each(function (i, o) {
2548                var h = $(o).attr('href');
2549                if (h != undefined) {
2550                    if (h.substr(0, 4).toLowerCase() == 'tel:') {
2551                        $(o).css({ textDecoration: 'none' }).removeAttr('href');
2552                    }
2553                }
2554            });
2555        }
2556    },
2557
2558    supportVid: {},
2559
2560    supportVid_close: function () {
2561        console.log('support close');
2562        if (hd.supportVid.playing) {
2563            hd.supportVid.playing = false;
2564            hd.supportVid_logtime();
2565        }
2566    },
2567
2568    supportVid_events: function () {
2569        if (window.Vimeo) {
2570            var o = $('.supportiframe');
2571            if (o.length) {
2572                var player = new Vimeo.Player(o[0]);
2573                player.on('play', function () {
2574                    hd.supportVid.playing = true;
2575                    hd.supportVid.start = (new Date()).getTime();
2576                    if (hd.supportVid.ping) { window.clearTimeout(hd.supportVid.ping); }
2577                    hd.supportVid.ping = window.setTimeout(hd.supportVid_ping, 5000);
2578                });
2579                player.on('pause', function () {
2580                    hd.supportVid.playing = false;
2581                    hd.supportVid_logtime();
2582                });
2583                return false;
2584            }
2585        }
2586        window.setTimeout(hd.supportVid_events, 100);
2587    },
2588
2589    supportVid_init: function () {
2590        $('.tile-supportvid').click(function () {
2591            hd.supportVid.source = this;
2592            var h = $(this).attr('href');
2593            var r = $(this).attr('hd-resume');
2594            if ((h.indexOf('#') == -1) && (r)) { h += '#t=' + r; }
2595            hd.dialog({
2596                beforeClose: hd.supportVid_close,
2597                closer: true,
2598                content: '<iframe src="' + h + '" hd-svid="' + $(this).attr('hd-svid') + '" hd-uid="' + $(this).attr('hd-uid') + '" frameborder="0" class="supportiframe" style="vertical-align: middle;"></iframe>',
2599                padding: '0px'
2600            });
2601            $('.hd-dialog-container .dialog').css({ boxShadow: '0 0 50px #000' });
2602            hd.supportVid_size();
2603            if (!window.Vimeo) { $('<script>').attr('src', 'https://player.vimeo.com/api/player.js').appendTo('body'); }
2604            hd.supportVid_events();
2605            return false;
2606        });
2607        $(window).resize(hd.supportVid_size);
2608    },
2609
2610    supportVid_logtime: function () {
2611        var o = $('.supportiframe');
2612        if (o.length) {
2613            var player = new Vimeo.Player(o[0]);
2614            player.getCurrentTime().then(function (t) {
2615                var c = (new Date()).getTime();
2616                var l = (c - hd.supportVid.start) / 1000;
2617                if (l) {
2618                    hd.supportVid.start = c;
2619                    $.ajax('/support/logsvid.asp?sv=' + o.attr('hd-svid') + '&u=' + o.attr('hd-uid') + '&l=' + Math.round(l) + '&t=' + Math.round(t));
2620                    if (hd.supportVid.source) {
2621                        $(hd.supportVid.source).attr('hd-resume', t);
2622                    }
2623                }
2624            });
2625        }
2626    },
2627
2628    supportVid_ping: function () {
2629        if (hd.supportVid.playing) {
2630            hd.supportVid_logtime();
2631            hd.supportVid.ping = window.setTimeout(hd.supportVid_ping, 5000);
2632        }
2633    },
2634
2635    supportVid_size: function () {
2636        var si = $('.supportiframe');
2637        if (si.is(':visible')) {
2638            var ww = Math.round($(window).width() * 0.9);
2639            var wh = Math.round($(window).height() * 0.85);
2640            if ((ww / wh) > 1.777) {
2641                si.css({ width: wh * 1.777, height: wh });
2642            }
2643            else {
2644                si.css({ width: ww, height: ww / 1.777 });
2645            }
2646        }
2647    },
2648
2649    taglist_init: function (o) {
2650        var tl = $('.taglist', o || document);
2651        if (tl.length) {
2652            if (!window.Tagify) {
2653                $('<link href="https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.css" rel="stylesheet" type="text/css" />').appendTo('head');
2654                $.getScript('https://cdn.jsdelivr.net/npm/@yaireo/tagify', function () {
2655                    $.getScript('https://cdn.jsdelivr.net/npm/@yaireo/tagify/dist/tagify.polyfills.min.js', function () {
2656                        hd.taglist_init(o);
2657                    });
2658                });
2659            }
2660            else {
2661                console.log('taglist_init', tl);
2662                $(tl).each(function (i, o) {
2663                    var opts = { 
2664                        tagTextProp: 'name',
2665                        dropdown: { 
2666                            enabled: 0, 
2667                            mapValueTo: (d) => { return d.name || d.value }, 
2668                            searchKeys: ['value', 'name']
2669                        },
2670                        originalInputValueFormat: (v) => { return v.map(item => item.value).join(','); }
2671                    };
2672                    var wl = $(o).attr('hd-whitelist');
2673                    if (wl) {
2674                        var wlj = false;
2675                        try {
2676                            wlj = JSON.parse(wl);
2677                        }
2678                        catch (e) {}
2679                        if (wlj) {
2680                            opts.enforceWhitelist = true;
2681                            opts.whitelist = wlj;
2682                        }
2683                    }
2684                    var tagify = new Tagify(o, opts);
2685                    tagify.on('keydown', (e) => {
2686                        if(e.detail.event.key == 'Enter' && !tagify.state.inputText && !tagify.state.editing) {
2687                            $(o).trigger('submit');
2688                            e.preventDefault();
2689                        }
2690                    });
2691                    var tw = $(o).attr('hd-tagwidth');
2692                    if (tw) { $(tagify.DOM.scope).css({ width: tw }); }
2693                });
2694            }
2695        }
2696    },
2697
2698    texthint_animopts: {
2699        duration: 200,
2700        step: function () { hd.resize(); hd.selectBackgroundResize(this); }
2701    },
2702
2703    texthint_blur: function () {
2704        if (hd.texthint_shrinkable(this)) {
2705            if (this.tho) {
2706                $(this).stop(true, false).animate({ paddingTop: '0.25em' }, hd.texthint_animopts);
2707                $('div', this.tho).stop(true, false).animate({ fontSize: '1em', top: '0.25em' }, hd.texthint_animopts);
2708            }
2709        }
2710        if (!hd.errornoclear) { hd.errors_clear(this); }
2711    },
2712
2713    texthint_change: function () {
2714        if (hd.texthint_shrinkable(this)) { hd.texthint_blur.call(this); } else { hd.texthint_focus.call(this); }
2715    },
2716
2717    texthint_check: function (d) {
2718        if (d == undefined) { d = $('body'); }
2719        hd.errornoclear = true;
2720		$('input[type=text], input[type=password], input[type=date], input[type=number], textarea, select', d).each(function (i, o) { hd.texthint_change.call(o); });
2721        hd.errornoclear = false;
2722    },
2723
2724    texthint_click: function () {
2725        $(this.o).focus();
2726        if ($(this.o).hasClass('inputdiv')) {
2727            $(this.o).trigger('click');
2728        }
2729        return false;
2730    },
2731
2732    texthint_init: function (d) {
2733        if (d == undefined) { d = $('body'); }
2734		$('input[type=text], input[type=password], input[type=date], input[type=number], textarea, select, .inputdiv', d).each(function (i, o) {
2735            if (!o.tho) {
2736                var th = $(o).attr('hd-hint');
2737                if (th) {
2738                    var tho;
2739                    if ($(o).attr('disabled') != undefined || $(o).attr('readonly') != undefined) {
2740                        th += ' <span class="fas fa-lock" style="font-size: 0.8em;"></span>';
2741                    }
2742                    else if ($(o).attr('hd-required') != undefined) {
2743                        th += ' <span style="color: #e00; font-weight: 700;">*</span>';
2744                    }
2745                    if (hd.texthint_shrinkable(o)) {
2746                        o.tho = $('<div class="texthint"><div style="font-size: 1em; top: 0.25em;">' + th + '</div></div>');
2747                        $(o).css({ paddingTop: '0.25em' }).before(o.tho);
2748                    }
2749                    else {
2750                        o.tho = $('<div class="texthint"><div style="font-size: 0.8em; top: 0.1em;"> ' + th + '</div></div>');
2751                        $(o).css({ paddingTop: '1em' }).before(o.tho);
2752                    }
2753                    if ($(o).attr('hd-hintwrap') != undefined) { $('div', o.tho).css({ lineHeight: '1.2em', whiteSpace: 'normal' }); }
2754                    //$('div', o.tho).css({ maxWidth: $(o).width() || 'auto', overflow: 'hidden' });
2755                    o.tho[0].o = o;
2756                    $(o.tho).mousedown(hd.texthint_click)
2757                    $(o).blur(hd.texthint_blur).focus(hd.texthint_focus).change(hd.texthint_change);
2758                    if ($(o).is('select')) {
2759                        $(o).css({ backgroundColor: 'inherit' });
2760                        o.selectBackground = $('<div class="select-background' + ($(o).prop('disabled') ? ' disabled' : '') + '"></div>').insertBefore(o)[0];
2761                        hd.selectBackgroundResize(o);
2762                    }
2763                }
2764            }
2765        });
2766		$('select.textcolor', d).each(function (i, o) {
2767			//var cf = function () { $(this).css('color', $(this.options[this.selectedIndex]).css('color')); };  //FireFox doesn't read the jquery css color correctly. Always returns white.
2768			var cf = function () { $(this).css('color', '#' + $(this.options[this.selectedIndex]).val()); };
2769            $(o).change(cf);
2770            cf.apply(o);
2771        });
2772    },
2773
2774    texthint_focus: function () {
2775        if (this.tho) {
2776            $(this).stop(true, false).animate({ paddingTop: '1em' }, hd.texthint_animopts);
2777            $('div', this.tho).stop(true, false).animate({ fontSize: '0.8em', top: '0.1em' }, hd.texthint_animopts);
2778        }
2779    },
2780
2781    texthint_shrinkable: function (t) {
2782        return (($(t).val() == '') && ($(t).attr('placeholder') 
2782== '') && (($(t).prop('tagName') != 'SELECT') || ($('option:selected', t).text() == '')) && ($(t).css('backgroundColor') != 'rgb(250, 255, 189)') && ($(t).attr('hd-hint-noshrink') == undefined));
2783    },
2784
2785    tinyDate: function (v) {
2786        var d = new Date(v);
2787        return String(d.getMonth() + 1) + '/' + (d.getDate());
2788    },
2789
2790    today: function (f) {
2791        var d = new Date();
2792        $(f).val((d.getMonth() + 1) + '/' + d.getDate() + '/' + d.getFullYear());
2793    },
2794
2795    toggleClass: function (o, c1, c2) {
2796        if ($(o).hasClass(c1)) {
2797            $(o).removeClass(c1).addClass(c2);
2798            return 2;
2799        }
2800        else {
2801            $(o).removeClass(c2).addClass(c1);
2802            return 1;
2803        }
2804    },
2805
2806    trim: function (v) {
2807        while (v.substr(0, 1) == ' ') { v = v.substr(1, v.length); }
2808        while (v.substr(v.length - 1, 1) == ' ') { v = v.substr(0, v.length - 1); }
2809        return v;
2810    },
2811
2812    truncate_init: function () {
2813        $('.truncate').not('.truncate_mo').addClass('truncate_mo').mouseover(function () {
2814            if ($(this).attr('title') == undefined) {
2815                var $c = $(this).clone().css({ display: 'inline', width: 'auto', visibility: 'hidden' }).appendTo('body');
2816                if ($c.width() > $(this).width()) { $(this).attr('title', $(this).text()); }
2817                $c.remove();
2818            }
2819        });
2820    },
2821
2822	uploadbox_click: function (e, target) {
2823		var t = this;
2824		if (target != undefined) {
2825			t = target;
2826		}
2827        if (!t.uploadform) {
2828            t.uploadform = $('<div style="position: absolute; top: 0; left: -1000px;"><form><input type="file"></form></div>').appendTo(document.body);
2829            $('input', t.uploadform).change(function (e) { hd.uploadbox_upload(t, this.files); });
2830        }
2831        $('input', t.uploadform).val('').click();
2832    },
2833
2834    uploadbox_drop: function (e) {
2835        hd.uploadbox_upload(this, e.originalEvent.dataTransfer.files);
2836    },
2837
2838    uploadbox_init: function () {
2839        $('.uploadbox').each(function (i, o) {
2840            $('.dropmessage', o).hide();
2841        }).on('dragover dragenter', hd.uploadbox_over).on('dragleave dragend drop', hd.uploadbox_out).on('drop', hd.uploadbox_drop).click(hd.uploadbox_click);
2842    },
2843
2844    uploadbox_over: function () {
2845        var t = this;
2846        window.clearTimeout(this.dragtmr);
2847        this.dragtmr = window.setTimeout(function () { hd.uploadbox_over_ex.call(t); }, 1);
2848    },
2849
2850    uploadbox_over_ex: function () {
2851        if (!this.dragover) {
2852            $('.dropmessage', this).show();
2853            this.dragover = true;
2854        }
2855    },
2856
2857    uploadbox_out: function () {
2858        var t = this;
2859        window.clearTimeout(this.dragtmr);
2860        this.dragtmr = window.setTimeout(function () { hd.uploadbox_out_ex.call(t); }, 50);
2861    },
2862
2863    uploadbox_out_ex: function () {
2864        $('.dropmessage', this).hide();
2865        this.dragover = false;
2866    },
2867
2868    uploadbox_upload: function (t, f) {
2869        var ub = $(t).attr('hd-uploadbrand'); if (!ub) { ub = ''; }
2870        var ug = $(t).attr('hd-uploadgroup'); if (!uu) { uu = ''; }
2871        var uu = $(t).attr('hd-uploaduser'); if (!uu) { uu = ''; }
2872        var us = $(t).attr('hd-uploadsite'); if (!us) { us = ''; }
2873		var upc = $(t).attr('hd-uploadproductcategory'); if (!upc) { upc = ''; }
2874		var ufo = $(t).attr('hd-uploadfilteroption'); if (!ufo) { ufo = ''; }
2875		var uups = $(t).attr('hd-uploadupsell'); if (!uups) { uups = ''; }
2876        var ue = $(t).attr('hd-uploadext'); if (!ue) { ue = ''; }
2877        var umu = $(t).attr('hd-uploadmediause'); if (!umu) { umu = ''; }
2878        $('.facialshow', t).remove();
2879
2880        var bf = [];
2881        if (f.length > 0) {
2882            var fn = f[0].name;
2883            var e = fn.substring(('.' + fn).lastIndexOf('.')).toLowerCase().replace('jpeg', 'jpg').replace('mpeg4', 'mp4');
2884            if ((',' + ue.toLowerCase() + ',').indexOf(',' + e + ',') > -1) {
2885                $('> img', t).attr('src', '/art/spinner.gif').removeClass('nomedia').css({ background: '#a7a3a0', width: 60, height: 60, top: 0, left: 0, padding: Math.round(($(t).height() - 60) * 0.5) + 'px ' + Math.round(($(t).width() - 60) * 0.5) + 'px' });
2886                hd.uploadFile({
2887                    file: f[0],
2888                    brandID: ub,
2889                    groupID: ug,
2890                    userID: uu,
2891                    siteID: us,
2892					productCategoryID: upc,
2893					filterOptionID: ufo,
2894					upsellID: uups,
2895                    mediaUseID: umu,
2896                    mediaTypeID: (hd.isVideo(e) ? 6 : 1),
2897                    error: function (d) {
2898                        console.log('UPLOAD ERROR');
2899                        console.log(d);
2900                        $('> img', this.pb).attr('src', '/art/error.png').css({ background: '#e09090' });
2901                    },
2902                    success: function (d) {
2903                        $('> img', this.pb).removeAttr('src style');
2904                        hd.picbox_process($(this.pb).attr('hd-mid', d.id).attr('hd-media', d.sizes).attr('hd-mediaext', d.extension));
2905                        if (umu == 2) { $('.userphoto-' + uu + ' > img').removeAttr('src'); hd.picbox_process($('.userphoto-' + uu).attr('hd-media', d.sizes).attr('hd-mediaext', d.extension)); }
2906                        $(this.pb).blur();
2907                        var ua = $(t).attr('hd-uploadafter');
2908                        if (ua) { eval(ua); }
2909                    },
2910                    vars: { pb: t, file: f[0], name: fn, ext: e, isVideo: hd.isVideo(e) }
2911                });
2912            }
2913            else {
2914                bf.push(fn);
2915            }
2916        }
2917        if (bf.length) {
2918            var elist = ((ue.split(',').length == 1) ? ue.toUpperCase() : ue.toUpperCase().split(',').join(', ').replace(/,\s([^,]+)$/, ' or $1'));
2919            hd.error('Invalid File Type', 'This file was an invali
2919d file type.  Please use a ' + elist + ' file.');
2920        }
2921    },
2922
2923    uploadFile: function (o) {
2924        if (window.uploader) { 
2925            var start = (new Date()).getTime();
2926            uploader.uploadFile(o.file, {
2927                Name: o.vars.name ?? (o.file.name.slice(0, o.file.name.lastIndexOf('.')) || o.file.name),
2928                useId: o.mediaUseID,
2929                typeId: o.mediaTypeID,
2930                brandId: o.brandID,
2931                siteId: o.siteID,
2932                userId: o.userID,
2933                groupId: o.groupID,
2934                categoryId: o.productCategoryID,
2935                filterOptionId: o.filterOptionID,
2936                upsellId: o.upsellID,
2937                length: o.length
2938            }, (d) => {
2939                o.success.apply(o.vars, [{
2940                    id: d.mediaId,
2941                    type: d.typeId,
2942                    mediaName: d.name,
2943                    extension: d.extension,
2944                    mediaKey: d.mediaKey,
2945                    width: d.width,
2946                    height: d.height,
2947                    size: d.size,
2948                    sizes: d.sizes,
2949                    status: d.status
2950                }]);
2951                $('.progress', o.vars.tile).width(0);
2952            }, (p) => {
2953                $('.progress', o.vars.tile).width(p * $('.progress', o.vars.tile).parent().width());
2954            }, (d, r) => {
2955                $.ajax('/media/uploadfail.asp?nStatus=' + d.status + '&nSize=' + o.file.size + '&nDuration=' + ((new Date()).getTime() - start) +
2956                    (o.brandID ? '&nBrandID=' + o.brandID : '') +
2957                    (o.groupID ? '&nGroupID=' + o.groupID : '') +
2958                    (o.userID ? '&nUserID=' + o.userID : '') +
2959                    (o.siteID ? '&nSiteID=' + o.siteID : ''));
2960                return o.error.apply({ ...o, ...o.vars, retryFn: (oo) => { 
2961                    hd.uploadFile({ ...o, ...oo });
2962                }}, [d, r]);
2963            });
2964        }
2965        else {
2966            if (o.mediaTypeID == 6) {
2967                if (!(tus)) {
2968                    console.log('TUS library not loaded')
2969                    o.error.apply({ file: o.file, retry: 99, tile: o.vars.tile });
2970                }
2971                else if (!tus.isSupported) {
2972                    console.log('TUS not supported in this browser.')
2973                    o.error.apply({ file: o.file, retry: 99, tile: o.vars.tile });
2974                }
2975                else {
2976                    $.ajax({
2977                        url: '/media/video.asp?l=' + o.file.size + ((o.vars.name) ? '&n=' + encodeURIComponent(o.vars.name) : ''),
2978                        cache: false,
2979                        dataType: 'json',
2980                        error: function (d) { o.error.apply({ file: o.file, retry: 99, tile: o.vars.tile }); },
2981                        success: function (d) {
2982                            var upload = new tus.Upload(o.file, {
2983                                uploadUrl: d.upload.upload_link,
2984                                retryDelays: [0, 1000, 3000, 5000],
2985                                chunkSize: 10485760,
2986                                metadata: {
2987                                    filename: o.file.name,
2988                                    filetype: o.file.type
2989                                },
2990                                resume: true,
2991                                uploadSize: o.file.size,
2992                                onError: function (error) {
2993                                    console.log("Failed because: " + error);
2994                                },
2995                                onProgress: function (bytesUploaded, bytesTotal) {
2996                                    $('.progress', o.vars.tile).width((bytesUploaded / bytesTotal) * $('.progress', o.vars.tile).parent().width());
2997                                },
2998                                onSuccess: function () {
2999                                    console.log('Upload Complete');
3000                                    $.ajax($.extend({
3001                                        url: '/media/video.asp?u=' + encodeURIComponent(d.uri) +
3002                                            ((d.host_type) ? '&ht=' + encodeURIComponent(d.host_type) : '') +
3003                                            ((d.auth_id) ? '&aid=' + encodeURIComponent(d.auth_id) : '') +
3004                                            ((o.mediaUseID) ? '&mu=' + encodeURIComponent(o.mediaUseID) : '') +
3005                                            ((o.productCategoryID) ? '&pc=' + encodeURIComponent(o.productCategoryID) : '') +
3006                                            ((o.filterOptionID) ? '&fo=' + encodeURIComponent(o.filterOptionID) : '') +
3007                                            ((o.brandID) ? '&bid=' 
3007+ encodeURIComponent(o.brandID) : '') +
3008                                            ((o.siteID) ? '&s=' + encodeURIComponent(o.siteID) : '') +
3009                                            ((o.groupID) ? '&gid=' + encodeURIComponent(o.groupID) : '') +
3010                                            ((o.userID) ? '&uid=' + encodeURIComponent(o.userID) : '') +
3011                                            ((o.vars.name) ? '&n=' + encodeURIComponent(o.vars.name) : '') +
3012                                            ((o.vars.ext) ? '&e=' + encodeURIComponent(o.vars.ext.replace('.', '')) : ''),
3013                                        dataType: 'json',
3014                                        error: o.error,
3015                                        success: o.success
3016                                    }, o.vars));
3017                                }
3018                            });
3019                            upload.start();
3020                        }
3021                    })
3022                }
3023            }
3024            else {
3025            
3026                var prod = (hd.isDev !== true);
3027                var ajaxData = new FormData();
3028                if (o.brandID) { ajaxData.append('nBrandID', o.brandID); }
3029                if (o.groupID) { ajaxData.append('nGroupID', o.groupID); }
3030                if (o.userID) { ajaxData.append('nUserID', o.userID); }
3031                if (o.siteID) { ajaxData.append('nSiteID', o.siteID); }
3032                if (o.productCategoryID) { ajaxData.append('nProductCategoryID', o.productCategoryID); }
3033                if (o.filterOptionID) { ajaxData.append('nFilterOptionID', o.filterOptionID); }
3034                if (o.upsellID) { ajaxData.append('nUpsellID', o.upsellID); }
3035                if (o.mediaUseID) { ajaxData.append('nMediaUseID', o.mediaUseID); }
3036                if (o.mediaTypeID) { ajaxData.append('nMediaTypeID', o.mediaTypeID); }
3037                if (o.length) { ajaxData.append('nLength', o.length); }
3038                if (prod) { ajaxData.append('SessionKey', hd.sessionkey()); }
3039                ajaxData.append('sAjaxFile', o.file);
3040                $.ajax($.extend({
3041                    cache: false,
3042                    contentType: false,
3043                    data: ajaxData,
3044                    dataType: 'json',
3045                    error: function(d) {
3046                        $.ajax('/media/uploadfail.asp?nStatus=' + d.status + '&nSize=' + o.file.size + '&nDuration=' + ((new Date()).getTime() - this.start) +
3047                            (o.brandID ? '&nBrandID=' + o.brandID : '') +
3048                            (o.groupID ? '&nGroupID=' + o.groupID : '') +
3049                            (o.userID ? '&nUserID=' + o.userID : '') +
3050                            (o.siteID ? '&nSiteID=' + o.siteID : ''));
3051                        return o.error.apply(this, [d]);
3052                    },
3053                    processData: false,
3054                    success: o.success,
3055                    start: (new Date()).getTime(),
3056                    type: 'POST',
3057                    url: (prod ? '//upload.hd.pics' : '') + '/media/upload.aspx'
3058                }, o.vars));
3059            }
3060        }
3061    },
3062
3063    vimeo_init: function () {
3064        $('.vimeolocal').each(function (i, o) {
3065            $(o).removeClass('vimeolocal');
3066            var m = $(o).parent().parent().attr('hd-mid')
3067            $.ajax({
3068                success: function (d) {
3069                    var pw = $(o).parent().width();
3070                    var ph = $(o).parent().height();
3071                    var ms = ((pw < ph) ? pw : ph);
3072                    var px = Math.floor((pw - (ms * 0.35)) / 2);
3073                    var py = Math.floor((ph - (ms * 0.35)) / 2);
3074                    if (d.processing) {
3075                        var t = this;
3076                        if ($(o).attr('src').indexOf('spinner.gif') == -1) {
3077                            $(o).attr('src', '/art/spinner.gif').removeClass('nomedia').css({ background: '#b7b3b0', top: 0, left: 0, padding: py + 'px ' + px + 'px', width: pw - (px * 2), height: ph - (py * 2) });
3078                        }
3079                        window.setTimeout(function () { $.ajax(t); }, 7000);
3080                    }
3081                    else if (d.sizes) {
3082                        var pb = $(o).css({ padding: 0 }).parent().attr('hd-media', d.sizes);
3083                        hd.picbox_process(pb);
3084                    }
3085                    else {
3086                        $(o).attr('src', '/art/error.png').css({ background: '#e09090', top: 0, left: 0, padding: py + 'px ' + px + 'px', width: pw - (px * 2), height: ph - (py * 2) });
3087                    }
3088                },
3089                url: '/media/video.asp?t=' + encodeURIComponent($(o).attr('hd-vimeo')) +  ((m) ? '&nMediaID=' + m : '')
3090            });
3091        });
3092        $('.vimeosrc').each(function (i, o) {
3093            $(o).removeClass('vimeosrc');
3094
3095            var url = '';
3096            if ($(o).attr('hd-vimeo') != undefined) {
3097                url = 'https://player.vimeo.com/video/' + $(o).attr('hd-vimeo');
3098            }
3099            else {
3100                //we have a regular/custom vimeo link (that didn't have a vimeo ID at the end of it), try to use the original vimeo link to get the thumbnail
3101                if ($(o).attr('src') != undefined) {
3102                    url = $(o).attr('src');
3103                }
3104            }
3105
3106            if (url.length) {
3107                $.ajax({
3108                    success: function (d) {
3109						if (d && d.thumbnail_url) {
3110							$(o).attr('src', d.thumbnail_url);
3111						}
3112						else {
3113							if ($(o).attr('hd-vimeo') != undefined) {
3114								$(o).attr('src', '/media/vimeothumb.aspx?v=' + $(o).attr('hd-vimeo'));
3115							}
3116							else {
3117								$(o).attr('src', '/art/social/vimeo.png');
3118							}
3119						}
3120					},
3121					url: '//vimeo.com/api/oembed.json?url=' + url
3122                })
3123            }
3124        });
3125	},
3126
3127	vimeoHash: function(u) {
3128		if (u.toLowerCase().indexOf('h=') > -1) {
3129			//grab the h querystring formatted hash
3130			return (u.split('h=')[1] + '&').split('&')[0];
3131		}
3132		else {
3133			var tmp = (u + '?').split('?')[0].split('/');
3134			if (tmp[tmp.length - 1] != undefined && tmp[tmp.length - 1].toString().trim().length && tmp[tmp.length - 1].toString().trim() != hd.vimeoKey(u)) {
3135				//grab the hash that is just an extended /123abc
3136				return tmp[tmp.length-1].toString().trim();
3137			}
3138		}
3139		return '';
3140	},
3141
3142	vimeoKey: function(u) {
3143		var tmp;
3144		var authId;
3145		tmp = (u + '?').split('?')[0].split('/');
3146		authId = ((u + '?a=').split('?a=')[1] + '&').split('&')[0];
3147		for (var a = 0; a < tmp.length; a++) {
3148			if (tmp[a].length > 5) {
3149				if (!isNaN(tmp[a])) {
3150					return tmp[a] + (authId.length ? '?a=' + authId : '');
3151				}
3152			}
3153		}
3154		return '';
3155	},
3156
3157	youTubeKey: function(u) {
3158		if (u.toLowerCase().indexOf('v=') > -1) {
3159			//u += 'v=';
3160			return ((u + 'v=').split('v=')[1] + '&').split('&')[0];
3161		}
3162		else if (u.toLowerCase().indexOf('embed/') > -1) {
3163			return ((u + 'embed/').split('embed/')[1] + '/').split('/')[0];
3164		}
3165		return '';
3166	}
3167}
3168
3169
3170// init
3171$(window).on('load', hd.resize).resize(function () { hd.resize(); hd.picbox_init(); }).scroll(function () { hd.picbox_init(); });
3172$(document).keydown(hd.keydown);
3173$(function () {
3174    hd.maxrows();
3175    hd.gridsort_init();
3176    hd.resize();
3177    hd.required_init();
3178    hd.texthint_init();
3179    hd.persist_init();
3180    hd.popup_init();
3181    hd.mediaselect_init();
3182    hd.truncate_init();
3183    hd.uploadbox_init();
3184	hd.meldload_init();
3185	hd.designload_init();
3186    hd.vimeo_init();
3187    hd.taglist_init();
3188    hd.supportVid_init();
3189    hd.stripPhone();
3190    hd.cookieNotification();
3191    window.setTimeout(hd.selectFix, 10);
3192    window.setTimeout(hd.picbox_init, 10);
3193    window.setTimeout(hd.texthint_check, 100);
3194    window.setTimeout(hd.texthint_check, 250);
3195    $('body').on('drag dragstart dragend dragover dragenter dragleave drop', function (e) {
3196        if (!$(e.target).hasClass('ui-draggable')) { hd.nope(e); }
3197    });
3198    $('.contentwithsubnav').css({ minHeight: $('.subnav > div').height() });
3199    window.setTimeout(function () { $('.contentwithsubnav').css({ minHeight: $('.subnav > div').height() }); hd.resize(); }, 350);
3200});

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.