var monthName = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec', ];

var stIsIE = /*@cc_on!@*/false;
var nbrOfGoes = 0;

sorttable =
{
   init : function()
   {
      // quit if this function has already been called
      if (arguments.callee.done)
      {
         return;
      }

      // flag this function so we don't do the same thing twice
      arguments.callee.done = true;
      // kill the timer
      if (_timer)
      {
         clearInterval(_timer);
      }

      if ( ! document.createElement || ! document.getElementsByTagName)
      {
         return;
      }

      sorttable.DATE_RE = /^(\d\d?)[\/\.-](\d\d?)[\/\.-]((\d\d)?\d\d)$/;

      forEach(document.getElementsByTagName('table'), function(table)
      {
         if (table.className.search(/\bsortable\b/) != - 1)
         {
            sorttable.makeSortable(table);
         }
      }
      );
   }
   ,

   makeSortable : function(table)
   {
      var i = 0;
      var odd = true;

      if (table.getElementsByTagName('thead').length === 0)
      {
         // table doesn't have a tHead. Since it should have, create one and
         // put the first table row in it.
         the = document.createElement('thead');
         the.appendChild(table.rows[0]);
         table.insertBefore(the, table.firstChild);
      }
      // Safari doesn't support table.tHead, sigh
      if (table.tHead === null)
      {
         table.tHead = table.getElementsByTagName('thead')[0];
      }

      if (table.tHead.rows.length != 1)
      {
         return;
      }
      // can't cope with two header rows

      // Sorttable v1 put rows with a class of "sortbottom" at the bottom (as
      // "total" rows, for example). This is B & R, since what you're supposed
      // to do is put them in a tfoot. So, if there are sortbottom rows,
      // for backwards compatibility, move them to tfoot (creating it if needed).
      sortbottomrows = [];
      for (i = 0; i < table.rows.length; i ++ )
      {
         if (table.rows[i].className.search(/\bsortbottom\b/) != - 1)
         {
            sortbottomrows[sortbottomrows.length] = table.rows[i];
         }
      }
      if (sortbottomrows)
      {
         if (table.tFoot === null)
         {
            // table doesn't have a tfoot. Create one.
            tfo = document.createElement('tfoot');
            table.appendChild(tfo);
         }
         for (i = 0; i < sortbottomrows.length;
         i ++ )
         {
            tfo.appendChild(sortbottomrows[i]);
         }
         delete sortbottomrows;
      }

      // work through each column and calculate its type
      headrow = table.tHead.rows[0].cells;
      var j = 0;
      for (i = 0; i < headrow.length; i ++ )
      {
         // manually override the type with a sorttable_type attribute
         if ( ! headrow[i].className.match(/\bsorttable_nosort\b/))
         {
            // skip this col
            mtch = headrow[i].className.match(/\bsorttable_([a-z0-9]+)\b/);
            if (mtch)
            {
               override = mtch[1];
            }
            if (mtch && typeof sorttable["sort_" + override] == 'function')
            {
               headrow[i].sorttable_sortfunction = sorttable["sort_" + override];
            }
            else
            {
               headrow[i].sorttable_sortfunction = sorttable.guessType(table, i);
            }
            // make it clickable to sort
            headrow[i].sorttable_columnindex = i;
            headrow[i].sorttable_tbody = table.tBodies[0];
            dean_addEvent(headrow[i], "click", function(e)
            {
          if (this.className.search(/\bsorttable_sorted\b/) != -1) {
            // if we're already sorted by this column, just 
            // reverse the table, which is quicker
            sorttable.reverse(this.sorttable_tbody);
            this.className = this.className.replace('sorttable_sorted',
                                                    'sorttable_sorted_reverse');
            this.removeChild(document.getElementById('sorttable_sortfwdind'));
            sortrevind = document.createElement('span');
            sortrevind.id = "sorttable_sortrevind";
	    if (this.sorttable_columnindex == '2') { sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">5</font>' : '&nbsp;&#x25B4;'; }
	    if (this.sorttable_columnindex != '2') { sortrevind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25B4;'; }
            this.appendChild(sortrevind);
            return;
          }
          if (this.className.search(/\bsorttable_sorted_reverse\b/) != -1) {
            // if we're already sorted by this column in reverse, just 
            // re-reverse the table, which is quicker
            sorttable.reverse(this.sorttable_tbody);
            this.className = this.className.replace('sorttable_sorted_reverse',
                                                    'sorttable_sorted');
            this.removeChild(document.getElementById('sorttable_sortrevind'));
            sortfwdind = document.createElement('span');
            sortfwdind.id = "sorttable_sortfwdind";
            if (this.sorttable_columnindex == '2') { sortfwdind.innerHTML = stIsIE ? '&nbsp;<font face="webdings">6</font>' : '&nbsp;&#x25BE;'; }
            if (this.sorttable_columnindex != '2') { sortfwdind.innerHTML = stIsIE ? '&nbsp;<font face="webdings">5</font>' : '&nbsp;&#x25BE;'; }
            this.appendChild(sortfwdind);
            return;
          }
          
          // remove sorttable_sorted classes
          theadrow = this.parentNode;
          forEach(theadrow.childNodes, function(cell) {
            if (cell.nodeType == 1) { // an element
              cell.className = cell.className.replace('sorttable_sorted_reverse','');
              cell.className = cell.className.replace('sorttable_sorted','');
            }
          });
          sortfwdind = document.getElementById('sorttable_sortfwdind');
          if (sortfwdind) { sortfwdind.parentNode.removeChild(sortfwdind); }
          sortrevind = document.getElementById('sorttable_sortrevind');
          if (sortrevind) { sortrevind.parentNode.removeChild(sortrevind); }
          
          this.className += ' sorttable_sorted';
          sortfwdind = document.createElement('span');
          sortfwdind.id = "sorttable_sortfwdind";
          sortfwdind.innerHTML = stIsIE ? '&nbsp;<font face="webdings">5</font>' : '&nbsp;&#x25BE;';
          this.appendChild(sortfwdind);

               // build an array to sort. This is a Schwartzian transform thing,
               // i.e., we "decorate" each row with the actual sort key,
               // sort based on the sort keys, and then put the rows back in order
               // which is a lot faster because you only do getInnerText once per row
               row_array = [];
               sortedrows = [];
               col = this.sorttable_columnindex;
               rows = this.sorttable_tbody.rows;
               for (j = 0; j < rows.length; j ++ )
               {
                  row_array[row_array.length] = [sorttable.getInnerText(rows[j].cells[col]), rows[j]];
               }
               /* If you want a stable sort, uncomment the following line */
               // sorttable.shaker_sort(row_array, this.sorttable_sortfunction);
               /* and comment out this one */
               row_array.sort(this.sorttable_sortfunction);
	       if (this.sorttable_columnindex == '2') {
                  row_array.reverse(); 
                  sortfwdind.innerHTML = stIsIE ? '&nbsp<font face="webdings">6</font>' : '&nbsp;&#x25B4;';
	       }

               tb = this.sorttable_tbody;
               if (col == '2')
               {
                  for (j = 0; j < row_array.length; j ++ )
                  {
		     if(document.all){
                        generic_innerText = row_array[j][1].cells(2).innerText;
                     } else{
                        generic_innerText = row_array[j][1].cells(2).textContent;
                     }
                     if (generic_innerText !== 'TBA')
                     {
                        sortedrows[sortedrows.length] = row_array[j][1];
                     }
                  }
                  for (j = 0; j < row_array.length; j ++ )
                  {
		     if(document.all){
                        generic_innerText = row_array[j][1].cells(2).innerText;
                     } else{
                        generic_innerText = row_array[j][1].cells(2).textContent;
                     }
                     if (generic_innerText == 'TBA')
                     {
                        sortedrows[sortedrows.length] = row_array[j][1];
                     }
                  }
               }
               else
               {
                  for (j = 0; j < row_array.length; j ++ )
                  {
                     sortedrows[sortedrows.length] = row_array[j][1];
                  }
               }
               for (j = sortedrows.length - 1; j >= 0; j -- )
               {
                  if (odd)
                  {
                     odd = false;
                     sortedrows[j].className = "odd";
                  }
                  else
                  {
                     odd = true;
                     sortedrows[j].className = "";
                  }
               }

               for (j = 0; j < row_array.length; j ++ )
               {
                  tb.appendChild(sortedrows[j]);
               }
               delete row_array;
               delete sortedrows;
            }
            );
         }
      }
   }
   ,

   guessType : function(table, column)
   {
      var i = 0;
      // guess the type of a column based on its first non - blank row
      sortfn = sorttable.sort_alpha;
      for (i = 0; i < table.tBodies[0].rows.length;
      i ++ )
      {
         text = sorttable.getInnerText(table.tBodies[0].rows[i].cells[column]);
         if (text !== '')
         {
            if (text.match(/^-?[Ã?Â£$Ã?Â¤]?[\d,.]+%?$/))
            {
               return sorttable.sort_numeric;
            }
            // check for a date : dd / mm / yyyy or dd / mm / yy
            // can have / or . or - as separator
            // can be mm / dd as well
            possdate = text.match(sorttable.DATE_RE);
            if (possdate)
            {
               // looks like a date
               first = parseInt(possdate[1], 10);
               second = parseInt(possdate[2], 10);
               if (first > 12)
               {
                  // definitely dd / mm
                  return sorttable.sort_ddmm;
               }
               else if (second > 12)
               {
                  return sorttable.sort_mmdd;
               }
               else
               {
                  // looks like a date, but we can't tell which, so assume
                  // that it's dd/mm (English imperialism!) and keep looking
                  sortfn = sorttable.sort_ddmm;
               }
            }
         }
      }
      return sortfn;
   }
   ,

   getInnerText : function(node)
   {
      var i = 0;
      var innerText = '';
      // gets the text we want to use for sorting for a cell.
      // strips leading and trailing whitespace.
      // this is * not * a generic getInnerText function; it's special to sorttable.
      // for example, you can override the cell text with a customkey attribute.
      // it also gets .value for < input > fields.

      hasInputs = (typeof node.getElementsByTagName == 'function') &&
      node.getElementsByTagName('input').length;

      if (node.getAttribute("sorttable_customkey") !== null)
      {
         return node.getAttribute("sorttable_customkey");
      }
      else if (typeof node.textContent != 'undefined' && ! hasInputs)
      {
         return node.textContent.replace(/^\s+|\s+$/g, '');
      }
      else if (typeof node.innerText != 'undefined' && ! hasInputs)
      {
         return node.innerText.replace(/^\s+|\s+$/g, '');
      }
      else if (typeof node.text != 'undefined' && ! hasInputs)
      {
         return node.text.replace(/^\s+|\s+$/g, '');
      }
      else
      {
         switch (node.nodeType)
         {
            case 3 :
               if (node.nodeName.toLowerCase() == 'input')
               {
                  return node.value.replace(/^\s+|\s+$/g, '');
               }
               break;
            case 4 :
               return node.nodeValue.replace(/^\s+|\s+$/g, '');
            case 1 :
               break;
            case 11 :
               for (i = 0; i < node.childNodes.length;
               i ++ )
               {
                  innerText += sorttable.getInnerText(node.childNodes[i]);
               }
               return innerText.replace(/^\s+|\s+$/g, '');
            default :
               return '';
         }
      }
   }
   ,

   reverse : function(tbody)
   {
      var i = 0;
      var odd = true
      newrows = [];

      // reverse the rows in a tbody
      if (col == '2')
      {
         for (i = 0; i < tbody.rows.length; i ++ )
         {
	    if(document.all){
               generic_innerText = tbody.rows[i].cells(2).innerText;
            } else{
               generic_innerText = tbody.rows[i].cells(2).textContent;
            }
            if (generic_innerText == 'TBA')
            {
               newrows[newrows.length] = tbody.rows[i];
            }
         }
         for (i = 0; i < tbody.rows.length; i ++ )
         {
	    if(document.all){
               generic_innerText = tbody.rows[i].cells(2).innerText;
            } else{
               generic_innerText = tbody.rows[i].cells(2).textContent;
            }
            if (generic_innerText !== 'TBA')
            {
               newrows[newrows.length] = tbody.rows[i];
            }
         }
      }
      else
      {
         for (i = 0; i < tbody.rows.length; i ++ )
         {
            newrows[newrows.length] = tbody.rows[i];
         }
      }
      for (i = newrows.length - 1; i >= 0; i -- )
      {
         if (odd)
         {
            odd = false;
            newrows[i].className = "odd";
         }
         else
         {
            odd = true;
            newrows[i].className = "";
         }
      }
      for (i = newrows.length - 1; i >= 0; i -- )
      {
         tbody.appendChild(newrows[i]);
      }
      delete newrows;
   }
   ,

   /* sort functions
   each sort function takes two parameters, a and b
   you are comparing a[0] and b[0] */
   sort_numeric : function(a, b)
   {
      aa = parseFloat(a[0].replace(/[^0-9.-]/g, ''));
      if (isNaN(aa))
      {
         aa = 0;
      }

      bb = parseFloat(b[0].replace(/[^0-9.-]/g, ''));
      if (isNaN(bb))
      {
         bb = 0;
      }

      return aa - bb;
   }
   ,
   sort_alpha : function(a, b)
   {
      var yr = - 1;

      // * * * * * * * * * * * * * * * * * * * * * * * *    New Code    * * * * * * * * * * * * * * * * * * * * * * * *

      var dateregex = new RegExp("^\\d\\d?[\\/-](\\d\\d?|" + monthName.join("|") + ')[\\/-]\\d\\d(\\d\\d)?$', "i");
      // convert a[0]
      if (a[0] !== 'TBA')
      {
         // If the item matches a date pattern (MM / DD / YYYY or MM / DD / YY or M / DD / YYYY or DD / MMM / YYYY)
         if (a[0].match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/) ||
         a[0].match(/^\d\d[\/-]\d\d[\/-]\d\d$/) ||
         a[0].match(dateregex) ||
         a[0].match(/^\d[\/-]\d\d[\/-]\d\d\d\d$/) )
         {
            aaBits = a[0].split(/\/|-/);
            for (i = 0; i < monthName.length; i ++ )
            {
               // AG Convert Alpha month to two digit month
               if (monthName[i].toLowerCase() == aaBits[1].toLowerCase())
               {
                  a[0] = aaBits[0] + '/' + (i < 9 ? '0' : '') + (i + 1) + '/' + aaBits[2];
                  break;
               }
            }
            // Convert date to YYYYMMDD format for sort comparison purposes
            // y2k notes : two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
            if (a[0].length == 10)
            {
               a[0] = a[0].substr(6, 4) + a[0].substr(0, 2) + a[0].substr(3, 2);
            }
            else if (a[0].length == 9)
            {
               a[0] = a[0].substr(5, 4) + "0" + a[0].substr(0, 1) + a[0].substr(2, 2);
            }
            else if (a[0].length == 8)
            {
               yr = a[0].substr(6, 2);
               if (parseInt(yr, 10) < 50)
               {
                  yr = '20' + yr;
               }
               else
               {
                  yr = '19' + yr;
               }
               a[0] = yr + a[0].substr(3, 2) + a[0].substr(0, 2);
            }
            else if (a[0].length == 7)
            {
               yr = a[0].substr(5, 2);
               if (parseInt(yr, 10) < 50)
               {
                  yr = '20' + yr;
               }
               else
               {
                  yr = '19' + yr;
               }
               a[0] = yr + a[0].substr(2, 2) + "0" + a[0].substr(0, 1);
            }
            else if (a[0].length == 6)
            {
               yr = a[0].substr(6, 2);
               if (parseInt(yr, 10) < 50)
               {
                  yr = '20' + yr;
               }
               else
               {
                  yr = '19' + yr;
               }
               a[0] = yr + a[0].substr(3, 2) + a[0].substr(0, 2);
            }
         }
      }

      // convert b[0]
      if (b[0] !== 'TBA')
      {
         if (b[0].match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/) ||
         b[0].match(/^\d\d[\/-]\d\d[\/-]\d\d$/) ||
         b[0].match(dateregex) ||
         b[0].match(/^\d[\/-]\d\d[\/-]\d\d\d\d$/) )
         {

            aaBits = b[0].split(/\/|-/);
            for (i = 0; i < monthName.length; i ++ )
            {
               // AG Convert Alpha month to two digit month
               if (monthName[i].toLowerCase() == aaBits[1].toLowerCase())
               {
                  b[0] = aaBits[0] + '/' + (i < 9 ? '0' : '') + (i + 1) + '/' + aaBits[2];
                  break;
               }
            }
            // Convert date to YYYYMMDD format for sort comparison purposes
            // y2k notes : two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
            if (b[0].length == 10)
            {
               b[0] = b[0].substr(6, 4) + b[0].substr(0, 2) + b[0].substr(3, 2);
            }
            else if (b[0].length == 9)
            {
               b[0] = b[0].substr(5, 4) + "0" + b[0].substr(0, 1) + b[0].substr(2, 2);
            }
            else if (b[0].length == 8)
            {
               yr = b[0].substr(6, 2);
               if (parseInt(yr, 10) < 50)
               {
                  yr = '20' + yr;
               }
               else
               {
                  yr = '19' + yr;
               }
               b[0] = yr + b[0].substr(3, 2) + b[0].substr(0, 2);
            }
            else if (b[0].length == 7)
            {
               yr = b[0].substr(5, 2);
               if (parseInt(yr, 10) < 50)
               {
                  yr = '20' + yr;
               }
               else
               {
                  yr = '19' + yr;
               }
               b[0] = yr + b[0].substr(2, 2) + "0" + b[0].substr(0, 1);
            }
            else if (b[0].length == 6)
            {
               yr = b[0].substr(6, 2);
               if (parseInt(yr, 10) < 50)
               {
                  yr = '20' + yr;
               }
               else
               {
                  yr = '19' + yr;
               }
               b[0] = yr + b[0].substr(3, 2) + b[0].substr(0, 2);
            }
         }
      }

      // * * * * * * * * * * * * * * * * * * * * * * * *  New Code End  * * * * * * * * * * * * * * * * * * * * * * * *

      if (a[0] == b[0])
      {
         return 0;
      }

      if (a[0] < b[0])
      {
         return - 1;
      }

      return 1;
   }
   ,
   sort_ddmm : function(a, b)
   {
      mtch = a[0].match(sorttable.DATE_RE);
      y = mtch[3];
      m = mtch[2];
      d = mtch[1];
      if (m.length == 1)
      {
         m = '0' + m;
      }

      if (d.length == 1)
      {
         d = '0' + d;
      }

      dt1 = y + m + d;
      mtch = b[0].match(sorttable.DATE_RE);
      y = mtch[3];
      m = mtch[2];
      d = mtch[1];
      if (m.length == 1)
      {
         m = '0' + m;
      }

      if (d.length == 1)
      {
         d = '0' + d;
      }

      dt2 = y + m + d;
      if (dt1 == dt2)
      {
         return 0;
      }

      if (dt1 < dt2)
      {
         return - 1;
      }

      return 1;
   }
   ,
   sort_mmdd : function(a, b)
   {
      mtch = a[0].match(sorttable.DATE_RE);
      y = mtch[3];
      d = mtch[2];
      m = mtch[1];
      if (m.length == 1)
      {
         m = '0' + m;
      }

      if (d.length == 1)
      {
         d = '0' + d;
      }

      dt1 = y + m + d;
      mtch = b[0].match(sorttable.DATE_RE);
      y = mtch[3];
      d = mtch[2];
      m = mtch[1];
      if (m.length == 1)
      {
         m = '0' + m;
      }

      if (d.length == 1)
      {
         d = '0' + d;
      }

      dt2 = y + m + d;
      if (dt1 == dt2)
      {
         return 0;
      }

      if (dt1 < dt2)
      {
         return - 1;
      }

      return 1;
   }
   ,

   shaker_sort : function(list, comp_func)
   {
      var i = 0;
      var q = 0;
      // A stable sort function to allow multi - level sorting of data
      // see : http : // en.wikipedia.org / wiki / Cocktail_sort
      // thanks to Joseph Nahmias
      var b = 0;
      var t = list.length - 1;
      var swap = true;

      while(swap)
      {
         swap = false;
         for(i = b; i < t; ++ i)
         {
            if ( comp_func(list[i], list[i + 1]) > 0 )
            {
               q = list[i];
               list[i] = list[i + 1];
               list[i + 1] = q;
               swap = true;
            }
         }
         // for
         t -- ;

         if ( ! swap)
         {
            break;
         }

         for(i = t; i > b; -- i)
         {
            if ( comp_func(list[i], list[i - 1]) < 0 )
            {
               q = list[i];
               list[i] = list[i - 1];
               list[i - 1] = q;
               swap = true;
            }
         }
         // for
         b ++ ;

      }
      // while(swap)
   }
}
;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Supporting functions : bundled here to avoid depending on a library
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

