/*===============================================================
COPYRIGHT NOTICE
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copyright (C) 2006 - 2008 MRHS Class of 59 (MRHS59)

This is free  software; you can redistribute it  and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This  sofware is  made  available in  the  hope that  it will  be
useful,  but  WITHOUT  ANY  WARRANTY; without  even  the  implied
warranty of MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.

A copy of  the GNU General Public License  should be available on
the site where  you obtained this software. It  is also available
at:  http://www.gnu.org/licenses/licenses.html or  by  writing to
the Free Software Foundation,  Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301 USA.

This is merely a notice. The only legally binding document is the
GNU General Public License.
===============================================================*/


/*===============================================================
MANUAL
-----------------------------------------------------------------
NAME
@(#) mrhs59utils.js - utility functions for MRHS59 Web site

SYNOPSIS
     Place this  code at the top  of the BODY section  of the Web
     page on which  you want to make use of  any of the functions
     contained in this file (and spell SCRIPT correctly!):

          <SCIRPT TYPE="text/javascript"
                   SRC="[path/]mrhs59utils.js">
          </SCIRPT>

     Invoke the desired function as follows:

          <SCIRPT>function(args)</SCIRPT>

     Any output from  the  function  will  replace  the  function 
     invocation on the HTML page (including the SCRIPT tags).

     Some  functions  may  require  that the  invoking  page  has
     included  other  files or  set  certain  variables. See  the
     documentation of the individual functions below.

     (The reason  for misspelling SCRIPT is that  after this file
     has  been loaded  into an  HTML page,  the browser  tries to
     interpret  every SCRIPT-tag  that it  encounters --  even if
     it happens to be inside a JavaScript comment.)

DESCRIPTION
     This  file contains  utility functions  for the  Mount Royal
     High School Class of 59  Web site. Each function has its own
     self-contained documentation.

     A predecessor  to this file,  called 'mrhs59_utils.js', went
     through many  versions, and a  rump version of that  file is
     still around  for backwards compatability since  there are a
     number of HTML files  in the Classes subdirectory which call
     the    function   'set_title()'    in    that   file,    and
     'crash_course.html'    uses   both    that    function   and
     'get_browser()'.  Those  are the only two  functions left in
     'mrhs59_utils.js'. The email  functions have been moved from
     'mrhs59_utils.js' to 'spoofutils.js', where they belong.

     THERE  IS NOTHING  IN  'mrhs59_utils.js' WHICH  IS NOT  ALSO
     AVAILABLE IN 'mrhs59utils.js'.

     The  long-term  aim   is  to  phase  out  'mrhs59_utils.js'.
     However there  is no hurry.   Everything works as  is.  It's
     just a bit messy having  two files with almost the same name
     doing the same job.

IDENTIFIERS
     In this  file function names, and important  global (to this
     file) variable names, contain  underscores ('_'). This is to
     try  and avoid  conflicts  with any  similar identifiers  in
     loading files which (hopefully) do not contain underscores.

REDEFINING FUNCTIONS IN JAVASCRIPT
     JavaScript  takes  a  very  relaxed attitude  to  redifining
     functions.  As   is  the  case   with  redefined  variables,
     JavaScript simply uses the most recent definiton.

     We make use of this feature with the function 'set_title()',
     which is defined in the following four places:

       1) In this file, 'mrhs59utils.js' (no underscore).
       2) In 'mrhs59_utils.js'.
       3) In each of the 1959 'Torch' files.
       4) In 'spoofutils.js' of the SpamSpoofer package.

     The reason for having 'set_title()'  defined in 3) and 4) is
     that  the  'Torch' files  and  the  SpamSpoofer package  are
     copyright  under the  GPDL  and the  GPL, respectively,  and
     should therefore  not rely  on functions contained  in files
     not included in their respective packages.

     For  the  same  reason,  'set_title()'  and  'get_browser()'
     should   both   be    copied   from   'mrhs59_utils.js'   to
     'crash_course.html' which  is also covered by  the GPDL, and

     currently  loads  'mrhs59_utils.js'   to  access  these  two
     functions.

NOTE ON THE SRC ATTRIBUTE
     When the  SRC attribute is  used with the SCRIPT-tag,  it is
     exactly as  if the contents  of the file specified  with the
     SRC-attribute had  been placed between  the SCRIPT-tags. Any
     code  actually  appearing between  these  two  tags will  be
     ignored.

     This means, specifically, that  it is NOT possible to invoke
     a function between these two tags.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION
@(#) mrhs59utils.js    vers 2.3.0 - 2009 05 14
         Added 'nhons' to count number of "honorary" classmates.
         Added 'nemail' to count no of people with email address.
         Major expansion of totals printed at bottom of lists.
         The Alphabetical List no longer includes "honorary 
         classmates" (but the Hearsay and Missing Lists still do
         and will continue to do so). The Class and Alphabetical
         Lists contain only graduates, i e those classmates
         with entries in the 1959 'Torch'.

End MANUAL
===============================================================*/


/*===============================================================
GLOBAL VARIABLES ('global' to this file only)
---------------------------------------------------------------*/
var _ROOTPATH = ""; /* Path to 'MRHS59', set by 'list_start()' */
var listformat;
var alphaindex = "OFF";
var select_class = "ALL";
var ncols;
var counter = 0;
var nhons = 0;
var nemail = 0;
var nbios = 0;
class_total = new Array(7);
class_total["11A"] = 34;
class_total["11B"] = 33;
class_total["11C"] = 33;
class_total["11D"] = 30;
class_total["11E"] = 28;
class_total["11F"] = 31;
class_total["10L"] = 15;
var biourl;
var bioname;
var newwin;
a_arr = new Array(
  "A","B","C","D","E","F","G","H","I","J","K","L","M",
  "N","O","P","Q","R","S","T","U","V","W","X","Y","Z"
);
var a_index = 0;
var a_last  = "";
var a_now   = "";
var DEBUGmode = false;
var testvar = "BONK";
seats = new Array();
/*=============================================================*/


