var JS_PLX = "D:\\dh\\web\\DHD\\3\\HTM\\plx.js (1852 lines) 2007-09-14 05:24 Dean Hannotte";
/**********************************************************************/
/*                                                                    */
/*               Programming Language eXtensions (PLX)                */
/*               -------------------------------------                */
/*                                                                    */
/*                    (c) 1999-2007 Dean Hannotte                     */
/*                                                                    */
/**********************************************************************/
// alert(JS_PLX);
/*                                                                    */
/*      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_get_parm_prefix = '-';
// var plx_get_parm_delim  = ':';
var plx_hover_style     = new String("color: black; "
                        + "background-color: white; "
                        + "border: black 1 solid;");  // see x_hover_*()
var plx_hover_width     = 320;                        // see x_hover_*()
var plx_link_icon = new String('');                      // see x_link()
var plx_snapshot_border_out = new String('white');   // see x_snapshot()
var plx_snapshot_border_over = new String('white');  // see x_snapshot()
var plx_snapshot_icon;                               // see x_snapshot()
var plx_snapshot_img_dir;                            // see x_snapshot()
var plx_snapshot_next_align_flag = new String('');   // see x_snapshot()

/*                                                                    */
/*                         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_get_parm_prefix(a_new_val) {var old_val = plx_get_parm_prefix; plx_get_parm_prefix = a_new_val; return old_val;}
// function x_get_parm_delim(a_new_val) {var old_val = plx_get_parm_delim; plx_get_parm_delim = 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_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;}
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;}

/*                                                                    */
/*     Global variables that are used internally by this library      */
/*                                                                    */
var plx_log;                                              // 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()

