/*
 * Copyright (C) 2008 Toni Ronkko
 * 
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * ``Software''), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL TONI RONKKO BE LIABLE FOR ANY CLAIM, DAMAGES OR
 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 *
 * Feb 24, 2008, Toni Ronkko <http://softagalleria.net>
 */




/*** TABLE OF CONTENTS ***/

/*
 * Generate table of contents from h1 tags.  The generated table will be
 * placed inside the toc element which might be defined as:
 *
 *   <div id="toc"></div>
 */
function sg_toc () {
  var mainmatter = document.getElementById("sg_mainmatter");
  var toc = document.getElementById ("sg_toc");

  /* get length of document in pixels */
  var h = 0;
  if (document.body) {
    if (document.body.style.pixelHeight) {
      h = document.body.style.pixelHeight;
    } else if (document.body.offsetHeight) {
      h = document.body.offsetHeight;
    }
  }

  /* build table of contents */
  var n = 0;
  var html = "";
  if (mainmatter) {
    html = "<h1>Table of Contents</h1>";
    html += "<p class='toc'>";

    var j = 0;
    var p = mainmatter.childNodes[0];
    while (p != null) {
      /* see if the element is a title and format section number */
      var sectno = "";
      var type = "";
      if (p.nodeName.toUpperCase() == "H1") {
        type = "sg_toc1";
        sectno = ++n;
        j = 0;
      }
      if (p.nodeName.toUpperCase() == "H2") {
        type = "sg_toc2";
        sectno = n + "." + (++j);
      }

      /* process section header */
      if (sectno != "") {
        var title = p.innerHTML;

        /* prepend link to top */
        if (j > 1  ||  (j == 0  &&  n > 1)) {
          p.parentNode.insertBefore (sg_toplink(), p);
        }

        /* construct id for the title or use the existing one */
        var id = p.id;
        if (!id) {
          id = "sg" + sectno;
        }

        /* lay anchor so that the title can be reached */
        p.setAttribute ("id", id);

        /* add section number to title */
        p.innerHTML = "<span class='sectno'>" + sectno + " </span>" + title;

        /* add link to table of contents */
        html += "<div class='" + type + "'>" +
                "<span class='sectno'>" + sectno + " </span>" +
                "<a href='#" + id + "' onclick=\"return sg_show('" + id + "');\" class='sg_toctitle'>" + title + "</a></div>";

      }

      p = p.nextSibling;
    }
    html += "</p>";

    /* append link to the top */
    mainmatter.appendChild (sg_toplink());
  }

  /* display table of contents only for long pages */
  if (toc  &&  h > 700  &&  n >= 2) {
    toc.innerHTML = html;
    toc.style.display = "block";
  }
}


/*
 * Returns a DOM object that represents a link to the top of the page.
 *
 * Note that class name and onclick attribute cannot be set with the
 * setAttribute() function is MSIE 7.
 */
function sg_toplink() {
  var e = document.createElement ("a");

  /* set class */
  e.className = "sg_toplink";

  /* set link just in case */
  e.setAttribute ("href", "#top");

  /* register javascript function to scroll the screen */
  e.onclick = function() { return sg_show('top'); };

  /* add link text */
  e.appendChild(document.createTextNode("Back to the top"));

  /* place the link inside a paragraph */
  var p = document.createElement ("p");
  p.appendChild(e);
  return p;
}



/*** REFERENCES ***/

/*
 * Generate list of references from links.  The list of references will be 
 * placed inside the refs element which might be defined as:
 *
 *   <div id='sg_refs'></div>
 *
 * Moreover, if the list of references is to be visible only in the printed
 * media, then the style sheet should contain:
 *
 *   .sg_ref, #sg_refs, .sg_reftitle {
 *     display: none;
 *   }
 *   @media print {
 *     .sg_ref {
 *       display: inline;
 *     }
 *     li.sg_reftitle {
 *       display: list-item;
 *     }
 *     #sg_refs, h1.sg_reftitle {
 *       display: block;
 *     }
 *   }
 */