/*=============================================================*/
function get_rootpath()
/*---------------------------------------------------------------
NAME
     get_rootpath() - return path to ROOTDIR

DESCRIPTION
     This  function  looks for  ROOTDIR  in  the window  property
     location.pathname,  and  builds  up the  variable  ROOTPATH,
     containing the  RELATIVE path  between the file  which calls
     the function  and ROOTDIR.   This path can  then be  used to
     find and  load JavaScript  files, whose locations  are known
     relative  to  ROOTDIR.   I.e.   this function  produces  the
     relative path UP  to ROOTDIR.  To this must  be appended the
     path DOWN from ROOTDIR to the known JavaScript files.

     The function returns ROOTPATH, terminated with a slash.

EXPLOITER BEHAVIOUR
     RFC  3986  ("Uniform   Resource  Identifier  (URI):  Generic
     Syntax"), clearly stipulates the forward slash ('/') as path
     separator  in   URL  pathnames.   Furthermore   it  includes
     backslash  as  one of  the  characters  which  is neither  a
     Reserved  nor  an  Unreserved  Character, and  which  should
     therefore be encoded, if used at all.

     Despite this -- or perhaps  in order to spite it -- Internet
     Exploiter  uses  the backslash  ('\')  as  separator in  URL
     pathnames  with the  'file:' "scheme"  (protocol) --  if the
     file  resides on  one  of Bill's  machines.   Thus the  path
     separator for  the __SAME__ HTML  file will be  different in
     Exploiter depending on whether the file is being viewed with
     the 'file:' scheme on the developer's own PC running Windows
     or with the 'http:' scheme on a web server, which might even
     be the same PC.

     Mozilla,  of  course, always  uses  slashes.  Thus the  path
     separator  for  the __SAME__  HTML  file  will be  different
     depending on  whether the file is being  viewed with Firefox
     or Exploiter.

     This means  that we must determine which  separator is being
     used  before  attempting  to  split the  pathname  into  its
     components.   If we try  to split  one of  Bill's pathnames,
     using  '/'  as  separator,  with  the  JavaScript  'split()'
     function built into Internet Exploiter,

                  ======================
                  EXPLOITER WILL FREEZE. 
                  ======================

     No error message  will be produced. Just 100%  CPU usage and
     "Not responding".   Could it be  that Bill is doing  this on
     purpose, in the hopes  that people will think JavaScript and
     Java are  unreliable and turn to  Visual Basic (a  k a Virus
     Builder) or C#?

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION
@(#) get_rootpath() vers 1.1.1 - 2008 05 01
         Improved documentation.
     get_rootpath() vers 1.1.0 - 2007 05 28
         Based   on   'getRootPath()'   vers   2.1.0   from   the
         PORTABILBITY  CODE.  It  has been  renamed to  avoid any
         conflicts  in files  which contain  that code  and which
         also load this utility file.
---------------------------------------------------------------*/
{
  var ROOTDIR = "MRHS59";
  var ROOTPATH;
  var loc = window.location.pathname;
  urlarr = new Array();

  if (loc.indexOf("\\") > -1) {
    /*=============================
    This is one of Bill's machines. 
    =============================*/
    urlarr = window.location.pathname.split("\\");
  } else if (loc.indexOf("/") > -1) {
    urlarr = window.location.pathname.split("/");
  } else {
    alert(
      "'getRootPath()': unrecognized path format:\n"
      + window.location.pathname + "\n" + "bailing out"
    );
    return("aborted");
  }

  if (loc.indexOf(ROOTDIR) < 0) {
    alert(
      "'get_rootpath()': Can't find '" + ROOTDIR + "' in "
      + "window.location.pathname:\n"
      + window.location.pathname + ".\n" + "Bailing out."
    );
    return("aborted");
  }

  var len = urlarr.length - 2;
  ROOTPATH = "."
  for (var i = len; urlarr[i] != ROOTDIR; i--) {
    ROOTPATH += "/..";
  }
  ROOTPATH += "/";
  return ROOTPATH;
}
/* End of function 'get_rootpath()' */ 
/*=============================================================*/


/*=============================================================*/
function get_parentdir()
/*---------------------------------------------------------------
NAME
     get_parentdir() - return directory this file resides in

DESCRIPTION
     This function returns the name of the directory in which the
     HTML  file  which  invokes   it  resides.  It  is  based  on
     'get_rootpath()'. See that function for important comments.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION

@(#) get_parentdir() vers 1.0.0 - 2007 06 05
         Based   on   'get_rootpath()' vers 1.1.0
---------------------------------------------------------------*/
{
  var loc = window.location.pathname;
  urlarr = new Array();

  if (loc.indexOf("\\") > -1) {
    /*=============================
    This is one of Bill's machines. 
    =============================*/
    urlarr = window.location.pathname.split("\\");
  } else if (loc.indexOf("/") > -1) {
    urlarr = window.location.pathname.split("/");
  } else {
    alert(
      "'get_parentdir()': unrecognized path format:\n"
      + window.location.pathname + "\n" + "bailing out"
    );
    return("aborted");
  }

  var len = urlarr.length;
  if (len > 1) {
    return(urlarr[len -2])
  } else {
    alert(
      "'get_parentdir()': can't find parentdir in "
      + "window.location.pathname:\n"
      + window.location.pathname + ".\n" + "Bailing out."
    );
    return("aborted");
  }
}
/* End of function 'get_parentdir()' */ 
/*=============================================================*/


