var JS_PLX = "C:\\dh\\com\\Src\\plx.js (2467 lines) 2010-07-21 02:00 Rachel Bartlett";
/**********************************************************************/
/*                                                                    */
/*               Programming Language eXtensions (PLX)                */
/*               -------------------------------------                */
/*                                                                    */
/*                    (c) 1999-2009 Rachel Barlett                    */
/*                                                                    */
/**********************************************************************/
var YES = new String("yes");
var NO  = new String("no" );

/*--------------------------------------------------------------------*/
/*                                                                    */
/*      The following global settings can be modified externally      */
/*        at any time after this library is loaded and before         */
/*                the affected plx function is called.                */
/*                                                                    */
/*              Since Javascript always exports globals,              */
/*          they need to be protected with a 'plx_' prefix.           */
/*                                                                    */
/*         It is better to access them via accessor functions         */
/*            since data flow through these can be traced.            */
/*           Also, by returning the previous setting, they            */
/*            make it easy to implement a threaded queue.             */
/*                                                                    */
/*--------------------------------------------------------------------*/
// var plx_get_parm_debug  = false;
var plx_hover_style     = new String("color: black; "
                        + "background-color: white; "
                        + "border-color: black; "
                        + "border-width: 1; "
                        + "border-style: solid;");    // see x_hover_*()
var plx_hover_width     = 320;                        // see x_hover_*()
var plx_link_icon = new String('');                      // see x_link()

var plx_snapshot_frame_color = 'white';                 // user settable
var plx_snapshot_frame_caption_style                    // user settable
    = 'font-size: 12; font-weight: bold;';
var plx_snapshot_frame_width = 6;                       // user settable
var plx_snapshot_icon;                                  // user settable
var plx_snapshot_img_dir;                               // user settable
var plx_snapshot_next_align_flag                     // 1st-time default
     = new String('-right');
// var plx_snapshot_border_out = new String = 'white';
// (
//     'border-width: 4; border-style: solid; border-color: white;'
// );
// var plx_snapshot_border_over = new String = 'white';
// (
//     'border-width: 4; border-style: solid; border-color: white;'
// );
var plx_url_parms = new Object();               // see x_get_url_parms()

/*                                                                    */
/*     Global variables that are used internally by this library      */
/*                                                                    */
var plx_log;                                              // see x_log()
var plx_log_to_browser = false;                           // see x_log()
var plx_peek_window;                                     // see x_peek()
var plx_popup_number = 0;                               // see x_popup()
var plx_parse_imgsrc_caption;                    // see x_parse_imgsrc()
var plx_parse_imgsrc_width;                      // see x_parse_imgsrc()
var plx_parse_imgsrc_height;                     // see x_parse_imgsrc()
var plx_parse_imgsrc_type;                       // see x_parse_imgsrc()
var plx_resources_used = new Array();                  // see x_*used*()

/*                                                                    */
/*                  Global variables that are set by                  */
/*             similarly named global accessor functions              */
/*                                                                    */
var plx_browser;
var plx_browser_version;
var plx_domain;
var plx_email;
var plx_html;
var plx_os;
var plx_site;
var plx_user_agent = navigator.userAgent.toUpperCase();

/*                                                                    */
/*                     Global Accessor Functions                      */
/*                                                                    */
// function x_get_parm_debug              (a_new_val) {var old_val = plx_get_parm_debug              ; plx_get_parm_debug               = a_new_val; return old_val;}
function x_hover_style                 (a_new_val) {var old_val = plx_hover_style                 ; plx_hover_style                  = a_new_val; return old_val;}
function x_hover_width                 (a_new_val) {var old_val = plx_hover_width                 ; plx_hover_width                  = a_new_val; return old_val;}
function x_link_icon                   (a_new_val) {var old_val = plx_link_icon                   ; plx_link_icon                    = a_new_val; return old_val;}
function x_snapshot_frame_color        (a_new_val) {var old_val = plx_snapshot_frame_color        ; plx_snapshot_frame_color         = a_new_val; return old_val;}
function x_snapshot_frame_caption_style(a_new_val) {var old_val = plx_snapshot_frame_caption_style; plx_snapshot_frame_caption_style = a_new_val; return old_val;}
function x_snapshot_frame_width        (a_new_val) {var old_val = plx_snapshot_frame_width        ; plx_snapshot_frame_width         = a_new_val; return old_val;}
function x_snapshot_icon               (a_new_val) {var old_val = plx_snapshot_icon               ; plx_snapshot_icon                = a_new_val; return old_val;}
function x_snapshot_img_dir            (a_new_val) {var old_val = plx_snapshot_img_dir            ; plx_snapshot_img_dir             = a_new_val; return old_val;}
function x_snapshot_next_align_flag    (a_new_val) {var old_val = plx_snapshot_next_align_flag    ; plx_snapshot_next_align_flag     = a_new_val; return old_val;}
// function x_snapshot_border_out         (a_new_val) {var old_val = plx_snapshot_border_out         ; plx_snapshot_border_out          = a_new_val; return old_val;}
// function x_snapshot_border_over        (a_new_val) {var old_val = plx_snapshot_border_over        ; plx_snapshot_border_over         = a_new_val; return old_val;}

/*--------------------------------------------------------------------*/
/*        x_parse_url() global variables and wrapper functions        */
/*--------------------------------------------------------------------*/
var plx_anchor = new String();
var plx_page   = new String();
var plx_parms  = new String();
function x_page()   {x_parse_url(); return plx_page  ;}
function x_anchor() {x_parse_url(); return plx_anchor;}
function x_parms()  {x_parse_url(); return plx_parms ;}

/*--------------------------------------------------------------------*/
/*                          Setup hovercraft                          */
/*--------------------------------------------------------------------*/
// Create a <div> for hovercraft:
document.write("<div id='plx_hover_div'");
if (x_browser() == 'IE')
{
    document.write(" style='filter: "
        + "progid:DXImageTransform.Microsoft.GradientWipe"
        + "(GradientSize=1.0, wipeStyle=1, motion=forward) "
        + "progid:DXImageTransform.Microsoft.GradientWipe"
        + "(GradientSize=1.0, wipeStyle=1, motion=reverse)'");
}
document.write("></div>");

//    + "progid:DXImageTransform.Microsoft.Blinds"
//    + "(direction=down, bands=1, duration=0.25) "
//    + "progid:DXImageTransform.Microsoft.Blinds"
//    + "(direction=up, bands=1, duration=0.25) "
//    + "progid:DXImageTransform.Microsoft.Stretch(duration=0.5) "
//    + "progid:DXImageTransform.Microsoft.Stretch(duration=0.5) "
//    + "progid:DXImageTransform.Microsoft.RandomDissolve() "
//    + "progid:DXImageTransform.Microsoft.RandomDissolve() "
//    + "progid:DXImageTransform.Microsoft.Shadow(direction=135) "

// The following works only if the filetype is 'shtml':
//var plx_remote_addr = '<!--#echo var="REMOTE_ADDR"-->';

/*--------------------------------------------------------------------*/
/*                        Log Library Version                         */
/*--------------------------------------------------------------------*/
x_log("\nJS_PLX: '" + JS_PLX + "'");

/*--------------------------------------------------------------------*/
/*                            $() function                            */
/*                     (inspired by Prototype.js)                     */
/*--------------------------------------------------------------------*/
function $(a_elem_id)
{
    return document.getElementById(a_elem_id);
}

/*--------------------------------------------------------------------*/
/*                   x_bad_email_address() function                   */
/*--------------------------------------------------------------------*/
function x_bad_email_address(a_object, a_label)
{
// alert("x_bad_email_address(" + a_object.name + "='" + a_object.value + "', '" + a_label + "');");
// alert("typeof " + a_object.name + " = '" + (typeof a_object) + "'.");
    var value = a_object.value;
    var label = new String('your email address');
    var question = "Do you want to use this email address even though there's ";
    if (x_is_not_empty(a_label)) label = a_label;
    if (value == "")
    {
        return x_error_in_form(a_object, "Please enter " + label + ".");
    }
    if (value.indexOf("@") == -1)
    {
        if (!confirm(question + "no at sign ('@') in it?"))
        {
            return x_error_in_form(a_object);
        }
    }
    if (value.indexOf(".") == -1)
    {
        if (!confirm(question + "no period ('.') in it?"))
        {
            return x_error_in_form(a_object);
        }
    }
    var bad_chars = /[^A-Za-z0-9@_\-\.]/;
    var bad_x = value.search(bad_chars);
    if (bad_x > -1)
    {
        var bad_char = value.substr(bad_x, 1);
        if (!confirm(question + "a '" + bad_char
            + "' in position " + (bad_x + 1) + "?"))
        {
            return x_error_in_form(a_object);
        }
    }
    return false;
}

/*--------------------------------------------------------------------*/
/*                       x_bad_hhmm() function                        */
/*--------------------------------------------------------------------*/
function x_bad_hhmm(a_object, a_label, a_value)
{
// alert("x_bad_value(" + a_object + ", '" + a_label + "', '" + a_value + "');");
    if (x_no_object(a_object, a_label)) return true;
    var value = a_object.value;
    if (typeof a_value != 'undefined') value = a_value;
    var value_len = value.length;
    var hh = Math.floor(value.substr( 0, 2));
    var mm = Math.floor(value.substr( 2, 2));
// alert("    value: '" + value     + "'.\n"
//     + "value_len: '" + value_len + "'.\n"
//     + "       hh: '" + hh       + "'.\n"
//     + "       mm: '" + mm       + "'.");
    var err_msg = new String('');
    if (value_len != 2 && value_len != 4)
    {
        err_msg = "HHMM ('" + value + "') must be 2 or 4 digits in length.";
    }
    else if (isNaN(hh) || hh < 0 || hh > 23)
    {
        err_msg = "Invalid hour ('" + value.substr(0, 2) + "') in '" + value + "'.";
    }
    else if (value_len == 4 && (isNaN(mm) || mm < 0 || mm > 59))
    {
        err_msg = "Invalid minute ('" + value.substr(2, 2) + "') in '" + value + "'.";
    }
    if (err_msg != '') return x_error_in_form(a_object, err_msg);
    return false;
}

/*--------------------------------------------------------------------*/
/*                   x_bad_phone_number() function                    */
/*--------------------------------------------------------------------*/
function x_bad_phone_number(a_object, a_label)
{
    var val = a_object.value;
    var len = val.length;
    var chr = '';
    var label = new String('your phone number');
    var question = "Do you want to use this phone number even though ";
    if (x_is_not_empty(a_label)) label = a_label;
// Letters and syntax characters are allowed because
// sometimes people add annotations like "ext." and "cell:".
    var bad_chars = /[^ A-Za-z0-9()\*\-\:\.\/]/;
    var vx = val.search(bad_chars);
    if (vx > -1)
    {
        var bad_char = val.substr(vx, 1);
        if (!confirm(question + "there's a '" + bad_char
            + "' in position " + (vx + 1) + "?"))
        {
            return x_error_in_form(a_object);
        }
    }
    var num_digits = 0;
    for (vx = 0; vx < len; vx++)
    {
        chr = val.substr(vx, 1);
        if (chr >= '0' && chr <= '9') num_digits++;
    }
    if (num_digits < 10)
    {
        var only = 'only ';
        if (num_digits == 0) only = '';
        if (!confirm(question + 'it contains ' + only + x_cardinal(num_digits)
            + ' digit' + x_sing_plur(num_digits, '', 's') + '?'))
        {
            return x_error_in_form(a_object);
        }
    }
    return false;
}