function sg_refs () {
  var refs = document.getElementById("sg_refs");

  /* append references to links within main matter */
  var links = new Array();
  var mainmatter = document.getElementById("sg_mainmatter");
  if (refs  &&  mainmatter  &&  document.createElement) {
    var elems = mainmatter.getElementsByTagName("a");
    for (var i = 0; i < elems.length; ++i) {
      var url = elems[i].href;
      var title = elems[i].innerHTML;

      /* construct base name of the page without anchor */
      var base;
      if (url.indexOf ("#") >= 0) { 
        base = url.substr(0, url.indexOf ("#"));
      } else {
        base = url;
      }

      /* omit links within the current page */
      if (base != ""  &&  sg_pageurl() != base) {

        /* url already present in links array? */
        var present = false;
        var id = -1;
        var j = 0;
        while (j < links.length) {
          if (links[j][0] == url) {
            /* link declared already */
            present = true;
            break;
          }
          ++j;
        }
    
        /* add new link */
        if (!present) {
          links[j] = new Array (url, title);
        }

        /* 
         * Append reference number to the link.  If you wish to add space
         * between the link and the reference number, then use the expression
         * "\u00a0" which is the same as "&nbsp;".  HTML entities do not work
         * with createTextNode() but must be replaced by their character codes.
         * See http://www.w3schools.com/tags/ref_entities.asp for more info.
         */
        var e = document.createElement ("sup");
        e.setAttribute ("class", "ref");
        e.appendChild(document.createTextNode(j+1));
        elems[i].parentNode.insertBefore (e, elems[i].nextSibling);
      }
    }
  }

  /* generate list of references */
  if (refs  &&  links.length) {
    var html = "<ol>";
    for (var i = 0; i < links.length; ++i) {
      var title = links[i][1];
      var url = links[i][0];

      /* append link */
      html +=
        "<li>" +
        "<span class='sg_refname'>" + title + "</span><br />" +
        "<code>" + url + "</code>" +
        "</li>";
    }
    html += "</ol>";

    /* output generated content to refs element */
    refs.innerHTML = html;

    /* insert title before refs element so that the title will appear in toc */
    var h1 = document.createElement ("h1");
    h1.setAttribute ("class", "sg_reftitle");
    h1.appendChild(document.createTextNode("References"));
    refs.parentNode.insertBefore (h1, refs);
  }
}




/*** SMOOTH SCROLLING ***/

/* timer used in scrolling */
var sg_scrolltimer = null;


/*
 * Initiate smooth scrolling to show the object obj in the current page.  If
 * obj is null, then inspect the href property of current element and use
 * that as a target.
 */
function sg_show (obj) {
  /* find destination */
  var f = document.getElementById (obj);

  /* 
   * Interrupt previous scrolling.  This is important if user clicks on a
   * link when the screen is scrolling.  Having two destinations at once
   * would make the browser jump back and forth.
   */
  if (sg_scrolltimer) {
    window.clearInterval (sg_scrolltimer);
  }

  /* initiate scrolling */
  if (f) {
    var y1 = sg_screenpos ();
    var y2 = sg_itempos (f);
    if (y1 != y2) {
      sg_autoscroll (y1, y2, f);
      sg_autoscroll (y1, y2, f);
      sg_autoscroll (y1, y2, f);
      sg_scrolltimer = window.setInterval(
          function () { sg_autoscroll(y1,y2,f); },
          20);
    }

    /* do not follow link, will be scrolling slowly if needed */
    return false;
  } else {
    /* do jump directly to the target */
    return true;
  }
}


/*
 * Scroll window vertically towards coordinate y2 by some amount.
 */
function sg_autoscroll (y1, y2, f) {
  /* current scroll position */
  var curpos = sg_screenpos ();

  /* compute distance to scroll */
  var d;
  var max = 100;
  var min = 2;
  if (y1 < y2) {
    d = Math.sin (3.14 * (curpos-y1) / (y2-y1)) * (y2-y1) / 10;
    if (d < min) { d = min; }
    if (d > max) { d = max; }
    if (curpos + d > y2) { d = y2 - curpos; }
  } else {
    d = Math.sin (3.14 * (curpos-y2) / (y1-y2)) * (y2-y1) / 10;
    if (d > -min) { d = -min; }
    if (d < -max) { d = -max; }
    if (curpos + d < y2) { d = y2 - curpos; }
  }

  /* scroll window */
  window.scrollBy (0, Math.round(d));

  /* de-activate time once destination has been reached */
  if (Math.abs (curpos - y2) < min  ||  sg_screenpos () == curpos) {
    window.clearInterval (sg_scrolltimer);
  }
}


