/* author & reviser: Don Kent, eShopHost Ltd, unless otherwise noted */
/* Copyright (C) 2003-2006, eShopHost Ltd, all rights reserved. */

/* HISTORY
1.0, 24/09/03 Creation date
1.1, 06/10/03 added 4. isNumeric function
1.2, 08/11/03 added 5. emProtect function
1.3, 06/04/04 added to 1. - email address valid?
1.4, 18/08/04 added 6. submitEnquiry function
1.5, 03/11/04 modified 6. to use currentStyle property
1.6, 14/12/04 added 7. DisplayMeta function. Add to 5. new mode: hidden. Add to 6. .check property
1.7, 15/12/04 added 8. ProcessTextLinks function
1.8, 16/12/04 added 9. ProcessImageLinks function
1.9, 10/01/05 changed 8 & 9 to make all tags 2 digits complying with selfupdate.pl
1.10 18/02/05 9 removed any tags in webmaster's input; 8. ditto but trailing tag (such as <br>)
1.11 25/04/05 1.2 for email - Regex changed to match mail.pl's check; check for 'phone' added. 6. Added PhoneResponse, Phone, Copy standard fields + logic
1.12 07/05/05 8,9. Changed TextArea from attributes to class for width & height
1.13 18/05/05 10 added
1.14 19/05/05 10 debug for ordinals
1.15 06/07/05 11 added & used through eshophj1.js
1.16 12/07/05 12 added & used in this & IndexToItem.js
1.17 19/07/05 11 enhanced to work if only name attribute
1.18 20/07/05 6 now checks for empty message field
1.19 13/09/05 11 checks validity of document.all before using
1.20 14/09/05 Debug. Remove '== undefined' as IE5 (Mac) doesn't recognise.
1.21 18/10/05 as version 1.11 for email - cannot end in . or -
1.22 09/12/05 9. remove new lines from text included in HTML; 8. ditto + all tags
1.23 29/12/05 6. Shortened code by using eMsg variable. Shortened pre-amble comments
1.24 15/02/06 13. added
1.25 08/04/06 13. extended to include caption width
1.26 09/05/06 6. extended to exclude form elements that are not displayed (not just hidden), and also excludes submit, reset and unchecked radio & checkboxes
1.27 15/05/06 1. extra test: entered; 12. extra test for object validity; 6. mod error message
1.28 11/07/06 14. Added
1.29 31/07/06 6. added 'must have' Name
1.30 03/08/06 13. fix - now sets caption width even if contraining container dimension is not found
1.31 04/08/06 15. New
1.32 04/09/06 14. Now works on comma separated list
1.33 22/10/06 16. doprintpage(form) added
1.34 27/10/06 16 tuned (window attributes)
1.35 10/11/06 16 a iv - remove Jscripts - added
*/

/* CONTENTS of eshophj1.js (General utility functions for eShopHost Web Solutions:
	Public functions
1. Check (FieldId, CheckType) - Validates field is of specified type - true or false
2. FieldValue (FieldId) - returns the value of the field
3. MakeHiddenInput (FieldName, Value) - Returns HTML for hidden input field
4. isNumeric (TestNumber) - Parameter is STRING - returns true if only numerics
5. emProtect (several) - creates HTML for email address - hidden from robots
6. submitEnquiry (formObj) - enables any form fields to be formatted into an email via mail.pl
7. DisplayMeta (Option) - displays meta tag information as elements exist
8. ProcessTextLinks (Domain) - Takes webmaster's Link text and converts to HTML
9. ProcessImageLinks () - Takes webmaster's title words and adds them to the HTML
10 ShowDate(Format) - Displays current day & date. Not updated.
11 getObj(ObjId) - returns object reference given its id
12 getStyleProperty(obj,Property) - use instead of .currentStyle
13 AutoSize (this) - Resize an image (object via 'this') if too big for its container; set any caption width to that of image (Auto-Caption-Width)
14. AutoHide (imageid)- Unhides an image if it loads successfully
15. autoAdjustCopyright() - standard copyright year auto-adjusts range to current year
16. doprintpage(form) - optional support for printpage.pl

	Internal functions
A. NumToText (Num, Length) - returns string of Num, with leading zeroes to Length
B. ExtractText (Block, Start, End) - returns the characters between the strings Start & End from object Block
C. ReplaceText (Block, Start, End, Replacement) - replaces the characters between the strings Start & End from object Block
*/


	/* Global Variables */