/*--------------------------------------------------------------------*/
/*                       x_bad_range() function                       */
/*--------------------------------------------------------------------*/
function x_bad_range(a_object, a_label, a_min, a_max)
{
    if (x_no_input(a_object, a_label)) return true;
    if (isNaN(a_object.value) || a_object.value < a_min || a_object.value > a_max)
    {
        return x_error_in_form(a_object, "Please enter " + a_label
            + " between " + a_min + " and " + a_max + ".");
    }
    return false;
}

/*--------------------------------------------------------------------*/
/*                     x_bad_timeslot() function                      */
/*--------------------------------------------------------------------*/
function x_bad_timeslot(a_object, a_label)
{
    if (x_no_object(a_object, "The " + a_label)) return true;
    var timeslot = a_object.value;
    var pieces = timeslot.split('-');
    var yyyymmdd  = pieces[0];
    var hhmm_from = pieces[1];
    var hhmm_to   = pieces[2];
    if (x_bad_yyyymmdd(a_object, "The " + a_label, pieces[0])) return true;
    if (typeof hhmm_from != 'undefined' &&
        x_bad_hhmm(a_object, "The 'from' component ('hhmm') of the " + a_label, hhmm_from)) return true;
    if (typeof hhmm_to != 'undefined' &&
        x_bad_hhmm(a_object, "The 'to' component ('hhmm') of the " + a_label, hhmm_to)) return true;
    return false;
}

/*--------------------------------------------------------------------*/
/*                     x_bad_yyyymmdd() function                      */
/*--------------------------------------------------------------------*/
function x_bad_yyyymmdd(a_object, a_label, a_value)
{
// alert("x_bad_yyyymmdd(" + a_object + ", '" + a_label + "');");
    if (x_no_object(a_object, a_label)) return true;
    var yyyymmdd = a_object.value;
    if (typeof a_value != 'undefined') yyyymmdd = a_value;
    var yyyymmdd_len = yyyymmdd.length;
    var yyyy = Math.floor(yyyymmdd.substr( 0, 4));
    var mm   = Math.floor(yyyymmdd.substr( 4, 2));
    var dd   = Math.floor(yyyymmdd.substr( 6, 2));
// alert(a_label + ":\n"
//     + "yyyymmdd: '" + yyyymmdd + "'.\n"
//     + "yyyymmdd_len: '" + yyyymmdd_len + "'.\n"
//     + "yyyy: '" + yyyy     + "'.\n"
//     + "  mm: '" + mm       + "'.\n"
//     + "  dd: '" + dd       + "'.");
    var err_msg = new String('');
    if (yyyymmdd_len != 4 && yyyymmdd_len != 6 && yyyymmdd_len != 8)
    {
        err_msg = a_label + " must be 4, 6 or 8 digits in length.";
    }
    else if (isNaN(yyyy))
    {
        err_msg = "Invalid year ('" + yyyymmdd.substr(0, 4) + "') in '" + yyyymmdd + "'.";
    }
    else if (yyyymmdd_len >= 6 && (isNaN(mm) || mm < 1 || mm > 12))
    {
        err_msg = "Invalid month ('" + yyyymmdd.substr(4, 2) + "') in '" + yyyymmdd + "'.";
    }
    else if (yyyymmdd_len == 8 && (isNaN(dd) || dd < 1 || dd > 31))
    {
        err_msg = "Invalid day ('" + yyyymmdd.substr(6, 2) + "') in '" + yyyymmdd + "'.";
    }
    if (err_msg != '')
    {
        return x_error_in_form(a_object, err_msg);
    }
    return false;
}

/*--------------------------------------------------------------------*/
/*                        x_browser() function                        */
/*--------------------------------------------------------------------*/
function x_browser()
{
    if (typeof plx_browser != 'undefined') return plx_browser;
    plx_browser = 'Other';
    if (x_html() >= 4.0)
    {
//x_log_exp('navigator.appName', navigator.appName);
        if  (navigator.appName == 'Microsoft Internet Explorer')
        {
            plx_browser = 'IE';                 // IE 4.0 or greater
        }
        else if (navigator.appName == 'Netscape')
        {
            if (plx_user_agent.indexOf("FIREFOX") != -1)
            {
                plx_browser = 'FF'; // Mozilla Firefox 4.0 or greater
            }
            else
            {
                plx_browser = 'NN'; // Netscape Navigator 4.0 or greater
            }
        }
    }
//  x_log("\n\nx_browser() => '" + plx_browser + "'.");
    return plx_browser;
}

/*--------------------------------------------------------------------*/
/*                    x_browser_version() function                    */
/*--------------------------------------------------------------------*/
function x_browser_version()
{
    if (typeof plx_browser_version != 'undefined') return plx_browser_version;
    var browser = x_browser();
//x_log_exp('navigator.userAgent', navigator.userAgent);
    if  (browser == 'IE')
    {
/*                                                                    */
/*                         Index past "MSIE"                          */
/*                                                                    */
        if ((vx = plx_user_agent.indexOf("MSIE")) != -1)
        {
            plx_browser_version = parseFloat
            (
                plx_user_agent.substring
                (
                    vx + 5
//                  , plx_user_agent.indexOf(";", vx)
                )
            );
        }
    }
    else if (browser == 'NN')
    {
/*                                                                    */
/*                       Point past "Mozilla/"                        */
/*                                                                    */
        plx_browser_version = parseFloat(plx_user_agent.substring(8));
        if (navigator.appVersion.toLowerCase().indexOf("netscape6") != -1)
        {
            plx_browser_version = 6.0;
        }
    }
    else if (browser == 'FF')
    {
/*                                                                    */
/*                       Index past "Firefox/"                        */
/*                                                                    */
        if ((vx = plx_user_agent.indexOf("FIREFOX/")) != -1)
        {
// alert("vx = '" + vx + "'.");
            plx_browser_version = parseFloat
            (
                plx_user_agent.substring
                (
                    vx + 8
//                  , plx_user_agent.indexOf(";", vx)
                )
            );
// alert("plx_browser_version = '" + plx_browser_version + "'.");
        }
    }
//  x_log("\n\nx_browser_version() => '" + plx_browser_version + "'.");
    return plx_browser_version;
}

/*--------------------------------------------------------------------*/
/*                       x_cardinal() function                        */
/*--------------------------------------------------------------------*/
function x_cardinal(a_integer)
{
    var result = a_integer;
    var cardinal = new Array
    (
        'no', 'one', 'two', 'three', 'four',
        'five', 'six', 'seven', 'eight', 'nine'
    );
    if (a_integer < cardinal.length) result = cardinal[a_integer];
    return result;
}

/*--------------------------------------------------------------------*/
/*                  x_difference_in_days() function                   */
/*--------------------------------------------------------------------*/
// The value of any Date object is the time since 1/1/1970 in
// milliseconds. One day contains 1000 * 60 * 60 * 24, or 86,400,000
// milliseconds. 864E5 is equivalent to 86400000 in exponent notation.
// x = mydate and x = mydate.getTime() are equivalent.
function x_difference_in_days(a_date_1, a_date_2)
{
// alert("x_difference_in_days();");
    var result = Math.floor((a_date_2 - a_date_1) / 864e5);
// alert("x_difference_in_days(" + a_date_1.getTime() + ", " + a_date_2.getTime() + ");"
// + "\nThe difference in days between " + a_date_1 + " and " + a_date_2 + " is " + result + ".");
    return result;
}

/*--------------------------------------------------------------------*/
/*                        x_domain() function                         */
/*--------------------------------------------------------------------*/
function x_domain()
{
    if (typeof plx_domain == 'undefined')
    {
        plx_domain = location.host;
        var www = plx_domain.indexOf('www.');
        if (www == 0) plx_domain = plx_domain.substr(4);
x_log("\nx_domain() => '" + plx_domain + "'.");
    }
    return plx_domain;
}

/*--------------------------------------------------------------------*/
/*                         x_dots() function                          */
/*--------------------------------------------------------------------*/
function x_dots(a_count)
{
    var count = a_count;
    var result = new String('.');
    var cx;
    for (cx = 0; cx < count - 1; cx++) result += "&nbsp;.";
    return result;
}

/*--------------------------------------------------------------------*/
/*                        x_dropcap() function                        */
/*--------------------------------------------------------------------*/
function x_dropcap(a_letter)
{
    var result = "<table align='left' border=00 cellpadding=0 "
        + "cellspacing=0><tr>"
        + "<td style='font-size: 280%; line-height: .9;'>"
        + a_letter + "</td></tr></table>";
// alert(result);
    return result;
}

