
var newsTables = null,
    nextNewsTableIdx = null,
    recalcRubricIntervalId = null,
    leadRows = null,
    isIndexPage = (location.pathname == '/');

var isBlogPage = (location.pathname.match (/blog/i) != null);
var isCommentsPage = (location.pathname.match (/comment/i) !=  null);
var isSamPage = (location.pathname.match (/samizdat/i) !=  null);
var isDuelPage = (location.pathname.match (/duel/i) !=  null);
var isPostPage = (location.pathname.match (/^\/([0-9]+)\.html/i) != null);

function recalcRubrics() {
  newsTables = [];
  leadRows = [];
  var newsTable = findFirstNewsTable();
  while (newsTable) {
    if (isIndexPage) newsTables.push(newsTable);
    leadRows.push(findFirstChild(findFirstChild(newsTable, 'table', 'lead'), 'tr'));
    newsTable = findNextSibling(newsTable, 'table', 'top_news');
  }
  chkUpdateLeadRows();
  if (isIndexPage && newsTables.length > 0) {
    nextNewsTableIdx = 0;
    setTimeout(recalcNextRubricInTable, 0);
  }
}

function findFirstNewsTable() {
  return findFirstChild(findFirstChild(findFirstChild(
           document.body, 
            'tr', ['main_first', 'main']), 
              'td', 'col_mid'), 
                'table', 'top_news');
}

var  maxFill = 60;
//var  infoBlock = null;

function recalcNextRubricInTable() {
  recalcRubricInTable(newsTables[nextNewsTableIdx]);
  if ((++nextNewsTableIdx) < newsTables.length) setTimeout(recalcNextRubricInTable, 0);
}

