// (C) Gary Haran - www.xutopia.com - 2000-2002
//
// Usage of xapi is only granted to owners of individual, charity and non-profit
// organisations web sites that aren't racist, libelous or pornographic,
// political or commercial.
//
// Contact the creator of xapi for more information or any business talks.

var _dom = (document.getElementById);
var _def = (document.defaultView);
var _ie  = ((document.all && !_dom));
var _moz = (window.sidebar)
var language = (navigator.language ? navigator.language : navigator.userLanguage).substring(0,2);
var undefined;

if (typeof oldBrowserMessage == "undefined")
{
  var oldBrowserMessage = "The site you are looking at does not works with "
      + navigator.appName + " " + navigator.appVersion
      + ".\n\nYou should upgrade to Netscape 6, Mozilla 1.0 or Internet Explorer 6.";
}

if (!(_dom || _ie))
{
    alert(oldBrowserMessage)
}

function getElement(id)
{
  return Div(id);
}

function getValue(field)
{
  if (field.value)
  {
    return field.value;
  }
  else if (field.selectedIndex != 'undefined')
  {
    var selectedValues = new Array();
    for (var i = 0; i < field.options.length; i++)
    {
      if (field.options[i].selected)
      {
        selectedValues.push(field.options[i].value)
      }
    }
    return selectedValues;
  }
}

function show(id){ Div(id).show() }
function hide(id){ Div(id).hide() }
function displayAsBlock(id){ Div(id).setAsBlock() }
function displayAsNone(id){ Div(id).setAsNone() }

function reporter()
{
  var p = [];

  for (var prop in this)
  {
    if (typeof this[prop] != "function")
    {
      p.push(prop + "\t" + this[prop] + "\n");
    }
  }

  return p;
}
Object.prototype.report = reporter;

MenuBar = {
  titles : [],
  menus  : [],
  active : false,
  over   : false,
  lastClicked : -1,
  out : -500,
  write : function()
  {
    var str = "<div id=MenuBarDiv class=menuBar>\n  <table cellpadding=4 cellspacing=0 border=0>\n    <tr>\n";
    for (var i = 0; i < this.titles.length; i++)
    {
      str += "      <td id=titleDiv" + i + " class=menuTitleOff"
           + " onMouseOver='MenuBar.mouseOver(" + i + ");MenuBar.over = true;'"
           + " onMouseOut='MenuBar.mouseOut("   + i + ");MenuBar.over = false;'"
           + " onClick='MenuBar.click("         + i + ");'>"
           +   this.titles[i]
           + "</td>";
    }
    str += "    <tr>\n  </table>\n  </div>";

    for (var i = 0; i < this.menus.length; i++)
    {
      str += "<div id=MenuDiv" + i + " style='position:absolute;left:" + this.out + ";top:" + this.out + ";z-index:1000;filter:alpha(opacity=94);-Moz-Opacity:94%;'>\n"
           + "  <table cellpadding=2 cellspacing=0 border=0 class=itemTable>\n";

      for (var j = 0; j < this.menus[i].items.length; j++)
      {
        var item = this.menus[i].items[j];
        str += "    <tr>\n      <td class=itemOff"
             + " onMouseOver='this.className=\"itemOn\"'"
             + " onMouseOut=\"this.className='itemOff'\""
             + " onClick=\"" + item.action + "\">"
             + "&nbsp;&nbsp;"
             +   item.title
             + "&nbsp;&nbsp;&nbsp;</td>\n    </tr>\n";
      }

      str += "    </tr>\n  </table>\n  </div>\n";
    }
    //document.forms[0].elements[0].value = str
    document.write(str);
  },
  mouseOver : function(num)
  {
    if (this.active)
    {
      this.makePressed(num);
    }
    else
    {
      this.makeOn(num);
    }
  },
  mouseOut : function(num)
  {
    if (!this.active)
    {
      this.makeOff(num);
    }
  },
  click : function(num)
  {
    if (this.lastClicked == num)
    {
      this.active = false;
      this.makeOn(num);
      Div("MenuDiv" + num).moveTo(this.out, this.out);
      this.lastClicked = -1;
    }
    else
    {
      this.makePressed(num);
    }
  },
  makePressed : function(num)
  {
    this.active = true;
    if (this.lastClicked != -1)
    {
      this.makeOff(this.lastClicked);
      var child = Div("MenuDiv" + this.lastClicked);
      if (child)
      {
        child.moveTo(this.out, this.out);
      }
    }
    this.lastClicked = num;

    var title = Div("titleDiv" + num);
    title.className = 'menuTitleActive';

    var menuBar = Div("MenuBarDiv");

    var top    = parseInt(title.offsetTop) + parseInt(menuBar.offsetTop);
    var height = parseInt(title.offsetHeight);
    var left   = parseInt(title.offsetLeft) + parseInt(menuBar.offsetLeft);

    var childMenu = Div("MenuDiv" + num);
    childMenu.moveTo(left, top + height);
  },
  makeOn : function(num)
  {
    Div("titleDiv" + num).className = 'menuTitleOn';
  },
  makeOff : function(num)
  {
    Div("titleDiv" + num).className = 'menuTitleOff';
    Div("MenuDiv"  + num).moveTo(this.out, this.out);
  },
  reset : function()
  {
    if (!MenuBar.over && this.lastClicked != -1)
    {
      this.active = false;
      this.makeOff(this.lastClicked);
      this.lastClicked = -1;
    }
  },
  add : function(menu)
  {
    this.menus.push(menu);
    this.titles.push(menu.title);
  },
  addToLastMenu : function(item)
  {
    this.menus.last().items.push(item);
  },
  moveTo : function(x, y)
  {
    Div('MenuBarDiv').moveTo(x, y);
  },
  resizeTo : function(x, y)
  {
    Div('MenuBarDiv').resizeTo(x, y);
  }
}