/*=============================================================*/
function set_listformat(format)
/*---------------------------------------------------------------
NAME
     setlistformat() - Select format for list functions to use

DESCRIPTION
     This function  sets the global variable  'listformat' to one
     of the  available list formats,  which are used by  the list
     functions, 'list_start()',  list_item()' and 'list_end()' to
     determine what type of list to generate.

FORMATS
     Currently implemented formats are:

     ALPHABETICAL
       Format for the Alphabetical List:
       -----------------------------------------------------
       ID MRHS_Name Class New_Name S_Name Email Bio Comments
       -----------------------------------------------------
       This list contains all MRHS59 classmates  in  alphabetical
       order.

     HEARSAY
       This  list contains  all the  MRHS59 classmates  with whom
       contact has  been made, or about whom  something is known.
       Some of the "knowledge"  is hearsay, hence the name.  This
       list has the same columns as the Alphabetical List.

     CLASS
       Format for  each of the class lists:
       -----------------------------------------------
       ID MRHS_Name New_Name S_Name Email Bio Comments
       -----------------------------------------------
       When  this format  is chosen,  the value  of  the variable
       select_class is used to  determine which class to generate
       the list for.
       Legal values of select_class are:
       ---------------------------------
       11A  11B  11C  11D  11E  11F  10L
       ---------------------------------

     MISSING
       If select_class == "ALL":
       -----------------------------------
       MRHS_Name, Class, Torch, Comments 
       -----------------------------------
       If select_class == "11A", "11B", etc
       --------------------------
       MRHS_Name, Torch, Comments 
       --------------------------

     SEATING
       This format creates a (two-dimensional) matrix, instead of
       a  (one-dimensional) list, to  represent the  seating plan
       for the class specified  by the variable select_class.  It
       is implemented as a 6X6 table, in which each cell contains
       the (scaled-down)  1959 'Torch'  photo of the  student who
       sat in that position plus his or her MRHS name, "reversed"
       so that the last name comes last.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION
     vers 2.1.0  2008 04 10
---------------------------------------------------------------*/
{
  listformat = format;
} 
/* End function 'set_listformat()' */
/*=============================================================*/


/*=============================================================*/
function set_alphaindex(TO)
/*---------------------------------------------------------------
NAME
     set_alphaindex() - Turn alphabetical index on/off

DESCRIPTION
     This function  sets the global variable  alphaindex to the
     value  of the  argument  TO.  When on, this  variable tells
     the list functions to make an alphabetical index for
     the list generated.

LEGAL VALUES OF TO
     Legal values of TO are: "ON" or "OFF"
---------------------------------------------------------------*/
{
  alphaindex = TO;
  return;
} 
/* End function 'set_alphaindex()' */
/*=============================================================*/


/*=============================================================*/
function set_class(gazonk)
/*---------------------------------------------------------------
NAME
     setclass() - Select class for list functions to use

DESCRIPTION
     This function  sets the global variable  select_class to the
     value  of the  argument  class.  This  variable  is used  by
     'list_item()' to limit the  selection of classmates to those
     from   select_class  (or   to  choose   all   classmates  if
     select_class == "ALL").

WARNING
     Don't  be tempted  to use  'class' as  an argument  here (or
     anywhere  else).  Although  'class'  is  not  a  keyword  in
     JavaScript, it IS  in Java, and for this  reason is Reserved
     by  JavaScript  (on  behalf  of  Java,  with  which  it  can
     cooperate).  Although  Firefox can  cope with 'class'  as an
     identifier  in JavaScript,  Exploiter definitely  can't. The
     error message Exploiter produces is

          <line no> expected identifier

     Helpfully, this <line no> seems to be reset at the beginning
     of  each loaded ('SRC-ed')  file, although  the name  of the
     file  is  not specified  in  the  error  message.  This  can
     probably be  taken as a  general indication that  a Reserved
     word has  been used as  an identifier.  At any  rate, that's
     probably a good premiss on which to start debugging.

LEGAL VALUES OF CLASS
     Legal values of gazonk are:
     ALL, 11A, 11B, 11C, 11D, 11E, 11F, 10L.
---------------------------------------------------------------*/
{
  select_class = gazonk;
  return;
} 
/* End function 'set_class()' */
/*=============================================================*/


/*=============================================================*/
function set_debugmode()
/*---------------------------------------------------------------
NAME
     set_debugmode() - Turn on DEBUG_mode

DESCRIPTION
     Turn  on  the variable  DEBUG_mode,  which causes  dubugging
     output to be produced by some functions.
---------------------------------------------------------------*/
{
  DEBUGmode = true;
} 
/* End function 'set_debugmode()' */
/*=============================================================*/