function recalcRubricInTable(newsTable) {
  var rubricsContainer = findFirstChild(findFirstChild(
                           newsTable, 
                            'table', 'lead'), 
                              'table', 'rubric');
  var rubricsRow = findFirstChild(rubricsContainer, 'tr');
  var rubricsCells = rubricsRow.cells;
  var middleRubric = null;
  var ss = '', ws = 0, wb = 0, wa = 0, ci = -1, len = rubricsCells.length;
  for (var i = 0; i < len; i++) {
    var rubric = findFirstChild(rubricsCells[i], 'table');
    var w = rubric.offsetWidth;
    rubricsCells[i].textWidth = w;
    ws += w;
    if (i > 0 && i < len-1 && ci < 0 && findFirstChild(rubric, 'div', 'connect')) ci = i;
    if (ci < 0) wb += w; else if (ci < i) wa += w;
    ss += (i == ci ? '<b>' : '') + w + (i == ci ? '</b>' : '') + (i < len-1 ? '+' : '');
  }
//if (ci > 0) {

//  var info = document.createElement('DIV');
//  info.style.fontSize = '70%';
//  info.style.color = 'gray';
//  rubricsContainer.parentNode.insertBefore(info, rubricsContainer.parentNode.firstChild);
//  infoBlock = info;
//  var mw = Math.round(Math.max(document.body.scrollWidth, 900)*0.55);
//  info.innerHTML += 'cont.w: '+rubricsContainer.offsetWidth+', body.w: '+document.body.scrollWidth+', 55%: '+mw+'<br>';
    var a, b, idx, l, r, cell, wid;
    var wc = Math.min(rubricsContainer.offsetWidth, Math.round(Math.max(document.body.scrollWidth, 900)*0.55));
    var prc = Math.round(100*ws/wc);
//  info.innerHTML += prc+'%<br>';
    if (prc > maxFill) {
      var superTable = createSuperTable(rubricsContainer);
      var superRow = findFirstChild(superTable, 'tr');
//    info.innerHTML += '<b>Lipka</b>: len: '+len+', ci: '+ci+'<br>';
//    info.innerHTML += ss+'<br>';
      do {
//      info.innerHTML += 'prc: '+prc+'% ('+ws+'/'+wc+')<br>';
        a = (ci > 0 && wb <= wa ? ci+1 : 1);
        b = (ci > 0 && wb > wa ? ci-1 : len-2);
        idx = getArrayMaxIndex(rubricsCells, a, b, 'textWidth');
//      info.innerHTML += 'idx(max): '+idx+', ci: '+ci+'<br>';
        if (idx < 0) break;
        cell = rubricsCells[idx];
        wid = cell.textWidth;
        rubricsRow.removeChild(cell);
        superRow.appendChild(cell);
        len--;
        ws -= wid;
        if (ci > 0) {
          if (idx < ci) ci--;
          if (wb > wa) wb -= wid; else wa -= wid;
          l = ci-1; // ýë-òîâ ñëåâà îò ci êðîìå ïåðâîãî
          r = len-ci-2; // ýë-òîâ ñïðàâà îò ci rðîìå ïîñëåäíåãî
        } else {
          l = 1; // l - r = 1 - óáèðàåì ïî 1 ýëåìåíòó
          r = 0;
        }
//      info.innerHTML += 'ci: '+ci+', l: '+l+', r: '+r+'<br>';
        for (var n = 0; n < Math.abs(l - r); n++) {
          a = (ci > 0 && l <= r ? ci+1 : 1);
          b = (ci > 0 && l > r ? ci-1 : len-2);
          idx = getArrayMinIndex(rubricsCells, a, b, 'textWidth');
//        info.innerHTML += 'idx(min): '+idx+', ci: '+ci+'<br>';
          if (idx < 0) break;
          cell = rubricsCells[idx];
          wid = cell.textWidth;
          rubricsRow.removeChild(cell);
          superRow.appendChild(cell);
          len--;
          ws -= wid;
          if (ci > 0) {
            if (idx < ci) ci--;
            if (wb > wa) wb -= wid; else wa -= wid;
          }
        }
        prc = Math.round(100*ws/wc);
      } while (prc > maxFill);
//    info.innerHTML += '<small>lipka: full width: '+wc+',  rubrics width: '+ss+' ('+ws+') = '+prc+'%</small>';
    }
    if (ci > 0) {
      middleRubric = rubricsCells[ci];
      var mrLeft = getOffsetLeft(middleRubric, newsTable);
      var mrCenter = mrLeft + Math.round(middleRubric.offsetWidth/2);
    }
//}

//if (!rubricsContainer) return;
//rubricsContainer.style.border = '1px dashed red';
  var bubbleContainer = findFirstChild(newsTable, 'table', 'anonses');
//if (!bubbleContainer) return;
//bubbleContainer.style.border = '1px dashed blue';
  var middleBubble = findFirstChild(bubbleContainer, 'td', 'bg_m');
  if (middleBubble && middleRubric) {
//  middleBubble.style.border = '1px dashed green';
//  var leftBubble = findFirstChild(bubbleContainer, 'td', 'bg_l');
//  var rightBubble = findFirstChild(bubbleContainer, 'td', 'bg_r');
    var mbLeft = getOffsetLeft(middleBubble, newsTable);
    var mbRight = mbLeft + middleBubble.offsetWidth;
    var d;
    do {  // one-pass do while
      if (mrCenter < mbLeft+18) {
//      info.innerHTML += '&lt;!-- Lipka: mr center ('+mrCenter+') &lt; mb left+18 ('+(mbLeft+18)+') --&gt;<br>';
        a = ci+1;
        b = len-1;
        if (a >= b) break; // no elements right
        d = +1;
      } else if (mrCenter > mbRight-20) {
//      info.innerHTML += '&lt;!-- Lipka: mr center ('+mrCenter+') &gt; mb right-20 ('+(mbRight-20)+') --&gt;<br>';
        a = ci-1;
        b = 0;
        if (a <= b) break; // no elements left
        d = -1;
      } else break; // ok
      idx = -1;
      do {
        cell = rubricsCells[a];
        var cellLeft = getOffsetLeft(cell, newsTable);
        var cellCenter = cellLeft + Math.round(cell.offsetWidth/2);
        if (d > 0) {
          if (cellCenter > mbRight-20) break;
          if (cellCenter >= mbLeft+18) {
            idx = a;
            break;
          }
        } else {
          if (cellCenter < mbLeft+18) break;
          if (cellCenter <= mbRight-20) {
            idx = a;
            break;
          }
        }
        a += d;
      } while (a != b);
      if (idx < 0) break;
      var leftNextCell, rightNextCell;
      var idxText = trim((cell.innerText || cell.textContent));
      var ciText = trim((middleRubric.innerText || middleRubric.textContent));
      var s;
      if (idx < ci) {
        if (idx == ci-1) {
          rubricsRow.removeChild(middleRubric);
          rubricsRow.insertBefore(middleRubric, cell);
        } else {
          leftNextCell = rubricsCells[idx+1];
          rightNextCell = rubricsCells[ci+1];
          rubricsRow.removeChild(cell);
          rubricsRow.removeChild(middleRubric);
          rubricsRow.insertBefore(cell, rightNextCell);
          rubricsRow.insertBefore(middleRubric, leftNextCell);
        }
        s = '"'+idxText+'" &lt;-&gt; <b>"'+ciText+'"</b>';
      } else {
        if (idx == ci+1) {
          rubricsRow.removeChild(cell);
          rubricsRow.insertBefore(cell, middleRubric);
        } else {
          leftNextCell = rubricsCells[ci+1];
          rightNextCell = rubricsCells[idx+1];
          rubricsRow.removeChild(middleRubric);
          rubricsRow.removeChild(cell);
          rubricsRow.insertBefore(middleRubric, rightNextCell);
          rubricsRow.insertBefore(cell, leftNextCell);
        }
        s = '<b>"'+ciText+'"</b> &lt;-&gt; "'+idxText+'"';
      }
//    info.innerHTML += '&lt;!-- Lipka: '+s+' --&gt;<br>';
    } while (false); // where to break

//  var s = document.createElement('span');
//  s.innerHTML = '<small>lipka: l: '+wl+', m: '+wm+', r: '+wr+'</small>';
//  middleBubble.appendChild(s);
  }
}