var LinksImageStart = 91; // PerlTag for Image Links - start
var LinksImageEnd = 93;
var LinksTextStart = 95; // PerlTag for Text Links - start
var LinksTextEnd = 98;

/* Public Functions */
function Check (FieldId, CheckType) { // 1.
	/*  Validates field is of specified type (numeric, email, phone, entered) - true or false */
	// 1.1. Retrieve Field Value
	var eMessage = "Please refresh the page and re-attempt. If no success, please do tell us! - see the 'contact us' page - and tell us which product you were trying to buy, which page you were on or what you were trying to do. Thanks!";
	var Field = getObj (FieldId);
	if (!Field) {
		alert ("There is an error on the web page. Function call: 'Check(" + FieldId + ")' has an undefined element or your browser does not support the industry standard DOM. " + eMessage);
		return false;
	}
	var Value = Field.value;
	var Truth = false;
	var RegExTrue; // Regex matches if Check should pass (.search is not equal to -1)
	var RegExFalse; // Regex does NOT match if Check should pass (.search returns -1)

	// 1.2. Set Regex
	switch (CheckType) {
		case "numeric": {
			RegExFalse = /\D/;
			break;
		}
		case "email": {
			RegExTrue = /^[\w.-]+\@[\w-]+\.[\w.-]*\w$/; // e.g. a1@b.c or d.2-e@f_g.h.i
			break;
		}
		case "phone": {
			RegExTrue = /^\s*\+?[\d()\s]+$/; // e.g. +44 (0)1793 740303
			break;
		}
		case "entered": {
			RegExTrue = /.+/; // e.g. w
			break;
		}
		default: {
			alert ("There is a problem with the web page. The requested check for an input field has not been understood. " + eMessage);
			return false;
		}
	}

	// 1.3. Test value
	if ( (RegExTrue) && (Value.search(RegExTrue) != -1 ) ) {
		Truth = true;
	}
	if ( (RegExFalse) && (Value.search(RegExFalse) == -1 ) ) {
		Truth = true;
	}

	// 1.4. Return
	return Truth;

}

function FieldValue (FieldId) { // 2.
	/* Returns the value of the field */
	// 2.1. Get the Element's Object
	var FieldObject = getObj (FieldId);
	if (FieldObject) {
		// 2.2 Return value of object
		return FieldObject.value;
	}
	alert ("There is an error on the web page. Function call: 'FieldValue(" + FieldId + ")' has undefined element. Please refresh the page and re-attempt. If no success, please do tell us! - see the 'contact us' page - and tell us which product you were trying to buy. Thanks!");
	return undefined;
}

function MakeHiddenInput (FieldName, Value) { // 3.
	/* Returns HTML for hidden input field */
	var HiddenInput = '<input type="hidden" name="' + FieldName + '" value="' + Value + '">\n';
	return HiddenInput;
}

function isNumeric (TestNumber) { // 4.
	/* Parameter is STRING - returns true if only numerics */
	var RegExTrue = /\D/;
	if (TestNumber.search(RegExTrue) == -1 ) {
		return true;
	}
	return false;
}

function emProtect (mode, to, domain, subject, name) { // 5.
	/* Creates HTML for email address - hidden from robot harvesting */
	/* mode =	inline - normal mailto: link displaying email address
				inlinetext - normal mailto: link but displaying text from parameter 'name'
				inlineimg - normal mailto: link but using an image. Add </a> after image
				formmailto - simple action on FORM
				formcgi - call to eshop standard form2mail (mail.pl)
				hidden - creates a hidden form field
				 */
	var em = to + '@' + domain; // to = 1st part of email address; domain = 2nd part
	var result;
	if (subject == "") { subject = "Enquiry from web site"; }
	var URL = 'mailto:' + em + "?subject=" + subject;
	var RegEx = /hidden/;
	if (mode.search(RegEx) > -1) { // mode = hidden
		result = '<input type="hidden" name="' + name + '" id="' + name + '" value="' + em + '">';
		document.write (result);
		return;
	}
	RegEx = /inline/;
	if (mode.search(RegEx) != -1) { // mode = inline or inlinetext or inlineimg
		result = '<a href="' + URL + '">' ; // Double quote around href
		RegEx = /text/;
		if (mode.search(RegEx) == -1) { // mode is not inlinetext, it may be just inline
			name = em;
		}
		RegEx = /img/;
		if (mode.search(RegEx) == -1) { // mode is not inlineimg
			result += name + "</a>"; // so add text and close tag
		}
		document.write (result);
	}
	else { // mode = formmailto  or formcgi
		var FormObject = getObj (name);
		RegEx = /mailto/;
		if (mode.search(RegEx) != -1) { // mode is formmailto
			FormObject.action = URL;
			FormObject.encoding = 'Text/Plain';
			FormObject.method = 'POST';
		}
		else { // mode is formcgi
			// form action is already set in NOF e.g. ../cgi-bin/mail.pl
			// form hidden fields to be set:
			FormObject.To.value = em;
			FormObject.Domain.value = domain;
		}
	}
}