// Dean Edwards / Matthias Miller / John Resig

/* for Mozilla / Opera9 */
if (document.addEventListener)
{
   document.addEventListener("DOMContentLoaded", sorttable.init, false);
}

/* for Internet Explorer */
/* @cc_on @ */
/* @if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function()
{
if (this.readyState == "complete")
{
sorttable.init();
// call the onload handler
}
}
;
/* @end @ */

/* for Safari */
if (/WebKit/i.test(navigator.userAgent))
{
   // sniff
   var _timer = setInterval(function()
   {
      if (/loaded|complete/.test(document.readyState))
      {
         sorttable.init();
         // call the onload handler
      }
   }
   , 10);
}

/* for other browsers */
window.onload = sorttable.init;

// written by Dean Edwards, 2005
// with input from Tino Zijdel, Matthias Miller, Diego Perini

// http : // dean.edwards.name / weblog / 2005 / 10 / add - event /

function dean_addEvent(element, type, handler)
{
   if (element.addEventListener)
   {
      element.addEventListener(type, handler, false);
   }
   else
   {
      // assign each event handler a unique ID
      if ( ! handler.$$guid) handler.$$guid = dean_addEvent.guid ++ ;
      // create a hash table of event types for the element
      if ( ! element.events) element.events =
      {
      }
      ;
      // create a hash table of event handlers for each element / event pair
      var handlers = element.events[type];
      if ( ! handlers)
      {
         handlers = element.events[type] =
         {
         }
         ;
         // store the existing event handler (if there is one)
         if (element["on" + type])
         {
            handlers[0] = element["on" + type];
         }
      }
      // store the event handler in the hash table
      handlers[handler.$$guid] = handler;
      // assign a global event handler to do all the work
      element["on" + type] = handleEvent;
   }
}
;
// a counter used to create unique IDs
dean_addEvent.guid = 1;