/*                                                                    */
/*                  Global variables that are set by                  */
/*                 similarly named 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();

// Create a division 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) "

// This works only if the filetype is 'shtml':
//var plx_remote_addr = '<!--#echo var="REMOTE_ADDR"-->';

x_log("JS_PLX = '" + JS_PLX + "'.");

/*--------------------------------------------------------------------*/
/*                            $() function                            */
/*                     (taken from 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 (typeof a_label != 'undefined' && a_label != '') label = a_label;
    if (value == "")
    {
        return x_error(a_object, "Please enter " + label + ".");
    }
    if (value.indexOf("@") == -1)
    {
        if (!confirm(question + "no at sign ('@') in it?"))
        {
            return x_error(a_object);
        }
    }
    if (value.indexOf(".") == -1)
    {
        if (!confirm(question + "no period ('.') in it?"))
        {
            return x_error(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(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(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 (typeof a_label != 'undefined' && 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(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(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(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(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_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() == "Ninth Street Center")
            {
                plx_email = new String(x_yyyy() + '@ninthstreetcenter.org');
            }
            else if (x_site() == "Dean's Dean")
            {
                plx_email = new String(x_yyyy() + '@hannotte.net');
            }
            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 (typeof a_domain != 'undefined' && a_domain != '') domain = a_domain;
    var e_addr = a_mailbox + "@" + domain;
    var name   = new String(e_addr);
    var parms  = new String('');
    if (typeof a_name  != 'undefined' && a_name  != '') name  = a_name;
    if (typeof a_parms != 'undefined' && a_parms != '') parms = '?' + a_parms;
    var result = "<a href='mailto:" + e_addr + parms + "'>"
        + "<b>" + name + "</b>"
//      + "<img border=0 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_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 != '') alert(a_message);
    }
    return true;
}

/*--------------------------------------------------------------------*/
/*                       x_get_parm() function                        */
/*--------------------------------------------------------------------*/
function x_get_parm(a_parms, a_keyword, a_default)
{
if (plx_get_parm_debug) alert("x_get_parm('" + a_parms + "', '" + a_keyword + "', '" + a_default + "');");
// Can't use $ in a character class, otherwise we could use [ $] as the
// ending delimiter. Pad the parm string instead and look for blanks.
    var parms = new String('  ');
    if (typeof a_parms != 'undefined') parms = ' ' + a_parms + ' ';
// if (plx_get_parm_debug) alert("parms: '" + parms + "'");
//    var default = false; <-- invalid variable name!
    var deflt = false;
    if (typeof a_default != 'undefined') deflt = a_default;
    var regex, result;
// if (plx_get_parm_debug && typeof a_keyword == 'string') alert("keys is typeof 'string'.");
// if (plx_get_parm_debug && a_keyword instanceof String ) alert("keys instanceof String.");
// if (plx_get_parm_debug && a_keyword instanceof Array  ) alert("keys instanceof Array.");
    if (typeof a_keyword == 'string')
    {
//         regex = new RegExp(' '
//             + plx_get_parm_prefix + a_keyword
//             + plx_get_parm_delim + '(.*) ');
        regex = new RegExp(' ' + a_keyword + '(.*) ');
// if (plx_get_parm_debug) alert("regex: '" + regex + "'");
        var match = regex.exec(parms);
//         match = parms.match(regex);
        if (match != null)
        {
            result = match[1];
if (plx_get_parm_debug) alert("match.input: '" + match.input + "'"
  + "\nmatch.index: '" + match.index + "'"
  + "\nmatch[0]: '"    + match[0]    + "'"
  + "\nmatch[1]: '"    + match[1]    + "'"
  + "\nmatch[2]: '"    + match[2]    + "'"
  + "\nmatch[3]: '"    + match[3]    + "'"
  + "\nmatch[4]: '"    + match[4]    + "'"
  + "\nmatch[5]: '"    + match[5]    + "'"
  + "\nmatch[6]: '"    + match[6]    + "'"
  + "\nmatch[7]: '"    + match[7]    + "'"
  + "\nmatch[8]: '"    + match[8]    + "'"
  + "\nmatch[9]: '"    + match[9]    + "'");
        }
    }
    else if (a_keyword instanceof Array)
    {
        var kx;
        result = null;
        for (kx = 0; kx < a_keyword.length; kx++)
        {
//             regex = ' ' + plx_get_parm_prefix + a_keyword[kx] + ' ';
            regex = ' ' + a_keyword[kx] + ' ';
// if (plx_get_parm_debug) alert("regex: '" + regex + "'");
            if (parms.indexOf(regex) > -1)
            {
                result = a_keyword[kx];
                break;
            }
        }
    }
    else
    {
        result = "get_parm('" + a_parms + "', '" + a_keyword
            + "', '" + a_deflt + "') error:"
            + "\n\nKeyword is neither a string nor an Array().";
        alert(result);
    }
    if (result == null)
    {
        result = deflt;
if (plx_get_parm_debug) alert("... not found, defaults to '" + deflt + "'.");
    }
    else
    {
if (plx_get_parm_debug) alert("result: '" + 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: 1px 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: 1px 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_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 (typeof a_target != 'undefined' && a_target != '')
    {
        result += " target='" + target + "'";
    }
    if (typeof a_href != 'undefined' && a_href != '')
    {
        result += " href=\"" + href + "\"";
    }
    result += " title=\"" + title + "\"";
    if (typeof a_title != 'undefined' && a_title != '')
    {
        result += " style='border-bottom: 1px 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_log() function                          */
/*--------------------------------------------------------------------*/
function x_log(a_message)
{
    if (typeof plx_log == 'undefined')
    {
        plx_log = new String('');
    }
    plx_log += 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.host: \"" + location.host              + '" (' + typeof location.host              + ')'
      + "\n             location.href: \"" + location.href              + '" (' + typeof location.href              + ')'
      + "\n         location.pathname: \"" + location.pathname          + '" (' + 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_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_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_yyyy(): \"" + x_yyyy()                   + '" (' + 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_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(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(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(a_object, a_label + " is not an Javascript object.");
}

/*--------------------------------------------------------------------*/
/*                     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(a_object, "Please select " + a_label + ".");
    }
    return false;
}

var x_ordered_rows_order          = 0;              // default order
var x_ordered_rows_sequence       = 'ascending'; // default sequence
var x_ordered_rows_prior_order    = 0;
var x_ordered_rows_prior_sequence = '';
var x_ordered_rows_headers        = new Array();
var x_ordered_rows_data           = new Array();
var x_ordered_rows_id             = new String('x_ordered_rows_id');

/*--------------------------------------------------------------------*/
/*                      x_ordered_rows() function                     */
/*--------------------------------------------------------------------*/
// Only the first operand is used on recursive calls.
function x_ordered_rows(a_order, a_sequence, a_id, a_data)
{
    var comment = new String("x_ordered_rows(" + a_order
       + ", '" + a_sequence                     + "'"
       + ", '" + a_id                           + "'"
       + ", '" + typeof a_data                  + "');");
// alert(comment);

//  var result = new String("\n\n<!-- " + comment + " -->");
    var result = new String();
//
// Save prior order and sequence:
//
    x_ordered_rows_prior_order    = x_ordered_rows_order;
    x_ordered_rows_prior_sequence = x_ordered_rows_sequence;
//
// Save arguments in global variables:
//
    if (typeof a_order != 'undefined')
    {
        x_ordered_rows_order = a_order;
    }
    if (typeof a_sequence != 'undefined')
    {
        if (a_sequence != 'ascending' && a_sequence != 'descending')
        {
            result = "x_ordered_rows: Sequence must be 'ascending' "
                + "or 'descending', not '" + a_sequence + "'.";
            alert(result);
            return result;
        }
        x_ordered_rows_sequence = a_sequence;
    }
    if (typeof a_data != 'undefined')
    {
        if (a_data instanceof Array)
        {
            x_ordered_rows_data    = a_data;
            x_ordered_rows_headers = x_ordered_rows_data.shift();
        }
        else
        {
            result = "x_ordered_rows: Data must be an array of arrays.";
            alert(result);
            return result;
        }
    }
    if (typeof a_id != 'undefined')
    {
        if ($(a_id) == null)
        {
            result = "x_ordered_rows: Id ('" + a_id
                + "') must be defined before call.";
            alert(result);
            return result;
        }
        x_ordered_rows_id = a_id;
    }
//
// 'Order' defaults to prior order.
//
// 'Sequence' defaults to 'ascending'
// if a new order, otherwise it flips:
//
    if (typeof a_sequence == 'undefined')
    {
        if (x_ordered_rows_order != x_ordered_rows_prior_order)
        {
            x_ordered_rows_sequence = 'ascending';
        }
        else
        {
            if (x_ordered_rows_prior_sequence == 'ascending')
            {
                x_ordered_rows_sequence = 'descending';
            }
            else
            {
                x_ordered_rows_sequence = 'ascending';
            }
        }
    }

//alert("x_ordered_rows_order = '" + x_ordered_rows_order + "',\n"
//+ "x_ordered_rows_prior_order = '" + x_ordered_rows_prior_order + "',\n"
//+ "x_ordered_rows_sequence = '" + x_ordered_rows_sequence + "',\n"
//+ "x_ordered_rows_prior_sequence = '" + x_ordered_rows_prior_sequence + "'.");

//
// Sort the data:
//
    data = x_ordered_rows_data;
    data.sort(x_ordered_rows_compare);
//
// Generate the HTML:
//
//    result += "\n<table>";
    result += "\n<tr align=center valign=bottom>";
    headers = x_ordered_rows_headers;
    for (hx = 0; hx < headers.length; hx++)
    {
        result += ("\n<td><button onclick='"
            + "x_ordered_rows(" + hx + ");"
            + "'>" + headers[hx] + "</button></td>");
    }
    result += "</tr>";
    for (dx1 = 0; dx1 < data.length; dx1++)
    {
        result += "\n<tr valign=top>";
        for (dx2 = 0; dx2 < headers.length; dx2++)
        {
            val = data[dx1][dx2];
            if (typeof val == 'undefined') val = "";
// Pad with a space to generate cell borders:
            result += ("<td>" + val + "&nbsp;</td>");
        }
        result += "</tr>";
    }
//    result += "<table>";
//
// Insert the HTML into the document element:
//
    $(x_ordered_rows_id).innerHTML = result;
//
// Return the HTML in case the user wants to put it in an alert box:
//
    return result;
}

/*--------------------------------------------------------------------*/
/*                  x_ordered_rows_compare() function                 */
/*--------------------------------------------------------------------*/
function x_ordered_rows_compare(a, b)
{
    var o = x_ordered_rows_order;
    var s = x_ordered_rows_sequence;
    if (s == 'ascending') {first = a[o]; second = b[o];}
    else                  {first = b[o]; second = a[o];}
// If a row is short, the last colums may be 'undefined'!
    if (typeof first  == 'undefined') first  = "";
    if (typeof second == 'undefined') second = "";
    first  = first.toString().toLowerCase();
    second = second.toString().toLowerCase();
    var result = 0;
    if (first < second) result = -1;
    if (first > second) result = 1;
//alert("Comparing '" + first + "' with '" + second + "' gives " + result);
    return result;
}

/*--------------------------------------------------------------------*/
/*                        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_page() function                          */
/*--------------------------------------------------------------------*/
function x_page()
{
    result = new String(location);
    if (slash = result.lastIndexOf('/')) result = result.substr(slash + 1);
    if (dot = result.indexOf('.'))       result = result.substr(0, dot);
    if (result == '')                    result = 'index';
    return result;
}

/*--------------------------------------------------------------------*/
/*                     x_parse_imgsrc() function                      */
/*--------------------------------------------------------------------*/
// substr(from, [len])
// substring(from, to)
function x_parse_imgsrc(a_src, a_debug)
{
    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 + "'.";
        alert(plx_parse_imgsrc_caption);
        return;
    }
    else
    {
        src = src.replace(/_/g, ' ');
        var dot = src.lastIndexOf('.');
        if (dot <= -1)
        {
            plx_parse_imgsrc_caption =
                "x_parse_imgsrc(): Dot missing in filename: '" + a_src + "'.";
            alert(plx_parse_imgsrc_caption);
            return;
        }
        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: '" + a_src + "'.";
                alert(plx_parse_imgsrc_caption);
                return;
            }
            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(): Space missing in filename: '" + a_src + "'.";
                    alert(plx_parse_imgsrc_caption);
                    return;
                }
                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);
                    }
                }
            }
        }
    }
    if (a_debug)
    {
        alert("x_parse_imgsrc(\"" + a_src + "\", \"" + a_debug + "\");\n"
            + "\ncaption: \"" + plx_parse_imgsrc_caption + "\""
            + "\nwidth: "     + plx_parse_imgsrc_width
            + "\nheight: "    + plx_parse_imgsrc_height
            + "\ntype: '"     + plx_parse_imgsrc_type    + "'");
    }
}