/*
 * Compute the scroll bar position.
 * http://www.softcomplex.com/docs/get_window_size_and_scrollbar_position.html
 */
function sg_screenpos () {
  var y = 0;

  /* Opera, MSIE (Strict), Firefox (Strict) */
  if (document.documentElement.scrollTop) {
    var t = document.documentElement.scrollTop;
    if (t > y) { y = t; }
  }

  /* MSIE (quirks), Firefox (quirks) */
  if (document.body.scrollTop) {
    var t = document.body.scrollTop;
    if (t > y) { y = t; }
  }

  /* Safari */
  if (window.pageYOffset) {
    var t = window.pageYOffset;
    if (t > y) { y = t; }
  }

  return y;
}


/*
 * Compute position of and element within page.
 * http://www.quirksmode.org/js/findpos.html
 */
function sg_itempos (f) {
  var curtop = 0;
  if (f.offsetParent) {
    curtop = f.offsetTop;
    while (f = f.offsetParent) {
      curtop += f.offsetTop;
    }
  }
  return curtop;
}




/*** TABLE OF CONTENTS IMAGE ***/

/*
 * Move tocimage to upper right corner.
 */
function sg_tocimg() {
  var tocimage = document.getElementById("sg_tocimage");
  if (tocimage) {
    var content = document.getElementById("sg_content");

    /* compute the width of the largest image within tocimage */
    var imgs = tocimage.getElementsByTagName("img");
    var w = -1;
    for (var i = 0; i < imgs.length; ++i) {
      if (imgs[i].width > w) {
        w = imgs[i].width;
      }
      if (imgs[i].style.width > w) {
        w = imgs[i].style.width;
      }
    }

    /* 
     * Set the maximum width according to the largest image.  This is
     * important to fold long image captions automatically.
     */
    if (w > 0  &&  !tocimage.style.maxWidth) {
      tocimage.style.maxWidth = w + "px";
    }

    /* move toc image as the first child of content */
    if (content) {
      content.insertBefore (tocimage, content.childNodes[0]);
    }
  }
}




/*** DATA ENTRY FORMS ***/

/* set to 1 if data has been submitted through submit button */
var sg_submitted = 0;

/*
 * Check input fields in contact form prior to submitting a message.  Returns
 * true if the message may be submitted.
 */
function sg_checkcontact() {
  var f;

  /* must give a name */
  f = document.getElementById("sg_name");
  if (f) {
    if (!f.value.match(/[A-Za-z0-9äöÄÖ]{2}/)) {
      f.focus();
      alert("Missing name or initials!");
      return false;
    }
  }

  /* check e-mail address for validity */
  f = document.getElementById("sg_from");
  if (f) {
    if (f.value != ""  &&  !f.value.match(/^ *[_a-z0-9-]+(\.[_a-z0-9-]+)*@([0-9a-z][0-9a-z-]*[0-9a-z]\.)+[a-z]{2}[mtgvu]? *$/)) {
      f.focus();
      alert("Invalid e-mail address!");
      return false;
    }
  }

  /* must have a message */
  f = document.getElementById("sg_msg");
  if (f) {
    if (!f.value.match(/[A-Za-z0-9äöÄÖ]/)) {
      f.focus();
      alert("Missing message!");
      return false;
    }
    if (!f.value.match(/[A-Za-z0-9äöÄÖ]{3}/)) {
      f.focus();
      alert("Message too short!");
      return false;
    }
  }

  /* allow changes to be submitted */
  return true;
}


/*
 * Accept changes in a form prior to submitting it.  This function is
 * necessary to bypass onbeforeunload handler which would confirm exit
 * from a page when user submits a form through the submit button.
 *
 * This very function must be attached to form.onsubmit handler to work.
 */
function sg_acceptform() {
  sg_submitted = 1;
  return true;
}


/*
 * Discard changes to a form and allow user to leave the current page 
 * without confirmation.
 */
function sg_discardform() {
  sg_resetform();
  return true;  
}


/*
 * Called prior to leaving the current page in Mozilla, Firefox, MSIE and 
 * Safari.  The purpose of this function is to check if the page has unsaved
 * changes and confirm the exit if there is a risk of losing some data.
 *
 * This function has unusual calling schemantics.  If the function does not
 * return anything, then no questions will be asked and the user is free to
 * navigate to another page.  However, if the function does return something,
 * even an empty string or null, then the return value is shown to user in
 * a question dialog and user is asked to make a choice.
 */