function submitEnquiry (formObj) {// 6.
	// Checks standard fields and puts others into message body
	// Form action: ../cgi-bin/mail.pl" id='ContactUs' onsubmit="return runemProtect(), submitEnquiry(this)
	var eMsg = "";
	// Check Response requirement
	if (!formObj.Response) { // Intelligent Form format - don't check this part here
		// Standard Brochure Web format
		if (formObj.Name) { // check exists (backwards compatibility)
			if (formObj.Name.value.length < 2) {
				eMsg += "\nSorry, please enter your name.";
			}
		}
		// Phone response requested?
		if (formObj.PhoneResponse && formObj.PhoneResponse.checked) { // Yes
			if (!Check('Phone', 'phone')) { // Must have valid phone number
				eMsg += "\nSorry, you need to enter a valid phone number.";
			}
			// if there is an entry for Email, it must be valid
			if (formObj.Email.value.length > 0) {
				if (!Check('Email', 'email')) {
					eMsg += "\nSorry, your email address is missing or has an incorrect format.";
				}
			} else { // No email
				if (formObj.Copy) {
					formObj.Copy.checked = false; // So cannot request an email copy
				}
				formObj.Email.value = "noaddressentered@" + formObj.Domain.value; // Use dummy value
			}
		} else { // Not requesting phone response
			// Check email field is valid
			if (!Check('Email', 'email')) {
				eMsg += "\nSorry, your email address is incorrect.";
			}
			// If Phone exists, it must be valid
			if (formObj.Phone && formObj.Phone.value.length > 0) {
				if (!Check('Phone', 'phone')) {
					eMsg += "\nSorry, you do not need to enter a phone number, but if you do it must be valid.";
				}
			}
		} // end else (not requesting phone response)
	} // end if (not Intelligent For)m

	if (formObj.Text.value.length == 0) {
		eMsg += "\nSorry, you need to enter a message.";
	}
	if (formObj.Subject.value.length == 0) {
		formObj.Subject.value = "An enquiry from web site " + formObj.Domain.value;
	}
	// Anything to correct before submission?
	if (eMsg) {
		alert (eMsg);
		return false;
	}
	// Get all form elements
	var Body = "\n";
	var Checked = "";
	// Standard fields: Email (of user), Subject, Text (email body), Message (to display to user after mail successfully sent), Copy, To, Domain (Last 2 fields populated by emProtect())
	var RegEx = /Email|Subject|Text|Message|To|Domain|Submit|Copy/;
	for (i=0; i<formObj.elements.length; i++) {
		if ( (formObj.elements[i].name.search(RegEx) == -1) // Not a standard field
		&& ( (getStyleProperty(formObj.elements[i], "visibility") != "hidden") // & not hidden
		  || (getStyleProperty(formObj.elements[i], "display") != "none") ) ) { // or not displayed
			// Construct output string from field name & value
			//alert ("Element " + i + " is not a standard field; Name " + formObj.elements[i].name + "; Visibility " + getStyleProperty(formObj.elements[i], "visibility"));// Debug
			if (formObj.elements[i].checked) { // Property valid for all input elements
				Checked = " - CHECKED";
			} else {
				elType = formObj.elements[i].type;
				if (elType.search(/radio|checkbox|submit|reset/i) != -1) {
					// Radio or checkbox not checked, or submit or reset so ignore
					continue;
				} else { // an ordinary element to be shown
					Checked = "";
				}
			}
			Body += formObj.elements[i].name + ": " + formObj.elements[i].value + Checked + "\n";
		}
	}
	formObj.Text.value = Body + "\r\rMessage:\r" + formObj.Text.value;
	return true;
}