var
  isIE = (navigator.userAgent.indexOf('MSIE') >= 0 && navigator.userAgent.indexOf('Opera') < 0),
  testFontSizeBlock = null,
  lastFontSize = 0,
  lastWindowSize = 0,
  lastLeadClass = '';
//documentTitle = '';

function chkUpdateLeadRows() {
  if (testFontSizeBlock == null) {
    testFontSizeBlock = document.createElement('SPAN');
    testFontSizeBlock.style.position = 'absolute';
    testFontSizeBlock.style.top = '0px';
    testFontSizeBlock.style.visibility = 'hidden';
    testFontSizeBlock.innerHTML = 'MMM';
    document.body.appendChild(testFontSizeBlock);
    setInterval(chkUpdateLeadRows, 250);
    addResizeHandler(chkUpdateLeadRows);
//  documentTitle = document.title;
  }
  var fs = Math.round(testFontSizeBlock.offsetWidth/3);
  var ws = document.body.clientWidth;
  if (fs != lastFontSize || ws != lastWindowSize) {
    lastFontSize = fs;
    lastWindowSize = ws;
    var leadClass = (ws >= 1100 ? (fs > 15 ? '' : 'big') : (fs > 15 ? 'small' : ''));
    if (leadClass != lastLeadClass) {
      lastLeadClass = leadClass;
      for (var i = 0; i < leadRows.length; i++) {
        leadRows[i].className = leadClass;
      }
    }
  }
}


function createSuperTable(subTable) {
  var table = document.createElement('TABLE');
  table.className = 'rubric_auto';
//table.width = '100%';
  table.cellSpacing = '0';
  table.cellPadding = '0';
  table.border = '0';
  var tbody = document.createElement('TBODY');
  table.appendChild(tbody);
  var tr = document.createElement('TR');
  tbody.appendChild(tr);
  subTable.parentNode.insertBefore(table, subTable);
  return table;
}

var
  rightCol = null,
  rightBlocks = null,
  rightLoadBlock = null,
  rightLoadBlocks = null,
  chkLoadRightBlocksIntervalId = null,
  lastMidColElement = null,
  lastVisRightIdx = -1;

function getGoogleContext () {
  return;
}

function prepareGoogleContext() {
  //alert ("Index:" + isIndexPage + "\n" + "Blog:" + isBlogPage + "\n" +  "comments:" + isCommentsPage + "\n" +  "Sam:" + isSamPage + "\n" + "Duel:" + isDuelPage);
  if (!isSamPage && !isBlogPage) {  
  
  var ColLeft = findFirstChild(findFirstChild(document.body, 
                  'tr', ['main_first', 'main']),'td', ['col_left','col_left_inside']);
  googleContext = $('gcontext');
  googleContext.style.display = 'block';
  if (isIndexPage || isCommentsPage) {
  Insert = findFirstChild (ColLeft, 'div','tape_news');
  for (var i = 0; i < 2; i++) {
    Insert = findNextSibling (Insert, 'div','tape_news');
  }
  Insert = findNextSibling (Insert, 'div');
  } else {
    Insert = findFirstChild (ColLeft, 'table','other_news');
  }
  ColLeft.insertBefore (googleContext, Insert);
  }
  //MidCol = findFirstChild(findFirstChild(document.body, 'tr', 'main'), 'td', 'col_mid');
  //P = findFirstChild(findFirstChild (findFirstChild (MidCol,'table','main_post'),'td'),'table');
  //if (MidCol == null) return;
  //YandexContext = $('ycontext');
 //P.insertBefore (YandexContext,P.nextSibling);
  
}