/*=============================================================*/
function list_start()
/*---------------------------------------------------------------
NAME
     list_start() - create table headers, etc for new list

DESCRIPTION
     This function  does whatever is  required (possibly nothing)
     to initiate a new list. A common task would be to write HTML
     table headers if the list is implemented as an HTML table.

FORMATS
     See the documentation of the function 'setlistformat()' for
     a list of currently implemented formats.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION
     vers 4.0.0  2008 04 10
         Implemented SEATING format.
     vers 3.0.0  2008 03 15
         Implemented MISSING format.
     vers 2.2.0  2008 01 30
         Removed kluge.  Each letter  of the alphabet now has its
         own anchor,  regardless of  whether there happens  to be
         someone in the list whose name begins with that letter.
     vers 2.0.0  2007 04 25
         Added alphabetical  indexing to HEARSAY  format. 
---------------------------------------------------------------*/
{
  /*-------------------------------------------------------------
  We don't need the variable  _ROOTPATH here, but we set it here,
  instead  of  in 'listitem()',  where  it  is  used, since  this
  function is  only called  once, whereas 'listitem()'  is called
  once  for every  classmate on  the list  being  generated.  One
  function call is preferrable to 204.
  -------------------------------------------------------------*/ 
  _ROOTPATH = get_rootpath();

  /*------------------------
  Create alphabetical index.
  ------------------------*/
  if (  (listformat == "ALPHABETICAL") 
     || (listformat == "HEARSAY")  
     || (  (listformat == "MISSING") 
        && (alphaindex == "ON") 
        && (select_class == "ALL") 
        )
     ) 
  {
    document.write("<CENTER><B>\
      <A HREF=#A>A</A>&nbsp;\
      <A HREF=#B>B</A>&nbsp;\
      <A HREF=#C>C</A>&nbsp;\
      <A HREF=#D>D</A>&nbsp;\
      <A HREF=#E>E</A>&nbsp;\
      <A HREF=#F>F</A>&nbsp;\
      <A HREF=#G>G</A>&nbsp;\
      <A HREF=#H>H</A>&nbsp;\
      <A HREF=#I>I</A>&nbsp;\
      <A HREF=#J>J</A>&nbsp;\
      <A HREF=#K>K</A>&nbsp;\
      <A HREF=#L>L</A>&nbsp;\
      <A HREF=#M>M</A>&nbsp;\
      <A HREF=#N>N</A>&nbsp;\
      <A HREF=#O>O</A>&nbsp;\
      <A HREF=#P>P</A>&nbsp;\
      <A HREF=#Q>Q</A>&nbsp;\
      <A HREF=#R>R</A>&nbsp;\
      <A HREF=#S>S</A>&nbsp;\
      <A HREF=#T>T</A>&nbsp;\
      <A HREF=#U>U</A>&nbsp;\
      <A HREF=#V>V</A>&nbsp;\
      <A HREF=#W>W</A>&nbsp;\
      <A HREF=#X>X</A>&nbsp;\
      <A HREF=#Y>Y</A>&nbsp;\
      <A HREF=#Z>Z</A>&nbsp;\
      </CENTER></B><P>\
    ");
  } /* End if ( (listformat == "ALPHABETICAL") ... */

  /*--------------------------------------
  Create HTML table headers for this list.
  --------------------------------------*/
  if (  (listformat == "HEARSAY")
     || (listformat == "ALPHABETICAL")
     )
  {
    /*=====================================================
    MRHS_Name, Class, New_Name, Email, Torch, Bio, Comments
    =====================================================*/
    ncols = 7;
    document.write("<TABLE BORDER=1 ALIGN='center'>"
    + "<TR>"
    + "<TH ALIGN='center'>MRHS Name</TH>"
    + "<TH ALIGN='center'>Class</TH>"
    + "<TH ALIGN='center'>New Name</TH>"
    + "<TH ALIGN='center'>Email</TH>"
    + "<TH ALIGN='center'>Torch</TH>"
    + "<TH ALIGN='center'>Bio</TH>"
    + "<TH ALIGN='center'>Comments</TH>"
    + "</TR>"
    );
  } else if (listformat == "CLASS")
  {
    /*==============================================
    MRHS_Name, New_Name, Email, Torch, Bio, Comments
    ==============================================*/
    ncols = 6;
    document.write("<TABLE BORDER=1 STYLE='CLEAR: left'>"
    + "<TR>"
    + "<TH ALIGN='center'>MRHS Name</TH>"
    + "<TH ALIGN='center'>New Name</TH>"
    + "<TH ALIGN='center'>Email</TH>"
    + "<TH ALIGN='center'>Torch</TH>"
    + "<TH ALIGN='center'>Bio</TH>"
    + "<TH ALIGN='center'>Comments</TH>"
    + "</TR>"
    );
  } else if (listformat == "MISSING") 
  {
    /*=================================
    MRHS_Name, [Class,] Torch, Comments 
    =================================*/
    if (select_class == "ALL") {
      ncols = 4;
    } else {
      ncols = 3;
    }
    document.write("<TABLE BORDER=1 ALIGN='center'>"
    + "<TR>"
    + "<TH ALIGN='center'>MRHS Name</TH>"   
    + ((select_class == "ALL")?(
      "<TH ALIGN='center'>Class</TH>"):"") 
    + "<TH ALIGN='center'>Torch</TH>"
    + "<TH ALIGN='center'>Comments</TH>"
    + "</TR>"
    );
  } else if (listformat == "SEATING") 
  {
    /*===============================
    'Torch' photo, reversed MRHS_Name
    ===============================*/
    ncols = 6;
    rows = new Array("A","B","C","D","E","F");
    cols = new Array("1","2","3","4","5","6");
    for (r = 0; r < 6; r++) {
      for (c = 0; c < 6; c++) {
        seats[rows[r] + cols[c]] = 0;
      }
    }
    document.write("<TABLE BORDER=1 ALIGN='center' "
    + "CELLPADDING=5 CELLSPACING=1>"
    + "<TR>"
    + "<TH ALIGN='center'>&nbsp;</TH>"
    + "<TH ALIGN='center' WIDTH=140>1</TH>"
    + "<TH ALIGN='center' WIDTH=140>2</TH>"
    + "<TH ALIGN='center' WIDTH=140>3</TH>"
    + "<TH ALIGN='center' WIDTH=140>4</TH>"
    + "<TH ALIGN='center' WIDTH=140>5</TH>"
    + "<TH ALIGN='center' WIDTH=140>6</TH>"
    + "</TR>"
    );
  } /* End if (listformat == "SEATING") */
} 
/* End function 'list_start()' */
/*=============================================================*/


/*=============================================================*/
function list_item
   (ID,MRHS_Name,TheClass,New_Name,S_Name,Email,Bio,Comments,XXX) 