function removeEvent(element, type, handler)
{
   if (element.removeEventListener)
   {
      element.removeEventListener(type, handler, false);
   }
   else
   {
      // delete the event handler from the hash table
      if (element.events && element.events[type])
      {
         delete element.events[type][handler.$$guid];
      }
   }
}
;

function handleEvent(event)
{
   var i = 0;
   var returnValue = true;
   // grab the event object (IE uses a global event object)
   event = event || fixEvent(((this.ownerDocument || this.document || this).parentWindow || window).event);
   // get a reference to the hash table of event handlers
   var handlers = this.events[event.type];
   // execute each event handler
   for (i in handlers)
   {
      this.$$handleEvent = handlers[i];
      if (this.$$handleEvent(event) === false)
      {
         returnValue = false;
      }
   }
   return returnValue;
}
;

function fixEvent(event)
{
   // add W3C standard event methods
   event.preventDefault = fixEvent.preventDefault;
   event.stopPropagation = fixEvent.stopPropagation;
   return event;
}
;
fixEvent.preventDefault = function()
{
   this.returnValue = false;
}
;
fixEvent.stopPropagation = function()
{
   this.cancelBubble = true;
}

// Dean's forEach: http://dean.edwards.name/base/forEach.js
/*
forEach, version 1.0
Copyright 2006, Dean Edwards
License : http : // www.opensource.org / licenses / mit - license.php
 */