function prepareRightBlock() {
  rightCol = findFirstChild(document.body, 'td', 'col_right');
  if (rightCol == null) return;
  rightLoadBlock = $('right_load');
  rightLoadBlock.style.top = '-'+(rightLoadBlock.offsetHeight)+'px';
  rightLoadBlock.style.width = rightCol.offsetWidth;
  rightLoadBlocks = [];
  var el = rightLoadBlock.firstChild;
  while (el) {
    var tag = el.tagName;
    if (tag) {
      tag = tag.toLowerCase();
      if (tag == 'table' || tag == 'div') {
        el.style.visibility = 'hidden';
        rightLoadBlocks.push(el);
      }
    }
    el = el.nextSibling;
  }
  if (rightLoadBlocks.length == 0) return;
  if (window.isSamizdat && rightLoadBlocks.length > 2) {
    var selfAdv = rightLoadBlocks[0].cloneNode(true);
    rightLoadBlock.appendChild(selfAdv);
    rightLoadBlocks.push(selfAdv);
  }
  rightLoadBlock.style.display = 'block';
  rightBlocks = [];
  var midCol = findFirstChild(findFirstChild(
                 document.body, 
                  'tr', ['main_first', 'main']), 
                    'td', 'col_mid');
  lastMidColElement = midCol.lastChild;
  while (lastMidColElement) {
    var t = (lastMidColElement.tagName ? lastMidColElement.tagName.toLowerCase() : '');
    if (t && (t == 'table' || t == 'div')) break;
    lastMidColElement = lastMidColElement.previousSibling;
  }
//$('top_mid_banner').style.height = '10px';
//$('menu_logo_section').style.height = '80px';
//$('menu_navy_section').style.height = '60px';
  chkLoadRightBlocks();
  if (rightLoadBlocks.length > 0) {
    chkLoadRightBlocksIntervalId = setInterval(chkLoadRightBlocks, 500);
  }
  addResizeHandler(chkUpdateRightBlocks);
}

function chkLoadRightBlocks() {
  prepareGoogleContext();
  var n = false;
  var i = 0;
  while (rightLoadBlocks.length > 0) {
    var b = rightLoadBlocks[0];
    if (b.offsetHeight < 30) break;
    b.style.display = 'none';
    b.style.visibility = '';
    b.parentNode.removeChild(b);
    rightCol.appendChild(b);
    rightLoadBlocks.splice(0, 1);
    rightBlocks.push(b);

    n = true;
    i++;
  }  
  if (!isSamPage) {
  RL = $('rel_block3');
  RL.style.display = 'none';
  RL.style.visibility = '';
  rightCol.appendChild(RL);
  rightBlocks.push(RL);
  }
  if (rightLoadBlocks.length == 0) {
    if (chkLoadRightBlocksIntervalId != null) {
      clearInterval(chkLoadRightBlocksIntervalId);
      chkLoadRightBlocksIntervalId = null;
    }
    rightLoadBlock.style.display = 'none';
  }
  if (n) chkUpdateRightBlocks();
}

function chkUpdateRightBlocks() {
  for (var i = lastVisRightIdx; i >= 0; i--) {
    rightBlocks[i].style.display = 'none';
  }
  lastVisRightIdx = -1;
  if (lastMidColElement)
    var contentBottom = getOffsetTop(lastMidColElement) + lastMidColElement.offsetHeight;
  else
    var contentBottom = 0;
  for (var i = 0, l = rightBlocks.length; i < l; i++) {
    var el = rightBlocks[i];
    el.style.display = 'block';
    if (getOffsetTop(el) > contentBottom) {
      el.style.display = 'none';
      break;
    }
    lastVisRightIdx = i;
  }
  RL.style.display = 'block';
}

function matchStrArr(val, str) {
  if (val == null) val = '';
  else val = val.toLowerCase();
  if (!isArray(str)) {
    if (val == str) return true;
  } else {
    for (var i = 0; i < str.length; i++) {
      if (val == str[i]) return true;
    }
  }
  return false;
}