/*---------------------------------------------------------------
NAME
     list_item() - create new list entry for MRHS59 classmate

DESCRIPTION
     This  function  contains   all  the  formatting  information
     required to format the  abstract student entries in the file
     'clasmates.js',  each of which  has the  form of  a separate
     call to 'list_item()'.   The function arguments contain only
     personal  data  about a  particular  student,  which can  be
     formated in any number of different ways.

      The  format   to  be  used  in  any   given  invocation  of
     'list_item()'   is  determined   by   the  global   variable
     'listformat', which should be set by the page requesting the
     list by calling the function 'setlistformat()'.

     This  means  that  there  need  be  only  ONE  (1)  list  of
     classmates on this site, which is stored in its own file and
     is unaffected  by any editing  changes on the  invoking HTML
     pages or any formatting changes in this file.

     In addition  to making the job of  creating, and maintaining
     lists  a lot  easier, robustness  is also  greatly improved,
     since  there is  much less  room for  error, and  any errors
     which do creep in are much easier to locate.

THE EMAIL ARGUMENT
     The default  subject, which gets placed on  the Subject line
     of all emails generated  by this file with 'SpamSpoofer', is
     'MRHS59:'.   A  different subject  can  be  created for  any
     particular classmate as shown in the following example.

          This Email argument: "aaa,_at_,bbb,_dot_,ccc,',',xxx"
          puts "xxx" on the Subject line of the generated email.

     This is useful if, for  example, a classmate uses a business
     address, and "Attn Miss  Marples: for Hercule", etc needs to
     be placed on the Subject line.

THE XXX ARGUMENT
     This is  the "for future use" argument,  which could perhaps
     be compared to the CGOS  argument in the UNIX password file.
     So far it has been  pressed into use for two purposes, which
     can best be explained with an example.

         list_item("JacCha",...,...,"11G",
                   ...,...,...,...,...,
                   "#E2(Minie Muffet) via Jack Sprat");

     This means that the student  with ID == "JacCha" sat in seat
     E2  in  classroom  11G,  that the  seating  information  was
     supplied by  Minnie Muffet, but the  contact (email address,
     location) came from Jack Sprat.

     The string '#rc', where r (row) is in A..F and c (column) is
     in 1..6, may occur anywhere in the XXX field, or not at all.

FORMATS
     See the documentation of the function 'setlistformat()' for
     a list of currently implemented formats.

FILES AND VARIABLES
     clasmates.js
       This is the file containing the abstract entries for  each
       classmate. Each entry has the form of a  seperate  call to
       the function 'list_item()'.

     _ROOTPATH
       Relative path to the root directory 'MRHS59', needed to
       generate links to the 'Torch' and bios.

     listformat
       This global variable determines the format for the entries
       and should be set by  the  HTML  page  which  invokes  the 
       list-building   functions   by   calling   the    function
       'setlistformat()'.

     select_class
       This global variable is used when  listformat == CLASS  to
       determine which class to generate a list for.

     spoofutils.js
       Some formats (those which generate  email  links)  require
       that 'spoofutils.js' of the SpamSpoofer package  has  been
       included on the calling page.
     
AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION
     vers 5.1.0  2009 05 14
         Added 'nhons' & 'nemail' counters
     vers 5.0.0  2008 04 10
         Implemented SEATING format.
     vers 4.0.0  2008 03 15
         Implemented MISSING format.
     vers 3.5.0  2008 01 30
         Removed kluge.  Each letter  of the alphabet now has its
         own anchor,  regardless of  whether there happens  to be
         someone in the list whose name begins with that letter.
     vers 3.4.0  2008 01 30
         Added alphabetical  indexing to HEARSAY  format.
     vers 3.3.0  2007 05 26
         Replaced global var <rootdir> with <_ROOTPATH>, which is
         now generated by  'get_rootpath()', instead of being set
         by each HTML file which includes these utilities.
     vers 3.4.0  2007 10 05
         Added nbios counter.
---------------------------------------------------------------*/
{
  /*---------------------------------------------------------
  Select or reject this list_item  for inclusion in the list.
  ---------------------------------------------------------*/
  if ( 
    ( (listformat == "ALPHABETICAL")
      && (TheClass != 0)
      && (TheClass != "NA")
      && (TheClass.indexOf("13") == -1)
    ) || (
      (listformat == "CLASS") && (select_class == TheClass)
    ) || (
      (listformat == "HEARSAY") 
       && ( (Email != 0) || (Comments != 0) || (Bio != 0) ) 
    ) || ( 
      (listformat == "MISSING") 
       && ( (select_class == "ALL") 
         || (select_class == TheClass) )
       && (  (Email == 0) && (Comments == 0) && (Bio == 0) )
    )
  ) /* End 'if' condition */
  {
    /*-----------------------------------------
    If  list  has  alphabetical  index,   insert 
    new headers ("A", "B", etc) where necessary.
    ------------------------------------------*/
    if (  (listformat == "ALPHABETICAL") 
       || (listformat == "HEARSAY")
       || (  (listformat == "MISSING") 
          && (alphaindex == "ON") 
          && (select_class == "ALL") ) 
       ) 
    {
      var initial = MRHS_Name.charAt(0).toUpperCase();
      var str = "&nbsp;";

      while (initial != a_last) {
        a_now = a_arr[a_index];
        if (initial != a_now) {
          str += "<SPAN ID=" + a_now + ">&nbsp;</SPAN>";
        } else {
          document.write(
            "<TR><TH COLSPAN=" + ncols
            + " ID=" + a_now + " ALIGN=\"left\">"
              + "&nbsp;&nbsp;&nbsp;&nbsp;" 
              + a_now + str +"</TH></TR>"
          );
        } /* End else ( initial == a_now ) */
        a_last = a_now;
        a_index++;
      } /* End while (initial != a_last) */
    } /* End inner if ( (listformat == "ALPHABETICAL") ... */

    /*==========================================================
    Function argument list repeated here for convenience:
    ------------------------------------------------------------
    ID,MRHS_Name,TheClass,New_Name,S_Name,Email,Bio,Comments,XXX
    ============================================================
    Deal with formats ALPHABETICAL, HEARSAY, CLASS, and MISSING:
    ------------------------------------------------------------
    o) If Email is non-null, generate link  to  SpamSpoofer  and
       place  envelope icon in anchor body. 
    o) If Torch is non-null, generate link  to  Torch  page  and
       place Torch icon in anchor body.
    o) If Bio is  non-null,  generate  call  to  'getbio()'  and
       place bio icon (m or f) in anchor body.
    o) If all three  are  null,  do  not  create  an  entry  for  
       this classmate if listformat == HEARSAY.
    o) If listformat == CLASS, do not generate  table  cell  for
       'Class', and do not generate entry at all unless argument
       TheClass == variable select_class.       
    o) If listformat == MISSING, do not generate table cells for
       'Class', and do not generate entry at all unless argument
       TheClass == variable select_class.   
    ==========================================================*/
    document.write("<TR ID=" + ID +">"
    + "<TD ALIGN='left'>" + MRHS_Name + "</TD>"
    + ( (  (listformat != "CLASS")
        && ( ! (  (listformat == "MISSING")
               && (select_class != "ALL") ) ) )?(
      "<TD ALIGN='center'>" + ((TheClass == 0)?"&nbsp;":TheClass)
      +  "</TD>"):"")
    + ((listformat != "MISSING")?(
      "<TD ALIGN='left'>" + ((New_Name == 0)?"&nbsp;":New_Name)
      + "</TD>"):"") 
    + ((listformat != "MISSING")?(
      "<TD ALIGN='center'>" + ((Email == 0)?"&nbsp;":("<SCRIPT"
      + ">" + "spoofer(\"" + ID + "\",\"" + S_Name + "\",\"" 
      + Email + "\",\"MRHS59:\",\"#SPOOFLINKIMG#\");"
      + "</" + "SCRIPT>")) + "</TD>"):"") 
    + "<TD ALIGN='center'>" + ((TheClass == 0)?"&nbsp;":("<A "
    + "HREF=\"" + _ROOTPATH + "Torch/" + TheClass + "/" 
    + TheClass + "_Torch.html#"
    + ID + "\" TARGET=\"TorchWin\"><IMG "
    + "SRC='" + _ROOTPATH + "Classes/torch.png' BORDER=0></A>"))
    + "</TD>"
    + ((listformat != "MISSING")?(
      "<TD ALIGN='center'>" + ((Bio == 0)?"&nbsp;":("<A "
      + "CLASS=\"bio\" ONCLICK='getbio(\"" + S_Name + "\","
      + "\"Classes/" 
      + TheClass + "/" + ID + "/" + ID + ".html\")'><IMG SRC=\"" 
      + ((Bio == 'm')?(_ROOTPATH 
        + "Classes/BioMan.jpg"):(_ROOTPATH
        + "Classes/BioWom.jpg"))
      + "\" ALIGN='middle' WIDTH=18 HEIGHT=20 BORDER=0></A>"))
      + "</TD>"):"") 
    + "<TD ALIGN='left'>" + ((Comments == 0)?"&nbsp;":Comments)
    +   "</TD>"
    + "</TR>"
    ); /* End document.write */        
    if ( (TheClass != 0) && (TheClass != "NA") && 
         (TheClass.indexOf("13") == -1)  )
      { counter++; } else { nhons++; }
    if (Email != 0 ) { nemail++; }
    if (Bio != 0 ) { nbios++; }
  } /* End outer if ( (listformat == "ALPHABETICAL") || ... */
  else if ((listformat == "SEATING")&&(select_class == TheClass))
  {
    /*==========================================================
    Function argument list repeated here for convenience:
    ------------------------------------------------------------
    ID,MRHS_Name,TheClass,New_Name,S_Name,Email,Bio,Comments,XXX
    ============================================================
    Do  not  generate table  at  all  here.   The table  will  be
    generated in 'list_end()'. Instead,  the job of this function
    is  to  put  selected  entries  into  the  associative  array
    seats[]. Entries are selected if the XX argument  contains  a
    seat no. These are of the form #rc, where r == "A",..,"F" and
    c = 1,..,6.
    ==========================================================*/
    if (XXX != 0) {
      var ix = XXX.indexOf("#");
      if (ix >= 0) {
        var row = XXX.charAt(ix + 1);
        var col = XXX.charAt(ix + 2);
        seats[row + col] = ID + ";" + revname(MRHS_Name);
      }
    }
  } /* End if ((listformat == "SEATING") ... ) */

} /* End function 'list_item()' */
/*=============================================================*/