// array - like enumeration
var i = 0;
if ( ! Array.forEach)
{
   // mozilla already supports this
   Array.forEach = function(array, block, context)
   {
      for (i = 0; i < array.length; i ++ )
      {
         block.call(context, array[i], i, array);
      }
   }
   ;
}

// generic enumeration
Function.prototype.forEach = function(object, block, context)
{
   for (var key in object)
   {
      if (typeof this.prototype[key] == "undefined")
      {
         block.call(context, object[key], key, object);
      }
   }
}


// character enumeration
String.forEach = function(string, block, context)
{
   Array.forEach(string.split(""), function(chr, index)
   {
      block.call(context, chr, index, string);
   }
   )
}


// globally resolve forEach enumeration
var forEach = function(object, block, context)
{
   if (object)
   {
      var resolve = Object;
      // default
      if (object instanceof Function)
      {
         // functions have a "length" property
         resolve = Function;
      }
      else if (object.forEach instanceof Function)
      {
         // the object implements a custom forEach method so use that
         object.forEach(block, context);
         return;
      }
      else if (typeof object == "string")
      {
         // the object is a string
         resolve = String;
      }
      else if (typeof object.length == "number")
      {
         // the object is array - like
         resolve = Array;
      }
      resolve.forEach(object, block, context);
   }
}