function DisplayMeta(Option) {// 7.
	// Displays Meta Tag Information in form fields (if existing)
	// Expected form field ids: metaTitle, metaKeywords, metaDescription
	// Call this function after page & form has loaded. E.g. when radio button selected

	// 7.0 Hide if Option = Keywords
	var objF = getObj("DisplayMetaForm");
	if (Option == "Keywords") {
		if (objF) {
			objF.style.display = "none";
		}
		return;
	}
	// 7.1 Meta Objects on the page
	var objMT	= getObj("title");
	var objMKW	= getObj("keywords");
	var objMD	= getObj("description");
	// 7.2 Form Objects
	var objFT	= getObj("metaTitle");
	var objFKW	= getObj("metaKeywords");
	var objFD	= getObj("metaDescription");
	// 7.3 Display Title
	if (objFT) {
		if (objMT) {
			objFT.value = objMT.text;
		}
		else {
			objFT.value = "No TITLE tag found.";
		}
	}
	// 7.4 Display Keywords
	if (objFKW) {
		if (objMKW) {
			objFKW.value = objMKW.content;
		}
		else {
			objFKW.value = "No meta tag found for KEYWORDS.";
		}
	}
	// 7.5 Display Description
	if (objFD) {
		if (objMD) {
			objFD.value = objMD.content;
		}
		else {
			objFD.value = "No meta tag found for DESCRIPTION.";
		}
	}
	// 7.6 Show Meta Tags Display Form
	if (objF) {
		objF.style.display = "block";
	}
}

function ProcessTextLinks (Domain) { // 8.
	// Takes webmaster's Link text and converts to HTML.
	// Standard LINKS page. For each Link text found in between tags (PerlTagStart95 to 98):
	// - overwrites with the HTML in a text area
	// - plugs the HTML into the adjacent area (with suffix a e.g. PerlTagStart95a)
	var objForm200 = getObj ("Form200");
	if (!objForm200) {return;} // Can't do anything!
	var Form200 = objForm200.innerHTML;
	var i, From, To, LT, HTML, TextArea;
	for (i = LinksTextStart; i < LinksTextEnd; i++) { // several text links allowed for
		From = "<!--PerlTagStart" + NumToText(i, 2) + "-->";
		To = "<!--PerlTagEnd" + NumToText(i, 2) + "-->";
		LT = ExtractText(Form200, From, To); // Link text from Webmaster
		if (LT != "") {
			LT = LT.replace ( /<[^>]*>/g, ""); // get rid of any html tags (selfupdate.pl may insert)
			LT = LT.replace ( /[\n\r]+/g, " "); // get rid of any new lines or returns
			HTML = '<a href="http://www.' + Domain + '">' + LT + '</a>';
			TextArea = '<textarea class="HtmlLinks">' + HTML + '</textarea>';
			Form200 = ReplaceText(Form200, From, To, TextArea);
			// alert ("Loop: " + i + ". TextArea: " + TextArea + ". Form200 after replacement: " + Form200);
			From = "<!--PerlTagStart" + NumToText(i, 2) + "a-->";
			To = "<!--PerlTagEnd" + NumToText(i, 2) + "a-->";
			Form200 = ReplaceText(Form200, From, To, "<p>" + HTML + "</p>");
		}
	}
	objForm200.innerHTML = Form200;
}

function ProcessImageLinks (Domain) {// 9.
	// Takes webmaster's title words and adds them to the HTML
	// Standard LINKS page. For each image Title text found in between tags (PerlTagStart991 to 93):
	// - adds the Title HTML attribute to the generated HTML image/ link & puts into a textarea tag in the adjacent area (with suffix a e.g. PerlTagStart101a)
	// - adds the HTML into the original area (e.g. PerlTagStart101)
	var objForm100 = getObj ("Form100");
	if (!objForm100) {return;} // Can't do anything!
	var Form100 = objForm100.innerHTML;
	var i, From, To, TT, HTML, TextArea;
	for (i = LinksImageStart; i < LinksImageEnd; i++) { // several image links allowed for
		From = "<!--PerlTagStart" + NumToText(i, 2) + "-->";
		To = "<!--PerlTagEnd" + NumToText(i, 2) + "-->";
		TT = ExtractText(Form100, From, To); // Title attribute's text from Webmaster
		if (TT != "") {
			TT = TT.replace ( /<[^>]*>/g, ""); // get rid of any html tags (selfupdate.pl may insert some)
			TT = TT.replace ( /[\n\r]+/g, " "); // get rid of any new lines or returns
			HTML = '<a href="http://www.' + Domain + '" title="' + TT + '" alt="' + TT + '"><img src="http://www.' + Domain + '/assets/images/photolinks' + NumToText(i, 2) + '.gif" border="0"></a>';
			TextArea = '<textarea class="HtmlLinks">' + HTML + '</textarea>';
			Form100 = ReplaceText(Form100, From, To, '<p>' + TT + '</p>' + HTML);
			// alert ("Loop: " + i + ". TextArea: " + TextArea + ". Form100 after replacement: " + Form100);
			From = "<!--PerlTagStart" + NumToText(i, 2) + "a-->";
			To = "<!--PerlTagEnd" + NumToText(i, 2) + "a-->";
			Form100 = ReplaceText(Form100, From, To, TextArea);
		}
	}
	objForm100.innerHTML = Form100;
}