function sg_confirmexit() {
  if (sg_submitted == 0) {
    /* iterate form elements in all forms */
    var changed = false;
    for (var i = 0; i < document.forms.length; ++i) {
      for (var j = 0; j < document.forms[i].length; ++j) {
        var f = document.forms[i].elements[j];
        if (f.type == "checkbox") {
          if (f.checked != f.defaultChecked) {
            changed = true;
          }
        } else if (f.type == "text"  ||  f.type == "textarea") {
          if (f.defaultValue != f.value) {
            /* value changed */
            changed = true;
          }
        } else if (f.type == "select-one") {
          for (var k = 0; k < f.options.length; ++k) {
            if (f.options[k].selected != f.options[k].defaultSelected) {
              /* selection changed */
              changed = true;
            }
          }
        }
      }
    }

    /* confirm exit (see header for discussion on calling schemantics) */
    if (changed) {
      return "Changes will be lost if you navigate away from this page without submitting the form.";
    }
  }
  sg_submitted = 0;
}


/*
 * Clear all input fields in a form.  This is mostly useful when the default
 * values are retrieved from database.
 */
function sg_resetform() {
  /* iterate form elements in all forms */
  var changed = false;
  for (var i = 0; i < document.forms.length; ++i) {
    for (var j = 0; j < document.forms[i].length; ++j) {
      var f = document.forms[i].elements[j];
      if (f.type == "checkbox"  ||  f.type == "radio") {
        f.checked = false;
      } else if (f.type == "text"  ||  f.type == "textarea") {
        f.value = "";
      } else if (f.type == "select-one") {
        f.selectedIndex = 0;
      }
    }
  }

  return false;
}



/*** MENU ***/

/*
 * Add menus to the page.
 */
function sg_menu() {
  var f = document.getElementById("sg_sidebar");
  if (f) {
    f.innerHTML =
"<div id='sg_gamemenu'>" + 
"<h1>Games</h1>" + 
"<ul>" + 
"<li id='sg_openttd'><a href='openttd.php'>OpenTTD</a></li>" + 
"<li id='sg_freecell'><a href='freecell.php'>Freecell</a></li>" + 
"<li id='sg_potris'><a href='potris.php'>Potris</a></li>" + 
"<li id='sg_ps2yabasic'><a href='ps2yabasic.php'>PS2 Yabasic</a></li>" + 
"</ul>" + 
"</div>" + 
"" + 
"<div id='sg_utilmenu'>" + 
"<h1>Utilities</h1>" + 
"<ul>" + 
"<li id='sg_dirent'><a href='dirent.php'>Dirent</a></li>" + 
"<li id='sg_jsphoto'><a href='jsphoto.php'>JsPhoto</a></li>" + 
"<li id='sg_mixer'><a href='mixer.php'>Mixer</a></li>" + 
"<li id='sg_yabwrite'><a href='yabwrite.php'>Yabwrite</a></li>" + 
"</ul>" + 
"</div>" + 
"" + 
"<div id='sg_solarismenu'>" + 
"<h1>Solaris</h1>" + 
"<ul>" + 
"<li id='sg_virtualbox'><a href='virtualbox.php'>VirtualBox</a></li>" + 
"<li id='sg_seamonkey'><a href='seamonkey.php'>SeaMonkey</a></li>" + 
"<li id='sg_openttd-solaris'><a href='openttd-solaris.php'>OpenTTD</a></li>" + 
"<li id='sg_icewm'><a href='icewm.php'>IceWM</a></li>" + 
"<li id='sg_mplayer'><a href='mplayer.php'>MPlayer</a></li>" + 
"<li id='sg_xfig'><a href='xfig.php'>XFig</a></li>" + 
"<li id='sg_subversion'><a href='subversion.php'>Subversion</a></li>" + 
"</ul>" + 
"</div>" + 
"" + 
"<div id='sg_infomenu'>" + 
"<h1>Info</h1>" + 
"<ul>" + 
"<li id='sg_news'><a href='news.php'>News</a></li>" + 
"<li id='sg_about'><a href='about.php'>This Site</a></li>" + 
"<li id='sg_person'><a href='person.php'>Toni Rönkkö</a></li>" + 
"<li id='sg_thanks'><a href='thanks.php'>Thanks</a></li>" + 
"<li id='sg_contact'><a href='contact.php'>Contact</a></li>" + 
"</ul>" + 
"</div>" + 
"" + 
"<div id='sg_othermenu'>" + 
"<h1>See also</h1>" + 
"<ul>" + 
"<li><a href='about.php'>About</a></li>" + 
"<li><a href='news.php'>News</a></li>" + 
"<li><a href='contact.php'>Contact</a></li>" + 
"</ul>" + 
"</div>" + 
"" + 
"<p>" + 
"<a href='http://validator.w3.org/check?uri=referer'><img src='xhtml10.gif' alt='' height='31' width='88' /></a>" + 
"</p>";
  }

  f = document.getElementById("sg_linkbar");
  if (f) {
    f.innerHTML = 
"<a href='index.php' id='sg_home'>Home</a>" +
"<a href='dirent.php' id='sg_util'>Utilities</a>" +
"<a href='openttd.php' id='sg_game'>Games</a>" +
"<a href='virtualbox.php' id='sg_solaris'>Solaris</a>" +
"<a href='news.php' id='sg_info'>Info</a>" +
"<a href='sitemap.php' id='sg_sitemap'>Site map</a>";
  }
}



