function addOnloadEvent(fun) {    
  var old = window.onload;
  if (old) {  
    window.onload = function () { old(); fun(); }}
  else {
    window.onload = fun; }}

function addEventCatcher(element, event, fun) {
  element["on" + event] = 
    function (event) { 
      fun(); 
      return false; }}

// DOM utils

function innerText(element) {
  if (element.innerText != undefined) {
    return element.innerText }
  else {    
    var text = ""; 
    mapArray(element.childNodes, 
      function (e) { 
        switch (e.nodeType) { 
          case 1: text += innerText(e); break;
          case 3: text += e.nodeValue; break; }});
    return text }}

function elementInsertFirst(element, newChild) {
  if (element.firstChild) {
    element.insertBefore(newChild, element.firstChild); }
  else {
    element.appendChild(newChild); }}
   
        
function elementInsertAfter(element, newChild, refChild) {
  var before = refChild.nextSibling;
  if (before) {
    element.insertBefore(newChild, before); } 
  else {
    element.appendChild(newChild); }}     
        
function elementHasClass(element, className) {
  if (!element.className) { return false }
  var re = new RegExp("(^|\\s+)" + className + "($|\\s+)");
  return re.exec(element.className); }

function elementSetClass(element, className) {
  if (!element.className) { 
    return element.className = className }
  else if (!elementHasClass(element, className)) {
    return element.className += " " + className }}
    
// FIXME: \b does not work when hypens are used in class    

function elementRemoveClass(element, className) {
  if (!element.className) { return false }
  var removed = false;
  var re = new RegExp("\\s*\\b" + className + "\\b\\s*");
  element.className = element.className.replace(re, 
    function (str, offset, s) {
      removed = true;
      return offset==0 || str.length+offset==s.length ? "" : " " })
  return removed }  
    
function elementsWithClass(elements, className) {
  return filterArray(elements, elementHasClass.rcurry(className)); }

function getElementsByClass(element, className, tagName) { 
  return elementsWithClass(element.getElementsByTagName(tagName || "*"),
                           className); }

function getElementsByName(name) {
  return filterArray(document.getElementsByTagName("*"), 
    function (e) { return e.name == name; })}

// General utils


// Return a function bound to an object
function delegate(object, methodName) {
  return function () {
    return object[methodName].apply(object, arguments); }}    
                                                                        
function doArray(array, fun) {
  for (var i=0; i<array.length; i++) {
    fun(array[i]); }}

function mapArray(array, fun) {
  var collect = new Array();
  for (var i=0; i<array.length; i++) {
    collect.push(fun(array[i])); }
  return collect; }
  
function filterArray(array, fun) {
  var a = [];
  doArray(array, function (i) { if (fun(i)) { a.push(i); }});
  return a; }

Array.prototype.contains = function (value) {
  for (var i=0; i<this.length; i++) {
    if (this[i]==value) { 
      return true; }}
  return false; }

function makeArray(fakeArray) {
  var array = [];
  for (var i=0; i<fakeArray.length; i++) {
    array.push(fakeArray[i]); }
  return array; }

Function.prototype.curry = function () { 
  var args = makeArray(arguments), self = this;
  return function () { 
    return self.apply(self, args.concat(makeArray(arguments))); }}
  
Function.prototype.rcurry = function () { 
  var args = makeArray(arguments), self = this;
  return function () { 
    return self.apply(self, makeArray(arguments).concat(args)); }}
     
               