function ShowDate(Format) { // 10.
	/* Displays current day & date. Not updated. */
	/* Format e.g. "sday, d mmm yyyy" - not currently used*/
	var mydate=new Date();
	var year=mydate.getFullYear();
	var day=mydate.getDay();
	var month=mydate.getMonth();
	var daym=mydate.getDate();
	var superscript="th";
	if (daym==1 || daym==21 || daym==31) {superscript="st"}
	if (daym==2 || daym==22) {superscript="nd"}
	if (daym==3 || daym==23) {superscript="rd"}
	superscript = "<sup>" + superscript + "</sup>";
	var dayarray=new Array("Sun","Mon","Tues","Wed","Thur","Fri","Sat");
	var montharray=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
	document.write("<p class='date'>"+dayarray[day]+", "+daym+superscript+" "+montharray[month]+" "+year+"</p>");
}


function getObj(ObjId) { // 11.
	// returns object reference given its id. Avoids rare problems with DOM
	if (document.getElementById && document.getElementById(ObjId)) { // W3C DOM
		return document.getElementById(ObjId);
	} else if (document.all && document.all[ObjId]) { // Old IE
		return document.all[ObjId];
	}
	var A = document.getElementsByName(ObjId); // if only the name attribute
	return A[0]; // first element of that name
}


function getStyleProperty(obj, Property){ // 12.
	// use instead of .currentStyle
	if (obj.currentStyle) { // IE model
		return eval("obj.currentStyle." + Property);
	} else { // W3C DOM model
		var vw = document.defaultView;
		if (vw) {
			var currStyle = vw.getComputedStyle(obj, "");
			return currStyle.getPropertyValue(Property);
		}
	}
}


function AutoSize (image) { // 13.
	// 1. Resize an image if too big for its container
	// 2. Set any caption width to that of image (Auto-Caption-Width)

	// a. Obtain photo's dimensions
	var PictureW = image.width;
	var PictureH = image.height;

	// b. Find size dimension(s) of any container & find caption container
	var obj = image;
	var CaptionObj;
	var found = false;
	while (obj && !found) {
		obj = obj.parentNode;
		if (!obj) {
			break; // if we get to this point, there is little we can do
		}
		if (obj.nodeType != 1) { // Not an element node
			continue; // try again
		}
		// b.i. We have an element node object ...
		var AreaW = getStyleProperty(obj, "width");
		if (AreaW && AreaW != "auto" && AreaW.indexOf("%") == -1) {
			AreaW = AreaW.replace( /\D/g, "");
			found = true;
		}
		var AreaH = getStyleProperty(obj, "height");
		if (AreaH && AreaH != "auto" && AreaH.indexOf("%") == -1) {
			AreaH = AreaH.replace( /\D/g, "");
			found = true;
		}
		// b.ii. Caption container?
		if (obj.tagName && obj.tagName == "DIV" &&
			obj.className && obj.className.indexOf("EmbeddedImageCaption") != -1) {
			// Yes, save object for later
			CaptionObj = obj;
		}
	} // end while
if (found) {
		// c. Adjust image dimensions if required
		var Wadj = 0;
		if (PictureW > AreaW) {
			Wadj = 1 - (PictureW - AreaW)/PictureW;
		}
		var Hadj = 0;
		if (PictureH > AreaH) {
			Hadj = 1 - (PictureH - AreaH)/PictureH;
		}
		var Adj;
		Adj = Math.min(Wadj, Hadj);
		if (Adj == 0) { // probably one size limit not present
			Adj = Math.max(Wadj, Hadj); // so take the other
		}
		//alert ("PictureW: " + PictureW + "\nAreaW: " + AreaW + "\nPictureH: " + PictureH + "\nAreaH: " + AreaH + "\nAdj: " + Adj + "\nTag: " + obj.tagName); // Debug
		if (Adj > 0) {
			PictureW = Math.floor(PictureW * Adj); // also overwrite PictureW for setting caption width
			image.width = PictureW;
			image.height = Math.floor(PictureH * Adj);
		}
	}
	// d. Caption width to that of picture (original or as adjusted)
	if (CaptionObj && CaptionObj.style) {
		CaptionObj.style.width = PictureW;
	}
}