/*=============================================================*/
function list_end()
/*---------------------------------------------------------------
NAME
     list_end() - do any tidying-up at end of list

DESCRIPTION
     This function  does whatever is  required (possibly nothing)
     to end a  new list. A common task would be  to write the end
     tag for an HTML table, if the list is implemented as an HTML
     table.

FORMATS
     See the documentation of the function 'setlistformat()' for
     a list of currently implemented formats.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION
     vers 3.3.0  2009 05 14
         Major expansion of totals printed at bottom of lists.
     vers 3.0.0  2008 04 10
         Implemented SEATING listformat.
     vers 2.0.0  2008 03 15
         Implemented MISSING listformat.
     vers 1.2.0  2008 01 30
         Added  any  anchors  not  created by  'list_item()'  for
         letters at end of alphabet.
     vers 1.1.1  2008 01 30
         Changed captions for totatls at end of list.
     vers 1.1.0  2007 10 05
         Total no of classmates and no of bios now output at  end 
         of list.
---------------------------------------------------------------*/
{
  if ((listformat == "HEARSAY") ||
      (listformat == "ALPHABETICAL") ||
      (listformat == "MISSING") ||
      (listformat == "CLASS"))    
  {
    /*---------------------------
    Write end tag for HTML table:
    ---------------------------*/
    document.write("</TABLE>");

  } /* End if (listformat == ...) */

  if (  (listformat == "HEARSAY")
     || (listformat == "ALPHABETICAL")
     || (  (listformat == "MISSING") 
        && (alphaindex == "ON") 
        && (select_class == "ALL") )
     ) 
  {
    /*----------------------------
    Create any missing anchors for
    letters at end of alphabet.
    ----------------------------*/
    var str = "&nbsp;";
    while ( a_last < "Z" ) {
      a_now = a_arr[a_index];
      str += "<SPAN ID=" + a_now + ">&nbsp;</SPAN>";
      a_last = a_now;
      a_index++;
    }
    if ( str.length > 1) {
      document.write(str);
    }
  } /* End if ( (listformat == "HEARSAY") ... */

  /*-------------------------------------
  Format & print totals at bottom of list
  -------------------------------------*/
  if ((listformat == "HEARSAY") ||
      (listformat == "ALPHABETICAL") ||
      (listformat == "MISSING") ||
      (listformat == "CLASS"))    
  {
    document.write("<BR>"
    + "Number of classmates in this list: " + counter + "." 
    );
  } /* End if ((listformat == "HEARSAY") ... */
  if (listformat == "HEARSAY")
  {
    document.write("  " +
    "(There were 204 graduates in the class of 1959.)"
    );
  } /* End if ((listformat == "HEARSAY") */
  if ((listformat == "MISSING") && (select_class == "ALL"))
  {
    document.write("<BR>" +
    "(There were 204 graduates in the class of 1959.)"
    );
  } /* End if ((listformat == "MISSING" ..._class == "ALL")) */
  if ((listformat == "MISSING") && (select_class != "ALL"))
  {
    document.write("<BR>"
    + "(Total number of classmates in " 
    + select_class + ": " + class_total[select_class]
    + ".)"
    );
  } /* End if ((listformat == "MISSING" ..._class != "ALL")) */
  if (listformat == "HEARSAY")
  {
    document.write("<BR>"
    + "Number of honorary classmates in list: " + nhons
    + ".  (Not included in above totals.)"
    );
  } /* End if ((listformat == "HEARSAY") */
  if ((listformat == "MISSING") && (select_class == "ALL"))
  {
    document.write("<BR>"
    + "Number of honorary classmates in list: " + nhons
    + ".<BR>(Not included in above totals.)"
    );
  } /* End if ((listformat == "MISSING" ..._class == "ALL")) */
  if ((listformat == "HEARSAY") ||
      (listformat == "ALPHABETICAL") ||
      (listformat == "CLASS"))    
  {
    document.write("<BR>"
    + "Number of people in list with email address: "
    + nemail + ".<BR>"
    + "Number of bios: " + nbios
    );
  } /* End if ((listformat == "HEARSAY") ... */

  /*========================*/
  if (listformat == "SEATING")
  /*========================*/
  {
    rows = new Array("A","B","C","D","E","F");
    cols = new Array("1","2","3","4","5","6");
    for (r = 0; r < 6; r++) {
      document.write(
        "<TR>"
        + "<TH ALIGN='center' HEIGHT=100 VALIGN='middle'>"
        + rows[r] + "</TH>"
      );
      for (c = 0; c < 6; c++) {
        document.write("<TD>");
        if (seats[rows[r] + cols[c]] == 0) {
          document.write("&nbsp;");
        } else {
          seat = new Array();
          seat = seats[rows[r] + cols[c]].split(";");
          document.write(
            "<TABLE CLASS='person'><TR><TD VALIGN='center'>"
            + "<IMG SRC='../../Torch/" 
              + select_class + "/" + seat[0] + ".jpg' "
            + "HEIGHT=90></TD><TD>&nbsp;</TD>"
            + "<TD VALIGN='bottom'>"
            + seat[1] + "</TD></TR></TABLE>"
          );
        } /* End else (seats[rows[r] + cols[c]] != 0) */
        document.write("</TD>");
      } /* End for (c = 0; c < 6; c++) */
      document.write("</TR>");
    } /* End for (r = 0; r < 6; r++) */
    document.write("</TABLE>");
  } /* End if (listformat == "SEATING") */

  if (DEBUGmode == true) {
    /*-------------
    DEBUGGING INFO:
    -------------*/
    document.write("<BR>DEBUG: listformat == " + listformat);
    document.write("<BR>DEBUG: select_class == " + select_class);
    document.write("<BR>");
  }
} 
/* End function 'list_end()' */
/*=============================================================*/