/*--------------------------------------------------------------------*/
/*                         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()
{
    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);
    if (location.protocol == 'file:')
    {
        if (loc.indexOf('/CRK/') > -1)
        {
            plx_site = new String("Charles R. Knight");
        }
        else if (loc.indexOf('/DHD/') > -1)
        {
            plx_site = new String("Dean's Den");
        }
        else if (loc.indexOf('/NSC/') > -1)
        {
            plx_site = new String("Ninth Street Center");
        }
        else if (loc.indexOf('/PRC/') > -1)
        {
            plx_site = new String("Paul Rosenfels Collection");
        }
    }
    else if (location.protocol == 'http:')
    {
             if (location.host == 'charlesrknight.com'
             ||  location.host == 'www.charlesrknight.com')
        {
            plx_site = new String("Charles R. Knight");
        }
        else if (location.host == 'hannotte.net'
             ||  location.host == 'www.hannotte.net')
        {
            plx_site = new String("Dean's Den");
        }
        else if (location.host == 'www.ninthstreetcenter.org')
        {
            plx_site = new String("Ninth Street Center");
        }
        else if (location.host == 'eserver.org'
             ||  location.host == 'www.eserver.org')
        {
            plx_site = new String("Paul Rosenfels Collection");
        }
        else if (location.host == 'geocities.com'
             ||  location.host == 'www.geocities.com')
        {
            if (location.pathname.substr(0, 10) == '/dhannotte'
            ||  location.pathname.substr(0, 23) == '/SiliconValley/Lab/1783')
            {
                plx_site = new String("Dean's Den");
            }
            else if (location.pathname.substr(0,  9) == '/nscenter'
                 ||  location.pathname.substr(0, 19) == '/Athens/Delphi/5179')
            {
                plx_site = new String("Ninth Street Center");
            }
        }
    }
//  x_log("\nx_site() => '" + plx_site + "'.");
    return plx_site;
}

/*--------------------------------------------------------------------*/
/*                       x_snapshot() function                        */
/*--------------------------------------------------------------------*/
function x_snapshot
(
    a_filespec, a_resize, a_flags, a_caption
)
{
x_log("\nx_snapshot('" + a_filespec + "', '" + a_resize + "', '" + a_flags + "', '" + a_caption + "');");
    var debug = x_get_parm(a_flags, ['-debug']);
    if (typeof a_filespec == 'undefined')
    {
        alert("Image source parameter missing in call to x_snapshot().");
        return;
    }
    var filespec = new String(a_filespec);
    if (filespec.substr(0, 7) != "http://"
    &&  filespec.substr(0, 1) != "/")
    {
x_log("\nPrefixing '" + plx_snapshot_img_dir + "/' to '" + filespec + "'.");
        filespec = plx_snapshot_img_dir + "/" + filespec;
    }
x_log("\nfilespec = '" + filespec + "'.");
// apostrophes break the 'onclick' handler specification when resize != 0:
    if (filespec.indexOf("'") > -1)
    {
        alert("Illegal apostrophe in x_snapshot() image source parameter.");
        return;
    }
    x_parse_imgsrc(filespec, debug);
    var caption = new String(plx_parse_imgsrc_caption);
    var width   = plx_parse_imgsrc_width;
    var height  = plx_parse_imgsrc_height;

x_log("\ncaption: '" + caption + "', width: '" + width + "', height: '" + height + "'");

// Allow caption in filename to be overriden:
    if (typeof a_caption != 'undefined' && a_caption != '')
    {
        caption = new String(a_caption);
    }
    else
    {

// Convert "caption codes" in filename to HTML:
        caption = caption.replace(/\[b\]/gi, "<b>");
        caption = caption.replace(/\[i\]/gi, "<i>");
        caption = caption.replace(/\[-b\]/gi, "</b>");
        caption = caption.replace(/\[-i\]/gi, "</i>");
        caption = caption.replace(/\[br\]/gi, "<br>");
        caption = caption.replace(/\[apost\]/gi, "'");
    }

// If there is at least one <BR> tag, consider all spaces and
// hyphens to be non-breaking and all break tags to be spaces:
    caption = x_soften_breaks(caption);

    var alt = new String();

// Reduce the image if requested:
    var resize = 1.0, resized_width, resized_height;
    if (typeof a_resize != 'undefined' && a_resize != '')
    {
        resize = a_resize;
    }
    if (typeof resize == 'string')
    {
        if (resize.substr(resize.length - 1, 1) == '%')      // 'resize'
        {               // can be a percent of document.body.clientWidth
            resize         = resize.substr(0, resize.length - 1);
            resized_width  = Math.floor(document.body.clientWidth * resize / 100);
            resized_height = Math.floor(resized_width * height / width);
        }
        else
        {
            alert("Invalid width: '" + resize + "'");
        }
    }
    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
+ "', document.body.clientWidth = '" + document.body.clientWidth
+ "', resized_width = '" + resized_width
+ "', resized_height = '" + resized_height);

