var JS_PLX = "C:\\!\\dh\\com\\Src\\plx.js (3451 lines) 2011-10-22 03:26 Rachel Bartlett";
/**********************************************************************/
/*                                                                    */
/*               Programming Language eXtensions (PLX)                */
/*               -------------------------------------                */
/*                                                                    */
/*                    (c) 1999-2011 Rachel Barlett                    */
/*                                                                    */
/**********************************************************************/
var plx_log_is_enabled = true;        // calls to x_log() depend on this
x_log("\nJS_PLX: \"" + JS_PLX + "\"");
// 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; " // see x_hover_*()
                        + "background-color: white; " // see x_hover_*()
                        + "border-color: black; "     // see x_hover_*()
                        + "border-width: 1; "         // see x_hover_*()
                        + "border-style: solid;");    // see x_hover_*()

// document.body.clientWidth doesn't exist yet, but we can say
// what fraction of clientWidth we want hover craft to take up:
var plx_hover_width_fraction = 0.3;

var plx_link_icon = new String('');                      // see x_link()
var plx_media_frame_color = 'white';        // see x_media_frame_color()
var plx_media_frame_caption_style   // see x_media_frame_caption_style()
    = 'font-size: 12; font-weight: bold;';
var plx_media_frame_width = 6;              // see x_media_frame_width()
var plx_media_icon;                                     // user settable
var plx_media_folder;                                   // user settable
var plx_media_next_align_flag                        // 1st-time default
     = new String('-right');