function Menu(title)
{
  this.title = title;
  this.items = [];
}

function MenuItem(title, action)
{
  this.title  = title  || "";
  this.action = action || "void(0)";
}

if(!Array.prototype.push || (Array.prototype.push && ([0].push(true) == true)))
{
  Array.prototype.push = function()
  {
    for(i = 0; i < arguments.length; i++)
    {
      this[this.length] = arguments[i];
    }
    return this.length;
  }
}

if (!Array.prototype.pop)
{
  Array.prototype.pop = function()
  {
    var oldLen      = this.length;
    var lastElement = this[oldLen];
    this[oldLen]    = null;
    if (oldLen - this.length)
    {
      this.length -= 1;
    }
    return lastElement;
  }
}

Array.prototype.last = function()
{
  return this[this.length-1];
}

if (!Array.prototype.reverse)
{
  Array.prototype.reverse = function()
  {
    var reversed = new Array();
    while(this.length)
    {
      reversed.push(this.pop());
    }
    var len = this.length;
    for (var i = 0; i < len; i++)
    {
      this[i] = reversed[i]
    }
    return this;
  }
}

Array.prototype.contains = function(elm)
{
  var len = this.length;
  for (var i = 0; i < len; i++)
  {
    if (this[i] == elm)
    {
      return true
    }
  }
  return false
}

Array.prototype.indexOf = function(elm)
{
  var len = this.length;
  for (var i = 0; i < len; i++)
  {
    if (this[i] == elm)
    {
      return i;
    }
  }
  return -1;
}