// Examine the a_flags parameter:
    var align_flag = x_get_parm
    (
        a_flags,
        ['-left', '-right', '-center', '-noalign', '-alternate'],
        '-alternate'
    );
x_log("\nalign_flag: '" + align_flag + "', nocaption: '" + nocaption + "', nohelp: '" + nohelp + "', newwin: '" + newwin + "'");
    var nocaption = x_get_parm(a_flags, ['-nocaption']);
    var nohelp    = x_get_parm(a_flags, ['-nohelp']);
    var newwin    = x_get_parm(a_flags, ['-newwin']);

    if (nocaption) caption = '';

    var style    = new String(" border: 4px solid " + plx_snapshot_border_out + ";");
    var handlers = new String('');
    var popup    = new String('');

// Convert align_flag to align_parm:
    var align_parm = '';
    if (align_flag == '-left'     ) align_parm = 'left'  ;
    if (align_flag == '-right'    ) align_parm = 'right' ;
    if (align_flag == '-center'   ) align_parm = 'center';
    if (align_flag == '-alternate')
    {
        if (plx_snapshot_next_align_flag == '-right')
        {
            align_parm = 'right';
        }
        else
        {
            align_parm = 'left';
        }
    }
    if (align_parm == '' && align_flag != '-noalign')
    {
        align_parm = 'left';                         // 1st-time default
    }