/*=============================================================*/
function revname(MRHS_name)
/*---------------------------------------------------------------
NAME
     revname() - "reverse" MRHS_name, putting last name last

DESCRIPTION
     This  function  is  used  by 'list_item'  to  "reverse"  the
     MRHS_name  of the  classmate, so  that the  last  name comes
     last, and there is no comma.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
---------------------------------------------------------------*/
{
  names = new Array();
  var lastname;
  var firstnames;

  names = MRHS_name.split(",");
  lastname = strip(names[0]);
  firstnames = strip(names[1]);

  return firstnames + "<BR>" + lastname;
}
/* End of function 'revname()' */ 
/*=============================================================*/


/*=============================================================*/
function strip(str)
/*---------------------------------------------------------------
NAME
     strip(str)  - remove leading and trailing spaces from str

DESCRIPTION
     'strip(str)' returns 'str' after removing any leading and/or
     trailing spaces.

     NB! Don't  use 'char' here  (or anywhere else); 'char'  is a
     reserverd   word  in   Java,   which  FireFox's   JavaScript
     interpreter  also reserves  on Java's  behalf,  whereas IE's
     doesn't.  It  would have been  nice if FireFox had  come out
     and said so, instead of just failing silently!

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
---------------------------------------------------------------*/
{
  var len  = str.length;
  var tstr = str;
  for (i = len; i > 0, tstr.substring(i - 1, i) == " "; i--) {
    str = tstr.substring(0, i - 1);
  }
  tstr = str;
  len  = str.length;
  for (i = 0; tstr.substring(i, i +1 ) == " "; i++) {
    str = tstr.substring(i + 1, len);
  }
  return str;
}
/* End function 'strip()' */
/*=============================================================*/