function findFirstChild(parent, tagName, clsName) {
  if (parent == null) return null;
  var el = parent.firstChild;
  while (el) {
    if ((tagName == null || (matchStrArr(el.tagName, tagName))) &&
        (clsName == null || (matchStrArr(el.className, clsName)))) return el;
    var s = findFirstChild(el, tagName, clsName);
    if (s) return s;
    el = el.nextSibling;
  }
  return null;
}

function findNextSibling(el, tagName, clsName) {
  if (el == null) return null;
  el = el.nextSibling;
  while (el) {
    if ((tagName == null || (matchStrArr(el.tagName, tagName))) &&
        (clsName == null || (matchStrArr(el.className, clsName)))) return el;
    el = el.nextSibling;
  }
  return null;
}

function getArrayMinIndex(array, a, b, property) {
  var v, vmin, vmini = -1;
  for (var i = a; i <= b; i++) {
    v = array[i][property];
    if (i == a || v < vmin) {
      vmin = v;
      vmini = i;
    }
  }
  return vmini;
}

function getArrayMaxIndex(array, a, b, property) {
  var v, vmax, vmaxi = -1;
  for (var i = a; i <= b; i++) {
    v = array[i][property];
    if (i == a || v > vmax) {
      vmax = v;
      vmaxi = i;
    }
  }
  return vmaxi;
}

function getOffsetLeft(el, parent) {
  parent = parent || document.body;
  var left = 0;
  while (el && el != parent) {
    left += el.offsetLeft;
    el = el.offsetParent;
  }
  return left;
}

function getOffsetTop(el, parent) {
  parent = parent || document.body;
  var top = 0;
  while (el && el != parent) {
    top += el.offsetTop;
    el = el.offsetParent;
  }
  return top;
}

function trim(s) {
  return s.replace(/^\s+/, '').replace(/\s+$/, '');
}

var resizeHandlers = null;

function addResizeHandler(handler) {
  if (resizeHandlers == null) {
    resizeHandlers = [];
    document.body.setAttribute('onresize', (isIE ? bodyResizeEvent : 'bodyResizeEvent(event)'));
  }
  resizeHandlers.push(handler);
}

function bodyResizeEvent(event) {
  for (var i = 0; i < resizeHandlers.length; i++) {
    resizeHandlers[i](event);
  }
}

function updateBubbles() {
  if (!isIE) return;  // set filter for IE only
  setTimeout(updateBubbles2, 0);
}

var 
  updateBubblesTable = null;

function updateBubbles2() {
  if (updateBubblesTable == null) updateBubblesTable = findFirstNewsTable();
  if (updateBubblesTable) {
    var bubbleCell = findFirstChild(findFirstChild(updateBubblesTable, 'table', 'anonses'), 'td');
    while (bubbleCell) {
      var topTable = findFirstChild(bubbleCell, 'table', 't');
      var topLeft  = findFirstChild(topTable, 'td', 'l');
      var topMidd  = findNextSibling(topLeft, 'td', 'm');
      var topMDiv  = findFirstChild(topMidd, 'div');
      var topRight = findNextSibling(topMidd, 'td', 'r');

      var mdlTable = findNextSibling(topTable, 'table', 'm');
      var mdlLeft  = findFirstChild(mdlTable, 'td', 'l');
      var mdlRight = findNextSibling(mdlLeft, 'td', 'r');

      var btmTable = findNextSibling(mdlTable, 'table', 'b');
      var btmLeft  = findFirstChild(btmTable, 'td', 'l');
      var btmMidd  = findNextSibling(btmLeft, 'td', 'm');
      var btmMDiv  = findFirstChild(btmMidd, 'div');
      var btmRight = findNextSibling(btmMidd, 'td', 'r');

      topLeft.style.filter  = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'/i/bubble/tl.png\',sizingMethod=scale)';
      topMDiv.style.filter  = 'progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=\'#22f8f8ec\', EndColorStr=\'#5540401b\')'
      topRight.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'/i/bubble/tr.png\',sizingMethod=scale)';
      
      mdlLeft.style.filter  = 'progid:DXImageTransform.Microsoft.Gradient(GradientType=1, StartColorStr=\'#22f8f8ec\', EndColorStr=\'#5540401b\')';
      mdlRight.style.filter = 'progid:DXImageTransform.Microsoft.Gradient(GradientType=1, StartColorStr=\'#9940401b\', EndColorStr=\'#00f8f8ec\')';

      btmLeft.style.filter  = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'/i/bubble/bl.png\',sizingMethod=scale)';
      btmMDiv.style.filter  = 'progid:DXImageTransform.Microsoft.Gradient(GradientType=0, StartColorStr=\'#CC40401b\', EndColorStr=\'#00f8f8ec\')';
      btmRight.style.filter = 'progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'/i/bubble/br.png\',sizingMethod=scale)';
      
      bubbleCell = findNextSibling(bubbleCell, 'td');
    }
    updateBubblesTable = findNextSibling(updateBubblesTable, 'table', 'top_news');
    if (updateBubblesTable) setTimeout(updateBubbles2, 0);
  }
}