x_log("\nalign_parm: '" + align_parm + "'");

// Derive margins and next align flag from align_parm:
    var margin_left  = 0;
    var margin_right = 0;
    if (align_parm == 'left')
    {
        margin_right = 4;
        x_snapshot_next_align_flag('-right');
    }
    if (align_parm == 'right')
    {
        margin_left = 4;
        x_snapshot_next_align_flag('-left');
    }

    style += " margin-left: "  + margin_left  + ";"
          +  " margin-right: " + margin_right + ";"

// Should the image link to its fullsize version?
    var percent = Math.floor(100 * width / resized_width);
    if (percent != 100)
    {
        style += " cursor: pointer;";

// NOTE: The DOM 'border' property must be given in 'style color size' order!
        handlers += " \n\nonmouseover='this.style.border=\"solid "
                 + plx_snapshot_border_over + " 4px;\"'"
                 + " \n\nonmouseout='this.style.border=\"solid "
                 + plx_snapshot_border_out + " 4px;\"'";

        if (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=\\\"" + filespec + "\\\">"
                + "<br><font face=\\\"Verdana\\\"><big><b>"
                + title + "</b></big></font></td></tr></table></body></html>";

            handlers += " \n\nonclick='x_popup(\"\", \"\", "
                     + Math.floor(resized_width  + 50) + ", "
                     + Math.floor(resized_height + 60) + ", \"\", \""
                     + popup + "\");'";
        }
        else
        {
            handlers += " \n\nonclick='location=\"" + filespec + "\";'";
        }

        if (!nohelp)
        {
            var modify = 'enlarge';
//             if (percent < 100) modify = 'reduce';
            if (alt != '')
            {
                alt += "\n(Click to " + modify + " " + percent + "%)";
            }
            else
            {
                alt = "Click to " + modify + " " + percent + "%";
            }
        }
    }

    if (style != '') style = " \n\nstyle='" + style + "'";

    if (caption != '') caption = "<br><small>" + caption + "</small>"

    var result = new String("<table border=00 bgcolor='" + plx_snapshot_border_over + "' "
        + "align='" + align_parm + "' width=" + resized_width + style + handlers + ">"
        + "\n<tr><td align='center'>"
        + "\n<img src=\""    + filespec       + "\""
        + "\n alt=\""        + alt            + "\""
        + "\n width="        + resized_width
        + " height="         + resized_height + ">"
        + caption
        + "</td></tr></table>");