Array.prototype.getRandom = function()
{
  return this[Math.floor(Math.random() * this.length)]
}
Cookie = {
  get : function(name)
  {
    var prefix = name + "=";
    var begin =document.cookie.indexOf("; "+prefix);

    if (begin==-1)
    {
      begin=document.cookie.indexOf(prefix);
      if (begin !=0) return null;
    }
    else
    {
      begin += 2;
    }

    var end = document.cookie.indexOf(";", begin);

    if (end == -1)
    {
      end = document.cookie.length;
    }

    return unescape(document.cookie.substring(begin+prefix.length, end));
  },
  set : function(name, value, date, expires, path, domain, secure)
  {
    var expires=(expires) ? expires : new Date(3000,11,31) ;
    document.cookie = name + "=" + escape(value)
                    + "; expires="+expires
                    + ((path) ? "; path=" +path : "")
                    + ((domain) ? "; domain=" +domain : "")
                    + ((secure) ? "; secure" : "");
  },
  eat : function(name)
  {
    if (Cookie.get(name))
    {
      var cookie = Cookie.get(name);
      document.cookie = name + "=; expires=Thu, 01-Jan-70 00:00:01 GMT";
      return cookie;
    }
	}
}
var monthNames,dayNames,shortDayNames;
switch (language)
{
  case "fr" :
    monthNames = ["Janvier","Fevrier","Mars","Avril","Mai","Juin","Juillet","Aout","Septembre","Octobre","Novembre","Decembre"];
    dayNames   = ["Dimanche","Lundi","Mardi","Mercredi","Jeudi","Vendredi","Samedi"];
    shortDayNames   = ["Dim","Lun","Mar","Mer","Jeu","Ven","Sam"];
    break;
  default :
    monthNames = ["January","February","March","April","May","June","July","August","September","October","November","December"];
    dayNames   = ["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
    shortDayNames = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
}

Date.prototype.getMonthName = function(){ return monthNames[this.getMonth()] }
Date.prototype.getDayName   = function(){ return dayNames[this.getDay()] }

Date.prototype.getHumanTime = function()
{
  var minutes = this.getMinutes();
  return this.getHours() + ":" + (minutes > 9 ? minutes : "0" + minutes);
}

Date.prototype.getDaysInMonth = function()
{
 return [31,(this.isLeap() ? 29 : 28),31,30,31,30,31,31,30,31,30,31][this.getMonth()];
}

Date.prototype.isLeap = function()
{
  var year = this.getFullYear();
  return ( (year % 4) && (year % 100) || !(year % 400) );
}

Date.prototype.getMonthStartDay = function()
{
  var date = this;
  date.setDate(1);
  return date.getDay();
}

Date.prototype.getYearStartDay = function()
{
  var date = this;
  date.setDate(1);
  date.setMonth(0);
  return date.getMonthStartDay();
}

Date.prototype.getWorkingWeek = function()
{
  var yearReference = new Date(this.getFullYear(), 0, 0);
  var yearInMills = yearReference.getTime() + (yearReference.getYearStartDay() * 24 * 60 * 60);
  return (Math.ceil(Math.abs(yearInMills - this.getTime()) / ((1000 * 60 * 60 * 24 * 7) - yearReference.getYearStartDay())));
}

Date.prototype.getDaysInBetween = function(date)
{
  return Math.abs(this.getTime() - date.getTime());
}

Date.prototype.getHtml = function(element)
{
  var startDay  = this.getMonthStartDay();
  var month     = this.getMonth();
  var year      = this.getFullYear();
  var daysTotal = this.getDaysInMonth();
  var cols      = 7;

  var output = "<table cellpadding=3 cellspacing=0 border=0 class=calTable bgcolor=white>"
             +   "<tr>";

  var mouseStr = " align=center valign=center class=selOff"
               + " onmouseover=\"this.className='selOver'\""
               + " onmouseout=\"this.className='selOff'\"";

  // month and year select boxes.
  output += "<td colspan=" + cols + " class=calSelect>"
          +   "<table width=100%>\n"
          +     "<tr>\n"
          +       "<td" + mouseStr + " onclick=\"if(typeof onCalendarChange == 'function'){"
          +         "onCalendarChange(new Date(" + (year - 1) + "," + month + "))}else"
          +         "{defaultCalendarChange(new Date(" + (year - 1) + "," + month + "))}\">\n<<</td>\n"
          +       "<td" + mouseStr + " onclick=\"if(typeof onCalendarChange == 'function'){"
          +         "onCalendarChange(new Date(" + year + "," + (month - 1) + "))}else"
          +         "{defaultCalendarChange(new Date(" + year + "," + (month - 1) + "))}\">\n<</td>\n"
          +       "<td align=center>" + this.getMonthName() + " " + year + "</td>"
          +       "<td" + mouseStr + " onclick=\"if(typeof onCalendarChange == 'function'){"
          +         "onCalendarChange(new Date(" + year + "," + (month + 1) + "))}else"
          +         "{defaultCalendarChange(new Date(" + year + "," + (month + 1) + "))}\">\n></td>\n"
          +       "<td" + mouseStr + " onclick=\"if(typeof onCalendarChange == 'function'){"
          +         "onCalendarChange(new Date(" + (year + 1) + "," + month + "))}else"
          +         "{defaultCalendarChange(new Date(" + (year + 1) + "," + month + "))}\">\n>></td>\n"
          +     "</tr>\n"
          +   "</table>\n"
          + "</td>\n</tr>\n"

  output += "<tr>\n"

  // days of the week
  for (var i = 0; i < 7; i++)
  {
    output += "    <td class=calDays>" + shortDayNames[i] + "</td>\n"
  }
  output += "  </tr>\n"

  // writes the table with the day numbers
  // but first we have to find how big our table will be.
  var bLen = (daysTotal + startDay);
  var len = (bLen % 7) ? ( bLen + Math.abs((bLen % 7) - 7) )  : bLen ;

  // and also to highlight today we have to get an index for it
  var today = new Date();
  var coloredDay = (today.getFullYear() == year && today.getMonth() == month)? today.getDate() : -100 ;

  for (var i = (-7 + startDay); i < len; i++)
  {
    if (i < 0)
    {
      continue;
    }

    var cellDate = (i - startDay + 1);

    if (i == 0)
    {
      output += "  <tr>\n";
    }
    else if (i % 7 == 0)
    {
      output += "  </tr>\n"
              +"  <tr>\n";
    }


    if ( (i >= startDay) && (cellDate <= daysTotal) && cellDate)
    {
      var dateStr = "new Date(" + this.getFullYear() + "," + this.getMonth() + "," + cellDate +")";
      output += "    <td class=calTdOff"
              + " onclick=\"if(typeof onCalendarClick=='function')"
              + "{onCalendarClick(" + dateStr + ")}"
              + "else{defaultCalendarClick(" + dateStr + ")}\""
              + " onmouseover='this.className=\"calTdOn\"'"
              + " onmouseout='this.className=\"calTdOff\"' > " + cellDate + " </td>\n";
    }
    else
    {
      // puts the empty cells at the beginning and end of the month
      output += "    <td class=calTdOff>&nbsp;</td>\n";
    }

    if (i == len)
    {
      output += "  </tr>\n"
    }
  }
  output += "  </table>\n</form>\n"
  return output;
}

Date.prototype.write = function()
{
  document.write(this.getHtml())
}

Date.prototype.getHumanForm = function()
{
  return this.getDate() + "/" +  (this.getMonth()+1) +  "/" + this.getFullYear()
}

var _calDivId;
var _calField;
var _calFieldMs;
function getCalendarFor(field, id, fieldMs)
{
  _calField   = field;
  _calFieldMs = fieldMs;
  _calDivId   = id;
  var div = Div(_calDivId);
  div.innerHTML = new Date().getHtml();
  div.setAsBlock();
}

function defaultCalendarClick(date)
{
  if (_calField)
  {
    _calField.value = date.getHumanForm();
    Div(_calDivId).setAsNone();
  }
}

function defaultCalendarChange(date)
{
  if(_calDivId)
  {
    Div(_calDivId).innerHTML = date.getHtml();
  }
}
var anything = /.*/;
var url = /^http[s]?:\/\/[\da-z]+[\w+\.]+\w+$/i;
var handle = /^[a-z|\d]*$/i;
/*
valid first names are :
  Ja
  John
  Jean-Marc // yup in French you can have this.
  Anémone   // accentuated characters too.
*/
var firstName = /^[a-z\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f9\u00fa\u00fb\u00fc\u00fd\u00ff]+-?[a-z\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f9\u00fa\u00fb\u00fc\u00fd\u00ff]+$/i;
/*
valid last names are :
  Ot
  Haran
  De Florette  // yup some people hold on to their honorable names
  D'entremont
  Sanchez-Punto // in spain, Quebec and children of divorced parents.

  TODO : Sanchez-De loytt
*/
var lastName     = /^([a-z\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f9\u00fa\u00fb\u00fc\u00fd\u00ff]+[\b]?[a-z\u00e0\u00e1\u00e2\u00e3\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed\u00ee\u00ef\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f9\u00fa\u00fb\u00fc\u00fd\u00ff]?[\b]?){2}$/i;
//                         | i18n code        | area code                 | city number        | optional extension
var telephoneNumber = /^(\+\d{1,3}[ -\.]?)?(\(\d{1,5}\)|\d{1,5})[ -\.]?\d{2,4}[ -\.]?\d{0,7}( ?e?xt ?\d{1,5})?/i;
var emailAddress = /^[\da-z+.\-_]+\@[\da-z+.\-_]+\.[\da-z+.\-_]+$/i;
var age = /^[1]?\d{1,2}$/i;

function checkField(field)
{
  var value     = field.value;
  var isEmpty   = (field.value == "");

  var mandatory = field.getAttribute("mandatory");
  mandatory = (mandatory) ? mandatory : false ;

  var mustBe    = field.getAttribute("mustBe");
  mustBe        = (mustBe) ? mustBe : false ;

  var errorMsg  = field.getAttribute("errorMsg");

  var emptyMsg  = field.getAttribute("emptyMsg");

  if (typeof field.selectedIndex == "undefined")// not a combo box.
  {
    if (!mandatory && (value == ""))
    {
      return true
    }

    if (mandatory && (value == ""))
    {
      alert(emptyMsg);
      field.select();
      return false;
    }

    if ((mustBe) && !eval(mustBe + ".test(\"" + value + "\")"))
    {
      alert(errorMsg)
      field.select();
      return false;
    }
  }
  else// combo box
  {
    value = field[field.selectedIndex].value;
    if (mandatory && (value == ""))
    {
      alert(emptyMsg);
      field.focus();
      return false;
    }
  }
  return true;
}

function checkFormValidity(myForm)
{
  for(var i = 0; i < myForm.elements.length; i++)
  {
    document.title = i
    if (!checkField(myForm.elements[i]))
    {
      return false;
    }
  }
  return true;
}

var _images = [];
function preload(src)
{
  var myImage = new Image();
  myImage.src = src;
  _images.push(myImage);
}

function RollOver(offSrc, onSrc, action, width, height, border)
{
  document.write(RollOverString(offSrc, onSrc, action, width, height, border))
}

function RollOverString(offSrc, onSrc, action, width, height, border)
{
  preload(onSrc);
  preload(offSrc);
  return "<img src='" + offSrc + "' onMouseOver='this.src = \""
          + onSrc + "\"' onMouseOut='this.src = \""
          + offSrc + "\"' "+ ((width) ? "width=" + width + " " : "")
          + ((height) ? "height=" + height + " "  : "")
          + "onClick=\"" + ((action) ? action : "") + "\""
          + ((border) ? "border=" + border : "") + " style='cursor:"
          + ((action != null) ? 'pointer' : 'default') + ";'>";
}
var windowWidth  = 0;
var windowHeight = 0;

function _hw()
{
  var t = (document.body && document.body.clientHeight);
  windowWidth  = (t) ? document.body.clientWidth  : window.innerWidth  ;
  windowHeight = (t) ? document.body.clientHeight : window.innerHeight ;
}

window.onresize = function()
{
  _hw();
  if (typeof onPageResize == 'function'){onPageResize()};
}

window.onload = function(e)
{
  _hw();
  _xy(e);

  if (typeof checkDependencies == "function")checkDependencies();
  if (typeof onPageResize == "function")onPageResize();
  if (typeof onPageLoad == "function")onPageLoad();
}

Mouse = {};
Mouse.x = 0;
Mouse.y = 0;
Mouse.xOff = 0;
Mouse.yOff = 0;
Mouse.report = reporter;

function _xy(e)
{
//  var x = Mouse.x = window.event ? event.x : e.clientX ;
//  var y = Mouse.y = window.event ? event.y : e.clientY ;
//  Mouse.xOff = window.event ? x + document.body.scrollLeft : x + window.pageXOffset ;
//  Mouse.yOff = window.event ? y + document.body.scrollTop  : y + window.pageYOffset ;
}

document.onmousemove=function(e)
{
  _xy(e);
  if(typeof DragManager!="undefined") DragManager.update();
  if(typeof mouseMove=="function")return onMouseMove();
}

document.onmouseup=function(e)
{
  if(typeof DragManager!="undefined")DragManager.update = function(){};
  if(typeof mouseUp=="function")return mouseUp();
}

document.onmousedown=function(e)
{
  if(typeof mouseDown=="function")return mouseDown(e);
}

document.oncontextmenu=function(e)
{
  if(typeof contextMenu=="function")return contextMenu(e);
}

document.onclick = function(e)
{
  if (!MenuBar.over)
  {
    MenuBar.reset();
  }
  if(typeof mouseClick=="function")return mouseClick(e);
}
DragManager = {};
DragManager.zIndex = 100;
DragManager.update = function(){};

dragStart = function(event, id)
{
  var elm = window.event ? window.event.srcElement : event.target ;

  if (elm.nodeType == 3)
  {
    elm = elm.parentNode;
  }

  DragManager.id = id ? id : elm.getAttribute("id") ;

  var dragElm = Div(DragManager.id);
  dragElm.setZIndex(DragManager.zIndex++);
  DragManager.offSetX = Mouse.x - parseInt(dragElm.getLeft());
  DragManager.offSetY = Mouse.y - parseInt(dragElm.getTop());

  DragManager.update = function()
  {
    Div(DragManager.id).moveTo(Mouse.x - DragManager.offSetX, Mouse.y - DragManager.offSetY);
  }
}
if (!Number.prototype.toFixed)
{
  Number.prototype.toFixed = function(digits)
  {
    var digits = digits || 0;
    return (Math.round(this*Math.pow(10,digits))/Math.pow(10,digits))
  }
}

var _divs = new Array();

function Div(id)
{
  var obj = _dom ? document.getElementById(id) : document.all[id] ;

  if (!obj)
  {
     return false;
  }

  obj._id = _divs.length;

  obj.time     = 10; // how long between moves
  obj.distance = 2; // how far we move in one time unit

  // visibility
  obj.show = function(){obj.style.visibility = "visible"}
  obj.hide = function(){obj.style.visibility = "hidden"}
  obj.isVisible = function(){return (obj.style.visibility != "hidden")}
  obj.setZIndex = function(z){obj.style.zIndex = z}
  obj.getZIndex = function(){return obj.style.zIndex}

  // display
  obj.setAsNone = function(){obj.style.display = "none"}
  obj.setAsBlock = function(){obj.style.display = "block"}
  obj.swapDisplay = function(){var flag = (obj.style.display != "none"); obj.style.display = flag ? "none" : "block"; return (!flag);}

  // size
  obj.setHeight = function(h){obj.style.height = h}
  obj.setWidth = function(w){obj.style.width = w}
  obj.getHeight = function(){return parseInt(obj.style.height)}
  obj.getWidth = function(){return parseInt(obj.style.width) }
  obj.resizeTo = function(h, w){obj.setHeight(h || obj.getHeight());obj.setWidth(w  || obj.getWidth())}

  // position
  obj.setLeft = function(x){obj.style.left = x;return x}
  obj.setTop = function(y){obj.style.top = y;return y}
  obj.getLeft = function(){return parseInt(obj.style.left)}
  obj.getTop = function(){return parseInt(obj.style.top)}
  obj.getPosition = function(){return [obj.getLeft(), obj.getTop()]}
  obj.moveTo = function(x, y){return [obj.setLeft(x), obj.setTop(y)]}
  obj.moveBy = function(x, y)
  {
    return obj.moveTo( (x ? obj.getLeft() + x : obj.getLeft()),(y ? obj.getTop()  + y : obj.getTop()) )
  }

  obj.slideTo = function(left, top, lod, nextAction)
  {
    if (!obj.sliding)
    {
      obj.slideFromPath(twoPointPath([obj.getLeft(), obj.getTop()], [left, top], lod), nextAction)
    }
  }

  obj.slideFromPath = function(path, nextAction)
  {
    obj.nextAction = nextAction;
    obj.path = path.reverse();
    obj._startSlideFromPath();
  }

  obj._startSlideFromPath = function()
  {
    if (!obj.sliding)
    {
      obj.sliding = true;
      obj._slide();
    }
  }

  obj._startSlide = function()
  {
    if (obj.sliding) return
    obj.sliding = true;
  	repsTotal = Math.sqrt(Math.pow(obj.leftTravelDistance, 2) + Math.pow(obj.topTravelDistance, 2)) / obj.distance
  	mX = obj.leftTravelDistance / repsTotal;
  	mY = obj.topTravelDistance  / repsTotal;

    obj.path = [[obj.getLeft(), obj.getTop()]];

  	for (var i = 0; i < repsTotal; i++)
  	{
  	  var last = obj.path.last();
      obj.path.push([last[0] + mX, last[1] + mY])
  	}

    obj.path.reverse();
  	obj._slide()
  }

  obj._slide = function()
  {
    if (obj.sliding)
    {
      if (obj.path.length)
      {
        var point = obj.path.pop();
        obj.moveTo(point[0], point[1]);
        setTimeout("_divs[" + obj._id + "]._slide()", obj.time)
        return false;
      }
      else
      {
        obj.repsDone  = 0;
        obj.repsTotal = 0;
        obj.leftTravelDistance = 0;
        obj.topTravelDistance = 0;
        obj.sliding = false;
        eval(obj.nextAction)
        obj.nextAction = ""
        return true;
      }
    }
  }

  // clipping
  obj.clip = function(trbl)
  {
    obj.style.clip = "rect(" + trbl + ")";
  }

  obj.getClip = function()
  {
    /rect\((\d{1,3})\D+(\d{1,3})\D+(\d{1,3})\D+(\d{1,3})\D+/i.test(obj.style.clip);
    return [RegExp.$1, RegExp.$2, RegExp.$3, RegExp.$4]
  }

  // special
  obj.getOpacity = function()
  {
    /opacity=(\d{1,3})/i.test(obj.style.filter);
    return (_ie) ? RegExp.$1 : parseInt(obj.style.MozOpacity) ;
  }

  obj.setOpacity = function(o)
  {
    if (_moz)
    {
      obj.style.MozOpacity = o + "%";
    }
    else if (obj.style.filter)
    {
      obj.style.filter = 'alpha(opacity=' + o +')'
    }
  }

  obj.report = reporter;

  _divs.push(obj)
  return obj;
}

function fastBezierPoint(perc, start, flex1, flex2, end)
{
  var oneMinusPerc = 1 - perc;
  var bp1 = Math.pow(perc,3);
  var bp2 = 3*Math.pow(perc, 2)*oneMinusPerc;
  var bp3 = 3*perc*Math.pow(oneMinusPerc, 2);
  var bp4 = Math.pow(oneMinusPerc, 3);

  return [ start[0]*bp1 + flex1[0]*bp2 + flex2[0]*bp3 + end[0]*bp4,
           start[1]*bp1 + flex1[1]*bp2 + flex2[1]*bp3 + end[1]*bp4 ]
}

function bezierPath(start, flex1, flex2, end, lod)
{
  var iterations  = lod ? lod : 100;
  var iteration   = iterations;
  var path = [];
  while (iteration--)
  {
    path.push(fastBezierPoint(1 / (iterations / iteration), start, flex1, flex2, end));
  }
  return path;
}

function twoPointPath(start, end, lod)
{
  var iterations  = lod ? lod : 100;

  var xMoveBy = (start[0] - end[0]) / iterations;
  var yMoveBy = (start[1] - end[1]) / iterations;

  var path = [[start[0], start[1]]];
  var last;

  while (iterations--)
  {
    last = path.last();
    path.push([last[0] - xMoveBy, last[1] - yMoveBy])
  }
  return path;
}