//-- common -----------------------------------------------

if (!('$' in window)) {
  $ = function(el) {
    return (typeof(el) == 'string' ? document.getElementById(el) : el);
  }
}

if (!Array.prototype.indexOf) {
  Array.prototype.indexOf = function(item, first) {
    for (var i = first || 0; i < this.length; i++) {
      if (this[i] == item) return i;
    }
    return -1;
  }
}

Array.prototype.addItem = function(item) {
  var i = this.indexOf(item);
  if (i < 0) {
    i = this.length;
    this.push(item);
  }
  return i;
}

Array.prototype.removeItem = function(item) {
  var i = this.indexOf(item);
  if (i >= 0) this.removeItemByIndex(i, true);
  return i;
}

Array.prototype.removeItemByIndex = function(i, shrink) {
  if (shrink) {
    if (this.splice) this.splice(i, 1)
    else {
      for (var j = i+1; j < this.length; j++) this[j-1] = this[j];
      this.length = this.length-1;
    }
  } else {
    if (i < this.length-1) this[i] = null
    else {
      do { this.length = (i--) } while (i >= 0 && this[i] == null);
    }
  }
  return true;
}


function isString(prm) {
  return (typeof(prm) == 'string');
}

function isFunction(prm) {
  return (typeof(prm) == 'function');
}

function isArray(prm) {
  return (typeof(prm) == 'object' && 'length' in prm);
}

function callEventHandler(method, object) {
  if (method == null)     return false;
  if (!object) object = window;
  if (isFunction(method)) return method.call(object);
  if (isArray(method))    return method[0].apply(object, method.slice(1));
  if (isString(method))   return eval(method);
  warn('callEventHandler('+method+'): unsupported method type: '+method.constructor);
  return false;
}

function warn(s) {
//alert(s);
}

function setupEvent(el, eventType, handler, capture) {
  if (el.attachEvent) el.attachEvent('on'+eventType, handler)
  else if (el.addEventListener) el.addEventListener(eventType, handler, capture)
}

function removeEvent(el, eventType, handler, capture) {
  if (el.detachEvent) el.detachEvent('on'+eventType, handler)
  else if (el.removeEventListener) el.removeEventListener(eventType, handler, capture)
}

var
  mouseMoveListeners = [],
  mouseAbsPosX = 0,
  mouseAbsPosY = 0;

function addMouseMoveListener(handler, object) {
  var i, o;
  for (i = 0; i < mouseMoveListeners.length; i++) {
    o = mouseMoveListeners[i];
    if (o.method == handler && o.instance == object) return false;
  }
  if (mouseMoveListeners.length == 0)
    setupEvent(document, 'mousemove', mouseMoveEventHandler);
  mouseMoveListeners.push({method: handler, instance: object});
  return true;
}

function removeMouseMoveListener(handler, object) {
  var i, o;
  for (i = 0; i < mouseMoveListeners.length; i++) {
    o = mouseMoveListeners[i];
    if (o.method == handler && o.instance == object) {
      mouseMoveListeners.splice(i, 1);
      if (mouseMoveListeners.length == 0)
        removeEvent(document, 'mousemove', mouseMoveEventHandler);
      return;
    }
  }
}

function mouseMoveEventHandler(event) {
  mouseAbsPosX = event.clientX + document.body.scrollLeft;
  mouseAbsPosY = event.clientY + document.body.scrollTop;
  var i, o;
  for (i = 0; i < mouseMoveListeners.length; i++) {
    o = mouseMoveListeners[i];
    if (o.method) o.method.call(o.instance || window, event);
  }
}

var DEF_FADE_TIME    = 200;