/*=============================================================*/
function horizspace(pix)
/*---------------------------------------------------------------
NAME
     horizspace(pix) - insert horizontal space pix pixels wide

DESCRIPTION
     'horizspace()' will replace its invocation with a horizontal
     space ('tab') exactly pix pixels wide.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
---------------------------------------------------------------*/
{
  var ROOTPATH = get_rootpath();

  document.write(
    "<IMG SRC=\"" + ROOTPATH + "pixel.png\" "
      + "HEIGHT=10 WIDTH=" + pix +">"
  );
}
/* End function 'horzspace()' */
/*=============================================================*/


/*=============================================================*/
  function getbio (name, url, mode) 
/*---------------------------------------------------------------
NAME
     getbio() - present name's bio, which is in url

SYNOPSIS
     getbio( name, url [,mode] )

DESCRIPTION
     This fuction  is designed to handle links to classmate bios.
     There are two reasons for having this function:

     1. By opening the window ourselves (instead of  using  HFREF
        in an anchor) we can ensure that it is  always  moved  to
        the front.
     2. It gives us the opportunity to intersperse  a  page  with
        important   messages  before  presenting  the  bio.  (For
        example, a reminder that other  classmates  are  just  as
        interested in reading YOUR  bio as  you  are  in  reading
        theirs.)

     The   optional  mode   argument  is   used  to   bypass  any
     interspersed page.

AUTHOR
     Donald MacLean          IGdonaldNOatREmacCAleansPIdotTAnetLS
                                      (Do what the capitals say.)
VERSION
     vers 1.0.0  2006 04 09
---------------------------------------------------------------*/
{
  _ROOTPATH = get_rootpath();
  var prebio = _ROOTPATH + "Classes/prebio.html";

  biourl = url;
  bioname = name;

  if ( getbio.arguments.length > 2) {
    newwin = window.open(
                   _ROOTPATH + biourl, "biowin", "");
    newwin.focus();
  } else {
    newwin = window.open(prebio, "biowin", "");
    newwin.focus();
  }

  return true;

} /* End function 'getbio()' */
/*=============================================================*/


/*=============================================================*/
function set_title(str)
/*---------------------------------------------------------------
NAME
     set_title() - put "(LOCAL)", etc in title of disk file

DESCRIPTION
     When we are viewing a  local (disk) version of an HTML file,
     this function will  prepend "(C:)", etc, to the  title if it
     can  figure out  the name  of  the disk.  Otherwise it  will
     default to  "(LOCAL)".  Nothing will be prepended  if we are
     viewing the file over the Web.

     This is so that if we have a remote and a local version open
     at  the same time,  we can  distinguish easily  between them
     especially when they are iconized (or "minimized").

     In addition,  the intrusive browser  name will be  pushed to
     the right on the Title Bar.
---------------------------------------------------------------*/
{
  var title = str;

  if ( /http:\/\/.*/.test(window.location.href) ) {
    /*-------------------
    Web file. Do nothing.
    -------------------*/
    ;
  } else if ( /file:\/\/\/.*/.test(window.location.href) ) {
    /* 
     *  Local file. Prepend disk name to Title
     */
    title = "("   + window.location.href.substring(8,10) 
          + ") "  + title;
  } else  {
    /*-------------------------
    Can't figure out disk name.
    -------------------------*/ 
    title = "(LOCAL) " + title;
  }
  /*---------------------------------------
  Push intrusive browser name to the right.
  ---------------------------------------*/
  title +=
    "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
  + "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"
  + "(&nbsp;-&nbsp;:&nbsp;)";

  document.write("<TITLE>" + title + "</TITLE>");
}
/* End function 'set_title()' */
/*=============================================================*/


/*=============================================================*/
function get_browsername()
/*---------------------------------------------------------------
NAME
     get_browsername() - get name of browser being used

DESCRIPTION
     This function illustrates how  it is possible to recognize a
     Firefox browser, even though its appName is 'Navigator'.  It
     also eliminates blatant Microsoft advertising.
---------------------------------------------------------------*/
{
  if (navigator.userAgent.indexOf("Firefox")!= -1) {
    return "Firefox";
  } else if (navigator.userAgent.indexOf("Opera")!= -1) {
    return "Opera";
  } else if (navigator.appName.indexOf("Microsoft")!= -1) {
    return "Internet Explorer";
  } else {
    return "Unknown";
  }
}
/* End of function 'get_browsername()' */ 
/*=============================================================*/


/*=============================================================*/
function get_browser()
/*---------------------------------------------------------------
NAME
     get_browser() - return name of user's browser

DESCRIPTION
     This  function  is  included   for  the  sake  of  backwards
     compatibility.   It will  replace it's  invocation  with the
     name of  the browser that  the user is reading  the invoking
     page with.

---------------------------------------------------------------*/
{
  document.write(get_browsername());
}

/* End function 'get_browser()' */
/*=============================================================*/


/*=============================================================*/
function concat(args)
/*---------------------------------------------------------------
NAME
     concat() - concatenate strings passed as arguments

DESCRIPTION
     This  function  concatenates  the  strings  it  receives  as
     arguments into  one string. It's principal use  is to handle
     long strings,  such as  pathnames, that would  extend beyond
     the right  margin of  a printout  (or make a  mess of  it if
     word-wrapped).

EXAMPLE
  [Remove underscores after copying]
  blah blah blah
  <SCR_IPT>concat(
    "\n<A HREF=\"",
    "../../../Directory/AnotherDirectory/",
    "VeryLongDirectoryName/",
    "VeryLongFileName.html#location\"\n",
    ">AnchorText</A>\n" 
  );</SCR_IPT>
  blah blah blah
---------------------------------------------------------------*/
{
  var n = concat.arguments.length;
  var i = 0;
  var longstr="";

  while (n > i) {
    longstr += concat.arguments[i];
    i++;
  }

  document.write(longstr);
}

/* End function 'concat()' */
/*=============================================================*/


/*==================
Local Variables:
indent-tabs-mode:nil
fill-column:65
fill-prefix:"     "
End:
==================*/