/*** FANCY CHECK BUTTON ***/

/*
 * Toggle background image of current check button from off.gif to on.gif, and
 * scroll to show the target.
 */
function sg_togglecheckbtn (obj) {
  var jump = true;

  /* identifier of check button in page */
  var id = obj.id;

  /* extract base and anchor from object url */
  var base;
  var anchor;
  var url = String (obj.href);
  var i = url.indexOf ("#"); 
  if (i >= 0) { 
    base = url.substr (0, i);
    anchor = url.substr (i + 1);
  } else {
    base = url;
    anchor = "";
  }

  /* toggle button */
  if (obj.style.backgroundImage == "url(on.gif)") {

    sg_setcookie (id, "", -1);
    obj.style.backgroundImage = "url(off.gif)";

    /* prevent browser from jumping directly to the link (was toggled off) */
    jump = false;

  } else {

    sg_setcookie (id, "1", 7);
    obj.style.backgroundImage = "url(on.gif)";

    /* jump to next heading */
    if (obj.href != "") {

      /* scroll smoothly to internal links only */
      if (sg_pageurl() == base  &&  anchor != "") {
        sg_show (anchor);

        /* prevent browser from jumping directly to the link */
        jump = false;
      }
    }
  }

  /* allow/disallow browser from following the link */
  return jump;
}


/*
 * Check all fancy check buttons in a page depeding on cookies.  This allows
 * user to tick the boxes and see his porgrams later.
 *
 * The function also specifies identifiers for the buttons such that the
 * state of the button can be saved to a cookie.
 */
function sg_checkbtns() {
  var ids = 0;
  var mainmatter = document.getElementById("sg_mainmatter");
  if (mainmatter) {

    /* check all links within mainmatter */
    var elems = mainmatter.getElementsByTagName("a");
    for (var i = 0; i < elems.length; ++i) {
      var obj = elems[i];

      /* only process fancy check buttons */
      if (obj.className == "sg_checkbtn") {

        /* set hint */
        obj.title = "Acknowledge this step";

        /* set function */
        obj.onclick = function () { return sg_togglecheckbtn(this); };

        /* specify id so that value can be saved */
        var id = sg_pageid() + (++ids);
        obj.setAttribute ("id", id);

        /* set button image depending on cookie */
        var value = sg_getcookie (id);
        if (value == "1") {
          obj.style.backgroundImage = "url(on.gif)";
        }
      }
    }
  }
}


/*
 * Reset all fancy check buttons to their default state.
 */
function sg_resetcheckbtns() {
  var ids = 0;
  var mainmatter = document.getElementById("sg_mainmatter");
  if (mainmatter) {

    /* check all links within mainmatter */
    var elems = mainmatter.getElementsByTagName("a");
    for (var i = 0; i < elems.length; ++i) {
      var obj = elems[i];
      if (obj.className == "sg_checkbtn") {

        sg_setcookie (obj.id, "", -1);
        obj.style.backgroundImage = "url(off.gif)";

      }
    }
  }

  /* prevent browser from following link */
  return false;
}


/*** COOKIES ***/

/*
 * Get value of a cookie.
 */