var plx_player_folder = "JW_Player_5.0.753";            // user settable
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_source_caption;                    // see x_parse_source()
var plx_parse_source_width;                      // see x_parse_source()
var plx_parse_source_height;                     // see x_parse_source()
var plx_parse_source_ext;                        // see x_parse_source()
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_hover_style              (a_new_val) {var old_val = plx_hover_style              ; plx_hover_style                  = 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_media_frame_color        (a_new_val) {var old_val = plx_media_frame_color        ; plx_media_frame_color         = a_new_val; return old_val;}
function x_media_frame_caption_style(a_new_val) {var old_val = plx_media_frame_caption_style; plx_media_frame_caption_style = a_new_val; return old_val;}
function x_media_frame_width        (a_new_val) {var old_val = plx_media_frame_width        ; plx_media_frame_width         = a_new_val; return old_val;}
function x_media_icon               (a_new_val) {var old_val = plx_media_icon               ; plx_media_icon                = a_new_val; return old_val;}
function x_media_folder             (a_new_val) {var old_val = plx_media_folder             ; plx_media_folder             = a_new_val; return old_val;}
function x_media_next_align_flag    (a_new_val) {var old_val = plx_media_next_align_flag    ; plx_media_next_align_flag     = a_new_val; return old_val;}
function x_player_folder            (a_new_val) {var old_val = plx_player_folder            ; plx_player_folder             = a_new_val; return old_val;}

// 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_width              (a_new_val) {var old_val = plx_hover_width              ; plx_hover_width                  = a_new_val; return old_val;}
// function x_media_border_out         (a_new_val) {var old_val = plx_media_border_out         ; plx_media_border_out          = a_new_val; return old_val;}
// function x_media_border_over        (a_new_val) {var old_val = plx_media_border_over        ; plx_media_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 ;}

/*--------------------------------------------------------------------*/
/*         x_lookup() wrapper functions (see also x_lookups()         */
/*--------------------------------------------------------------------*/
function x_abebooks(a_show, a_sarg) {return x_lookup(a_show, a_sarg, "http://www.abebooks.com/servlet/SearchResults?tn=");}
function x_alibris (a_show, a_sarg) {return x_lookup(a_show, a_sarg, "http://www.alibris.com/booksearch?keyword="       );}
function x_amazon  (a_show, a_sarg) {return x_lookup(a_show, a_sarg, "http://www.amazon.com/s?field-keywords="          );}
function x_google  (a_show, a_sarg) {return x_lookup(a_show, a_sarg, "http://www.google.com/search?q="                  );}
function x_wiki    (a_show, a_sarg) {return x_lookup(a_show, a_sarg, "http://en.wikipedia.org/wiki/"                    );}

/*--------------------------------------------------------------------*/
/*                          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.Blinds"
        + "(direction=down, bands=1, duration=0.5) "
        + "progid:DXImageTransform.Microsoft.Blinds"
        + "(direction=up, bands=1, duration=0.5) "
        + "'"
    );
//         + "progid:DXImageTransform.Microsoft.GradientWipe"
//         + "(GradientSize=1.0, wipeStyle=1, motion=forward) "
//         + "progid:DXImageTransform.Microsoft.GradientWipe"
//         + "(GradientSize=1.0, wipeStyle=1, motion=reverse) "
//     + "progid:DXImageTransform.Microsoft.RandomDissolve() "
//     + "progid:DXImageTransform.Microsoft.RandomDissolve()'"
}
document.write("></div>");

//    + "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"-->';

/*--------------------------------------------------------------------*/
/*                         Start doing stuff                          */
/*--------------------------------------------------------------------*/

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

/*--------------------------------------------------------------------*/
/*                          x_age() function                          */
/*--------------------------------------------------------------------*/
function x_age(a_birthday)
{
x_log("\nx_age(\"" + a_birthday + "\");");
    var today      = x_yyyymmdd();
    var birth_yyyy = a_birthday.substr(0, 4);
    var birth_mmdd = a_birthday.substr(4, 4);
    var today_yyyy = today.substr(0, 4);
    var today_mmdd = today.substr(4, 4);
    var result     = Number(today_yyyy) - Number(birth_yyyy);
    if (Number(today_mmdd) < Number(birth_mmdd)) result--;
x_log("\n       today: \"" + today      + "\"");
x_log("\n  birth_yyyy: \"" + birth_yyyy + "\"");
x_log("\n  birth_mmdd: \"" + birth_mmdd + "\"");
x_log("\n  today_yyyy: \"" + today_yyyy + "\"");
x_log("\n  today_mmdd: \"" + today_mmdd + "\"");
x_log("\n => \"" + result   + "\"");
    return String(result);
}

/*--------------------------------------------------------------------*/
/*                   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_code() function                          */
/*--------------------------------------------------------------------*/
function x_code()
{
    return "<table align=center style='color: black;'><tr><td><pre><b>";
}

/*--------------------------------------------------------------------*/
/*                       x_code_end() function                        */
/*--------------------------------------------------------------------*/
function x_code_end()
{
    return "</b></pre></td></tr></table>";
}

/*--------------------------------------------------------------------*/
/*                         x_deal() function                          */
/*                                                                    */
/*   Given a deck of a_deck cards, shuffle them and return the top    */
/*   a_deal cards. The cards are returned in the form of integers in  */
/*   the range 0 to a_deal - 1. If you want to repeat a particular    */
/*   pattern, supply a_seed.                                          */
/*                                                                    */
/*   Since "cards" are dealt, no duplicates are returned.             */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_deal(a_deal, a_deck, a_seed)
{
    var i_deal = a_deal;                            // num cards to deal
    var i_deck = a_deck;                            // num cards in deck
    var i_seed = a_seed;                                 // shuffle seed

x_log("\nx_deal(" + i_deal + ", " + i_deck + ", " + i_seed + ");");

    var result = new Array();
    var i_prior_prng, i_dx, i_dx2, i_rand, i_dup, i_num_dupes, i_card;

    if (typeof i_seed != 'undefined')
    {
x_log("\nSeed '" + i_seed + "' was supplied.");
        i_prior_prng = Math.random;         // Remember the current prng
// x_log("\ni_prior_prng = \"" + i_prior_prng + "\"");
        Math.seedrandom(i_seed);   // Create new prng with explicit seed
    }
    else
    {
x_log("\nSeed was NOT supplied.");
    }
    i_num_dupes = 0;
    for (i_dx = 0; i_dx < i_deal; i_dx++)
    {
        result[i_dx] = -1;
        while(result[i_dx] == -1)
        {
            i_rand = Math.random();
            i_card = Math.floor(i_rand * i_deck);
            i_dup = '';
            for (i_dx2 = 0; i_dx2 < i_dx; i_dx2++)
            {
                if (result[i_dx2] == i_card)
                {
                    i_dup = 1;
                }
            }
// x_log("\ni_rand " + i_rand + " => i_card " + i_card);
            if (i_dup)
            {
// x_log(" (DUPLICATE!)");
                i_num_dupes++;
            }
            else
            {
                result[i_dx] = i_card;
                break;
            }
        }
    }
    if (typeof i_seed != 'undefined')
    {
        Math.random = i_prior_prng;    // Resume the prior prng sequence
    }
x_log("\ni_num_dupes: " + i_num_dupes);
x_log("\n => (" + result.join(', ') + ")");
    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'><tr><td style='"
//         + "border: 1px solid black; "
//         + "background-color: FFFFFF; "
        + "font-family: Arial Black; "
//         + "font-family: Rockwell Extra Bold; "
//         + "font-family: Franklin Gothic Heavy; "
        + "padding-top: 4; "
        + "padding-left: 4; "
        + "padding-right: 4; "
        + "padding-bottom: 0; "
        + "font-size: 300%; "
        + "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></a>";
x_log("\nx_email('" + a_name
+ "', '" + a_mailbox
+ "', '" + a_domain
+ "', '" + a_parms
+ "')\n => \"" + 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 + "')");
}

/*--------------------------------------------------------------------*/
/*                      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("\nx_error('" + a_message + "'");
    x_write("\n<br><big><b>" + a_message + "</b></big>\n");
    return a_message;
}

/*--------------------------------------------------------------------*/
/*                     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()
{
    x_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_folder() function                         */
/*--------------------------------------------------------------------*/
function x_folder(a_date)
{
    var result = location.pathname;
    result = result.substr(1, result.lastIndexOf('/') - 1);
x_log("\nx_folder() => \"" + result + "\".");
    return result
}

/*--------------------------------------------------------------------*/
/*                      x_format_date() function                      */
/*--------------------------------------------------------------------*/
function x_format_date(a_date)
{
    var months = ["January", "February", "March",
        "April", "May", "June", "July", "August",
        "September", "October", "November", "December"];
    var i_date = new Date();
    if (typeof a_date != 'undefined') i_date = a_date;
    return months[i_date.getMonth()] + " "
        + i_date.getDate() + ", "
        + i_date.getFullYear();
}

/*--------------------------------------------------------------------*/
/*                     x_format_dates() function                      */
/*--------------------------------------------------------------------*/
function x_format_dates
(
    a_num_events, a_month_interval, a_ordinal, a_dow, a_month, a_year
)
{
    var result = new String();
    var this_date = new Date();
    for (nex = 0; nex < a_num_events; nex++)
    {
        this_date = x_get_rel_date(a_ordinal, a_dow, a_month, a_year);
        result += x_format_date(this_date);
        if (nex  < a_num_events - 2) result += ", ";
        if (nex == a_num_events - 2) result += " and ";
        a_month += a_month_interval;
        if (a_month > 12)
        {
            a_month -= 12;
            a_year++;
        }
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*                    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, including an empty string.                 */
/*                                                                    */
/*     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, the value returned */
/* is undefined. This makes it simple to test for the presence        */
/* of a parm by coding:                                               */
/*                                                                    */
/*         hidden_flag = x_get_parm(input, ['-hidden']);              */
/*         if (typeof hidden_flag == 'undefined') {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)
{
    var db = plx_get_parm_debug;
if (db) x_log("\nx_get_parm(\"" + a_input + "\", \"" + a_find + "\", \"" + a_default + "\")");

    var i_input   = a_input;
    var i_find    = a_find;
    var i_default = null; // undefined
    var result    = "";

if (db) x_log("\n  i_input: \"" + i_input + "\"");
if (db) x_log("\n   i_find: \"" + i_find + "\"");
if (db) x_log("\ni_default: \"" + i_default + "\"");
if (db) x_log("\n   result: \"" + result + "\"");

    if (x_is_not_empty(a_default))
    {
        result = i_default = a_default;
if (db) x_log("\ni_default: '" + i_default + "'");
if (db) x_log("\n   result: '" + result + "'");
    }

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

// Pad the i_input string to make searching easier:
    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;
            }
        }
    }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                  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);
        }
    }

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

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                         Return the result                          */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    if (db)
    {
        x_log("\n => \"" + result + "\"");
    }
    else
    {
        x_log("\nx_get_parm(\"" + a_input + "\", \"" + a_find + "\", \"" + a_default + "\")");
        x_log(" => \"" + result + "\"");
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*                    x_get_parm_tester() function                    */
/*--------------------------------------------------------------------*/
// set x_get_parm_debug to 'true' before using this function:
// function x_get_parm_tester()
// {
//     var input = "a=b c-\"d\" efg:\"Dean Hannotte\" hij='Rachel Bartlett' -center";
//     var undef;
// x_log("\nx_get_parm_tester();");
// x_log("\ninput: \"" + input + "\"");
// x_log("\nundef: \"" + undef + "\"");
//     x_get_parm('', '', '');
//     x_get_parm(input, '');
//     x_get_parm(input, 'a=');
//     x_get_parm(input, 'c-');
//     x_get_parm(input, 'efg:');
//     x_get_parm(input, 'hij=');
//     x_get_parm(input, 'nodefault=');
//     x_get_parm(input, ['-left', '-right'], '-right');
//     x_get_parm(input, ['-left', '-right', '-center'], '-right');
// }
// x_get_parm_tester();

/*--------------------------------------------------------------------*/
/*                     x_get_rel_date() function                      */
/*--------------------------------------------------------------------*/
// If numeric, then ordinal, dow and month begin with '1', not '0':
function x_get_rel_date(a_ordinal, a_dow, a_month, a_year)
{
x_log("\nx_get_rel_date('" + a_ordinal + "', '" + a_dow + "', '" + a_month + "', '" + a_year + "');");
    var ordinals = ["First", "Second", "Third", "Fourth"];
    var dows = ["Sunday", "Monday", "Tuesday",
        "Wednesday", "Thursday", "Friday", "Saturday"];
    var months = ["January", "February", "March",
        "April", "May", "June", "July", "August",
        "September", "October", "November", "December"];
    var ordinal_x = a_ordinal;
    var dow_x     = a_dow;
    var month_x   = a_month;
    if (typeof ordinal_x == 'number')
    {
        ordinal_x--;
    }
    else
    {
        for (ordinal_x = 0; ordinal_x < ordinals.length; ordinal_x++)
        {
            if (a_ordinal == ordinals[ordinal_x]) break;
        }
    }
    if (typeof dow_x == 'number')
    {
        dow_x--;
    }
    else
    {
        for (dow_x = 0; dow_x < dows.length; dow_x++)
        {
            if (a_dow == dows[dow_x]) break;
        }
    }
    if (typeof month_x == 'number')
    {
        month_x--;
    }
    else
    {
        for (month_x = 0; month_x < months.length; month_x++)
        {
            if (a_month == months[month_x]) break;
        }
    }
x_log("\n" + "ordinal_x: " + ordinal_x + ", dow_x: " + dow_x + ", month_x: " + month_x + ", year: " + a_year);
    var result = new Date(a_year, month_x, 1);
x_log("\nFirst day of " + a_month + ", " + a_year + " is " + result);
    var days_till_first_dow_x = dow_x - result.getDay();
    if (days_till_first_dow_x < 0) days_till_first_dow_x += 7;
    result.setDate(result.getDate() + days_till_first_dow_x);
x_log("\nFirst " + a_dow + " of " + a_month + ", " + a_year + " is " + result);
    result.setDate(result.getDate() + (7 * ordinal_x));
x_log("\n" + a_ordinal + " " + a_dow + " of " + a_month + ", " + a_year + " is " + result);
    return result;
}

/*--------------------------------------------------------------------*/
/*                     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 i_div = document.getElementById('plx_hover_div');
    if (x_browser() == 'IE') i_div.filters[1].Apply();
    i_div.style.visibility = "hidden";
    if (x_browser() == 'IE') i_div.filters[1].Play();
}

/*--------------------------------------------------------------------*/
/*                      x_hover_hint() function                       */
/*                                                                    */
/* When your mouse hovers over a_anchor, a box pops up showing        */
/*     a_hint.                                                        */
/*                                                                    */
/* When your mouse leaves a_anchor, the box disappears.               */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_hover_hint(a_anchor, a_hint, a_top, a_left)
{
x_log("\nx_hover_hint(\"" + a_anchor + "\","
+ "\n \"" + a_hint + "\","
+ "\n " + a_top + ", " + a_left + ");");

    var i_anchor = new String(a_anchor);
    var i_hint   = new String(a_hint);
    var i_top    = a_top;
    var i_left   = a_left;

// An embedded quote in i_hint is tricky. Since i_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
// " and &quot; to "&amp;quot;" seems to work.
    i_hint = i_hint.replace(/"/g, "&quot;");
    i_hint = i_hint.replace(/&quot;/g, "&amp;quot;");

    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(i_hint) + "\", " + i_top + ", " + i_left + ");'"
        + "\nonmouseout='x_hover_hide();'>"
        + "\n" + i_anchor + "</span>");

x_log("\n => \"" + result + "\"");
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_hover_link() function                       */
/*                                                                    */
/* When your mouse hovers over a_anchor, a box pops up showing        */
/*     a_hint.                                                        */
/*                                                                    */
/* When your mouse leaves a_anchor, the box remains until you         */
/* click on '[close]' in the upper right hand corner.                 */
/*                                                                    */
/* If a_link is given, an extra line appears at the bottom of the     */
/* box containing a link to a_link and saying "Read more . . .".      */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_hover_link(a_anchor, a_link, a_hint, a_top, a_left)
{
x_log("\nx_hover_link(\"" + a_anchor + "\","
+ "\n \"" + a_link + "\","
+ "\n \"" + a_hint + "\","
+ "\n " + a_top + ", " + a_left + ");");

    var i_anchor = new String(a_anchor);
    var i_link   = new String(a_link);
    var i_hint   = new String(a_hint);
    var i_top    = a_top;
    var i_left   = a_left;
//     var a_tag = new Array();

// (See comment above about embedded quotes.)
    i_hint = i_hint.replace(/"/g, "&quot;");
    i_hint = i_hint.replace(/&quot;/g, "&amp;quot;");
    if (i_link != "")
    {
        i_link = new String("<br><a href='" + i_link + "'>"
            + "<b>Read&nbsp;more&nbsp;.&nbsp;.&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(i_hint + i_link) + "\", "
        + "\n" + i_top + ", " + i_left + ");'>"
        + "\n" + i_anchor + "</span>");
    return result;
}

/*--------------------------------------------------------------------*/
/*                      x_hover_show() function                       */
/*--------------------------------------------------------------------*/
function x_hover_show(a_retain, a_this, a_style, a_hint, a_top, a_left)
{
x_log("\nx_hover_show(" + a_retain + ","
+ "\n" + a_this + ","
+ "\n\"" + a_style + "\","
+ "\n\"" + a_hint + "\","
+ "\n" + a_top + ", " + a_left + ");");
    i_retain = a_retain;
    i_this   = a_this;
    i_style  = new String(a_style);
    i_hint   = new String(a_hint);
    i_top    = a_top;
    i_left   = a_left;

    var i_div = document.getElementById('plx_hover_div');
    i_div.style.position = "absolute";
    i_div.style.visibility = "hidden";

x_log("\ni_this.offsetHeight: " + i_this.offsetHeight);
x_log("\n i_this.offsetWidth: " + i_this.offsetWidth);
x_log("\n   i_this.offsetTop: " + i_this.offsetTop);
x_log("\n  i_this.offsetLeft: " + i_this.offsetLeft);

    var i_hover_width = Math.floor(document.body.clientWidth * plx_hover_width_fraction);
x_log("\ndocument.body.clientWidth: " + document.body.clientWidth);
x_log("\n plx_hover_width_fraction: " + plx_hover_width_fraction);
x_log("\n            i_hover_width: " + i_hover_width);

    var i_div_style_top, i_div_style_left;

// Hovercraft pop up just under the "i_link" anchor, and try to
// align with its left edge. But don't let them get too close
// to the anchor or the left and right edges of the client window.
// (There's no way to determine the bottom edge.)

    var i_min_margin_top = 12;
    var i_min_margin_sides = 64;

    if (typeof i_top != 'undefined')
    {
        i_div_style_top = i_top;
    }
    else
    {
        i_div_style_top = x_top(i_this) + i_this.offsetHeight + i_min_margin_top;
    }

    if (typeof i_left != 'undefined')
    {
        i_div_style_left = i_left;
    }
    else
    {
        i_div_style_left = x_left(i_this);
    }

x_log("\ni_div_style_top: " + i_div_style_top);
x_log("\ni_div_style_left: " + i_div_style_left);

// Once document.body.clientWidth exists, we can figure out if the
// hover box is going past the right edge of the document window.

// The following method of correcting overflow insures that
// the left edge of the hovercraft aligns with the left edge
// of the anchor unless overflow would otherwise occur.

// Set the minimal margin of the hovercraft from
// both the left and right edges of the client window:

    if (i_div_style_left < i_min_margin_sides)
    {
x_log("\nIncreasinging i_div_style_left from " + i_div_style_left);
        i_div_style_left = i_min_margin_sides;
x_log(" to " + i_div_style_left);
    }

    if (i_div_style_left > document.body.clientWidth - (i_hover_width + i_min_margin_sides))
    {
x_log("\nReducing i_div_style_left from " + i_div_style_left);
        i_div_style_left = document.body.clientWidth - (i_hover_width + i_min_margin_sides);
x_log(" to " + i_div_style_left);
    }

    i_div.style.top  = i_div_style_top ;
    i_div.style.left = i_div_style_left;

    i_div.style.padding = 0;
    var i_close_button = '';
    if (i_retain == 1)
    {
        i_close_button = "\n<p style='text-align: right; margin: 0; padding: 0;'>"
            + "<a href='javascript:x_hover_hide();'>[close]</a></p><hr>";
    }
    var i_hint = "<table width=" + i_hover_width
        + " cellpadding=0 cellspacing=0>"
        + "<tr><td style='" + i_style + " padding: 4;'>"
        + i_close_button + i_hint + "</td></tr></table>";

x_log("\n       i_div.style.top = '" + i_div.style.top        + "'.");
x_log("\n      i_div.style.left = '" + i_div.style.left       + "'.");
x_log("\n  i_div.style.position = '" + i_div.style.position   + "'.");
x_log("\ni_div.style.visibility = '" + i_div.style.visibility + "'.");
x_log("\n       i_div.innerHTML = '" + i_div.innerHTML        + "'.");

    i_div.innerHTML = i_hint;
    if (x_browser() == 'IE') i_div.filters[0].Apply();
    i_div.style.visibility = "visible";
    if (x_browser() == 'IE') i_div.filters[0].Play();
}

/*--------------------------------------------------------------------*/
/*                         x_html() function                          */
/*--------------------------------------------------------------------*/
function x_html()
{
    if (typeof plx_html != 'undefined') return plx_html;
    plx_html = parseFloat(navigator.appVersion);
    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 + "') => " + true);
            return true;
        }
    }
x_log("\nx_is_a_used_resource('" + a_resource + "') => " + false);
    return false;
}

/*--------------------------------------------------------------------*/
/*                       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(a_object)
{
    var result = 0;
    while (a_object.offsetParent)
    {
        result += a_object.offsetLeft
        a_object = a_object.offsetParent;
    }
x_log("\nx_left(" + a_object + ") => " + result);
    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>";
x_log("\nx_link(\"" + anchor + "\", \"" + href + "\", \"" + target + "\", \"" + title + "\") => \"" + result + "\"");
    return result;
}

/*--------------------------------------------------------------------*/
/*                   x_is_external_link() function                    */
/*                                                                    */
/*                                                                    */
/*   This function returns true ONLY if                               */
/*                                                                    */
/*   1) the string you pass it begins with "http://" or "https://",   */
/*                                                                    */
/*   2) whatever is left (barring anything past a possible slash)     */
/*      is not the same as the current host (location.hostname).      */
/*                                                                    */
/*   Note that this will fail to detect that a link such as           */
/*   "google.com" is external, so if you want such links to be        */
/*   recognized as external, pass "http://google.com".                */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_is_external_link(a_new_link)
{
x_log("\nx_is_external_link(\"" + a_new_link + "\");");
    var result       = false;
    var new_link     = new String(a_new_link);
    var new_protocol = new String();
    var new_hostname = new String();
    var slash        = 0;
    if  (new_link.substr(0, 7) == "http://")
    {
        new_protocol = new_link.substr(0, 7);
        new_link     = new_link.substr(7);
    }
    if  (new_link.substr(0, 8) == "https://")
    {
        new_protocol = new_link.substr(0, 8);
        new_link     = new_link.substr(8);
    }
    if (new_protocol != "")
    {
x_log("\nnew_protocol: \"" + new_protocol + "\"");
x_log("\n    new_link: \"" + new_link     + "\"");
        slash = new_link.indexOf("/");
x_log("\n       slash: " + slash);
        if (slash > -1)
        {
            new_hostname = new_link.substr(0, slash);
                new_link = new_link.substr(slash + 1);
            if (new_hostname != location.hostname) result = true;
        }
        else
        {
            new_hostname = new_link;
                new_link = "";
        }
        if (new_hostname != location.hostname) result = true;
x_log("\nnew_hostname: \"" + new_hostname + "\"");
x_log("\n    new_link: \"" + new_link     + "\"");
    }
x_log("\nx_is_external_link(\"" + a_new_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 (plx_log_is_enabled)
    {
        if (typeof plx_log == 'undefined')
        {
            plx_log = new String('');
        }
        plx_log += a_message;
        if (plx_log_to_browser)
        {
            a_message.replace(/\n/g, '\n<br>');
            x_write(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"
      + "\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"
      + "\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 navigator.browserLanguage: \"" + navigator.browserLanguage  + '" (' + typeof navigator.browserLanguage  + ')'
      + "\n  navigator.systemLanguage: \"" + navigator.systemLanguage   + '" (' + typeof navigator.systemLanguage   + ')'
      + "\n    navigator.userLanguage: \"" + navigator.userLanguage     + '" (' + typeof navigator.userLanguage     + ')'
      + "\n"
      + "\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_folder(): \"" + x_folder()                 + '" (' + typeof x_folder()                 + ')'
      + "\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_yyyymmdd()               + ')'
    );
//    + "\n  plx_hover_width_fraction: \"" + plx_hover_width_fraction   + '" (' + typeof plx_hover_width_fraction   + ')'
//    + "\n           plx_remote_addr: \"" + plx_remote_addr            + '" (' + typeof plx_remote_addr            + ')'
//    + "\n   navigator.javaEnabled(): \"" + navigator.javaEnabled()    + '" (' + typeof navigator.javaEnabled()    + ')'
}

/*--------------------------------------------------------------------*/
/*                      x_log_disable() function                      */
/*--------------------------------------------------------------------*/
function x_log_disable()
{
x_log("\nDISABLING THE LOG ...");
   plx_log_is_enabled = false;
}

/*--------------------------------------------------------------------*/
/*                      x_log_enable() function                       */
/*--------------------------------------------------------------------*/
function x_log_enable()
{
   plx_log_is_enabled = true;
x_log("\nENABLING THE LOG ...");
}

/*--------------------------------------------------------------------*/
/*                        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 rx;
    for (rx = 0; rx < plx_resources_used.length; rx++)
    {
        x_log("\n " + plx_resources_used[rx]);
    }
}

/*--------------------------------------------------------------------*/
/*                    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_lookup() function                         */
/*                                                                    */
/*    This function is called by other functions to lookup subjects   */
/* on abebooks, alibris, amazon, google and wikipedia.                */
/*                                                                    */
/*    a_show is how the subject is to be displayed in HTML.           */
/*                                                                    */
/*    a_sarg is the subject formatted as a search argument to         */
/*       the external website in question (defaults to a_show).       */
/*                                                                    */
/*    a_html is the HTML prefix that tickles the external website     */
/*        to lookup the subject passed to it.                         */
/*                                                                    */
/*    NOTE: a_show and a_sarg can have underscores instead of         */
/*          spaces to prevent invalid breaks in Javascript strings.   */
/*                                                                    */
/*    To surround the search argument in quotes, use "&quot;".        */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_lookup(a_show, a_sarg, a_html)
{
    var show = new String(a_show);
    var sarg = new String(a_sarg);
    var html = new String(a_html);
    if (typeof a_sarg == 'undefined') sarg = show;
    var result  = new String("");
    show = show.replace(/_/g, " ");
    sarg = sarg.replace(/_/g, " ");
// x_log("\n              show.substr(0, 6): '" + show.substr(0, 6) + "'");
// x_log("\nshow.substr(show.length - 6, 6): '" + show.substr(show.length - 1, 6) + "'");
    if (show.substr(0, 6)               == "&quot;"
    &&  show.substr(show.length - 6, 6) == "&quot;")
    {
x_log("\nStripping quotes from '" + show + "'");
        show = show.substr(6, show.length - 12);
    }
    result = "<a href=\"" + html + sarg + "\"><b><i>" + show + "</i></b></a>";
x_log("\nx_lookup(\"" + show + "\", \"" + sarg + "\", \"" + html + "\")\n =>\n \"" + result + "\"");
    return result;
}

/*--------------------------------------------------------------------*/
/*                       x_lookups() function                         */
/*                                                                    */
/*    This function is called to lookup a subjects on two or more     */
/* of Abebooks, Alibris, Amazon, Google and Wikipedia.                */
/*                                                                    */
/*    a_show is how the subject is to be displayed in HTML.           */
/*                                                                    */
/*    a_sarg is the subject formatted as a search argument to         */
/*       the external website in question (defaults to a_show).       */
/*                                                                    */
/*    a_sources is an array of one or more of the following flags:    */
/*                                                                    */
/*        '-abebooks'                                                 */
/*        '-alibris'                                                  */
/*        '-amazon'                                                   */
/*        '-google'                                                   */
/*        '-wiki'                                                     */
/*                                                                    */
/*    NOTE: a_show can have underscores instead of spaces to          */
/*          prevent invalid breaks in Javascript strings.             */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_lookups(a_show, a_sarg, a_sources)
{
    var sx, source;
    var result = new String();
    result += "<b><i>" + a_show + "</i></b> (";
    for (sx = 0; sx < a_sources.length; sx++)
    {
        if (sx) result += ", ";
        source = a_sources[sx];
        if (source == '-abebooks') result += x_abebooks("Abebooks" , a_sarg);
        if (source == '-alibris' ) result += x_alibris ("Alibris"  , a_sarg);
        if (source == '-amazon'  ) result += x_amazon  ("Amazon"   , a_sarg);
        if (source == '-google'  ) result += x_google  ("Google"   , a_sarg);
        if (source == '-wiki'    ) result += x_wiki    ("Wikipedia", a_sarg);
    }
    result += ")";
    return result;
}

/*--------------------------------------------------------------------*/
/*                         x_media() function                         */
/*--------------------------------------------------------------------*/
function x_media
(
    a_type, a_source, a_resize, a_parms, a_caption_override
)
{
x_log("\nx_media('"
+ a_type   + "', '"
+ a_source  + "', '"
+ a_resize  + "', '"
+ a_parms   + "', '"
+ a_caption_override + "');");

    var i_type             = a_type;
    var i_source           = a_source;
    var i_resize           = a_resize;
    var i_parms            = a_parms;
    var i_caption_override = a_caption_override;

    var i_result  = new String('');

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                            Parse i_type                            */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    if (i_type != 'snapshot' && i_type != 'soundbite' && i_type != 'videoclip')
    {
        return x_error("Type parameter, '" + i_type
            + "', illegal in call to x_media().");
    }
    var i_funcname = 'x_' + i_type + '()';

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                           Parse i_source                           */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    if (typeof i_source == 'undefined')
    {
        return error("Source parameter missing in call to " + i_funcname + ".");
    }
// Apostrophes break the 'onclick' handler specification when i_resize != 0:
    if (i_source.indexOf("'") > -1)
    {
        return error("Apostrophe in " + i_funcname + " source "
            + "parameter is illegal, use \"[039]\" instead:\n \"" + i_source + "\".");
    }

x_log("\nPrefixing '" + i_type + "s/' to '" + i_source + "'.");
    i_source = i_type + "s/" + i_source;
// x_log("\ni_source = '" + i_source + "'.");

    if (i_source.substr(0, 7) != "http://"
    &&  i_source.substr(0, 1) != "/"
    &&  x_is_not_empty(plx_media_folder))
    {
x_log("\nPrefixing '" + plx_media_folder + "/' to '" + i_source + "'.");
        i_source = plx_media_folder + "/" + i_source;
    }
x_log("\ni_source = '" + i_source + "'.");

    x_parse_source(i_source);
    var i_caption = new String(plx_parse_source_caption);
    var i_width   = plx_parse_source_width;
    var i_height  = plx_parse_source_height;
    var i_ext     = new String(plx_parse_source_ext);

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                    Parse the i_resize parameter                    */
/*                                                                    */
/*          100       specifies the width in pixels                   */
/*          'x100'    specifies the height in pixels                  */
/*          '100x100' specifies the width and height in pixels        */
/*                      (only this format can distort an image)       */
/*          '20%'     specifies the width as a percentage of          */
/*                    document.body.clientWidth                       */
/*          .25       specifies the width as a fraction of            */
/*                      the actual width.                             */
/*                                                                    */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// The 'i_resize' parameter modifies the size of the table cell AND the media footprint.
// The '-noexpand' flag can suppress expansion of the media.
// The '-noshrink' flag can suppress shrinkage of the media.
    var i_resized_width = i_width, i_resized_height = i_height;
// x_log("\ni_resize: " + i_resize + ", i_resized_width: " + i_resized_width + ", i_resized_height: " + i_resized_height);

// x_log("\n    typeof '20%': '" + (typeof      '20%') + "'");
// x_log("\n   typeof 'x100': '" + (typeof     'x100') + "'");
// x_log("\ntypeof '100x100': '" + (typeof  '100x100') + "'");
// x_log("\n      typeof 100: '" + (typeof        100) + "'");
// x_log("\n      typeof .25: '" + (typeof        .25) + "'");

x_log("\ni_resize: '" + i_resize + "'");
x_log("\ntypeof i_resize: '" + (typeof i_resize) + "'");
    if (x_is_not_empty(i_resize))
    {
        if (typeof i_resize == 'string')
        {
            var pos_x = i_resize.indexOf('x');
x_log("\npos_x: " + pos_x);
            if (i_resize.substr(i_resize.length - 1, 1) == '%')
            {               // can be a percent of document.body.clientWidth
                i_resize         = i_resize.substr(0, i_resize.length - 1) / 100;
                i_resized_width  = Math.floor(document.body.clientWidth * i_resize);
                i_resized_height = Math.floor(i_resized_width * i_height / i_width);
x_log("\nResize as percentage of window width, '" + i_resize + "', makes i_resized i_width " + i_resized_width + ", and i_resized i_height " + i_resized_height + ".");
            }
            else if (pos_x == 0)
            {
                i_resized_height = i_resize.substr(1);
                i_resized_width = Math.floor(i_width * i_resized_height / i_height);
x_log("\nResized height, " + i_resized_height + ", makes resized width " + i_resized_width + ".");
            }
            else if (pos_x > 0)
            {
                i_resized_width = i_resize.substr(0, x);
                i_resized_height = i_resize.substr(x + 1);
x_log("\nResize value, '" + i_resize + "', makes resized width " + i_resized_width + " and resized height " + i_resized_height + ".");
            }
            else
            {
                return x_error("Invalid i_resize parm, '" + i_resize
                    + "', in call to " + i_funcname + ": 'When "
                    + "a string it must contain an 'x' or end in '%'.");
            }
        }
        else // if (typeof i_resize == 'number')
        {
            if (i_resize <= 1.0)
            {
                i_resized_width  = Math.floor(i_width  * i_resize);
                i_resized_height = Math.floor(i_height * i_resize);
x_log("\nResize as a fraction of image width, " + i_resize + ", makes resized width " + i_resized_width + " and resized height " + i_resized_height + ".");
            }
            if (i_resize > 1.0)               // or a i_width override in pixels
            {
                i_resized_width  = i_resize;
                i_resized_height = Math.floor(i_resize * i_height / i_width);
x_log("\nResized width, " + i_resized_width + ", makes resized height " + i_resized_height + ".");
            }
        }

// Suppress expansion or shrinkage if requested:
        if (i_expand_flag == '-noexpand')
        {
            if (i_resized_width > i_width || i_resized_height > i_height)
            {
x_log("\nExpansion of the image suppressed.");
                i_resized_width  = i_width;
                i_resized_height = i_height;
            }
        }
        if (i_shrink_flag == '-noshrink')
        {
            if (i_resized_width < i_width || i_resized_height < i_height)
            {
x_log("\nShrinking of the image suppressed.");
                i_resized_width  = i_width;
                i_resized_height = i_height;
            }
        }
    }
// x_log("\ni_resize: '"    + i_resize
// + "', i_resized_width: " + i_resized_width
// + ", i_resized_height: " + i_resized_height);

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                           Parse i_parms                            */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    var i_align_flag = x_get_parm
    (
        i_parms,
        ['-left', '-right', '-center', '-noalign', '-alternate'],
        '-alternate'
    );
    var i_caption_flag = x_get_parm(i_parms, ['-caption', '-nocaption'], '-caption');
    var i_help_flag    = x_get_parm(i_parms, ['-help'   , '-nohelp'   ], '-help'   );
    var i_win_flag     = x_get_parm(i_parms, ['-oldwin' , '-newwin'   ], '-oldwin' );
    var i_expand_flag  = x_get_parm(i_parms, ['-expand' , '-noexpand' ], '-expand' );
    var i_shrink_flag  = x_get_parm(i_parms, ['-shrink' , '-noshrink' ], '-shrink' );

x_log("\ni_align_flag: '" + i_align_flag
+  "', i_caption_flag: '" + i_caption_flag
+     "', i_help_flag: '" + i_help_flag
+      "', i_win_flag: '" + i_win_flag
+   "', i_expand_flag: '" + i_expand_flag
+   "', i_shrink_flag: '" + i_shrink_flag + "'");

// 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>.

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                          Parse i_caption_override                  */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// A non-empty i_caption_override replaces the
// plx_parse_source_caption and cancels the '-nocaption' flag:
    if (i_caption_flag == '-nocaption') i_caption = '';
    if (x_is_not_empty(i_caption_override)) i_caption = i_caption_override;
x_log("\ni_caption: '" + i_caption + "'");

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

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                    Let's think about this a bit                    */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// Convert i_align_flag to i_align_parm and i_float attribute.
// (The float attribute was supposed to prevent containers
// from growing in depth such as in the Kate Middleton picture
// in rosenfels.org/WithRachel.htm, but it didn't work!)
    var i_align_parm = '';
    var i_float      = '';
    if (i_align_flag == '-left' )
    {
        i_align_parm = 'align=left ';
        i_float      = 'float: left;';
    }
    else if (i_align_flag == '-right')
    {
        i_align_parm = 'align=right ';
        i_float      = 'float: right;';
    }
    else if (i_align_flag == '-center' && x_browser() == 'IE')
    {
        i_align_parm = 'align=center ';
    }
    else if (i_align_flag == '-alternate')
    {
x_log("\nplx_media_next_align_flag: '" + plx_media_next_align_flag + "'");
        if (plx_media_next_align_flag == '-right')
        {
            i_align_parm = 'align=right ';
            i_float      = 'float: right;';
        }
        else
        {
            i_align_parm = 'align=left ';
            i_float      = 'float: left;';
        }
    }
x_log("\ni_align_parm: '" + i_align_parm + "'");
x_log("\n   i_float: '" + i_float  + "'");

// Derive margins and next align flag from i_align_parm:
    var i_margin_top    = plx_media_frame_width;
    var i_margin_bottom = plx_media_frame_width;
    var i_margin_left   = plx_media_frame_width;
    var i_margin_right  = plx_media_frame_width;
    if (i_align_flag == '-center')
    {
        i_margin_left   = 'auto';
        i_margin_right  = 'auto';
    }
    var i_hspace = 12;
    if (i_align_parm == 'align=left ')
    {
        i_margin_right += i_hspace;
        x_media_next_align_flag('-right');
x_log("\nplx_media_next_align_flag: '" + plx_media_next_align_flag + "'")
    }
    if (i_align_parm == 'align=right ')
    {
        i_margin_left += i_hspace;
        x_media_next_align_flag('-left');
x_log("\nplx_media_next_align_flag: '" + plx_media_next_align_flag + "'")
    }

    var i_margin = new String
    (
          "margin-left: "   + i_margin_left   + "; "
        + "margin-right: "  + i_margin_right  + "; "
        + "margin-top: "    + i_margin_top    + "; "
        + "margin-bottom: " + i_margin_bottom + ";"
    );

    var i_border_width = plx_media_frame_width;

    var i_border = new String
    (
          "border-width: " + i_border_width + "; "
        + "border-style: solid; "
        + "border-color: " + plx_media_frame_color + ";");

    var i_style = new String(i_margin + " " + i_border + " " + i_float);

// Should the resized source link to its original-size version?
    var i_percent = Math.floor(100 * i_width / i_resized_width);
    var i_handlers = new String('');
    var i_tooltip = new String();
    if (i_type == 'snapshot')
    {
        if (i_percent != 100)
        {
            i_style += " cursor: pointer;";

            i_handlers += "\n onmouseover='";
            if (i_align_flag != '-center')
            {
                i_handlers += "this.style.marginLeft" + " = " + (i_margin_left  - plx_media_frame_width) + "; "
                          + "this.style.marginRight"  + " = " + (i_margin_right - plx_media_frame_width) + "; ";
            }
            i_handlers += "this.style.marginTop"  + " = " + (i_margin_top    - plx_media_frame_width) + "; "
                      + "this.style.marginBottom" + " = " + (i_margin_bottom - plx_media_frame_width) + "; "
                      + "this.style.borderWidth"  + " = " + (i_border_width  + plx_media_frame_width) + ";'";

            i_handlers += "\n onmouseout='";
            if (i_align_flag != '-center')
            {
                i_handlers += "this.style.marginLeft"  + " = " + i_margin_left  + "; "
                            + "this.style.marginRight" + " = " + i_margin_right + "; ";
            }
            i_handlers += "this.style.marginTop"  + " = " + i_margin_top    + "; "
                      + "this.style.marginBottom" + " = " + i_margin_bottom + "; "
                      + "this.style.borderWidth"  + " = " + i_border_width  + ";'";

            if (i_win_flag == '-newwin')
            {
//                 var title = new String(i_caption.replace(/<br>/gi, " "));
//
//                 var popup = new String("<html><head><title>" + title + "</title></head><body>"
//                     + "<table width=\\\"100%\\\" height=\\\"100%\\\">"
//                     + "<tr><td align=\\\"center\\\" valign=\\\"middle\\\">"
//                     + "<img src=\\\"" + i_source + "\\\">"
//                     + "<br><font face=\\\"Verdana\\\"><big><b>"
//                     + title + "</b></big></font></td></tr></table></body></html>");
//
//                 i_handlers += "\n onclick='x_popup(\"\", \"\", "
//                          + Math.floor(i_resized_width  + 50) + ", "
//                          + Math.floor(i_resized_height + 60) + ", \"\", \""
//                          + popup + "\");'";
            }
            else // if (i_win_flag == '-oldwin')
            {
                if (i_type == 'snapshot')
                {
                    i_handlers += "\n onclick='";
                    if (i_align_flag != '-center')
                    {
                        i_handlers += "this.style.marginLeft"  + " = " + i_margin_left  + "; "
                                    + "this.style.marginRight" + " = " + i_margin_right + "; ";
                    }
                    i_handlers += "this.style.marginTop"    + " = " + i_margin_top    + "; "
                                + "this.style.marginBottom" + " = " + i_margin_bottom + "; "
                                + "this.style.borderWidth"  + " = " + i_border_width  + "; ";
                    i_handlers += "location=\"" + i_source + "\";'";
                }
            }

            if (i_help_flag == '-help')
            {
                if (i_percent > 100)
                {
                    i_tooltip = new String("Click to enlarge " + i_percent + "%");
                }
                if (i_percent < 100)
                {
                    i_tooltip = new String("Click to shrink to original size");
                }
            }
        }
    }

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

    if (x_is_not_empty(i_caption))
    {
// How shall we align the i_caption? "center", "left", etc. ?
        var i_align = "center";
        i_caption = "\n<table width='100%' cellspacing=0 cellpadding=4>"
            + "<tr><td align=" + i_align + " style='"
            + plx_media_frame_caption_style + "'>"
            + i_caption;
        i_caption += "</td></tr></table>";
    }

// The image i_width is also used as the cell i_width,
// making the cell wrap tightly around the image.

// The alt= and title= keywords can be used to specify a "tool tip".
// Neither IE nor Firefox ever uses both keywords.
//
//                                     IE uses the    Firefox uses
//                                     value of       the value of
//                                     -----------    ------------
// If only the alt= keyword is used    alt=
// If only the title= keyword is used  title=         title=
// If both keywords are used           title=         title=
//
// Therefor, only the title= keyword need be specified.

    result = "<table border=00 cellpadding=0 cellspacing=0 "
        + "bgcolor='" + plx_media_frame_color + "' "
        + i_align_parm
        + "width=" + i_resized_width
        + i_style
        + i_handlers + ">"
        + "\n<tr><td align='center'>";

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                         Format a snapshot                          */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    if (i_type == 'snapshot')
    {
        result += "\n<img"
            + " src=\""   + i_source         + "\""
            + " width="   + i_resized_width
            + " height="  + i_resized_height
            + " title=\"" + i_tooltip        + "\""
            + ">";
    }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                         Format a soundbite                         */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    else if (i_type == 'soundbite')
    {
    }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                         Format a videoclip                         */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    else if (i_type == 'videoclip')
    {
// replace the '.flv' with '.jpg':
        var i_jpg = i_source.substr(0, i_source.length -4) + '.jpg';
//         i_jpg = i_jpg.replace(/videoclips/, "videoclips/snapshots");
x_log("\ni_source: '" + i_source + "'");
x_log("\n   i_jpg: '" + i_jpg + "'");

// JW FLV Player was created by Jeroen "JW" Wijering and his
// company, LongTail Video. (http://www.longtailvideo.com/)
// WARNING: The file= locations are relative to the location of player.swf!

        result += "<table><tr><td>"
            + "\n<object classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' "
            + "\n id='player' name='player'"
            + "\n width='" + i_resized_width + "'"
            + "\n height='" + i_resized_height + "'> "
            + "\n <param name='movie' value='" + plx_media_folder + "/" + plx_player_folder + "/player.swf' /> "
            + "\n <param name='allowfullscreen' value='true' /> "
            + "\n <param name='allowscriptaccess' value='always' /> "
            + "\n <param name='flashvars' "
            + "\n value='file=../../" + i_source + "&image=" + i_jpg + "' "
            + "\n /> "
            + "\n<embed "
            + "\n type='application/x-shockwave-flash' "
            + "\n id='player2' "
            + "\n name='player2' "
            + "\n src='" + plx_media_folder + "/" + plx_player_folder + "/player.swf' "
            + "\n width='" + i_resized_width + "'"
            + "\n height='" + i_resized_height + "' "
            + "\n allowscriptaccess='always' "
            + "\n allowfullscreen='true' "
            + "\n flashvars='file=../../" + i_source + "&image=" + i_jpg + "' "
            + "\n /> "
            + "\n</object>"
            + "\n</td></tr></table>";
    }

/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*                         Format the caption                         */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
    result += i_caption
        + "\n</td></tr>"
        + "</table>";

x_log("\nx_media() => \"" + result + "\"");

// 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_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_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_source() function                      */
/*--------------------------------------------------------------------*/
// substr(from, [len])
// substring(from, to)
function x_parse_source(a_src)
{
x_log("\nx_parse_source(\"" + a_src + "\");");

    plx_parse_source_caption = new String('');
    plx_parse_source_width   = 0;
    plx_parse_source_height  = 0;
    plx_parse_source_ext    = new String('');

    var src = new String(a_src);
// x_log("\ntypeof src: '" + (typeof src) + "'");
// x_log("\nsrc: '" + src + "'");
    if (src == 'undefined' || src == '')
    {
        plx_parse_source_caption =
            "Source missing in call to x_parse_source('" + src + "');"
        return x_error(plx_parse_source_caption);
    }
    else
    {
//         src = src.replace(/_/g, ' ');
// x_log("\n                     src: '" + src + "'");
        var dot = src.lastIndexOf('.');
// x_log("\n                     dot: '" + dot + "'");
        if (dot <= -1)
        {
            plx_parse_source_caption =
                "Dot missing in filename in call to x_parse_source('" + src + "');"
            return x_error(plx_parse_source_caption);
        }
        else
        {
            plx_parse_source_ext = src.substr(dot);
// x_log("\n   plx_parse_source_ext: '" + plx_parse_source_ext + "'");
            var x = src.lastIndexOf('x', dot);
// x_log("\n                       x: '" + x + "'");
            if (x <= -1)
            {
                plx_parse_source_caption =
                    "'x' missing in filename in call to x_parse_source('" + src + "');"
                return x_error(plx_parse_source_caption);
            }
            else
            {
                plx_parse_source_height = parseInt(src.substring(x + 1, dot));
// x_log("\n plx_parse_source_height: '" + plx_parse_source_height + "'");
                var space = src.lastIndexOf(' ', x);
                if (space == -1) space = src.lastIndexOf('_', x);
// x_log("\n                   space: '" + space + "'");
                if (space <= -1)
                {
                    plx_parse_source_caption = "Neither space nor underscore found before "
                        + "'x' in filename in call to x_parse_source('" + src + "');";
                    return x_error(plx_parse_source_caption);
                }
                else
                {
                    plx_parse_source_width =
                        parseInt(src.substring(space + 1, x));
// x_log("\n  plx_parse_source_width: '" + plx_parse_source_width + "'");
                    plx_parse_source_caption = src.substring(0, space);
// x_log("\nplx_parse_source_caption: '" + plx_parse_source_caption + "'");
                    var slash = plx_parse_source_caption.lastIndexOf('/');
// x_log("\n                   slash: '" + slash + "'");
                    if (slash > -1)
                    {
                        plx_parse_source_caption =
                            plx_parse_source_caption.substr(slash + 1);
                    }
                }
            }
        }
    }
    if (isNaN(plx_parse_source_width))
    {
        plx_parse_source_caption =
            "Width not given in call to x_parse_source('" + a_src + "');"
        return x_error(plx_parse_source_caption);
    }
    if (isNaN(plx_parse_source_height))
    {
        plx_parse_source_caption =
            "Height not given in call to x_parse_source('" + a_src + "');"
        return x_error(plx_parse_source_caption);
    }
x_log("\n plx_parse_source_caption: \"" + plx_parse_source_caption + "\"");
x_log("\n   plx_parse_source_width: "   + plx_parse_source_width         );
x_log("\n  plx_parse_source_height: "   + plx_parse_source_height        );
x_log("\n     plx_parse_source_ext: '"  + plx_parse_source_ext     +  "'");
}

/*--------------------------------------------------------------------*/
/*                       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.protocol: '" + location.protocol + "'.");
x_log("\n    location.host: '" + location.host     + "'.");
x_log("\nlocation.hostname: '" + location.hostname + "'.");
x_log("\nlocation.pathname: '" + location.pathname + "'.");
x_log("\n    location.hash: '" + location.hash     + "'.");
x_log("\n    location.port: '" + location.port     + "'.");
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                           */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
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()
{
    width           = window.screen.width  - 50;
    height          = window.screen.height - 50;
    window_url      = new String('');
    window_name     = new String('plx_peek_window');
    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(window_url,
            window_name, 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_random() function                         */
/*                                                                    */
/*       A random number generator that supports seeding, from        */
/*     http://station.woj.com/2010/02/javascript-random-seed.html     */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*                                                                    */
/*     Note that "seed" is actually a remembered global variable,     */
/*    simply because we don't localize it using the "var" keyword.    */
/*            After the first call, it can never be empty.            */
/*                                                                    */
/*--------------------------------------------------------------------*/

// "JavaScript doesn't have a random seed function, which means you've
// got to roll you own. This little fella works like a charm:
//
// function random(seed) {
//   if (!seed)
//     seed = new Date().getTime();
//   seed = (seed*9301+49297) % 233280;
//   return seed/(233280.0);
// }"

function x_random(seed)
{
    var result;
x_log("\nx_random(" + seed + ")");
    if (!seed) seed = new Date().getTime();
    seed = (seed * 9301 + 49297) % 233280;
    result = seed/(233280.0);
x_log(" => " + result);
    return result;
}
/*--------------------------------------------------------------------*/
/*                       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_reverse() function                        */
/*--------------------------------------------------------------------*/
function x_reverse(a_string)
{
    var result = String("");
    for (rx = 0; rx < a_string.length; rx++)
    {
        result = a_string.substr(rx, 1) + result;
    }
    return result;
}

/*--------------------------------------------------------------------*/
/*                          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_scrapbook() function                       */
/*                                                                    */
/*     This function arranges images in rows of uniform height,       */
/* as does Google Images, thus eliminating wasted real estate.        */
/*

   GOAL:
   1. All the cells in any row should almost fill the width of the
      client window.
   2. Each cell in any row should be the same height to avoid wasted
      real estate.

       Thus, the height of each cell should be just that number of
   pixels which will make the width of the row be almost the client
   width.

   EXAMPLE:
       If a 100x200 cell is followed by a 200x100 cell, the height of
   the second cell could be double that of the first, giving a
   uniform height of 200. Then this height could be adjusted so that
   the total width would not be 500, but almost the client width.

   ALGORITHM:
       Let the uniform height be 100 (an arbitrary number) and find
   the total width of this row. Then, given the actual available
   width, adjust the uniform height accordingly.

   BUG:
       This function only knows the dimensions of each photo. Thus,
   if the captions differ in length, the rows can still be uneven in
   height!

----------------------------------------------------------------------*/
function x_scrapbook(a_title, a_rows)
{
x_log("\nx_scrapbook(\"" + a_title + "\");");

    var title  = a_title;
    var rows   = a_rows;
    var result = new String("\n");

    if (typeof title == 'string') result += "\n" + title;

// I'm not sure why, but document.body.clientWidth can
// change a little during the formatting of a scrapbook.
// So we capture it one time and use the same value throughout:
    if (typeof plx_client_width_for_scrapbooks != 'number')
    {
        plx_client_width_for_scrapbooks = document.body.clientWidth;
x_log("\nplx_client_width_for_scrapbooks is being initialized to "
    + plx_client_width_for_scrapbooks + " pixels.");
    }
    else
    {
x_log("\nplx_client_width_for_scrapbooks was already set to "
    + plx_client_width_for_scrapbooks + " pixels.");
    }

// Heuristics (i. e. "guesswork"):
    var AVAILABLE_WINDOW_FRACTION = .9;
    var CELL_BORDER_WIDTH = 24;

    var rx, row, cellx;
    var num_cells;
    var total_width;
    var uniform_height;
    var source  = new String();
    var caption = new String();
    var available_window_width = Math.floor
    (
        plx_client_width_for_scrapbooks * AVAILABLE_WINDOW_FRACTION
    );
x_log("\nThe available window is " + available_window_width + " pixels wide.");

    for (rx = 0; rx < rows.length; rx++)
    {
        result += "\n<table align=center cellspacing=0 cellpadding=0><tr>";

        row = rows[rx];
x_log("\ntypeof row[" + rx + "]: " + typeof row);
        if (row instanceof Array)
        {
            num_cells = row.length / 2;
x_log("\nThere are " + num_cells + " cells in row " + rx + ".");
            var this_available_window_width
                = available_window_width
                - ((num_cells - 1) * CELL_BORDER_WIDTH);
x_log("\nThe available width for this window, given " + num_cells
    + " cells with snapshot frames, is " + this_available_window_width + " pixels.");
            total_width = 0;
            uniform_height = 100;
            for (cellx = 0; cellx < row.length; cellx += 2)
            {
                source  = row[cellx + 0];
                caption = row[cellx + 1];
                x_parse_source(source);
                total_width += Math.floor(plx_parse_source_width
                    * (uniform_height / plx_parse_source_height));
            }
x_log("\nIf the uniform height of this row's cells were 100,");
x_log("\n the total width of this row would be " + total_width + ".");
            resize = 'x' + Math.floor(uniform_height
                * (this_available_window_width / total_width));
x_log("\nTherefor the uniform height has to be resized to " + resize + ".");

            for (cellx = 0; cellx < row.length; cellx += 2)
            {
                source  = row[cellx + 0];
                caption = row[cellx + 1];
                result += "\n<td valign=top>";
                result += x_snapshot(source, resize, '-noalign -nocaption', caption);
                result += "</td>";
            }
        }
        else
        {
x_log("\n*** Row[" + rx + "] of call to x_scrapbook() is not an Array but rather an '" + typeof row + "' and will be ignored ***");
        }

        result += "</tr></table>";
    }
// 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_source, a_resize, a_parms, a_caption_override
)
{
x_log("\nX _ S N A P S H O T ( ) -------------------------------------------------");
    var result = x_media("snapshot", a_source, a_resize, a_parms, a_caption_override);
x_log("\n------------------------------------------------- X _ S N A P S H O T ( )");
    return result;
}

/*--------------------------------------------------------------------*/
/*                     x_soften_breaks() function                     */
/*                                                                    */
/*    This function implements the "soften break" (<sbr>) tag.        */
/*                                                                    */
/*      1) Convert all blanks to non-breaking space characters.       */
/*      2) Convert all "<sbr>" tags to blanks.                        */
/*                                                                    */
/*--------------------------------------------------------------------*/
function x_soften_breaks(a_html)
{
    var result = a_html;
    var lower_case_html = a_html.toLowerCase();
    if (lower_case_html.indexOf('<sbr>') > -1)
    {
        result = result.replace(/ <sbr>/gi, "<sbr>");
        result = result.replace(/<sbr> /gi, "<sbr>");
        result = result.replace(/ /g, "&nbsp;");
        result = result.replace(/-/g, "&minus;");
        result = result.replace(/<sbr>/gi, " ");
x_log("\nx_soften_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 max_passes   = 10000;
    var max_flips    = 100000;
    var total_passes = 0;
    var total_flips  = 0;
    var finished = false;
    while (finished == false && total_passes < max_passes)
    {
        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 < max_flips)
        {
            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_soundbite() function                       */
/*--------------------------------------------------------------------*/
function x_soundbite
(
    a_source, a_resize, a_parms, a_caption_override
)
{
x_log("\nX _ S O U N D B I T E ( ) -----------------------------------------------");
    var result = x_media("soundbite", a_source, a_resize, a_parms, a_caption_override);
x_log("\n----------------------------------------------- X _ S O U N D B I T E ( )");
    return result;
}

/*--------------------------------------------------------------------*/
/*                        x_squeeze() function                        */
/*                                                                    */
/*                  Trim initial and trailing blanks                  */
/*                   and eliminate redundant blanks                   */
/*--------------------------------------------------------------------*/
function x_squeeze(a_input)
{
    var result = new String(a_input);
    while (result.search(/^ /) > -1) result = result.replace(/^ /, "");
    while (result.search(/ $/) > -1) result = result.replace(/ $/, "");
    result = result.replace(/  /g, " ");
    return result;
}

/*--------------------------------------------------------------------*/
/*                         x_stars() function                         */
/*--------------------------------------------------------------------*/
function x_stars(a_count)
{
    var count = a_count;
    var result = new String("<p class='center'>");
    var cx;
    for (cx = 0; cx < count; cx++) result += "* ";
    result = result.substring(0, result.length -1);
// alert("x_stars(" + a_count + ") => '" + result + "'");
    return result;
}

/*--------------------------------------------------------------------*/
/*                          x_tab() function                          */
/*--------------------------------------------------------------------*/
function x_tab()
{
    return x_tabs(1);
}

/*--------------------------------------------------------------------*/
/*                         x_tabs() function                          */
/*--------------------------------------------------------------------*/
function x_tabs(a_count)
{
    var count = a_count;
    var result = new String('');
    var cx;
    for (cx = 0; cx < count; cx++) result += "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
// x_log("\nx_tabs(" + count + ") = '" + 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 (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(a_object)
{
    var result = 0;
    while (a_object.offsetParent)
    {
        result += a_object.offsetTop
        a_object = a_object.offsetParent;
    }
x_log("\nx_top(" + a_object + ") => " + result);
    return result;
}

/*--------------------------------------------------------------------*/
/*                     x_use_resource() function                      */
/*--------------------------------------------------------------------*/
function x_use_resource(a_resource)
{
x_log("\nx_use_resource('" + a_resource + "')");
    plx_resources_used.push(a_resource);
// x_log_resources_used();
}

/*--------------------------------------------------------------------*/
/*                      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()
{
// x_log("\nx_window_width() => " + document.body.clientWidth);
    return document.body.clientWidth;
}

/*--------------------------------------------------------------------*/
/*                         x_write() function                         */
/*--------------------------------------------------------------------*/
function x_write(a_string)
{
// x_log("\nx_write(\"" + a_string + "\");");
    document.write(a_string);
}

/*--------------------------------------------------------------------*/
/*                       x_videoclip() function                       */
/*--------------------------------------------------------------------*/
function x_videoclip
(
    a_source, a_resize, a_parms, a_caption_override
)
{
x_log("\nX _ V I D E O C L I P ( ) -----------------------------------------------");
    var result = x_media("videoclip", a_source, a_resize, a_parms, a_caption_override);
x_log("\n----------------------------------------------- X _ V I D E O C L I P ( )");
    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_yyyymmdd_2_mm_dd_yyyy() function                 */
/*--------------------------------------------------------------------*/
function x_yyyymmdd_2_mm_dd_yyyy(a_yyyymmdd)
{
x_log("\nx_yyyymmdd_2_mm_dd_yyyy(" + a_yyyymmdd + ") ");
    var yyyymmdd      = a_yyyymmdd;
    var yyyy          = yyyymmdd.substr(0, 4);
    var mm            = yyyymmdd.substr(4, 2);
    var dd            = yyyymmdd.substr(6, 2);
    var result        = new String("");
// If an 8-digit date is given, you'll get "mm/dd/yyyy"
// If a  6-digit date is given, you'll get "mm/yyyy"
// If a  4-digit date is given, you'll get "yyyy"
// If a  0-digit date is given, you'll get ""
    if (mm)   result  = mm + "/";
    if (dd)   result += dd + "/";
    if (yyyy) result += yyyy;
x_log(" => '" + result + "'");
    return result;
}

/*--------------------------------------------------------------------*/
/*                        x_hhmmss() function                         */
/*--------------------------------------------------------------------*/
function x_hhmmss()
{
x_log("\nx_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) ss = '0' + ss;
// x_log("\nhh: '" + hh + "'");
// x_log("\nmm: '" + mm + "'");
// x_log("\nss: '" + ss + "'");
    var result = new String(hh + mm + ss);
x_log("\n ... returning '" + result + "'");
    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>