function AutoHide (PhotoId) { // 14. Unhides an image (or any object) if it loads successfully
	// include this call in the onload event handler
	var objC;
	var IdList = PhotoId.split(",");
	for (var i = 0; i < IdList.length; i++) {
		objC = getObj(IdList[i]);
		if (objC) {
			objC.style.visibility = 'visible'; // for unhiding
			objC.style.display = 'block'; // for uncontracting
		} 
	}
}


function autoAdjustCopyright() { // 15. standard copyright year auto-adjusts range to current year
	var obj = document.body;
	if (!obj.getElementsByTagName) {
		return;
	}
	var d = new Date();
	var y = d.getFullYear();
	var e;
	var Span = obj.getElementsByTagName ("span");
	for (var i = 0; i < Span.length; i++) {
		if (Span[i].className == "CopyrightYear") {
			e = Span[i].innerHTML.substr(0,4);
			if (e != y){ // year is not current
				Span[i].innerHTML = e + "-" + y; // add range to this year
			}
		}
	}
}


function doprintpage(form) { // 16. optional support for printpage.pl
	var H = location.href;
	if (H.search(/\.(asp|php|shtml)/) != -1 && (!form.Page || (form.Page && form.Page.value == ""))) {
		// Page not specified and page is actually active
		// a. Do local print page
		var Print = window .open("", "Print", "height=300,width=400,scrollbars=yes,resizable=yes,status=no");
		Print.document.open();
		// a i Start HTML
		var C = "<html><body>";
		// a ii Links
		var Links = "<table width='100%' bgcolor='#FFFFFF'><tr><td width='50%'>";
		Links += "<p><a href='javascript:window.print()'>Print</a></p></td><td width='50%'>";
		Links += "<p><a href='javascript:window.close()'>Close window</a></p></td></tr></table>";
		C += Links;
		// a iii Content to be printed
		var B = document.body.innerHTML;
		var PP = new RegExp("<!--PerlTagStartPrint-->(.|\n)*?<!--PerlTagEndPrint-->", "gim");
		PP.multiline = true;
		var CP = B.match(PP);
		if (CP != null) {
			C += CP.join("");
		}
		// a iv Remove Jscripts
		C = C.replace (/<script[^<]+<\/script>/igm, "");
		// b. Call .pl anyway to log?
		if (form.Log) {
			var L = form.Log.value;
			if (L.search(/Event|Print/i) != -1) { // Logging requested
				// b i. get relative address
				var PL = "";
				var A = H.match(/(\w\/\w)/g); 
				if (A != null) {
					for (var i = 0; i < A.length - 1; i++) {
						PL += "../";
					}
				}
				// b ii. get Page
				var PN = H.substring(H.search(/[^/]+$/), H.search(/\?.*$/));
				// b iii. build iframe with cgi call
				C += "<iframe style='display: none' src='" + PL + "cgi-bin/PrintPage.pl?Page=" + PN + "&Log=" + L + "Only'></iframe>";
			}
		}
		// c. complete
		C += Links + "</body></html>";
		Print.document.write (C);
		Print.document.close();
		return false; // inhibit direct call to .pl
	}
	return true; // do nothing if not active page
}


function NumToText (Num, Length) { // A. returns string of Num, with leading zeroes to Length
	var a = Num.toString();
	var j;
	for (j = a.length; j < Length; j++) {
		a = "0" + a;
	}
	return a;
}

function ExtractText (Block, Start, End) {
	// B. returns the characters between the strings Start & End from object Block
	var a = "";
	var s = Block.indexOf(Start);
	if (s == -1) { return a;} // Start not found
	var f = Block.indexOf(End);
	if (f == -1) { return a;} // End not found
	a = Block.substring(s + Start.length, f);
	return a;
}

function ReplaceText (Block, Start, End, Replacement) {
	// C. replaces the characters between the strings Start & End from object Block
	var s = Block.indexOf(Start);
	if (s == -1) { return a;} // Start not found
	var f = Block.indexOf(End);
	if (f == -1) { return a;} // End not found
	return Block.slice(0, s + Start.length) + Replacement + Block.slice(f);
}