function sg_getcookie (cookie) {
  /* find named cookie */
  var cookies = document.cookie.split (";");
  for (var i = 0; i < cookies.length; ++i) {
    var item = cookies[i];

    /* get name and value of this cookie */
    var value, name;
    var pos = item.indexOf("=");
    if (pos >= 0) {
      name = item.substr (0, pos);
      value = item.substr (pos + 1);
    } else {
      name = item;
      value = "";
    }
    name = name.replace(/^\s+|\s+$/g, "");

    /* found our cookie? */
    if (name == cookie) {
      return value;
    }
  }
  /* cookie not found */
  return "";
}


/*
 * Set cookie.  By default, the cookie will expire in one year.  To change
 * the expiration date, invoke the function with a third argument that
 * specifies the lifetime of the cookie in days.  Set the optional argument
 * to a negative value to remove cookie instantly.
 */
function sg_setcookie (cookie, value) {

  /* get optional lifetime */
  var lifetime;
  if (sg_setcookie.arguments.length > 2) {
    lifetime = sg_setcookie.arguments[2];
  } else {
    lifetime = 365;
  }

  /* compute expiration date in milliseconds after January 1, 1970 */
  var expiredate = new Date();
  expiredate.setTime (expiredate.getTime() + (lifetime*24*60*60*1000));

  /* set cookie */
  document.cookie = 
      cookie + "=" + escape(value) + "; " +
      "expires=" + expiredate.toGMTString();
}



/*** PAGE INFORMATION ***/

/*
 * Construct the name of the current document excluding possible anchor.  For
 * example, if the url is http://softagalleria,net/sg/virtualbox.php#gcc,
 * then construct the base name http://softagalleria,net/sg/virtualbox.php.
 * This is used for distinguishing the links within the current page from
 * the ones leading to other sites or pages.
 */
function sg_pageurl () {
  return window.location.protocol + "//" + 
      window.location.host + window.location.pathname +
      window.location.search;
}


/*
 * Get pseudo unique page identifier.  The page identifier can be used to
 * create page specific names for cookies, for example.
 */
function sg_pageid() {
  var path = window.location.pathname;

  /* get last component of the path */
  var base;
  var pos = path.lastIndexOf ("/");
  if (pos >= 0) {
    base = path.substr (pos + 1);
  } else {
    base = path;
  }

  /* remove suffix */
  pos = base.indexOf (".");
  if (pos >= 0) {
    base = base.substr (0, pos);
  }

  return base;
}



/*** MAILTO LINKS ***/

/*
 * Replace textual e-mail addresses with mailto links within the document.
 * For example, given element
 *
 *   <span id="sg_mailto">turnkey (at) spam dot invalid</span>
 *
 * turn that into
 * 
 *   <span id="sg_mailto"><a
 *   href='mailto:turnkey@spam.invalid'>turnkey@spam.invalid</a></span>
 *   
 * This ought to make the address invisible to email harvesting robots.
 */
function sg_mailto() {
  var f = document.getElementById ("sg_mailto");
  if (f) {
    var addr = f.innerHTML;
    addr = addr.replace(/\(at\)/, "@");
    addr = addr.replace(/[ \t\n\r]at[ \t\r\n]/, "@");
    addr = addr.replace(/[ \t\r\n]dot[ \t\r\n]/g, ".");
    addr = addr.replace(/[ \t\r\n]/g, "");
    f.innerHTML = "<a href='mailto:" + addr + "'>" + addr + "</a>";
  }
}


/*** INSTALLATION ***/

/*
 * Register a Javascript function to be invoked after the page has loaded.
 * If multiple functions are registered, then the functions will be executed
 * in an undefined order.  If certain functions must be executed before
 * others, then create a new function that calls other functions in the
 * proper order and register a single function instead.
 *
 * See also
 * http://onlinetools.org/articles/unobtrusivejavascript/chapter4.html
 */
function sg_onload (func) {
   if (window.addEventListener) {
    window.addEventListener ("load", func, false);
  } else if (window.attachEvent){
    window.attachEvent ("onload", func); 
  }
}


/* install the sg_exit to be called prior to navigating away */
window.onbeforeunload = sg_confirmexit;

/* generate content after the page has loaded */
sg_refs();
sg_toc();
sg_tocimg();
sg_menu();
sg_checkbtns();
sg_mailto();