/*--------------------------------------------------------------------*/
/*                         x_email() function                         */
/*--------------------------------------------------------------------*/
function x_email(a_name, a_mailbox, a_domain, a_parms)
{
// x_email() with no parms returns the default email for this site,
// otherwise it returns a "<a href='mailto:...'>...</a>" tag
    if (typeof a_name == 'undefined')
    {
        if (typeof plx_email == 'undefined')
        {
            if (x_site() == "DHD")
            {
                plx_email = new String(x_yyyy() + '@hannotte.com');
            }
            else if (x_site() == "PRC")
            {
                plx_email = new String(x_yyyy() + '@rosenfels.org');
            }
            else if (x_site() == "NSC")
            {
                plx_email = new String(x_yyyy() + '@rosenfels.org');
            }
            else
            {
                plx_email = new String('dh' + x_yyyy() + '@nyc.rr.com');
            }
x_log("\nx_email() => '" + plx_email + "'.");
        }
        return plx_email;
    }
// a_mailbox is required
    var result = new String();
    var domain = x_domain();
    if (x_is_not_empty(a_domain)) domain = a_domain;
    var e_addr = a_mailbox + "@" + domain;
    var name   = new String(e_addr);
    var parms  = new String('');
    if (x_is_not_empty(a_name))  name  = a_name;
    if (x_is_not_empty(a_parms)) parms = '?' + a_parms;
    var result = "<a href=\"mailto:" + e_addr + parms + "\">"
        + "<b>" + name + "</b>"
//      + "<img border=00 src='/nyc/images/email.gif'>"
        + "</a>";
x_log("\nx_email('" + a_name
+ "', '" + a_mailbox
+ "', '" + a_domain
+ "', '" + a_parms
+ "') => " + result);
// x_log("\nx_email() => '" + result + "'.");
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_email_href() function                       */
/*--------------------------------------------------------------------*/
function x_email_href()
{
    return new String("mailto:" + x_email()
        + "?subject=(Sent from '" + location + "')"
//      + "&cc=" + x_email_2()
        + "");
}

/*--------------------------------------------------------------------*/
/*                      x_email_link() function                       */
/*--------------------------------------------------------------------*/
function x_email_link(a_anchor)
{
    var anchor = a_anchor;
    if (typeof a_anchor == 'undefined') anchor = x_email();
// alert("anchor: '" + anchor + "'");
    return new String('<A HREF="' + x_email_href()
        + '">' + anchor + '</A>');
}

/*--------------------------------------------------------------------*/
/*                         x_error() function                         */
/*--------------------------------------------------------------------*/
function x_error(a_message)
{
    x_log("\n" + a_message);
//    alert(a_message);
    return "\n<br><big><b>" + a_message + "</b></big>";
}

/*--------------------------------------------------------------------*/
/*                     x_error_in_form() function                     */
/*--------------------------------------------------------------------*/
function x_error_in_form(a_object, a_message)
{
    if (typeof a_object == 'object')
    {
        if ("focus"  in a_object) a_object.focus();
        if ("select" in a_object) a_object.select();
    }
    if (typeof a_message != 'undefined')
    {
        if (a_message != '')
        {
            x_log("\nx_error_in_form(): " + a_message);
            alert(a_message);
        }
    }
    return true;
}

/*--------------------------------------------------------------------*/
/*                 x_expand_caption_codes() function                  */
/*                                                                    */
/*     This function converts "caption codes" to HTML. All caption    */
/* codes are within paired brackets:                                  */
/*                                                                    */
/*                  This            Becomes That                      */
/*                  -------         ------------                      */
/*                  [b]             <b>                               */
/*                  [i]             <i>                               */
/*                  [-b]            </b>                              */
/*                  [-i]            </i>                              */
/*                  [br]            <br>                              */
/*                  [apost]         &#039;                            */
/*                  [quote]         &#034;                            */
/*                  [123]           &#123;                            */
/*                  [xffff]         &#xffff;                          */
/*                                                                    */
/*--------------------------------------------------------------------*/
// function x_expand_caption_codes(a_caption)
// {
//     var result = new String(a_caption);
//     result = result.replace(/_/g, ' ');
//     result = result.replace(/\[b\]/gi, "<b>");
//     result = result.replace(/\[i\]/gi, "<i>");
//     result = result.replace(/\[-b\]/gi, "</b>");
//     result = result.replace(/\[-i\]/gi, "</i>");
//     result = result.replace(/\[br\]/gi, "<br>");
//     result = result.replace(/\[apost\]/gi, "&#039;");
//     result = result.replace(/\[quote\]/gi, "&#034;");
//     result = result.replace(/\[(\d{2,3})\]/g, "&#$1;");
//     result = result.replace(/\[x([\dabcdef]{2,4})\]/gi, "&#x$1;");
//
//     if (result != a_caption)
//     {
// x_log("\nx_expand_caption_codes(\"" + a_caption + "\")"
//     + "\n                    => \"" + result    + "\"");
//     }
//     return result;
// }

/*--------------------------------------------------------------------*/
/*                                                                    */
/*                 x_expand_caption_codes() function                  */
/*                                                                    */
/*     This function converts "caption codes" to HTML. Caption codes  */
/* are defined as anything within paired brackets. They are designed  */
/* to exist peacefully in Windows filenames and so avoid characters   */
/* that are illegal in such a context.                                */
/*                                                                    */
/*     Codes ending with '-' are starting HTML tags. Thus "[b-]"      */
/* becomes "<b>".                                                     */
/*                                                                    */
/*     Codes starting with '-' are ending HTML tags. Thus "[-b]"      */
/* becomes "</b>".                                                    */
/*                                                                    */
/*     Codes that are 2 or 3 digits are byte values in decimal.       */
/* Thus "[039]" becomes "&#039;".                                     */
/*                                                                    */
/*     Codes that are 2 or 4 hex digits preceeded by a single         */
/* 'x' are byte values in hex. Thus "[xffff]" becomes "&#xffff;".     */
/*                                                                    */
/*     The following codes become entities:                           */
/*                                                                    */
/*         CODE                ENTITY                                 */
/*         ----                ------                                 */
/*         [quot]              &quot;                                 */
/*                                                                    */
/*     NOTE: Things in brackets should not automatically be converted */
/* into entities. "[this is a comment]", for example, should NOT      */
/* become "&this is a comment;"                                       */
/*                                                                    */
/*     We also replace all underscores with space characters.         */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_expand_caption_codes(a_caption)
{
    var result = new String(a_caption);
    result = result.replace(/\[([^\[]*?)-\]/gi, "<$1>");
    result = result.replace(/\[-([^\[]*?)\]/gi, "<\/$1>");
    result = result.replace(/\[(\d{2,3})\]/g, "&#$1;");
    result = result.replace(/\[x([\dabcdef]{2,4})\]/gi, "&#x$1;");
//     result = result.replace(/\[(.*?)\]/g, "&$1;"); <-- too broad!
    result = result.replace(/\[quot\]/gi, "&quot;");
    result = result.replace(/_/g, " ");
    if (result != a_caption)
    {
x_log("\nx_expand_caption_codes(\"" + a_caption + "\")"
    + "\n                    => \"" + result    + "\"");
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*              x_expand_caption_codes_tester() function              */
/*--------------------------------------------------------------------*/
function x_expand_caption_codes_tester()
{
    document.write("<center>"
    + x_expand_caption_codes
      (
            "[97][98][99]"
       + " - [big-][039][120][121][122][039][-big]"
       + " - [quot][x61][x62][x63][quot]"
       + " - [x0078][x0079][x007a]"
       + " - [copyright 2010]"
       )
    + "</center>");
}

/*--------------------------------------------------------------------*/
/*                    x_format_yyyymmdd() function                    */
/*--------------------------------------------------------------------*/
function x_format_yyyymmdd(a_date)
{
    var result = new String('');
x_log("\nx_format_yyyymmdd(" + a_date + ")");
    var date = new String(a_date);
    while (date.length < 8) date += '0';
    var yyyy = date.substr(0, 4) * 1;                          // numify
    var mm   = date.substr(4, 2) * 1;                          // numify
    var dd   = date.substr(6, 2) * 1;                          // numify
x_log("\n => yyyy, mm, dd: '" + yyyy + "', '" + mm + "', '" + dd);
    var months = ['', 'January', 'February', 'March', 'April', 'May', 'June',
        'July', 'August', 'September', 'October', 'November', 'December'];
    if (mm > 0)           result += months[mm];
    if (mm > 0 && dd > 0) result += " " + dd;
    if (mm > 0)           result += ", ";
    result += yyyy;
x_log(" => '" + result + "'");
    return result;
}

/*--------------------------------------------------------------------*/
/*                 x_format_yyyymmddhhmmss() function                 */
/*--------------------------------------------------------------------*/
function x_format_yyyymmddhhmmss(a_time)
{
    var result = new String('');
x_log("\nx_format_yyyymmddhhmmss(" + a_time + ")");
    var yyyy = a_time.substr(0, 4);
    var mm   = a_time.substr(4, 2);
    var dd   = a_time.substr(6, 2);
    var hh   = a_time.substr(8, 2);
    var mi   = a_time.substr(10, 2);
    var ss   = a_time.substr(12, 2);
// x_log("\nyyyy, mm, dd: " + yyyy + ", " + mm + ", " + dd);
    result = yyyy + "/" + mm + "/" + dd + " " + hh + ":" + mi + ":" + ss;
x_log(" => '" + result + "'");
    return result;
}

/*--------------------------------------------------------------------*/
/*                       x_get_parm() function                        */
/*                                                                    */
/*     This function extracts one "parm" from the input string you    */
/* pass to it as the first parameter. The parm can be one of two      */
/* types: either it can be one of several flags, or it can follow a   */
/* keyword. The second parameter indicates how to find this parm      */
/* inside the string:                                                 */
/*                                                                    */
/*     --- An array such as ["-left", "-right", "-center"] is seen    */
/*         as the list of flags.                                      */
/*                                                                    */
/*     --- A bare string such as "length=" or "genre:" is seen as     */
/*         the keyword preceeding the parm and enables parms to       */
/*         have any value.                                            */
/*                                                                    */
/*     Parms (and the optional keywords that may precede them) begin  */
/* either at the start of the input field or at the next non-blank    */
/* after the previous parm. They end with the next blank or the end   */
/* of the input field. To make it easier to isolate the parms in the  */
/* input string, we pad both sides of the input field with one        */
/* blank.                                                             */
/*                                                                    */
/*     If the value after a keyword begins with a quotation mark or   */
/* an apostrophe then it must end with the next occurrence of that    */
/* same character instead of the next blank. This allows parms to     */
/* contain blanks and either apostrophes or quotation marks.          */
/*                                                                    */
/*     If the parm you're looking for isn't found, an empty string    */
/* ('') is returned. This makes it simple to test for the presence    */
/* of a parm by coding:                                               */
/*                                                                    */
/*         hidden_flag = x_get_parm(input, ['-hidden']);              */
/*         if (!hidden_flag) {display()}                              */
/*                                                                    */
/*     You can overide the default value returned by using the third  */
/* parameter to the x_get_parm() function.                            */
/*                                                                    */
/*     You can indicate that diagnostic messages be logged by         */
/* specifying a fourth parameter of 1.                                */
/*                                                                    */
/*     The documentation and logic of the x_get_parm() Perl function  */
/* in "Plx.pm" is identical to those of the x_get_parm() Javascript   */
/* function in "plx.js".                                              */
/*                                                                    */
/*--------------------------------------------------------------------*/
/* WARNING: I learned a lot about strings from writing this function. */
/*          Observe the following experimental results:               */
/*                                                                    */
/*                     literal typeof   instanceof                    */
/*          ------------------ -------- ----------                    */
/*                           3 'number'                               */
/*                      'word' 'string'                               */
/*              String('word') 'string' Object                        */
/*          new String('word') 'object' String                        */
/*--------------------------------------------------------------------*/
// alert(
// "                 3: " + (typeof                  3) + ", instanceof Object: " + (                 3 instanceof Object) + "\n" +
// "            'word': " + (typeof             'word') + ", instanceof Object: " + (            'word' instanceof Object) + "\n" +
// "    String('word'): " + (typeof     String('word')) + ", instanceof Object: " + (    Object('word') instanceof Object) + "\n" +
// "new String('word'): " + (typeof new String('word')) + ", instanceof String: " + (new String('word') instanceof String)
// );
function x_get_parm(a_input, a_find, a_default, a_debug)
{
    var i_debug = false;
    if (x_is_not_empty(a_debug)) i_debug = a_debug;
if (i_debug) x_log("\nx_get_parm(\"" + a_input + "\", \"" + a_find + "\", \"" + a_default + "\", \"" + a_debug + "\")");

    var result = "";
    var i_input   = a_input;
    var i_find    = a_find;
    var i_default = '';

    if (x_is_not_empty(a_default )) result = i_default = a_default ;

    if (x_is_empty(a_input) || x_is_empty(a_find))
    {
if (i_debug) x_log(" => \"" + result + "\"");
        return result;
    }

// Pad the i_input string:
    i_input = new String(' ' + i_input + ' ');

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*         Is the parm one of a list of pre-defined literals?         */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    if (i_find instanceof Array)
    {
        var fx;
        for (fx = 0; fx < i_find.length; fx++)
        {
            var flag = i_find[fx];
            if (i_input.indexOf(' ' + flag + ' ') > -1)
            {
                result = flag;
                break;
            }
        }
if (i_debug) x_log(" => \"" + result + "\"");
    }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                  Does the parm follow a keyword?                   */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    else if (typeof i_find == 'string')
    {
// If the parm is enclosed in quotation marks, the next quotation mark
// (rather than the next blank) defines the end of the parameter.
        var fromx, tox, char, delim;
        fromx = i_input.indexOf(' ' + i_find);
        if (fromx > -1)
        {
            fromx += 1 + i_find.length;
            delim = ' ';
            char = i_input.charAt(fromx);
            if (char == '"' || char == "'")
            {
                fromx++;
                delim = char;
            }
            tox = i_input.indexOf(delim, fromx);
            result = i_input.substring(fromx, tox);
        }
if (i_debug) x_log(" => \"" + result + "\"");
    }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                         a_find is invalid                          */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    else
    {
        var funcall = "x_get_parm(\"" + i_input + "\", \"" + a_find
            + "\", \"" + i_default + "\", \"" + i_debug + "\");";
        result =  funcall + " - second parameter "
            + "is neither a String() nor an Array().";
if (i_debug) x_log("\n => \"" + result + "\"");
    }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                         Return the result                          */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    return result;
}

/*--------------------------------------------------------------------*/
/*                    x_get_parm_tester() function                    */
/*--------------------------------------------------------------------*/
// function x_get_parm_tester()
// {
//     var input = "a=b c-\"d\" efg:\"Dean Hannotte\" hij='Rachel Bartlett' -center";
//     x_get_parm('', '', '', 1);
//     x_get_parm(input, '', '', 1);
//     x_get_parm(input, 'a=', '', 1);
//     x_get_parm(input, 'c-', '', 1);
//     x_get_parm(input, 'efg:', '', 1);
//     x_get_parm(input, 'hij=', '', 1);
//     x_get_parm(input, ['-left', '-right'], '-right', 1);
//     x_get_parm(input, ['-left', '-right', '-center'], '-right', 1);
// }
// x_get_parm_tester();

/*--------------------------------------------------------------------*/
/*                     x_get_url_parms() function                     */
/*                                                                    */
/*     The plx_url_parms object reflects positional and keyword       */
/* parms found in the URL. Positional parameters are associated with  */
/* numeric indexes, and keyword parameters are associated with the    */
/* indexes given in the URL itself. Element 0 will give the number    */
/* of positional parms (as in KEXX). Element 1 will give the first    */
/* positional parm, element 2 the second, etc.                        */
/*                                                                    */
/*     For example, a URL of "a.com?b&c&d&e=f&g=h&i=j" will give you  */
/* a plx_url_parms object of:                                         */
/*                                                                    */
/*                             KEY VALUE                              */
/*                             --- -----                              */
/*                              0    3                                */
/*                              1    b                                */
/*                              2    c                                */
/*                              3    d                                */
/*                              e    f                                */
/*                              g    h                                */
/*                              i    j                                */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_get_url_parms()
{
x_log("\nx_get_url_parms();");
    x_parse_url();
    if (plx_parms == '') return;
    plx_url_parms[0] = 0;
x_log("\nplx_parms: \"" + plx_parms + "\".");
    var parms = plx_parms.substr(1).split('&');
    for (var px = 0; px < parms.length; px++)
    {
// x_log("\nparms[" + px + "]: \"" + parms[px] + "\"");

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                          Positional parm                           */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
        if (parms[px].indexOf('=') == -1)
        {
            plx_url_parms[0]++;
            plx_url_parms[plx_url_parms[0]] = parms[px];
// x_log("\nplx_url_parms[\"" + plx_url_parms[0] + "\"]: \"" + parms[px] + "\".");
        }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                            Keyword parm                            */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
        else
        {
            elems = parms[px].split('=');
            plx_url_parms[elems[0]] = elems[1];
// x_log("\nplx_url_parms[\"" + elems[0] + "\"]: \"" + elems[1] + "\".");
        }
    }
// x_log("\nplx_url_parms[\"0\"]: \"" + plx_url_parms[0] + "\".");
var k; for (k in plx_url_parms) x_log("\nplx_url_parms[\"" + k + "\"]: \"" + plx_url_parms[k] + "\".");
}

/*--------------------------------------------------------------------*/
/*                     x_has_filetype() function                      */
/*--------------------------------------------------------------------*/
function x_has_filetype(a_link)
{
    var result = false;
    var link = new String(a_link);
    if (link.indexOf('.') > -1) result = true;
x_log("\nx_has_filetype('" + a_link + "') => " + result + ".");
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_hover_hide() function                       */
/*--------------------------------------------------------------------*/
function x_hover_hide()
{
    var hover_div = $('plx_hover_div');
    if (x_browser() == 'IE') hover_div.filters[1].Apply();
    hover_div.style.visibility = "hidden";
    if (x_browser() == 'IE') hover_div.filters[1].Play();
}

/*--------------------------------------------------------------------*/
/*                      x_hover_hint() function                       */
/*--------------------------------------------------------------------*/
function x_hover_hint(a_anchor, a_hint, a_left, a_top)
{
// alert("x_hover_hint: " + a_hint);
// An embedded quote in a_hint is tricky. Since a_hint
// is a quoted string, it must be represented as \" to be accepted.
// But once stored in the mouseover event as a plain quote,
// it can then cause a syntax error when the event is triggered.
// It must be escaped two more times. Converting each received
// quote to "&amp;quot;" seems to work.
    var hint = a_hint.replace(/"/g, "&amp;quot;");
    var left = a_left;
    if (typeof a_left == 'undefined') left = -1;
    var top = a_top;
    if (typeof a_top == 'undefined') top = -1;
    var result = new String("<span "
        + "style='font-weight: bold; "
        + "border-bottom-width: 1; border-bottom-style: dotted;'"
        + "\nonmouseover='x_hover_show(0, this, "
        + "\"" + plx_hover_style + "\", "
        + "\"" + x_javascript_safe(hint) + "\", " + left + ", " + top + ");'"
        + "\nonmouseout='x_hover_hide();'>"
        + a_anchor + "</span>");
// alert("x_hover_hint() => '" + result + "'.");
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_hover_link() function                       */
/*--------------------------------------------------------------------*/
function x_hover_link(a_anchor, a_href, a_hint)
{
// (See comment above about embedded quotes.)
    var hint = a_hint.replace(/"/g, "&amp;quot;");
    var link = new String("<br><a href='"
        + a_href + "'><b>Read&nbsp;more&nbsp;...</b></a>");
    var result = new String("<span"
        + " style='font-weight: bold; "
        + "border-bottom-width: 1; border-bottom-style: dotted;'"
        + "\nonmouseover='" + "x_hover_show(1, this, \""
        + plx_hover_style + "\", \""
        + x_javascript_safe(hint + link) + "\");'>"
        + "<a href='" + a_href + "'>"
        + a_anchor + "</a></span>");
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_hover_show() function                       */
/*--------------------------------------------------------------------*/
function x_hover_show(a_retain, a_this, a_style, a_hint, a_left, a_top)
{
// alert("x_hover_show: " + a_hint);
// alert("x_hover_show(" + a_retain + ", " + a_this + ", \"" + a_style
// + "\", \"" + a_hint + "\", " + a_left + ", " + a_top + ");");
    var hover_div = $('plx_hover_div');
    hover_div.style.position = "absolute";
    hover_div.style.visibility = "hidden";
    if (typeof a_left != 'undefined' && a_left != -1)
    {
        hover_div.style.left = a_left;
    }
    else hover_div.style.left = x_left(a_this);
    if (typeof a_top != 'undefined' && a_top != -1)
    {
        hover_div.style.top = a_top;
    }
    else hover_div.style.top  = x_top(a_this) + (2 * a_this.offsetHeight);
//     hover_div.style.border = plx_hover_border;
    hover_div.style.padding = 0;
    var close_button = '';
    if (a_retain == 1)
    {
        close_button = "\n<p style='text-align: right; margin: 0;'>"
            + "<span style=' cursor: pointer; "
//             + "/* border: 1 solid; */"
            + "' onclick='x_hover_hide();'>[close]</span></p><hr>";
//         close_button = "\n<p style='text-align: right; margin: 0;'>"
//             + "<span style=' cursor: pointer; /* border: 1 solid; */' "
//             + "onclick='x_hover_hide();'><img border=0 "
//             + "src='/nyc/images/close_button.gif'></span></p><hr>";
    }
    var hint = "<table width=" + plx_hover_width
        + " cellpadding=0 cellspacing=0>"
        + "<tr><td style='" + a_style + " padding: 4;'>"
        + close_button + a_hint + "</td></tr></table>";
    hover_div.innerHTML = hint;
// alert("hover_div.style.left = '" + hover_div.style.left + "'."
// + "\nhover_div.style.top = '" + hover_div.style.top + "'."
// + "\nhover_div.style.position = '" + hover_div.style.position + "'."
// + "\nhover_div.style.visibility = '" + hover_div.style.visibility + "'."
// + "\nhover_div.innerHTML = '" + hover_div.innerHTML + "'.");
    if (x_browser() == 'IE') hover_div.filters[0].Apply();
    hover_div.style.visibility = "visible";
    if (x_browser() == 'IE') hover_div.filters[0].Play();
}

/*--------------------------------------------------------------------*/
/*                         x_html() function                          */
/*--------------------------------------------------------------------*/
function x_html()
{
    if (typeof plx_html != 'undefined') return plx_html;
//x_log_exp('navigator.appVersion', navigator.appVersion);
    plx_html = parseFloat(navigator.appVersion);
//  x_log("\nx_html() => '" + plx_html + "'.");
    return plx_html;
}

/*--------------------------------------------------------------------*/
/*                  x_is_a_used_resource() function                   */
/*--------------------------------------------------------------------*/
function x_is_a_used_resource(a_resource)
{
    var rx;
    for (rx = 0; rx < plx_resources_used.length; rx++)
    {
        if (a_resource == plx_resources_used[rx])
        {
x_log("\nx_is_a_used_resource('" + a_resource + "') => 1");
            return 1;
        }
    }
x_log("\nx_is_a_used_resource('" + a_resource + "') => 0");
    return 0;
}

/*--------------------------------------------------------------------*/
/*                       x_is_empty() function                        */
/*--------------------------------------------------------------------*/
function x_is_empty(a_text)
{
    var result = typeof a_text == 'undefined' || a_text == '';
// x_log("\nx_is_empty('" + a_text + "') => " + result + ";");
    return result;
}

/*--------------------------------------------------------------------*/
/*                     x_is_not_empty() function                      */
/*--------------------------------------------------------------------*/
function x_is_not_empty(a_text)
{
    var result = typeof a_text != 'undefined' && a_text != '';
// x_log("\nx_is_not_empty('" + a_text + "') => " + result + ";");
    return result;
}

/*--------------------------------------------------------------------*/
/*                    x_javascript_safe() function                    */
/*--------------------------------------------------------------------*/
function x_javascript_safe(a_text)
{
    var result = new String(a_text);
    result = result.replace(/"/g, '&#034;');
    result = result.replace(/'/g, '&#039;');
// alert(a_text + "\n\n----------------------------------------------\n\n" + result);
    return result;
}

/*--------------------------------------------------------------------*/
/*                         x_left() function                          */
/*--------------------------------------------------------------------*/
function x_left(obj)
{
    var result = 0;
    while (obj.offsetParent)
    {
        result += obj.offsetLeft
        obj = obj.offsetParent;
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*                         x_link() function                          */
/*--------------------------------------------------------------------*/
function x_link(a_anchor, a_href, a_target, a_title)
{
    var anchor = a_anchor;
    var href   = a_href;
    var target = a_target;
    var title  = a_title;

    if (typeof a_anchor == 'undefined' || a_anchor == '') anchor = href;
    if (typeof a_title  == 'undefined' || a_title  == '') title  = href;

    var result = new String('');

    result += "<a";
    if (x_is_not_empty(a_target))
    {
        result += " target='" + a_target + "'";
    }
    if (x_is_not_empty(a_href))
    {
        result += " href=\"" + a_href + "\"";
    }
    result += " title=\"" + title + "\"";
    if (x_is_not_empty(a_title))
    {
        result += " style='border-bottom-width: 1; border-bottom-style: dotted; "
            + "text-decoration: none;'";
    }
    result += ">";
    result += "<b>" + anchor + "</b>";
    if (plx_link_icon != ''
    && (href.substr(0, 7) == 'http://' || href.substr(0, 8) == 'https://'))
    {
        result += " " + plx_link_icon;
    }
    result += "</a>";
// alert(result);
    return result;
}

/*--------------------------------------------------------------------*/
/*                   x_is_external_link() function                    */
/*--------------------------------------------------------------------*/
function x_is_external_link(a_link)
{
    var result = false;
    if ((a_link.length >= 7 &&  a_link.substr(0, 7) == "http://" )
    ||  (a_link.length >= 8 &&  a_link.substr(0, 8) == "https://"))
    {
        result = true;
    }
x_log("\nx_is_external_link('" + a_link + "') => " + result + ".");
    return result;
}

/*--------------------------------------------------------------------*/
/*                 x_is_not_external_link() function                  */
/*--------------------------------------------------------------------*/
function x_is_not_external_link(a_link)
{
    var result = true;
    if  (a_link.length >= 7
    &&  (a_link.substr(0, 7) == "http://"
    ||   a_link.substr(0, 7) == "https:/"))
    {
        result = false;
    }
x_log("\nx_is_not_external_link('" + a_link + "') => " + result + ".");
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_is_pdf_link() function                      */
/*--------------------------------------------------------------------*/
function x_is_pdf_link(a_link)
{
    var result = false;
    if  (a_link.length >= 4
    &&   a_link.substr(-4, 4).toLowerCase() == ".pdf")
    {
        result = true;
    }
x_log("\nx_is_pdf_link('" + a_link + "') => " + result + ".");
    return result;
}

/*--------------------------------------------------------------------*/
/*                    x_location_folder() function                    */
/*                                                                    */
/*    This function takes a location like                             */
/*                                                                    */
/*        "http://www.paul-rosenfels.org/Haiku.htm"                   */
/*        or "file:///C:/dh/web/PRC/1/HTM/index.htm"                  */
/*                                                                    */
/*    and returns everything but the filename and extension:          */
/*                                                                    */
/*        "http://www.paul-rosenfels.org"                             */
/*        or "file:///C:/dh/web/PRC/1/HTM"                            */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_location_folder()
{
    var result = new String(location);
    var last_slash = result.lastIndexOf('/');
    if (last_slash > -1)
    {
        result = result.substr(0, last_slash);
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*                          x_log() function                          */
/*--------------------------------------------------------------------*/
function x_log(a_message)
{
    if (typeof plx_log == 'undefined')
    {
        plx_log = new String('');
    }
    plx_log += a_message;
    if (plx_log_to_browser == true)
    {
        document.write("\n<br>" + a_message);
    }
}

/*--------------------------------------------------------------------*/
/*                        x_log_all() function                        */
/*--------------------------------------------------------------------*/
function x_log_all()
{
    x_log
    (
      "\n\n                  document: \"" + document                   + '" (' + typeof document                   + ')'
      + "\ndocument.body.clientHeight: \"" + document.body.clientHeight + '" (' + typeof document.body.clientHeight + ')'
      + "\n document.body.clientWidth: \"" + document.body.clientWidth  + '" (' + typeof document.body.clientWidth  + ')'
      + "\n         document.referrer: \"" + document.referrer          + '" (' + typeof document.referrer          + ')'
      + "\n            document.title: \"" + document.title             + '" (' + typeof document.title             + ')'
      + "\n  document.fileCreatedDate: \"" + document.fileCreatedDate   + '" (' + typeof document.fileCreatedDate   + ')'
      + "\n document.fileModifiedDate: \"" + document.fileModifiedDate  + '" (' + typeof document.fileModifiedDate  + ')'
      + "\n     document.lastModified: \"" + document.lastModified      + '" (' + typeof document.lastModified      + ')'
      + "\n         document.protocol: \"" + document.protocol          + '" (' + typeof document.protocol          + ')'
      + "\n                  location: \"" + location                   + '" (' + typeof location                   + ')'
      + "\n             location.hash: \"" + location.hash              + '" (' + typeof location.host              + ')'
      + "\n             location.host: \"" + location.host              + '" (' + typeof location.host              + ')'
      + "\n         location.hostname: \"" + location.hostname          + '" (' + typeof location.hostname          + ')'
      + "\n             location.href: \"" + location.href              + '" (' + typeof location.href              + ')'
      + "\n         location.pathname: \"" + location.pathname          + '" (' + typeof location.pathname          + ')'
      + "\n             location.port: \"" + location.port              + '" (' + typeof location.pathname          + ')'
      + "\n         location.protocol: \"" + location.protocol          + '" (' + typeof location.protocol          + ')'
      + "\n           location.search: \"" + location.search            + '" (' + typeof location.search            + ')'
      + "\n                 navigator: \"" + navigator                  + '" (' + typeof navigator                  + ')'
      + "\n     navigator.appCodeName: \"" + navigator.appCodeName      + '" (' + typeof navigator.appCodeName      + ')'
      + "\n         navigator.appName: \"" + navigator.appName          + '" (' + typeof navigator.appName          + ')'
      + "\n      navigator.appVersion: \"" + navigator.appVersion       + '" (' + typeof navigator.appVersion       + ')'
      + "\n navigator.appMinorVersion: \"" + navigator.appMinorVersion  + '" (' + typeof navigator.appMinorVersion  + ')'
      + "\n   navigator.cookieEnabled: \"" + navigator.cookieEnabled    + '" (' + typeof navigator.cookieEnabled    + ')'
      + "\n        navigator.cpuClass: \"" + navigator.cpuClass         + '" (' + typeof navigator.cpuClass         + ')'
      + "\n          navigator.onLine: \"" + navigator.onLine           + '" (' + typeof navigator.onLine           + ')'
      + "\n        navigator.platform: \"" + navigator.platform         + '" (' + typeof navigator.platform         + ')'
      + "\n       navigator.userAgent: \"" + navigator.userAgent        + '" (' + typeof navigator.userAgent        + ')'
      + "\n window.screen.availHeight: \"" + window.screen.availHeight  + '" (' + typeof window.screen.availHeight  + ')'
      + "\n  window.screen.availWidth: \"" + window.screen.availWidth   + '" (' + typeof window.screen.availWidth   + ')'
      + "\n      window.screen.height: \"" + window.screen.height       + '" (' + typeof window.screen.height       + ')'
      + "\n       window.screen.width: \"" + window.screen.width        + '" (' + typeof window.screen.width        + ')'
      + "\n"
      + "\n                x_anchor(): \"" + x_anchor()                 + '" (' + typeof x_anchor()                 + ')'
      + "\n               x_browser(): \"" + x_browser()                + '" (' + typeof x_browser()                + ')'
      + "\n       x_browser_version(): \"" + x_browser_version()        + '" (' + typeof x_browser_version()        + ')'
      + "\n                 x_email(): \"" + x_email()                  + '" (' + typeof x_email()                  + ')'
      + "\n            x_email_href(): \"" + x_email_href()             + '" (' + typeof x_email_href()             + ')'
      + "\n            x_email_link(): \"" + x_email_link()             + '" (' + typeof x_email_link()             + ')'
      + "\n                  x_html(): \"" + x_html()                   + '" (' + typeof x_html()                   + ')'
      + "\n                    x_os(): \"" + x_os()                     + '" (' + typeof x_os()                     + ')'
      + "\n                  x_page(): \"" + x_page()                   + '" (' + typeof x_page()                   + ')'
      + "\n                 x_parms(): \"" + x_parms()                  + '" (' + typeof x_parms()                  + ')'
      + "\n                  x_site(): \"" + x_site()                   + '" (' + typeof x_site()                   + ')'
      + "\n           x_wide_screen(): \"" + x_wide_screen()            + '" (' + typeof x_wide_screen()            + ')'
      + "\n         x_window_height(): \"" + x_window_height()          + '" (' + typeof x_window_height()          + ')'
      + "\n          x_window_width(): \"" + x_window_width()           + '" (' + typeof x_window_width()           + ')'
      + "\n              x_yyyymmdd(): \"" + x_yyyymmdd()               + '" (' + typeof x_yyyy()                   + ')'
    );
//    + "\n           plx_remote_addr: \"" + plx_remote_addr            + '" (' + typeof plx_remote_addr            + ')'
//    + "\n   navigator.javaEnabled(): \"" + navigator.javaEnabled()    + '" (' + typeof navigator.javaEnabled()    + ')'
}

/*--------------------------------------------------------------------*/
/*                        x_log_exp() function                        */
/*--------------------------------------------------------------------*/
function x_log_exp(a_name, a_value)
{
    value = new String(a_value);
    if (typeof a_value != 'number') value = "'" + value + "'";
    x_log("\n" + a_name + " = " + value + " (" + typeof a_value + ").");
}

/*--------------------------------------------------------------------*/
/*                  x_log_resources_used() function                   */
/*--------------------------------------------------------------------*/
function x_log_resources_used()
{
    x_log("\nResources used:");
    var resource;
    while (resource = plx_resources_used.shift())
    {x_log("\n " + resource)}
}

/*--------------------------------------------------------------------*/
/*                    x_log_to_browser() function                     */
/*--------------------------------------------------------------------*/
function x_log_to_browser(a_new_value)
{
x_log("\nChanging plx_log_to_browser from '" + plx_log_to_browser + "' to '" + a_new_value + "'.");
    var old_value = plx_log_to_browser;
    plx_log_to_browser = a_new_value;
    return old_value;
}

/*--------------------------------------------------------------------*/
/*                       x_no_choice() function                       */
/*                                                                    */
/* NOTE: This function works for radio buttons as well as checkboxes. */
/*       For radio buttons, each button has the same name. Passing    */
/*       that name to this function passes an array of buttons.       */
/*       For checkboxes, each button has a different name, so you     */
/*       must create an array of button names and then pass that      */
/*       array to this function to achieve the same effect.           */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_no_choice(a_objects, a_label)
{
    for (ox = 0; ox < a_objects.length; ox++)
    {
        if (a_objects[ox].checked) return false;
    }
    return x_error_in_form(a_objects[0], "Please choose " + a_label + ".");
}

/*--------------------------------------------------------------------*/
/*                       x_no_input() function                        */
/*--------------------------------------------------------------------*/
function x_no_input(a_object, a_label)
{
    if (a_object.value != '') return false;
    return x_error_in_form(a_object, "Please enter " + a_label + ".");
}

/*--------------------------------------------------------------------*/
/*                       x_no_object() function                       */
/*--------------------------------------------------------------------*/
function x_no_object(a_object, a_label)
{
    if (typeof a_object == 'object') return false;
    return x_error_in_form(a_object, a_label + " is not an Javascript object.");
}

/*--------------------------------------------------------------------*/
/*                          x_rgb() function                          */
/*--------------------------------------------------------------------*/
function x_rgb(a_red, a_green, a_blue)
{
    var red   = a_red * 256 * 256;
    var green = a_green * 256;
    var blue  = a_blue;

    red   =   a_red.toString(16).toUpperCase();
    green = a_green.toString(16).toUpperCase();
    blue  =  a_blue.toString(16).toUpperCase();

    if (red.length   == 1) red   = '0' + red;
    if (green.length == 1) green = '0' + green;
    if (blue.length  == 1) blue  = '0' + blue;

    var result = '#' + red + green + blue;
x_log("\nx_rgb(a_red, a_green, a_blue) => '" + result + "'");
    return result;
}

/*--------------------------------------------------------------------*/
/*                     x_no_selection() function                      */
/*--------------------------------------------------------------------*/
function x_no_selection(a_object, a_label)
{
    if (a_object.selectedIndex == -1
    ||  a_object.options[a_object.selectedIndex].value == ''
    ||  a_object.options[a_object.selectedIndex].value == '[not set]') // PHP constant
    {
        return x_error_in_form(a_object, "Please select " + a_label + ".");
    }
    return false;
}

/*--------------------------------------------------------------------*/
/*                        x_ordinal() function                        */
/*--------------------------------------------------------------------*/
function x_ordinal(a_integer)
{
    var result = a_integer;
    var ordinal = new Array
    (
        'zeroeth', 'first', 'second', 'third', 'fourth',
        'fifth', 'sixth', 'seventh', 'eighth', 'ninth'
    );
    if (a_integer < ordinal.length) result = ordinal[a_integer];
    return result;
}

/*--------------------------------------------------------------------*/
/*                          x_os() function                           */
/*--------------------------------------------------------------------*/
function x_os()
{
    if (typeof plx_os != 'undefined') return plx_os;
    plx_os = new String('Windows');
//x_log_exp('plx_user_agent', plx_user_agent);
    if (plx_user_agent.indexOf('MACINTOSH') != -1) plx_os = "MacOS";
    if (plx_user_agent.indexOf('MAC_POWER') != -1) plx_os = "MacOS";
    if (plx_user_agent.indexOf('HP-UX'    ) != -1) plx_os = "HP-UX";
    if (plx_user_agent.indexOf('SUNOS'    ) != -1) plx_os = "SunOS";
    if (plx_user_agent.indexOf('WEBTV'    ) != -1) plx_os = "WebTV";
//  x_log("\nx_os() => '" + plx_os + "'.");
    return plx_os;
}

/*--------------------------------------------------------------------*/
/*                     x_parse_imgsrc() function                      */
/*--------------------------------------------------------------------*/
// substr(from, [len])
// substring(from, to)
function x_parse_imgsrc(a_src)
{
x_log("\nx_parse_imgsrc(\"" + a_src + "\");");

    plx_parse_imgsrc_caption = new String('');
    plx_parse_imgsrc_width   = 0;
    plx_parse_imgsrc_height  = 0;
    plx_parse_imgsrc_type    = new String('');

    var src = new String(a_src);
    if (src == '')
    {
        plx_parse_imgsrc_caption =
            "x_parse_imgsrc(): Filename is empty: '" + a_src + "'.";
        return x_error(plx_parse_imgsrc_caption);
    }
    else
    {
        src = src.replace(/_/g, ' ');
        var dot = src.lastIndexOf('.');
        if (dot <= -1)
        {
            plx_parse_imgsrc_caption =
                "x_parse_imgsrc(): Dot missing in filename: '" + src + "'.";
            return x_error(plx_parse_imgsrc_caption);
        }
        else
        {
            plx_parse_imgsrc_type = src.substr(dot);
            var x = src.lastIndexOf('x', dot);
            if (x <= -1)
            {
                plx_parse_imgsrc_caption =
                    "x_parse_imgsrc(): 'x' missing in filename: '" + src + "'.";
                return x_error(plx_parse_imgsrc_caption);
            }
            else
            {
                plx_parse_imgsrc_height = parseInt(src.substring(x + 1, dot));
                var space = src.lastIndexOf(' ', x);
                if (space <= -1)
                {
                    plx_parse_imgsrc_caption =
                        "x_parse_imgsrc(): Neither underscore nor space "
                        + "found before 'x' in filename: '" + src + "'.";
                    return x_error(plx_parse_imgsrc_caption);
                }
                else
                {
                    plx_parse_imgsrc_width =
                        parseInt(src.substring(space + 1, x));
                    plx_parse_imgsrc_caption = src.substring(0, space);
                    var slash = plx_parse_imgsrc_caption.lastIndexOf('/');
                    if (slash > -1)
                    {
                        plx_parse_imgsrc_caption =
                            plx_parse_imgsrc_caption.substr(slash + 1);
                    }
                }
            }
        }
    }
x_log("\n plx_parse_imgsrc_caption: \"" + plx_parse_imgsrc_caption + "\"");
x_log("\n   plx_parse_imgsrc_width: "   + plx_parse_imgsrc_width         );
x_log("\n  plx_parse_imgsrc_height: "   + plx_parse_imgsrc_height        );
x_log("\n    plx_parse_imgsrc_type: '"  + plx_parse_imgsrc_type    +  "'");
}

/*--------------------------------------------------------------------*/
/*                       x_parse_url() function                       */
/*                                                                    */
/* If location contains "http://www.a.com/b.htm#c?d", then:           */
/*                                                                    */
/*      plx_page   will contain  "b.htm"                              */
/*      plx_anchor will contain  "#c"                                 */
/*      plx_parms  will contain  "?d"                                 */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_parse_url()
{
x_log("\nx_parse_url();");
    if (plx_page == '' && plx_anchor == '' && plx_parms == '')
    {
x_log("\n         location: '" + location          + "'.");
x_log("\n    location.href: '" + location.href     + "'.");
x_log("\nlocation.pathname: '" + location.pathname + "'.");
x_log("\n    location.hash: '" + location.hash     + "'.");
x_log("\n  location.search: '" + location.search   + "'.");

        var pathname  = new String(location.href);
        var poundsign = location.href.lastIndexOf('#');
        var ques_mark = location.href.lastIndexOf('?');
x_log("\n        poundsign: '" + poundsign         + "'.");
x_log("\n        ques_mark: '" + ques_mark         + "'.");

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                    Get plx_anchor and plx_parms                    */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
        if (poundsign > -1 || ques_mark > -1)
        {
            if (poundsign > -1 && ques_mark > -1)
            {
                if (ques_mark > poundsign)
                {
                    pathname   = location.href.substring(0, poundsign);
                    plx_anchor = location.href.substring(poundsign, ques_mark);
                    plx_parms  = location.href.substr(ques_mark);
                }
                else
                {
                    pathname   = location.href.substring(0, ques_mark);
                    plx_parms  = location.href.substring(ques_mark, poundsign);
                    plx_anchor = location.href.substr(poundsign);
                }
            }
            else if (poundsign > -1)
            {
                pathname   = location.href.substring(0, poundsign);
                plx_anchor = location.href.substr(poundsign);
            }
            else
            {
                pathname   = location.href.substring(0, ques_mark);
                plx_parms  = location.href.substr(ques_mark);
            }
        }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                            Get plx_page                            */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
        pathname      = pathname.replace(/\\/g, "/");
        var backslash = pathname.lastIndexOf('/');
        plx_page      = pathname.substr(backslash + 1);
        if (plx_page == "") plx_page = "index.htm";

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                          Log the results                           */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// alert("\nplx_page: '"   + plx_page + "'."
//     + "\nplx_anchor: '" + plx_anchor + "'."
//     + "\nplx_parms: '"  + plx_parms + "'.");
x_log("\n  plx_page: '" + plx_page + "'.");
x_log("\nplx_anchor: '" + plx_anchor + "'.");
x_log("\n plx_parms: '" + plx_parms + "'.");
    }
}

/*--------------------------------------------------------------------*/
/*                         x_peek() function                          */
/*--------------------------------------------------------------------*/
function x_peek()
{
    open_url = new String('');
    open_window_name = new String('plx_peek_window');
    width  = window.screen.width  - 100;
    height = window.screen.height - 150;
    open_window_features = new String("scrollbars=yes,menubar=no,"
        + "resizable=yes,toolbar=no,"
        + "left=25, top=25, width=" + width + ", height=" + height);
    if (!plx_peek_window || plx_peek_window.closed)
    {
        plx_peek_window = window.open(open_url,
            open_window_name, open_window_features);
    }
    setTimeout('x_peek_fill()', 500);
}

/*--------------------------------------------------------------------*/
/*                       x_peek_fill() function                       */
/*--------------------------------------------------------------------*/
function x_peek_fill()
{
    x_log_all();
    var safe_log = new String(plx_log);
    safe_log = new String(safe_log.replace(/&/g, '&amp;'));
    safe_log = new String(safe_log.replace(/</g, '&lt;'));
    plx_peek_window.document.write('<PRE>' + safe_log + '</PRE>');
}

/*--------------------------------------------------------------------*/
/*                         x_popup() function                         */
/*                                                                    */
/*      Width and height are given in pixels or, if either is 1       */
/* or less, a percentage of the screen width or height.               */
/*                                                                    */
/*      If you want your link to look like a link (i. e. underlined   */
/* and in blue), code:                                                */
/*                                                                    */
/*      <a href="javascript:x_popup('www.google.com');">              */
/*      Popup Google!</a>                                             */
/*                                                                    */
/*      If you want your link to look like normal text where the only */
/* indication that it's a link is the fact that the pointer turns     */
/* into a hand, code:                                                 */
/*                                                                    */
/*      <span onClick="x_popup('www.google.com'">                     */
/*      Popup Google!</span>                                          */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_popup(a_url, a_name, a_width, a_height, a_features, a_content)
{
    var url      = a_url;
    var name     = a_name;
    var width    = a_width;
    var height   = a_height;
    var features = a_features;
    var content  = a_content;
    var left     = 0;
    var top      = 0;
    var result   = new String();

//alert("screen.availWidth  = '" + screen.availWidth  + "',"
//  + "\nscreen.availHeight = '" + screen.availHeight + "'.");
    if (typeof a_url == 'undefined') url = '';
    if (typeof a_name == 'undefined' || a_name == '')
    {
        name = 'plx_popup_' + plx_popup_number++;
//        name = 'plx_popup';
    }

    if (typeof a_width == 'undefined' || a_width == 0) width = .9;
    if (width <= 1.0)
    {
        width = Math.floor(screen.availWidth * width);
    }
    else if (width > screen.availWidth - 100)
    {
        width = screen.availWidth - 100;
    }
    left = Math.floor((screen.availWidth  - width) / 2);

    if (typeof a_height == 'undefined' || a_height == 0) height = .8;
    if (height <= 1.0)
    {
        height = Math.floor( screen.availHeight * height);
    }
    else if (height > screen.availHeight - 100)
    {
        height = screen.availHeight - 100;
    }
    top = Math.floor((screen.availHeight - height) / 2);

    if (typeof a_features == 'undefined' || a_features == '')
    {
        features = new String
        (
              "scrollbars=yes, menubar=no,"
            + "resizable=yes, toolbar=no, "
            + "left=" + left + ", top=" + top + ", "
            + "width=" + width + ", height=" + height
        );
    }
    if (typeof a_content == 'undefined') content = '';

// alert("x_popup('" + a_url + "', '" + a_name + "', "
//     + a_width + ", " + a_height + ", '" + a_features + "');"
//     + '\n\n... returning window.open("' + url
//     + '", "' + name + '", "' + features + '");');

    result = window.open(url, name, features);
    if (content)
    {
        result.document.write(content);
    }
    result.focus();
//  return result;                  // this sometimes caused the current
                                      // window in IE6 to say "[object]"
    return;
}

/*--------------------------------------------------------------------*/
/*                       x_raisecap() function                        */
/*--------------------------------------------------------------------*/
function x_raisecap(a_letter)
{
    var result = "<span style='font-size: 280%; line-height: .9;'>"
        + a_letter + "</span>";
// alert(result);
    return result;
}

/*--------------------------------------------------------------------*/
/*                       x_sing_plur() function                       */
/*--------------------------------------------------------------------*/
function x_sing_plur(a_integer, a_singular, a_plural)
{
x_log("\nx_sing_plur(" + a_integer + ", \"" + a_singular + "\", \"" + a_plural + "\");");
    if (a_integer == 1) return a_singular;
    return a_plural;
}

/*--------------------------------------------------------------------*/
/*                         x_site() function                          */
/*--------------------------------------------------------------------*/
function x_site()
{
    if (typeof plx_site != 'undefined') return plx_site;
    plx_site = '[unknown]';
    loc = new String(location.href);
    if (location.protocol == 'file:')
    {
        if (loc.indexOf('/CRK/') > -1)
        {
            plx_site = new String("CRK");
        }
        else if (loc.indexOf('/DHD/') > -1)
        {
            plx_site = new String("DHD");
        }
        else if (loc.indexOf('/ESR/') > -1)
        {
            plx_site = new String("ESR");
        }
        else if (loc.indexOf('/NSC/') > -1)
        {
            plx_site = new String("NSC");
        }
        else if (loc.indexOf('/PRC/') > -1)
        {
            plx_site = new String("PRC");
        }
    }
    else if (location.protocol == 'http:')
    {
        if (location.href.indexOf('charlesrknight.com') > -1)
        {
            plx_site = new String("CRK");
        }
        else if ((location.href.indexOf('hannotte.com') > -1)
             ||  (location.href.indexOf('hannotte.org') > -1)
             ||  (location.href.indexOf('hannotte.net') > -1)
             ||  (location.href.indexOf('deanhannotte.com') > -1)
             ||  (location.href.indexOf('dean-hannotte.com') > -1))
        {
            plx_site = new String("DHD");
        }
        else if (location.href.indexOf('eserver.org') > -1)
        {
            plx_site = new String("PRC");
        }
        else if (location.href.indexOf('geocities.com') > -1)
        {
            if (location.pathname.substr(0, 10) == '/dhannotte'
            ||  location.pathname.substr(0, 23) == '/SiliconValley/Lab/1783')
            {
                plx_site = new String("DHD");
            }
            else if (location.pathname.substr(0,  9) == '/nscenter'
                 ||  location.pathname.substr(0, 19) == '/Athens/Delphi/5179')
            {
                plx_site = new String("NSC");
            }
        }
        else if (location.href.indexOf('rosenfels.org') > -1
             ||  location.href.indexOf('paulrosenfels.org') > -1
             ||  location.href.indexOf('paul-rosenfels.org') > -1
             ||  location.href.indexOf('ninthstreetcenter.org/4') > -1)
        {
            plx_site = new String("PRC");
        }
        else if (location.href.indexOf('ninthstreetcenter.org') > -1)
        {
            plx_site = new String("NSC");
        }
    }
x_log("\nx_site() => '" + plx_site + "'.");
    return plx_site;
}

/*--------------------------------------------------------------------*/
/*                       x_snapshot() function                        */
/*--------------------------------------------------------------------*/
// WARNING: Using '-center' in snapshots embedded in table cells
//          causes width instability, so use '-noalign' instead.
function x_snapshot
(
    a_imgsrc, a_resize, a_parms, a_caption
)
{
    var result = new String();
x_log("\nX _ S N A P S H O T ( ) -------------------------------------------------");
x_log("\nx_snapshot('" + a_imgsrc + "', '" + a_resize + "', '" + a_parms + "', '" + a_caption + "');");
    if (typeof a_imgsrc == 'undefined')
    {
        return x_error("Image source parameter missing in call to x_snapshot().");
    }
    var imgsrc = new String(a_imgsrc);
    if (imgsrc.substr(0, 7) != "http://"
    &&  imgsrc.substr(0, 1) != "/"
    &&  typeof plx_snapshot_img_dir != 'undefined')
    {
x_log("\nPrefixing '" + plx_snapshot_img_dir + "/' to '" + imgsrc + "'.");
        imgsrc = plx_snapshot_img_dir + "/" + imgsrc;
x_log("\nimgsrc = '" + imgsrc + "'.");
    }
// apostrophes break the 'onclick' handler specification when resize != 0:
    if (imgsrc.indexOf("'") > -1)
    {
        return x_error("Apostrophe in x_snapshot() image "
            + "source parameter is illegal: '" + a_imgsrc + "'.");
    }
    x_parse_imgsrc(imgsrc);
    var caption = new String(plx_parse_imgsrc_caption);
    var width   = plx_parse_imgsrc_width;
    var height  = plx_parse_imgsrc_height;
    var type    = new String(plx_parse_imgsrc_type);

// x_log("\ncaption: '" + caption + "', width: " + width + ", height: " + height + ", type: '" + type + "'.");

// Allow caption in filename to be overriden:
    if (x_is_not_empty(a_caption))
    {
x_log("\nOverriding caption '" +   caption + "'"
    + "\n              with '" + a_caption + "'");
        caption = new String(a_caption);
    }

// Disallow breaks except where explicit <sbr> tags appear:
//     caption = x_soft_breaks(caption);

    var alt   = new String();
    var title = new String();

// Reduce the image if requested:
    var resize = 1.0, resized_width = width, resized_height = height;
x_log("\nresize: " + resize + ", resized_width: " + resized_width + ", resized_height: " + resized_height);
    if (x_is_not_empty(a_resize))
    {
        resize = a_resize;
        if (typeof resize == 'string')
        {
            if (resize.substr(0, 1) == 'x')
            {
                resized_height = resize.substr(1);
                resized_width = Math.floor(width * resized_height / height);
            }
            else if (resize.substr(resize.length - 1, 1) == '%')
            {               // can be a percent of document.body.clientWidth
                resize         = resize.substr(0, resize.length - 1) / 100;
                resized_width  = Math.floor(document.body.clientWidth * resize);
                resized_height = Math.floor(resized_width * height / width);
            }
            else
            {
                return x_error("Invalid width in call to x_snapshot(): '"
                    + resize + "' -- when in apostrophes it "
                    + "must begin with 'x' or end in '%'.");
            }
        }
        else
        {
            if (resize <= 1.0)                              // or a fraction
            {
                resized_width  = Math.floor(width  * resize);
                resized_height = Math.floor(height * resize);
            }
            if (resize > 1.0)               // or a width override in pixels
            {
                resized_width  = resize;
                resized_height = Math.floor(resize * height / width);
            }
        }

// but don't enlarge the image:
        if (resized_width > width || resized_height > height)
        {
            resized_width  = width;
            resized_height = height;
        }
    }
x_log("\nresize: " + resize + ", resized_width: " + resized_width + ", resized_height: " + resized_height);

// Using 'align=' in <table> is deprecated. In fact, Firefox will ignore
// 'align=center' in <table> if you also use 'style='. So to center
// tables using CSS, use 'margin-left: auto; margin-right: auto;' in
// 'style=' instead of 'align=center' in <table>.

// Extract parms from the a_parms parameter.
//
//
    var align_flag = x_get_parm
    (
        a_parms,
        ['-left', '-right', '-center', '-noalign', '-alternate'],
        '-alternate'
    );
    var caption_flag = x_get_parm(a_parms, ['-caption', '-nocaption'], '-caption');
    var help_flag    = x_get_parm(a_parms, ['-help'   , '-nohelp'   ], '-help'   );
    var win_flag     = x_get_parm(a_parms, ['-oldwin' , '-newwin'   ], '-oldwin' );
x_log("\nalign_flag: '" + align_flag + "', caption_flag: '" + caption_flag + "', help_flag: '" + help_flag + "', win_flag: '" + win_flag + "'");

// Respect '-nocaption' unless there was an explicit caption parameter:
    if (caption_flag == '-nocaption' && x_is_empty(a_caption))
    {
        caption = '';
    }

// Convert "caption codes" in filename to HTML:
    caption = x_expand_caption_codes(caption);

    var margin   = new String('');
    var border   = new String('');
    var style    = new String('');
    var handlers = new String('');
    var popup    = new String('');

// Convert align_flag to align_parm:
    var align_parm = '';
    if (align_flag == '-left' ) align_parm = 'align=left ';
    else if (align_flag == '-right') align_parm = 'align=right ';
    else if (align_flag == '-center' && x_browser() == 'IE')
    {
        align_parm = 'align=center ';
    }
    else if (align_flag == '-alternate')
    {
x_log("\nplx_snapshot_next_align_flag: '" + plx_snapshot_next_align_flag + "'");
        if (plx_snapshot_next_align_flag == '-right')
        {
            align_parm = 'align=right ';
        }
        else
        {
            align_parm = 'align=left ';
        }
    }
x_log("\nalign_parm: '" + align_parm + "'");

// Derive margins and next align flag from align_parm:
    var margin_top    = plx_snapshot_frame_width;
    var margin_bottom = plx_snapshot_frame_width;
    var margin_left   = plx_snapshot_frame_width;
    var margin_right  = plx_snapshot_frame_width;
    if (align_flag == '-center')
    {
        margin_left   = 'auto';
        margin_right  = 'auto';
    }
    var hspace = 12;
    if (align_parm == 'align=left ')
    {
        margin_right += hspace;
        x_snapshot_next_align_flag('-right');
x_log("\nplx_snapshot_next_align_flag: '" + plx_snapshot_next_align_flag + "'")
    }
    if (align_parm == 'align=right ')
    {
        margin_left += hspace;
        x_snapshot_next_align_flag('-left');
x_log("\nplx_snapshot_next_align_flag: '" + plx_snapshot_next_align_flag + "'")
    }

    margin = "margin-top: "    + margin_top    + ";"
          + " margin-bottom: " + margin_bottom + ";"
          + " margin-left: "   + margin_left   + ";"
          + " margin-right: "  + margin_right  + ";";

    var border_width = plx_snapshot_frame_width;
    var border_style = 'solid';
    var border_color = plx_snapshot_frame_color;

    border = "border-width: " + border_width + ";"
          + " border-style: " + border_style + ";"
          + " border-color: " + border_color + ";";

    style = margin + " " + border;

// Should the image link to its fullsize version?
    var percent = Math.floor(100 * width / resized_width);
    if (percent != 100)
    {
        style += " cursor: pointer;";

        handlers += "\n onmouseover='";
        if (align_flag != '-center')
        {
            handlers +=
                  "this.style.marginLeft"   + " = " + (margin_left   - plx_snapshot_frame_width) + "; "
                + "this.style.marginRight"  + " = " + (margin_right  - plx_snapshot_frame_width) + "; ";
        }
        handlers +=
              "this.style.marginTop"    + " = " + (margin_top    - plx_snapshot_frame_width) + "; "
            + "this.style.marginBottom" + " = " + (margin_bottom - plx_snapshot_frame_width) + "; "
            + "this.style.borderWidth"  + " = " + (border_width  + plx_snapshot_frame_width) + ";'";

        handlers += "\n onmouseout='";
        if (align_flag != '-center')
        {
            handlers +=
                  "this.style.marginLeft"   + " = " + margin_left   + "; "
                + "this.style.marginRight"  + " = " + margin_right  + "; ";
        }
        handlers +=
              "this.style.marginTop"    + " = " + margin_top    + "; "
            + "this.style.marginBottom" + " = " + margin_bottom + "; "
            + "this.style.borderWidth"  + " = " + border_width  + ";'";

        if (win_flag == '-newwin')
        {
            var title = new String(caption.replace(/<br>/gi, " "));

            popup = "<html><head><title>" + title + "</title></head><body>"
                + "<table width=\\\"100%\\\" height=\\\"100%\\\">"
                + "<tr><td align=\\\"center\\\" valign=\\\"middle\\\">"
                + "<img src=\\\"" + imgsrc + "\\\">"
                + "<br><font face=\\\"Verdana\\\"><big><b>"
                + title + "</b></big></font></td></tr></table></body></html>";

            handlers += "\n onclick='x_popup(\"\", \"\", "
                     + Math.floor(resized_width  + 50) + ", "
                     + Math.floor(resized_height + 60) + ", \"\", \""
                     + popup + "\");'";
        }
        else
        {
            handlers += "\n onclick='";
            if (align_flag != '-center')
            {
                handlers +=
                      "this.style.marginLeft"   + " = " + margin_left   + "; "
                    + "this.style.marginRight"  + " = " + margin_right  + "; ";
            }
            handlers +=
                  "this.style.marginTop"    + " = " + margin_top    + "; "
                + "this.style.marginBottom" + " = " + margin_bottom + "; "
                + "this.style.borderWidth"  + " = " + border_width  + "; ";
            handlers += "location=\"" + imgsrc + "\";'";
        }

        if (help_flag == '-help')
        {
            if (alt != '')
            {
                alt += "\n(Click to enlarge " + percent + "%)";
            }
            else
            {
                alt = "Click to enlarge " + percent + "%";
            }
            title = alt;
        }
    }

    style = "\n style='" + style + "'";

    if (caption != '')
    {
        caption = "\n<table width='100%' cellspacing=0 cellpadding=4>"
            + "<tr><td align=center style='"
            + plx_snapshot_frame_caption_style + "'>"
            + caption;
//         if (percent != 100)
//         {
//             caption += "<br><img border=0 "
//                 + "src='pix/magnify_28x16.gif'>Enlarge";
//             caption += "<br><img src='pix/magnify_28x16.gif' "
//                 + "border=0>Click to enlarge " + percent + "%";
//         }
        caption += "</td></tr></table>";
    }

    result = "<table border=00 cellpadding=0 cellspacing=0 "
        + "bgcolor='" + plx_snapshot_frame_color + "' "
        + align_parm
        + "width=" + resized_width
        + style
        + handlers + ">"
        + "\n<tr><td align='center'>"

        + "\n<img src=\""    + imgsrc         + "\""
        + "\n width="        + resized_width
        + " height="         + resized_height
        + " alt=\""          + alt            + "\""
        + " title=\""        + title          + "\">"

        + caption
        + "\n</td></tr>"
        + "</table>";

x_log("\n" + result);
x_log("\n------------------------------------------------- X _ S N A P S H O T ( )");

// Don't squeeze out the newlines because we
// need the newline(s) in the <img> title= parm:
//    result = result.replace(/\n/g, '');
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_soft_breaks() function                      */
/*                                                                    */
/*      This function implements the "soft break" (<sbr>) tag.        */
/*                                                                    */
/*      1) Convert all blanks to non-breaking space characters.       */
/*      2) Convert all "<sbr>" tags to blanks.                        */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_soft_breaks(a_html)
{
    var result = a_html;
    var lower_case_html = a_html.toLowerCase();
    if (lower_case_html.indexOf('<sbr>') > -1)
    {
        result = result.replace(/ /g, "&nbsp;");
        result = result.replace(/-/g, "&minus;");
        result = result.replace(/<sbr>/gi, " ");
x_log("\nx_soft_breaks(\"" + a_html + "\")\n => \"" + result + "\"");
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*            x_sort_table_selection_by_column() function             */
/*                                                                    */
/*     a_table is an array (table) of arrays (rows), equivalent       */
/*             in structure to an SQL table.                          */
/*                                                                    */
/*      a_rows is an array of indexes into the table where            */
/*             the rows to be included in the sort start.             */
/*             Thus this function doesn't need to                     */
/*             know how many cells each row contains.                 */
/*             This is the equivalent of the results of a SQL         */
/*             SELECT statement.                                      */
/*                                                                    */
/*      a_col  is an index into each row in which the sort            */
/*             key starts. This is the equivalent of a SORT           */
/*             BY parameter.                                          */
/*                                                                    */
/*          This function returns array of indexes into the           */
/*           table, sorted according to the caller's wishes.          */
/*           This is the equivalent of the results of a SQL           */
/*                         SELECT statement.                          */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_sort_table_selection_by_column(a_table, a_rows, a_col)
{
x_log("\nx_sort_table_selection_by_column(table of " + a_table.length
 + " cells, " + a_rows.length + " rows, column: " + a_col + ");");
    var total_passes = 0;
    var total_flips = 0;
    var finished = false;
    while (finished == false && total_passes < 1000)
    {
        total_passes++;
// x_log("\n Pass " + total_passes);
        var val1, val2;
        var ax1 = 0;
        var ax2 = 1;
        var flipped_on_this_pass = false;
        while (ax2 < a_rows.length && total_flips < 1000)
        {
            val1 = pagetree[a_rows[ax1] + a_col];
            val2 = pagetree[a_rows[ax2] + a_col];
            if (val1 > val2)
            {
                flipped_on_this_pass = true;
                total_flips++;
// x_log("\n  Putting '" + val1 + "'"
//     + "\n    after '" + val2 + "'.");
                var save_ax = a_rows[ax1];
                a_rows[ax1] = a_rows[ax2];
                a_rows[ax2] = save_ax;
            }
            ax1++;
            ax2++;
        }
        if (flipped_on_this_pass == false) finished = true;
    }
x_log("\n ... passes: " + total_passes + ", flips: " + total_flips + ".");
    return a_rows;
}

/*--------------------------------------------------------------------*/
/*                x_timeslot_as_date_object() function                */
/*--------------------------------------------------------------------*/
function x_timeslot_as_date_object(a_timeslot)
{
var msg = "x_timeslot_as_date_object('" + a_timeslot + "')";
    var pieces = a_timeslot.split('-');
    var yyyymmdd  = pieces[0];
    var hhmm_from = pieces[1];
msg += "\n => ('" + yyyymmdd + "', '" + hhmm_from + "')";
    var yyyy = yyyymmdd.substr(0, 4);
    var mm   = yyyymmdd.substr(4, 2);
    var dd   = yyyymmdd.substr(6, 2);
msg += "\n => " + mm + "/" + dd + "/" + yyyy;
    var hh   = 0;
    var mi   = 0;
    var ss   = 0;
    if (x_is_not_empty(hhmm_from))
    {
        hh = hhmm_from.substr(0, 2);
        if (hhmm_from.length > 2) mi = hhmm_from.substr(2, 2);
        if (hhmm_from.length > 4) ss = hhmm_from.substr(4, 2);
    }
msg += " " + hh + ":" + mi + ":" + ss;
    var result = new Date(yyyy, mm - 1, dd, hh, mi, ss);
msg += "\n => '" + result + "'.";
// alert(msg);
    return result;
}

/*--------------------------------------------------------------------*/
/*                          x_top() function                          */
/*--------------------------------------------------------------------*/
function x_top(obj)
{
    var result = 0;
    while (obj.offsetParent)
    {
        result += obj.offsetTop
        obj = obj.offsetParent;
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*                     x_use_resource() function                      */
/*--------------------------------------------------------------------*/
function x_use_resource(a_resource)
{
    plx_resources_used.push(a_resource);
}

/*--------------------------------------------------------------------*/
/*                      x_wide_screen() function                      */
/*--------------------------------------------------------------------*/
function x_wide_screen()
{
    if (x_window_width() > 800) return true;
    return false;
}

/*--------------------------------------------------------------------*/
/*                     x_window_height() function                     */
/*--------------------------------------------------------------------*/
function x_window_height()
{
    if (x_os() != 'Windows') return 600;
    if (x_browser() != 'IE') return 600;
    return document.body.clientHeight;
}

/*--------------------------------------------------------------------*/
/*                     x_window_width() function                      */
/*--------------------------------------------------------------------*/
function x_window_width()
{
//     if (x_os()     != 'Windows') return 800;
//     if (x_browser()     != 'IE') return 800;
//     if (x_browser_version() < 5) return 800;
//     if (x_html()            < 4) return 800;
    return document.body.clientWidth;
}

/*--------------------------------------------------------------------*/
/*                          x_wiki() function                         */
/*                                                                    */
/*    NOTE: a_article should have underscores instead of spaces       */
/*          to prevent invalid breaks in Javascript strings.          */
/*--------------------------------------------------------------------*/
function x_wiki(a_article, a_display)
{
    var article = new String(a_article);
    var display = new String(a_display);
    var result  = new String("");
    if (typeof a_display == 'undefined') display = article;
    display = display.replace(/_/g, " ");
    result = "<a href='http://en.wikipedia.org/wiki/"
         + article + "'><b><i>" + display + "</i></b></a>";
x_log("\nx_wiki('" + a_article + "', '" + a_display + "')\n => '" + result + "'");
    return result;
}

/*--------------------------------------------------------------------*/
/*                         x_yyyy() function                          */
/*--------------------------------------------------------------------*/
function x_yyyy()
{
    var now = new Date();
    return now.getFullYear();
}

/*--------------------------------------------------------------------*/
/*                       x_yyyymmdd() function                        */
/*--------------------------------------------------------------------*/
function x_yyyymmdd(a_plus_or_minus)
{
x_log("\nx_yyyymmdd(" + a_plus_or_minus + ");");
    var when = new Date();
    if (typeof a_plus_or_minus != 'undefined')
    {
        when.setDate(when.getDate() + a_plus_or_minus);
    }
    var yyyy = new String(when.getFullYear());
    var mm   = new String(when.getMonth() + 1);
    var dd   = new String(when.getDate());
// x_log("\nyyyy: '" + yyyy + "'");
// x_log("\n  mm: '" + mm + "'");
// x_log("\n  dd: '" + dd + "'");
// x_log("\n  mm.length: '" + mm.length + "'");
// x_log("\n  dd.length: '" + dd.length + "'");
    if (mm.length == 1) mm = '0' + mm;
    if (dd.length == 1) dd = '0' + dd;
    var result = '' + yyyy + mm + dd;
x_log("\n ... returning '" + result + "'");
    return result;
}

/*--------------------------------------------------------------------*/
/*                        x_hhmmss() function                         */
/*--------------------------------------------------------------------*/
function x_hhmmss()
{
    var now = new Date();
    var hh = now.getHours()  ; if (hh.length == 1) hh = '0' + hh;
    var mm = now.getMinutes(); if (mm.length == 1) mm = '0' + mm;
    var ss = now.getSeconds(); if (ss.length == 1) dd = '0' + dd;
    var result = new String(hh + mm + ss);
    return result;
}

/*--------------------------------------------------------------------*/
/*                       x_hh_mm_ss() function                        */
/*--------------------------------------------------------------------*/
function x_hh_mm_ss(a_delim)
{
    var delim = ':';
    if (typeof a_delim != 'undefined') delim = a_delim;
    var now = new Date();
    var hh = now.getHours()  ; if (hh.length == 1) hh = '0' + hh;
    var mm = now.getMinutes(); if (mm.length == 1) mm = '0' + mm;
    var ss = now.getSeconds(); if (ss.length == 1) dd = '0' + dd;
    var result = new String(hh + delim + mm + delim + ss);
    return result;
}

/**********************************************************************/
/*                               E N D                                */
/**********************************************************************/

// Left quote:
// <td
// style="padding: 10px; color: rgb(178, 183, 242); font-size: 40px; font-family: serif; font-weight: bold; text-align: left;"
// valign="top" width="20">“</td>
//
// Right quote:
//<td
// style="padding: 10px; color: rgb(178, 183, 242); font-size: 40px; font-family: serif; font-weight: bold; text-align: right;"
// valign="bottom" width="20">”</td>