var DEF_FADE_STEPS   = 4;

var DEF_DISPLAY_MODE = 'block';

function fadeIn(el, time, steps, displayMode) {
  fade(el, 'in', time, steps, displayMode);
}

function fadeOut(el, time, steps, displayMode) {
  fade(el, 'out', time, steps, displayMode);
}

// fade() v. 1.0
//  [how]: 'in' / 'out' (default)
//  [time]: ¬á¥ª.
//  [steps]: ª®«-¢® è £®¢
//  [displayMode]: à¥¦¨¬ à ¡®âë á ¡«®ª ¬¨
//
var
  fadingElements = [];

function fade(el, how, time, steps, displayMode) {
  el = $(el);
  if (time == undefined) time = DEF_FADE_TIME;
  if (steps == undefined) steps = DEF_FADE_STEPS; else if (steps <= 0) steps = 1;
  if (el.fadeIntervalId) {
    clearTimeout(el.fadeIntervalId);
    el.fadeIntervalId = null;
  }
  el.fadeStep = ((how == 'in' ? 1 : -1)/steps);
  if (!('fadeValue' in el)) el.fadeValue = (how == 'in' ? 0 : 1);
  el.fadeValue += el.fadeStep;
  el.fadeDisplayMode = displayMode; 
  if (hasAlpha(el)) setAlpha(el, el.fadeValue);
  if (!el.alphaMode || steps == 1) {
    setVisible(el, how == 'in', displayMode);
    if (el.afterFade) callEventHandler(el.afterFade, el);
    if (el.afterFadeEnd) {
      var i = fadingElements.addItem(el);
      setTimeout('callAfterFadeEnd('+i+')', 0);
    }
    return;
  }
  if (how == 'in') setVisible(el, true, displayMode);
  var i = fadingElements.addItem(el);
  el.fadeIntervalId = setInterval('stepFading('+i+')', time/(steps-1));
}

function stepFading(i) {
  var el = fadingElements[i];
  el.fadeValue += el.fadeStep;
  if (el.fadeValue > 1) el.fadeValue = 1; else if (el.fadeValue < 0) el.fadeValue = 0;
  setAlpha(el, el.fadeValue);
  if (el.fadeValue <= 0 || el.fadeValue >= 1) {
    clearInterval(el.fadeIntervalId);
    el.fadeIntervalId = null;
    if (el.fadeValue <= 0) setVisible(el, false, el.fadeDisplayMode);
    if (el.afterFade) callEventHandler(el.afterFade, el);
    if (el.afterFadeEnd) setTimeout('callAfterFadeEnd('+i+')', 0);
    else fadingElements.removeItemByIndex(i);
  }
}

function callAfterFadeEnd(i) {
  var el = fadingElements[i];
  fadingElements.removeItemByIndex(i);
  callEventHandler(el.afterFadeEnd, el);
}


// hasAlpha() v. 1.0
//  ¢®§¢à é ¥â: 'filter' / 'opacity' / false
//  § ¯®¬¨­ ¥â á®áâ®ï­¨¥ ¢ á¢®©áâ¢¥ alphaMode
//
function hasAlpha(el) {
  if (!('alphaMode' in el))
    el.alphaMode = ('filter' in el.style ? 'filter' :
                     ('opacity' in el.style ? 'opacity' : false));
  return el.alphaMode;
}

function getAlpha(el) {
  return ('alphaValue' in el ? el.alphaValue : 1);
}

function setAlpha(el, value) {
  if (el.alphaValue != value) {
    if (value < 0.01) value = 0;
    else if (value > 0.99) value = 1;
    el.alphaValue = value;
    if (!('alphaMode' in el)) hasAlpha(el);
    if (el.alphaMode == 'filter') 
      el.style.filter = 'alpha(opacity='+Math.round(el.alphaValue*100)+')';
    else if (el.alphaMode == 'opacity')
      el.style.opacity = el.alphaValue;
  }
}


function setVisible(el, value, displayMode) {
  if (displayMode != undefined) el.displayMode = displayMode;
  else if ('displayMode' in el) displayMode = el.displayMode;
  else displayMode = DEF_DISPLAY_MODE;
  if (displayMode != false) {
    if (displayMode == 'visible') el.style.visibility = (value ? 'visible' : 'hidden');
    else el.style.display = (value ? (displayMode == 'blank' ? '' : displayMode) : 'none');
  }
}