//     if (debug)
//     {
//         x_log("\nx_snapshot('" + filespec + "', '" + a_resize
//             + "', '" + a_flags + "', '" + a_caption + "');");
        x_log("\n______________________________________\n");
        x_log("\n" + result);
        x_log("\n______________________________________\n");
//     }
// 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_soften_breaks() function                     */
/*                                                                    */
/*     If there is at least one <BR> tag, consider all spaces and     */
/*     hyphens to be non-breaking and all break tags to be spaces     */
/*--------------------------------------------------------------------*/
function x_soften_breaks(a_html)
{
    var html    = a_html;
    var uc_html = html.toUpperCase();
    var result  = html;
    if (uc_html.indexOf('<BR>') > -1)
    {
        result = result.replace(/ /g, "&nbsp;");
        result = result.replace(/-/g, "&minus;");
        result = result.replace(/<BR>/gi, " ");
x_log("\nx_soften_breaks(\"" + html + "\")\n => \"" + result + "\"");
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*                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 (typeof hhmm_from != 'undefined' && 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_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_yyyy() function                          */
/*--------------------------------------------------------------------*/
function x_yyyy()
{
    var now = new Date();
    return now.getFullYear();
}

/*--------------------------------------------------------------------*/
/*                       x_yyyymmdd() function                        */
/*--------------------------------------------------------------------*/
function x_yyyymmdd(a_plus_or_minus)
{
    var then = new Date();
    if (typeof a_plus_or_minus != 'undefined')
    {
        then.setDate(then.getDate(a_plus_or_minus));
    }
    var yyyy = then.getFullYear();
    var mm = then.getMonth() + 1; if (mm.length == 1) mm = '0' + mm;
    var dd = then.getDate();      if (dd.length == 1) dd = '0' + dd;
    var result = new String(yyyy + mm + dd);
    return result;
}

/**********************************************************************/
/*                               E N D                                */
/**********************************************************************/

/*--------------------------------------------------------------------*/
/*                        x_log_obj() function                        */
/*--------------------------------------------------------------------*/
function x_log_obj(a_object_name)
{
x_log("\n------------------------------------------------------------");
//     x_log("\n" + a_object_name + ": " + x_obj(a_object_name));
    x_log("\n" + x_obj(a_object_name));
x_log("\n------------------------------------------------------------");
}

var plx_obj_depth = 0;
var plx_obj_indent = new String('');

/*--------------------------------------------------------------------*/
/*                          x_obj() function                          */
/*--------------------------------------------------------------------*/
function x_obj(a_object_name)                             // 20021030 DH
{
x_log("\nx_obj(\"" + a_object_name + "\");");
    plx_obj_depth++;
// x_log("\nplx_obj_depth == " + plx_obj_depth + ".");
    plx_obj_indent = '';
    for (dx = 0; dx + 1 < plx_obj_depth; dx++)
    {
        plx_obj_indent += '. ';
    }
// x_log("\nplx_obj_indent == '" + plx_obj_indent + "'.");
    var result = plx_obj_indent + a_object_name + ': ';
// x_log("\nBefore issuing \"object_value = eval('" + a_object_name + "');\" ...");
    object_value = eval(a_object_name);
    typeof_object_value = typeof object_value;
// x_log("\n After issuing \"object_value = eval('" + a_object_name + "');\" ...");
x_log("\ntypeof_object_value == '" + typeof_object_value + "'.");
x_log("\nobject_value == '" + object_value + "'.");
    if (typeof_object_value == 'string')
    {
        result += "'" + object_value + "' (typeof_object_value)";
    }
    else
    {
        result += object_value + ' (' + typeof_object_value + ')';
    }
    if (typeof_object_value == 'object')
    {
        if (plx_obj_depth < 3)
        {
            for (var elem in object_value)
            {
x_log("\nelem == '" + elem + "'.");
                result += "\n" + x_obj(a_object_name + "." + elem);
            }
        }
    }
    plx_obj_depth--;
// x_log("\n ... returning '" + result + "'.");
    return result;
}
