function iemOutput() {

    this.fldSetup = {
        'Title' : { 'req'  : true, 'key'  :'T' },
        'First_Name' : { 'alias' : 'First Name', 'req'  : true, 'key'  :'F', 'class':'l' },
        'Surname' : { 'alias' : 'Last Name', 'req':true, 'key':'L', 'class':'l' },
        'Company_Name' : { 'alias' : 'Company Name', 'key':'Y', 'class':'l' },
        'Address_1' : { 'alias' : 'House Number (or name)', 'req':true, 'key':'H', 'class':'m' },
        'Street' : { 'req': true, 'key':'S', 'class':'xl' },
        'Address_2' : { 'alias' : 'Address 2', 'key':'A', 'class':'xl' },
        'Town' : { 'alias' : 'Town (or district)', 'req':true, 'key':'W', 'class':'xl' },
        'County' : { 'alias' : 'County (or city)', 'req':true, 'key':'C', 'class':'xl' },
        'Postcode' : { 'req' :true, 'key':'P', 'class':'s' },
        'Country' : { 'req' :true, 'key':'O', 'class':'xl' },
        'Telephone' : { 'req' :true, 'key':'N', 'class':'m' },
        'Mobile' : { 'key':'m', 'class':'M' },
        'Fax' : { 'alias' : 'Other Number', 'key':'R', 'class':'m' },
        'EMail' : { 'alias' : 'E-mail Address', 'req':true, 'key':'E', 'class':'xl' },
        'Comments' : { 'alias' : 'Notes/Feedback', 'key':'B' },
        'Delivery_Title' : { 'alias' : 'Title', 'req': true, 'key':'T' },
        'Delivery_First_Name' : { 'alias' : 'First Name', 'req' : true, 'key':'F', 'class':'l' },
        'Delivery_Surname' : { 'alias' : 'Last Name', 'req':true, 'key':'L', 'class':'l' },
        'Delivery_Company_Name' : { 'alias' : 'Company Name', 'key':'Y', 'class':'l' },
        'Delivery_Address_1' : { 'alias' : 'House Number (or name)', 'req':true, 'key':'H', 'class':'m' },
        'Delivery_Street' : { 'alias' : 'Street', 'req':true, 'key':'S', 'class':'xl' },
        'Delivery_Address_2' : { 'alias' : 'Address 2', 'key':'A', 'class':'xl' },
        'Delivery_Town' : { 'alias' : 'Town (or district)', 'req':true, 'key':'W', 'class':'xl' },
        'Delivery_County' : { 'alias' : 'County (or city)', 'req':true, 'key':'C', 'class':'xl' },
        'Delivery_Postcode' : { 'alias' : 'Postcode', 'req':true, 'key':'P', 'class':'s' },
        'Delivery_Country' : { 'alias' : 'Country', 'req':true, 'key':'O' },
        'Delivery_Telephone' : { 'alias' : 'Telephone', 'key':'T', 'class':'m' },
        'Delivery_Notes' : { 'alias' : 'Delivery Instructions', 'key':'I' },
        'Card_Name' : { 'alias' : 'Name as it appears on Card', 'req':true, 'key':'N', 'class':'l' },
        'Card_Type' : { 'alias' : 'Card Type', 'req':true, 'key':'C' },
        'Card_Number' : { 'alias' : 'Card Number', 'req':true, 'key':'U' },
        'Card_Start' : { 'alias' : 'Start Date', 'key':'S' },
        'Card_End' : { 'alias' : 'Expiry Date', 'req':true, 'key':'E' },
        'Card_Issue_Number' : { 'alias' : 'Issue Number', 'key':'I', 'class':'xs', 'note' : '(switch/solo only)' },
        'Card_CV2' : { 'alias' : 'Card Security Code', 'key':'', 'class':'s', 'note' : 'last 3 digits on signature strip',  'req':true },
        'Pwd' : { 'alias' : 'Please choose a password', 'req':true, 'class':'l' },
        'Pwd_Check' : { 'alias' : 'Password Confirm', 'req':true, 'class':'l' },
        'Mail_Lists' : { 'alias' : 'Newsletter opt-ins' },
        'Old_Pwd' : { 'alias' : 'Password', 'req':true, 'class':'l' },
        'New_Pwd' : { 'alias' : 'New Password', 'class':'l', 'note' : '(complete to change password)' },
        'New_Pwd_Check' : { 'alias' : 'New Password Confirm', 'class':'l' }
    }

    this.displayCartList = function( cartRows ) {

        var htm = '';
        var rowCount = 0;

        for( var lineID in cartRows ) {

            rowCount++;

            var row = cartRows[ lineID ];

            htm += '<form name="frm' + lineID + '" onsubmit="if(this.productQty.value>0){iem.CartUpdate( \'[LineID] = [' + lineID + ']\', { \'fld' + lineID + '_' + row[ 'Qty' ][ 'index' ] + '\' : this.productQty.value } );iem.CartList( \'[Completed] = [-1]\' );iem.CartSubmit( window.location );}else{alert(\'Please enter a quantity\');}return false;">' +
                '<tr>' +
                ' <td rowspan="2">' +
                '   <img src="' + ( row[ 'Image_Thumbnail' ][ 'value' ] ? row[ 'Image_Thumbnail' ][ 'value' ] : '/_res/19.gif' ) + '" border="0" alt="' + row[ 'Product_Name' ][ 'value' ] + '" style="border: 1px solid #002C72;" />' +
                ' </td>' +
                ' <td colspan="4">' +
            '    <h2>' + row[ 'Product_Name' ][ 'value' ] + ' ' + row[ 'Product_Code' ][ 'value' ] + '</h2>';

            for( var i = 1; i <= 8; i++ ) {
                htm += ( row[ 'Option_' + i ][ 'value' ] != 0 ? row[ 'Option_' + i ][ 'value' ].replace( '|', ': ' ) + ' ' : '' );
            }

            htm += ' </td>' +
                '</tr>' +
                '<tr>' +
                ' <td>Quantity <input type="text" name="productQty" value="' + row[ 'Qty' ][ 'value' ] + '" size="2" maxlength="3" /></td>' +
                ' <td class="price">(Unit Cost £' + row[ 'Base_Price' ][ 'value' ] + ')</td>' +
                ' <td class="price"><strong>Total £' + row[ 'Sub_Total' ][ 'value' ] + '</strong></td>' +
                ' <td class="price"><input type="submit" class="button" value="Update" />&nbsp;' +
                '<input type="button" class="button" value="Remove" onclick="iem.CartDelete( \'[LineID] = [' + lineID + ']\' );iem.CartList( \'[Completed] = [-1]\' );iem.CartSubmit();return false;" /></td>' +
                '</tr>' +
                '<tr><td colspan="5"><hr /></td></tr>' +
            '</form>';
        }
        if( ! rowCount ) {
            htm += '<tr><td colspan="5">Sorry, your shopping basket is currently empty.<br /><br /></td></tr>';
        }
        document.write( htm );
    }

    this.displayCartPreview = function( cartRows ) {


        var htm = '';

        for( var lineID in cartRows ) {

            var row = cartRows[ lineID ];

            htm += //'<h2>Pricing</h2>' +
                '<form name="frm' + lineID + '" onsubmit="iem.CartUpdate( \'[LineID] = [' + lineID + ']\', { \'fld' + lineID + '_' + row[ 'Completed' ][ 'index' ] + '\' : \'-1\', \'fld' + lineID + '_' + row[ 'Qty' ][ 'index' ] + '\' : this.productQty.value } );iem.CartList( \'[Completed] = [-1]\' );iem.CartSubmit();return false;">' +
            '<table>';

            for( var i = 1; i <= 8; i++ ) {
                if( row[ 'Option_' + i ][ 'options' ] ) {

                    htm += '<tr>';
                    htm += '<th>' + row[ 'Option_' + i ][ 'optName' ] + '</th>';
                    htm += '<td>';

                    var optCount = 0;

                    for( var idx in row[ 'Option_' + i ][ 'options' ] ) {
                        optCount++;
                    }

                    if( optCount > 1 ) {
                        htm += '<select name="Option_' + i + '" onchange="iem.CartUpdate( \'[Product_ID] = [' + row[ 'Product_ID' ][ 'value' ] + '] and [Completed] = [0]\', { \'fld' + lineID + '_' + row[ 'Option_' + i ][ 'index' ] + '\' : this[ this.selectedIndex ].value } );iem.CartList( \'[Product_ID] = [' + row[ 'Product_ID' ][ 'value' ] + '] and [Completed] = [0]\' );iem.CartSubmit( window.location );">';
                		for( var idx in row[ 'Option_' + i ][ 'options' ] ) {
                        	htm += '<option value="' + idx + '"' + ( idx == row[ 'Option_' + i ][ 'value' ] ? ' selected="selected"' : '' ) + '>' + row[ 'Option_' + i ][ 'options' ][ idx ][ 0 ] + '</option>';
                		}
                        htm += '</select>';
                        //htm += '[' + row[ 'Option_' + i ][ 'value' ] + ']';
                    } else {
                		for( var idx in row[ 'Option_' + i ][ 'options' ] ) {
                        	htm += row[ 'Option_' + i ][ 'options' ][ idx ][ 0 ];
                		}
                    }

                    htm += '</td>';
                    htm += '</tr>';
                }
            }

            htm += '<tr>' +
                '<th>Quantity</th>' +
                '<td><input type="text" name="productQty" value="' + row[ 'Qty' ][ 'value' ] + '" size="2" maxlength="3" class="qty" title="Enter Quantity here..." /> @ £' + row[ 'Base_Price' ][ 'value' ] + '</td>' +
                '</tr>' +
                '</table>' +
                '<input type="submit" value="Add to basket &#187;" class="button" />' +
            '</form>';
        }
        document.write( htm );
    }

    this.displayCartTotal = function( totals ) {

        var htm = '';

        var lookup = {
            'Product_Total' : 'Subtotal',
            'Shipping_Total' : 'Shipping',
            'Grand_Total' : 'TOTAL (inc VAT)'
        }

        for( var total in totals ) {
            if( lookup[ total ] ) {
                htm += '<tr>' +
                    '<td colspan="3"><strong>' + ( lookup[ total ] ? lookup[ total ] : total ) +  '</strong></td>' +
                    '<td class="price">£' + totals[ total ] + '</td>' +
                    '<td>&nbsp;</td>' +
                '</tr>';
            }
        }

        document.write( htm );
    }

    this.displayCheckout = function( flds, currPage, frmAction, frmType ) {

        var htm = ''; // html of the form

        // perform a default set of manipulation on fields
        // which are ommitted from the setup array
        for( var fld in flds ) {
            if( ! iem.output.fldSetup[ fld ] ) {
                iem.output.fldSetup[ fld ] = {
                    'alias' : fld.split( '_' ).join( ' ' ),
                    'key'   : false,
                    'class' : false,
                    'note'  : false
                }
            }
        }

        // build the js command to validate required fields
        var reqCmd = '';

        for( var fld in flds ) {
            if( iem.output.fldSetup[ fld ] && iem.output.fldSetup[ fld ][ 'req' ] && flds[ fld ][ 'type' ] != 'HIDDEN' ) {
                reqCmd += 'this.fld' + flds[ fld ][ 'idx' ] + '_1,';
            }
        }
        if( reqCmd.length > 0 ) {
            reqCmd = reqCmd.substring( 0, reqCmd.length - 1 );
        }

        htm += '<form name="frmCheckout" method="post" action="' + frmAction + '" onsubmit="if( iem.output.validateForm(' + reqCmd + ') ) { this.submitButton.disabled = true; } else { return false; }" name="checkoutForm">';

        htm += '<div class="formText" style="text-align: left;">';

        if( frmType == 'checkout' ) {
            htm += '<h1>You are on Step ' + ( currPage + 1 ) + ' of 4</h1>';
        }

        if( iem.response.getField( 'cartErrNo' ) > 0 ) {
            document.write( '<p class="error">Error ' + iem.response.getField( 'cartErrNo' ) + ': <strong>' + iem.response.getField( 'cartError' ) + '</strong></p>' );
        }

        var formHeadings = {
            'checkout' : {
                '1' : 'STEP 2: User Details &amp; Profile',
                '2' : 'STEP 3: Delivery Details',
                '3' : 'STEP 4: Card Information'
            },
            'register' : {
                '1' : 'Your Details'
            }
        }

        document.title = formHeadings[ frmType ][ currPage ];

    	htm += '<div class="formText"><h2>' + formHeadings[ frmType ][ currPage ] + '</h2></div>';
    	htm += '</div>';
        htm += '<div class="formText">';

        // print out all hidden fields
        for( var fld in flds ) {
            if( flds[ fld ][ 'type' ] == 'HIDDEN' ) {
                htm += '<input type="hidden" name="' + fld + '" value="' + flds[ fld ][ 'value' ] + '" />\n';
            }
        }

        htm += '</div>' +
    	    '<div id="formDetails">';

        // print out input fields
        for( var fld in flds ) {
            if( flds[ fld ][ 'type' ] != 'HIDDEN' ) {

                var reqMark = '';
                var fldDesc = fld;

                if( iem.output.fldSetup[ fld ] ) {
                    if( iem.output.fldSetup[ fld ][ 'alias' ] ) {
                        fldDesc = iem.output.fldSetup[ fld ][ 'alias' ];
                    }
                    if( iem.output.fldSetup[ fld ][ 'req' ] ) {
                        reqMark = ' <span class="red">*</span>';
                    }
                }

                var fldDisp = '';

                var matchedChar = false;
                var currChar = 0;

                if( iem.output.fldSetup[ fld ] && iem.output.fldSetup[ fld ][ 'key' ] ) {
                    while( ! matchedChar && currChar <= fldDesc.length ) {
                        if( fldDesc.charAt( currChar ).toLowerCase() == iem.output.fldSetup[ fld ][ 'key' ].toLowerCase() ) {
                            fldDisp += '<u>' + fldDesc.charAt( currChar ) + '</u>';
                            matchedChar = true;
                        } else {
                            fldDisp += fldDesc.charAt( currChar );
                        }
                        currChar++;
                    }
                }

                fldDisp += fldDesc.substring( currChar ) + reqMark;

                var fldCode = '';
                if( iem.output.fldSetup[ fld ] ) {
                    fldCode += ' class="' + ( iem.output.fldSetup[ fld ][ 'class' ] ? iem.output.fldSetup[ fld ][ 'class' ] : 'l' ) + '"' + ( iem.output.fldSetup[ fld ][ 'key' ] ? ' accesskey="' + iem.output.fldSetup[ fld ][ 'key' ] + '"' : '' );
                }

                var fldName = 'fld' + flds[ fld ][ 'idx' ] + '_1';

                switch( fld ) {
                    case 'Card_Number' : {
                        htm += '<div class="formLabel">' + fldDisp + '</div>\n' +
                            '<div class="formElement">' +
                            '    <input' + fldCode + ' type="text" name="' + fldName + '" value="" onchange="this.value=this.value.replace( /[^0-9]*/g, \'\' );" title="' + fldDesc + '" />' +
                            '</div>';
                        break;
                    }
                    case 'Card_Start' :
                    case 'Card_End' : {
                    	htm += '<div class="formLabel">' + fldDisp + '</div>\n' +
                            '<div class="formElement">';

                        // generate month drop down
                        var months = new Array( 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' );
                        htm += '    <select' + fldCode + ' name="' + fldName + '_mm" onchange="this.form[ \'' + fldName + '\' ].value=this.form[ \'' + fldName + '_mm\' ][ this.form[ \'' + fldName + '_mm\' ].selectedIndex ].value + \'/\' + this.form[ \'' + fldName + '_yyyy\' ][ this.form[ \'' + fldName + '_yyyy\' ].selectedIndex ].value" title="' + fldDesc + '">' +
                            '     <option value=""> -- </option>';
                        for( var i = 0; i < 12; i++ ) {
                            htm += '     <option value="' + ( new String( i + 1 ).length == 1 ? '0' : '' ) + ( i + 1 ) + '">' + months[ i ] + '</option>';
                        }
                        htm += '    </select>';

                        // generate year drop down
                        var currDate = new Date();
                        var currYear = currDate.getFullYear();
                        var maxAge = 5;

                        htm += '    <select' + fldCode + 'name="' + fldName + '_yyyy" onchange="this.form[ \'' + fldName + '\' ].value=this.form[ \'' + fldName + '_mm\' ][ this.form[ \'' + fldName + '_mm\' ].selectedIndex ].value + \'/\' + this.form[ \'' + fldName + '_yyyy\' ][ this.form[ \'' + fldName + '_yyyy\' ].selectedIndex ].value" title="' + fldDesc + '">' +
                            '     <option value=""> -- </option>';
                        if( fld == 'Card_Start' ) {
                            for( var i = currYear; i > currYear - maxAge; i-- ) {
                                htm += '     <option value="' + i + '">' + i + '</option>';
                            }
                        } else {
                            for( var i = currYear; i < currYear + maxAge; i++ ) {
                                htm += '     <option value="' + i + '">' + i + '</option>';
                            }
                        }
                        htm += '    </select>' +
                            '    <input type="hidden" name="' + fldName + '" title="' + fldDesc + '">' +
                            '</div>';
                        break;
                    }
                    case 'Mail_Lists' : {
                        if( flds[ fld ][ 'options' ] ) {
                        	htm += '<hr /><div class="formLabelLong">' + fldDisp + ':</div>\n' +
                        	    '<div class="formElementLong">';
                            for( var opt in flds[ fld ][ 'options' ] ) {
                                htm += '    <input class="noborder" type="checkbox" name="' + fldName + '_' + opt + '" value="' + flds[ fld ][ 'options' ][ opt ].domain_id + '_' + flds[ fld ][ 'options' ][ opt ].name + '"'+ ( String( ',' + flds[ fld ][ 'value' ] + ',' ).indexOf( ',' + flds[ fld ][ 'options' ][ opt ].domain_id + '_' + flds[ fld ][ 'options' ][ opt ].name + ',' ) > -1 ? ' checked="checked"' : '' ) + ' title="' + fldDesc + '" />' + flds[ fld ][ 'options' ][ opt ].display_name + '<br />' +
                                '<span style="font-size: 11px;"><i>' + flds[ fld ][ 'options' ][ opt ].description + '</i></span><br /><br />';
                            }
                            htm += '</div><hr />';
                        }
                        break;
                    }                    
                    case 'Spare_1' :
                    case 'Pwd_Reminder' : {
                        break;
                    }
                    default : {
                        if( flds[ fld ][ 'options' ] ) {
                        	htm += '<div class="formLabel">' + fldDisp + '</div>\n' +
                        	    '<div class="formElement">' +
                                '    <select name="' + fldName + '"' + fldCode + ' title="' + fldDesc + '">';
                            for( var opt in flds[ fld ][ 'options' ] ) {
                                htm += '     <option value="' + flds[ fld ][ 'options' ][ opt ] + '"' + ( flds[ fld ][ 'value' ] == flds[ fld ][ 'options' ][ opt ] ? ' selected="selected"' : '' ) + '>' + flds[ fld ][ 'options' ][ opt ] + '</option>';
                            }
                            htm += '    </select>';
                            htm += '</div>';
                        } else {
                            switch( flds[ fld ][ 'type' ] ) {
                                case 'LARGE_TEXT' : {
                                    if( fld == 'Notes' && frmType == 'register' ) {
                                        break;
                                    }
                                	htm += '<div class="formLabelLong">' + fldDisp + ':</div>' +
                                	    '<div class="formElementLong">' +
                                        '    <textarea name="' + fldName + '"' + fldCode + ' style="width: 475px;" title="' + fldDesc + '">' + flds[ fld ][ 'value' ] + '</textarea>' +
                                        '</div>';
                                    break;
                                }
                                case 'BOOL' : {
                                	htm += '<div class="formLabel">' + fldDisp + '</div>\n' +
                                	    '<div class="formElement">' +
                                        '    <input' + fldCode + ' type="checkbox" style="border: 0" name="' + fldName + '" title="' + fldDesc + '" />' +
                                        '</div>';
                                    break;
                                }
                                case 'PASSWORD' : {
                                	htm += '<div class="formLabel">' + fldDisp + '</div>\n' +
                                	    '<div class="formElement">' +
                                        '    <input' + fldCode + ' type="password" name="' + fldName + '" value="' + flds[ fld ][ 'value' ] + '" title="' + fldDesc + '" /> ' + ( iem.output.fldSetup[ fld ] && iem.output.fldSetup[ fld ][ 'note' ] ? iem.output.fldSetup[ fld ][ 'note' ] : '' ) +
                                        '</div>';
                                    break;
                                }
                                default: {
                                    if( fld == 'EMail' ) {
                                        if( iem.request.getField( 'usr_1' ) ) {
                                            flds[ fld ][ 'value' ] = iem.request.getField( 'usr_1' );
                                        }
                                    }
                                	htm += '<div class="formLabel">' + fldDisp + '</div>\n' +
                                	    '<div class="formElement">' +
                                        '    <input' + fldCode + ' type="text" name="' + fldName + '" value="' + flds[ fld ][ 'value' ] + '" onblur="convert(this);" title="' + fldDesc + '" /> ' + ( iem.output.fldSetup[ fld ] && iem.output.fldSetup[ fld ][ 'note' ] ? iem.output.fldSetup[ fld ][ 'note' ] : '' ) +
                                        '</div>';
                                    break;
                                }
                            }
                        }
                        if( frmType == 'checkout' && fld == 'Country' ) {
                            htm += '<div class="formLabel" id="deliveryOptLabel">Use this as <u>D</u>elivery Address</div>\n' +
                                '<div class="formElement" id="deliveryOptElement">' +
                                '    <select name="nextPage" accesskey="d" title="' + fldDesc + '">' +
                                '     <option value="3" selected="selected">Yes</option>' +
                                '     <option value="2">No</option>' +
                                '    </select> If \'No\' you can change this next' +
                                '</div>' +
                                '<hr />';
                        }
                        break;
                    }
                }
            }
        }

        // confirm address details
        if( currPage == 3 ) {
            for( var fld in flds ) {
                if( flds[ fld ][ 'type' ] == 'HIDDEN' ) {
                    if( fld != 'cartId' && fld != 'location' && fld != 'func_1' && fld != 'nextPage' ) {
                        //htm += '<tr><td colspan="2">' + flds[ fld ][ 'value' ] + '</td></tr>\n';
                        //htm += '<tr><th>' + fld.split( '_' ).join( ' ' ) + '</th><td>' + flds[ fld ][ 'value' ] + '</td></tr>\n';
                    }
                }
            }
        }

        var btnText = ( frmType == 'register' && iem.response.getField( 'usr' ) != '' ? 'Update' : 'Continue' );

    	htm += '<span class="formLabel"><input type="button" onclick="javascript:history.go(-1)" value="&#171; Back" class="prev" /></span>';
    	htm += '<span class="formElement"><input type="submit" name="submitButton" value="' + btnText + ' &#187;" class="next" /></span>';

        htm += '<br style="clear: both;" />'

        if( currPage == 3 ) {
            if( new String( window.location ).indexOf( 'olives' ) != -1 ) {
				htm += '<p style="padding: 0 10px;">It may take several seconds for the card details to be processed. Please click the Continue button only once.</p><p style="padding: 0 10px;">If you experience a problem please call us on: 01258 474300 or email: giles@olivesetal.co.uk</p>';
            }
        }

        htm += '</form>';
        htm += '</div>';

        document.write( htm );
    }

    this.displayCartConfirm = function( success, cartError, cartErrNo ) {
        var htm = '';
        if( success ) {
            htm += '<h1>Thank you</h1>'
            htm += '<p>Your order details have been sent successfully and will receive our immediate attention.</p>';
            htm += '<p><strong>Please check your e-mail for a review of the order.</strong></p>';
        } else {
            htm += '<h1>Error</h1>';

            if( cartError ) {
                if( cartErrNo >= 500 ) {
                    htm += '<p>Error validating email address, please use a different email address or try again later</p>';
                }
                htm += '<p>' + cartErrNo + ' - ' + cartError + '</p>';
            }
            htm += '<p><a href="javascript:window.history.go(-1);">Back</a></p>';
        }
        document.write( htm );
    }

    this.displayCheckoutWin = function( checkoutUrl ) {
        window.location = checkoutUrl;
    }

    //  generic form validation function
    //  pass a list of form field objects, and each will be checked for a value
    //  fields containing 'email' in the name will be checked for an email-format value
    //  tim@saltstonemedia.co.uk

    this.validateForm = function() {

        var frm = null;
        var flds = iem.output.validateForm.arguments;
        var val = true;
        var err = '';

        var firstFld = null;

        for( var i = 0; i < flds.length; i++ ) {
            if( flds[ i ] && ! flds[ i ].disabled ) {

                frm = flds[ i ].form;

                if( typeof( flds[ i ].type ) != 'undefined' ) {
                    switch( flds[ i ].type ) {
                        case 'select-one' : {
                            if( flds[ i ].selectedIndex == -1 || ! flds[ i ].options[ flds[ i ].selectedIndex ].value ) {
                                val = false;
                                err += ( flds[ i ].title ? flds[ i ].title : flds[ i ].name ) + ' must be selected.\n';
                            }
                            break;
                        }
                        case 'checkbox' : {
                            if( ! flds[ i ].checked ) {
                                val = false;
                                err += ( flds[ i ].title ? flds[ i ].title : flds[ i ].name ) + ' must be checked.\n';
                            }
                            break;
                        }
                        default : {
                            if( ! flds[ i ].value ) {
                                val = false;
                                err += ( flds[ i ].title ? flds[ i ].title : flds[ i ].name ) + ' must be completed.\n';
                            } else {

                                var fldTxt = flds[ i ].name;
                                if( flds[ i ].title ) fldTxt += ' ' + flds[ i ].title;

                                if( fldTxt.toLowerCase().indexOf( 'email' ) != -1 || fldTxt.toLowerCase().indexOf( 'e-mail' ) != -1 ) {
                                    // assume from the field name that this should be an email address
                                    var mailEx = /^[a-zA-Z0-9._-]+@([a-zA-Z0-9.-]+\.)+[a-zA-Z0-9.-]{2,4}$/;
                                    if( ! mailEx.test( flds[ i ].value ) ) {
                                        val = false;
                                        err += ( flds[ i ].title ? flds[ i ].title : flds[ i ].name ) + ' must contain an e-mail address.\n';
                                    }
                                }
                            }
                        }
                    }
                    if( err && ! firstFld ) {
                        firstFld = flds[ i ];
                    }
                } else {
                    var chk = false;
                    for( var btn = 0; btn < flds[ i ].length; btn++ ) {
                        if( flds[ i ][ btn ].type == 'radio' ) {
                            if( flds[ i ][ btn ].checked ) chk = true;
                        }
                    }
                    if( ! chk ) {
                        val = false;
                        err += ( flds[ i ][ 0 ].title ? flds[ i ][ 0 ].title : flds[ i ][ 0 ].name ) + ' must be selected.\n';
                    }
                    if( err && ! firstFld ) {
                        firstFld = flds[ i ][ 0 ];
                    }
                }
            }
        }
        // strip back tick characters from form values
        if( frm ) {
            for( var i = 0; i < frm.elements.length; i++ ) {
                var el = frm.elements[ i ];
                if( el.value ) {
                    el.value = el.value.replace( /`/g, '\'' );
                }
            }
        }
        if( ! val ) {
            alert( err );
            if( typeof( firstFld.select ) == 'function' ) {
                firstFld.select();
            } else {
                firstFld.focus();
            }
        }
        return val;
    }
}