//-- Hint --------------------------------------
// v. 2.1, 02.03.2007

function Hint(type, defContent, w, h) {
  this.hintContainer = document.createElement('DIV');
//if (id) this.hintContainer.id = id;
  this.hintContainer.className = 'hint';
  this.type = type || 'text';
  this.defContent = defContent;
  this.width = w;
  this.height = h;
  this.inBody = false;
  this.visible = false;
  this.show = Hint_show;
  this.hide = Hint_hide;
  this.updatePos = Hint_updatePos;
  if (mouseMoveListeners.length == 0) addMouseMoveListener(null);  // add null handler to know mouse pos
}

function Hint_show(content) {
  if (content == null) content = this.defContent;
  var hintCont = this.hintContainer;
//hintCont.style.display = 'block';
//hintCont.style.visibility = 'hidden';

  hintCont.innerHTML = 
   '<table border="0" cellspacing="0" cellpadding="0"><tr><td>'+
     (this.type == 'image' ?
       '<img src="'+content+'"'+(this.w ? ' width="'+this.w+'"' : '')+(this.height ? ' height="'+this.height+'"' : '')+'>' :
       '<b></b><div>'+content+'</div><b></b>') +
   '</td></tr></table>';

  if (this.visible) return;
  hintCont.hintObject = this;
  if (!this.mouseHandlerAdded) {
    addMouseMoveListener(Hint_updatePos, this);
    this.mouseHandlerAdded = true;
  }

  if (!this.inBody) {
    document.body.appendChild(hintCont);
    this.inBody = true;
  }
  if (this.zIndex) hintCont.style.zIndex = this.zIndex;
  if (this.width) hintCont.style.width = this.width;
  if (this.fastShow) 
    setVisible(hintCont, true)
  else
    fade(hintCont, 'in');
  this.visible = true;
  var t = hintCont.getElementsByTagName('TABLE')[0];
  this.hintWidth = t.offsetWidth;
  this.hintHeight = t.offsetHeight;
  this.updatePos();
}

function Hint_hide(how) {
  if (!this.visible) return;
  this.visible = false;
  var hintCont = this.hintContainer;
  if (how == 'fast' || this.fastShow) {
    setVisible(hintCont, false);
    if (this.mouseHandlerAdded) {
      removeMouseMoveListener(Hint_updatePos, this);
      this.mouseHandlerAdded = false;
    }
    hintCont.hintObject = null;
  } else {
    if (this.mouseHandlerAdded) hintCont.afterFade = Hint_afterFade;
    fade(hintCont, 'out');
  }
}

function Hint_afterFade() {
  this.afterFade = null;
  var obj = this.hintObject;
  this.hintObject = null;
  obj.mouseHandlerAdded = false;
  removeMouseMoveListener(Hint_updatePos, obj);
}

function Hint_updatePos() {
  var body = document.body;
  var d = (body.clientWidth + body.scrollLeft) - this.hintWidth;
  var x = Math.min(mouseAbsPosX, d);
  var y = mouseAbsPosY + 20;
  var h = this.hintHeight;
  var ch = body.clientHeight + body.scrollTop;
  if (y + h >= ch) y = Math.min(mouseAbsPosY, ch) - h;
  this.hintContainer.style.left = x;
  this.hintContainer.style.top  = y;
}

var
  hint = new Hint('text');

function openFullScreenWindow(url) {
  window.open(url, '', 'fullscreen');
}

function addPageBookmark(title, url) {
  title = title || document.title; 
  url = url || location.href;
  try {
    if (window.sidebar) { // Firefox
      window.sidebar.addPanel(title, url, '');
      return true;
    } else if (window.external) { // IE
      window.external.AddFavorite(url, title);
      return true;
    } else if (window.opera) { // Opera
      var el = document.createElement('A');
      el.setAttribute('href', url);
      el.setAttribute('title', title);
      el.setAttribute('rel', 'sidebar');
      el.click();
      return true;
    }
  } catch(e) {}
  return false;
}


/*var
  logBlock = null;

function log(s) {
  if (logBlock == null) {
    logBlock = document.createElement('div');
    logBlock.style.padding = '1em';
    logBlock.style.color = 'gray';
    var cl = findFirstChild(document.body, 'td', 'col_left');
    cl.insertBefore(logBlock, cl.firstChild);
//  document.body.appendChild(logBlock);
  }
  logBlock.innerHTML += s + '<br>';
}*/
