
/*  Prototype JavaScript framework, version 1.5.0
 *  (c) 2005-2007 Sam Stephenson
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/
//Tom M. Yeh, Potix :prevent it from load twice
if (!window.z_prot_js) {
z_prot_js = true;

var Prototype = {
  Version: '1.5.0',
/* Tom M. Yeh, Potix: remove unused codes
  BrowserFeatures: {
    XPath: !!document.evaluate
  },
*/
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
  emptyFunction: function() {},
  K: function(x) { return x }
}

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

/* Tom M. Yeh, Potix: remove unused codes
var Abstract = new Object();
*/
Object.extend = function(destination, source) {
  for (var property in source) {
    destination[property] = source[property];
  }
  return destination;
}

Object.extend(Object, {
  inspect: function(object) {
    try {
      if (object === undefined) return 'undefined';
      if (object === null) return 'null';
      return object.inspect ? object.inspect() : object.toString();
    } catch (e) {
      if (e instanceof RangeError) return '...';
      throw e;
    }
  },

  keys: function(object) {
    var keys = [];
    for (var property in object)
      keys.push(property);
    return keys;
  },

  values: function(object) {
    var values = [];
    for (var property in object)
      values.push(object[property]);
    return values;
  },

  clone: function(object) {
    return Object.extend({}, object);
  }
});

Function.prototype.bind = function() {
  var __method = this, args = $A(arguments), object = args.shift();
  return function() {
    return __method.apply(object, args.concat($A(arguments)));
  }
}

Function.prototype.bindAsEventListener = function(object) {
  var __method = this, args = $A(arguments), object = args.shift();
  return function(event) {
    return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
  }
}

Object.extend(Number.prototype, {
  toColorPart: function() {
    var digits = this.toString(16);
    if (this < 16) return '0' + digits;
    return digits;
  },

  succ: function() {
    return this + 1;
  },

  times: function(iterator) {
    $R(0, this, true).each(iterator);
    return this;
  }
});

/* Tom M. Yeh, Potix: remove unused codes
var Try = {
  these: function() {
    var returnValue;

    for (var i = 0, length = arguments.length; i < length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}
*/
/*--------------------------------------------------------------------------*/
/* Tom M. Yeh, Potix: remove unused codes
var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  stop: function() {
    if (!this.timer) return;
    clearInterval(this.timer);
    this.timer = null;
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback(this);
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}
*/
String.interpret = function(value){
  return value == null ? '' : String(value);
}

Object.extend(String.prototype, {
  gsub: function(pattern, replacement) {
    var result = '', source = this, match;
    replacement = arguments.callee.prepareReplacement(replacement);

    while (source.length > 0) {
      if (match = source.match(pattern)) {
        result += source.slice(0, match.index);
        result += String.interpret(replacement(match));
        source  = source.slice(match.index + match[0].length);
      } else {
        result += source, source = '';
      }
    }
    return result;
  },

  sub: function(pattern, replacement, count) {
    replacement = this.gsub.prepareReplacement(replacement);
    count = count === undefined ? 1 : count;

    return this.gsub(pattern, function(match) {
      if (--count < 0) return match[0];
      return replacement(match);
    });
  },

/* Tom M. Yeh, Potix: remove unused codes
  scan: function(pattern, iterator) {
    this.gsub(pattern, iterator);
    return this;
  },

  truncate: function(length, truncation) {
    length = length || 30;
    truncation = truncation === undefined ? '...' : truncation;
    return this.length > length ?
      this.slice(0, length - truncation.length) + truncation : this;
  },
*/
  strip: function() {
    return this.replace(/^\s+/, '').replace(/\s+$/, '');
  },

/* Tom M. Yeh, Potix: remove unused codes
  stripTags: function() {
    return this.replace(/<\/?[^>]+>/gi, '');
  },

  stripScripts: function() {
    return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
  },

  extractScripts: function() {
    var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
    var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
    return (this.match(matchAll) || []).map(function(scriptTag) {
      return (scriptTag.match(matchOne) || ['', ''])[1];
    });
  },

  evalScripts: function() {
    return this.extractScripts().map(function(script) { return eval(script) });
  },

  escapeHTML: function() {
    var div = document.createElement('div');
    var text = document.createTextNode(this);
    div.appendChild(text);
    return div.innerHTML;
  },

  unescapeHTML: function() {
    var div = document.createElement('div');
    div.innerHTML = this.stripTags();
    return div.childNodes[0] ? (div.childNodes.length > 1 ?
      $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
      div.childNodes[0].nodeValue) : '';
  },

  toQueryParams: function(separator) {
    var match = this.strip().match(/([^?#]*)(#.*)?$/);
    if (!match) return {};

    return match[1].split(separator || '&').inject({}, function(hash, pair) {
      if ((pair = pair.split('='))[0]) {
        var name = decodeURIComponent(pair[0]);
        var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;

        if (hash[name] !== undefined) {
          if (hash[name].constructor != Array)
            hash[name] = [hash[name]];
          if (value) hash[name].push(value);
        }
        else hash[name] = value;
      }
      return hash;
    });
  },
*/
  toArray: function() {
    return this.split('');
  },

  succ: function() {
    return this.slice(0, this.length - 1) +
      String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
  },

  camelize: function() {
    var parts = this.split('-'), len = parts.length;
    if (len == 1) return parts[0];

    var camelized = this.charAt(0) == '-'
      ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
      : parts[0];

    for (var i = 1; i < len; i++)
      camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);

    return camelized;
  },

  capitalize: function(){
    return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
  },

  underscore: function() {
    return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
  },

  dasherize: function() {
    return this.gsub(/_/,'-');
  },

  inspect: function(useDoubleQuotes) {
    var escapedString = this.replace(/\\/g, '\\\\');
    if (useDoubleQuotes)
      return '"' + escapedString.replace(/"/g, '\\"') + '"';
    else
      return "'" + escapedString.replace(/'/g, '\\\'') + "'";
  }
});

String.prototype.gsub.prepareReplacement = function(replacement) {
  if (typeof replacement == 'function') return replacement;
  var template = new Template(replacement);
  return function(match) { return template.evaluate(match) };
}

/* Tom M. Yeh, Potix: remove unused codes
String.prototype.parseQuery = String.prototype.toQueryParams;
*/
var Template = Class.create();
Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
Template.prototype = {
  initialize: function(template, pattern) {
    this.template = template.toString();
    this.pattern  = pattern || Template.Pattern;
  },

  evaluate: function(object) {
    return this.template.gsub(this.pattern, function(match) {
      var before = match[1];
      if (before == '\\') return match[2];
      return before + String.interpret(object[match[3]]);
    });
  }
}

var $break    = new Object();
var $continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        try {
          iterator(value, index++);
        } catch (e) {
          if (e != $continue) throw e;
        }
      });
    } catch (e) {
      if (e != $break) throw e;
    }
    return this;
  },

/* Tom M. Yeh, Potix: remove unused codes
  eachSlice: function(number, iterator) {
    var index = -number, slices = [], array = this.toArray();
    while ((index += number) < array.length)
      slices.push(array.slice(index, index+number));
    return slices.map(iterator);
  },

  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      result = result && !!(iterator || Prototype.K)(value, index);
      if (!result) throw $break;
    });
    return result;
  },

  any: function(iterator) {
    var result = false;
    this.each(function(value, index) {
      if (result = !!(iterator || Prototype.K)(value, index))
        throw $break;
    });
    return result;
  },
*/
  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push((iterator || Prototype.K)(value, index));
    });
    return results;
  },

  detect: function(iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw $break;
      }
    });
    return result;
  },

  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },

/* Tom M. Yeh, Potix: remove unused codes
  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },
*/
  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw $break;
      }
    });
    return found;
  },

/* Tom M. Yeh, Potix: remove unused codes
  inGroupsOf: function(number, fillWith) {
    fillWith = fillWith === undefined ? null : fillWith;
    return this.eachSlice(number, function(slice) {
      while(slice.length < number) slice.push(fillWith);
      return slice;
    });
  },
*/
  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },

  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.map(function(value) {
      return value[method].apply(value, args);
    });
  },

  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value >= result)
        result = value;
    });
    return result;
  },

/* Tom M. Yeh, Potix: remove unused codes
  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (result == undefined || value < result)
        result = value;
    });
    return result;
  },

  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ?
        trues : falses).push(value);
    });
    return [trues, falses];
  },
*/
  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },

  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },

/* Tom M. Yeh, Potix: remove unused codes
  sortBy: function(iterator) {
    return this.map(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck('value');
  },
*/
  toArray: function() {
    return this.map();
/* Tom M. Yeh, Potix: remove unused codes
  },

  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == 'function')
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      return iterator(collections.pluck(index));
    });
  },

  size: function() {
    return this.toArray().length;
  },

  inspect: function() {
    return '#<Enumerable:' + this.toArray().inspect() + '>';
*/
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});
var $A = Array.from = function(iterable) {
  if (!iterable) return [];
  if (iterable.toArray) {
    return iterable.toArray();
  } else {
    var results = [];
    for (var i = 0, length = iterable.length; i < length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

if (!Array.prototype._reverse)
  Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0, length = this.length; i < length; i++)
      iterator(this[i]);
  },

/* Tom M. Yeh, Potix: remove unused codes
  clear: function() {
    this.length = 0;
    return this;
  },
*/
  first: function() {
    return this[0];
  },

/* Tom M. Yeh, Potix: remove unused codes
  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != null;
    });
  },
*/
  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value && value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

/* Tom M. Yeh, Potix: remove unused codes
  indexOf: function(object) {
    for (var i = 0, length = this.length; i < length; i++)
      if (this[i] == object) return i;
    return -1;
  },
*/
  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

/* Tom M. Yeh, Potix: remove unused codes
  reduce: function() {
    return this.length > 1 ? this : this[0];
  },

  uniq: function() {
    return this.inject([], function(array, value) {
      return array.include(value) ? array : array.concat([value]);
    });
  },
*/
  clone: function() {
    return [].concat(this);
  },

/* Tom M. Yeh, Potix: remove unused codes
  size: function() {
    return this.length;
  },
*/
  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});

Array.prototype.toArray = Array.prototype.clone;

function $w(string){
  string = string.strip();
  return string ? string.split(/\s+/) : [];
}

if(window.opera){
  Array.prototype.concat = function(){
    var array = [];
    for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
    for(var i = 0, length = arguments.length; i < length; i++) {
      if(arguments[i].constructor == Array) {
        for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
          array.push(arguments[i][j]);
      } else {
        array.push(arguments[i]);
      }
    }
    return array;
  }
}
var Hash = function(obj) {
  Object.extend(this, obj || {});
};

/* Tom M. Yeh, Potix: remove unused codes
Object.extend(Hash, {
  toQueryString: function(obj) {
    var parts = [];

	  this.prototype._each.call(obj, function(pair) {
      if (!pair.key) return;

      if (pair.value && pair.value.constructor == Array) {
        var values = pair.value.compact();
        if (values.length < 2) pair.value = values.reduce();
        else {
        	key = encodeURIComponent(pair.key);
          values.each(function(value) {
            value = value != undefined ? encodeURIComponent(value) : '';
            parts.push(key + '=' + encodeURIComponent(value));
          });
          return;
        }
      }
      if (pair.value == undefined) pair[1] = '';
      parts.push(pair.map(encodeURIComponent).join('='));
	  });

    return parts.join('&');
  }
});
*/
Object.extend(Hash.prototype, Enumerable);
Object.extend(Hash.prototype, {
  _each: function(iterator) {
    for (var key in this) {
      var value = this[key];
      if (value && value == Hash.prototype[key]) continue;

      var pair = [key, value];
      pair.key = key;
      pair.value = value;
      iterator(pair);
    }
  },

  keys: function() {
    return this.pluck('key');
  },

  values: function() {
    return this.pluck('value');
  },

/* Tom M. Yeh, Potix: remove unused codes
  merge: function(hash) {
    return $H(hash).inject(this, function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },
*/
  remove: function() {
    var result;
    for(var i = 0, length = arguments.length; i < length; i++) {
      var value = this[arguments[i]];
      if (value !== undefined){
        if (result === undefined) result = value;
        else {
          if (result.constructor != Array) result = [result];
          result.push(value)
        }
      }
      delete this[arguments[i]];
    }
    return result;
/* Tom M. Yeh, Potix: remove unused codes
  },

  toQueryString: function() {
    return Hash.toQueryString(this);
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
*/
  }
});

function $H(object) {
  if (object && object.constructor == Hash) return object;
  return new Hash(object);
};
ObjectRange = Class.create();
Object.extend(ObjectRange.prototype, Enumerable);
Object.extend(ObjectRange.prototype, {
  initialize: function(start, end, exclusive) {
    this.start = start;
    this.end = end;
    this.exclusive = exclusive;
  },

  _each: function(iterator) {
    var value = this.start;
    while (this.include(value)) {
      iterator(value);
      value = value.succ();
    }
  },

  include: function(value) {
    if (value < this.start)
      return false;
    if (this.exclusive)
      return value < this.end;
    return value <= this.end;
  }
});

var $R = function(start, end, exclusive) {
  return new ObjectRange(start, end, exclusive);
}

/* Tom M. Yeh, Potix: remove Ajax
var Ajax = {
...
}
*/
function $(element) {
  if (arguments.length > 1) {
    for (var i = 0, elements = [], length = arguments.length; i < length; i++)
      elements.push($(arguments[i]));
    return elements;
  }
  if (typeof element == 'string')
    element = document.getElementById(element);
  return Element.extend(element);
}

/* Tom M. Yeh, Potix: remove unused codes
if (Prototype.BrowserFeatures.XPath) {
  document._getElementsByXPath = function(expression, parentElement) {
    var results = [];
    var query = document.evaluate(expression, $(parentElement) || document,
      null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    for (var i = 0, length = query.snapshotLength; i < length; i++)
      results.push(query.snapshotItem(i));
    return results;
  };
}

document.getElementsByClassName = function(className, parentElement) {
  if (Prototype.BrowserFeatures.XPath) {
    var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
    return document._getElementsByXPath(q, parentElement);
  } else {
    var children = ($(parentElement) || document.body).getElementsByTagName('*');
    var elements = [], child;
    for (var i = 0, length = children.length; i < length; i++) {
      child = children[i];
      if (Element.hasClassName(child, className))
        elements.push(Element.extend(child));
    }
    return elements;
  }
};
*/
/*--------------------------------------------------------------------------*/

if (!window.Element)
  var Element = new Object();

Element.extend = function(element) {
  if (!element || _nativeExtensions || element.nodeType == 3) return element;

  if (!element._extended && element.tagName && element != window) {
    var methods = Object.clone(Element.Methods), cache = Element.extend.cache;

/* Tom M. Yeh, Potix: remove unused codes
    if (element.tagName == 'FORM')
      Object.extend(methods, Form.Methods);
    if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
      Object.extend(methods, Form.Element.Methods);

    Object.extend(methods, Element.Methods.Simulated);
*/
    for (var property in methods) {
      var value = methods[property];
      if (typeof value == 'function' && !(property in element))
        element[property] = cache.findOrStore(value);
    }
  }

  element._extended = true;
  return element;
};

Element.extend.cache = {
  findOrStore: function(value) {
    return this[value] = this[value] || function() {
      return value.apply(null, [this].concat($A(arguments)));
    }
  }
};

Element.Methods = {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function(element) {
    element = $(element);
    Element[Element.visible(element) ? 'hide' : 'show'](element);
    return element;
  },

  hide: function(element) {
    $(element).style.display = 'none';
    return element;
  },

  show: function(element) {
    $(element).style.display = '';
    return element;
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
    return element;
  },

/* Tom M. Yeh, Potix: remove unused codes
  update: function(element, html) {
    html = typeof html == 'undefined' ? '' : html.toString();
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  replace: function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    if (element.outerHTML) {
      element.outerHTML = html.stripScripts();
    } else {
      var range = element.ownerDocument.createRange();
      range.selectNodeContents(element);
      element.parentNode.replaceChild(
        range.createContextualFragment(html.stripScripts()), element);
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  },

  inspect: function(element) {
    element = $(element);
    var result = '<' + element.tagName.toLowerCase();
    $H({'id': 'id', 'className': 'class'}).each(function(pair) {
      var property = pair.first(), attribute = pair.last();
      var value = (element[property] || '').toString();
      if (value) result += ' ' + attribute + '=' + value.inspect(true);
    });
    return result + '>';
  },

  recursivelyCollect: function(element, property) {
    element = $(element);
    var elements = [];
    while (element = element[property])
      if (element.nodeType == 1)
        elements.push(Element.extend(element));
    return elements;
  },

  ancestors: function(element) {
    return $(element).recursivelyCollect('parentNode');
  },
*/
  descendants: function(element) {
    return $A($(element).getElementsByTagName('*'));
  },

/* Tom M. Yeh, Potix: remove unused codes
  immediateDescendants: function(element) {
    if (!(element = $(element).firstChild)) return [];
    while (element && element.nodeType != 1) element = element.nextSibling;
    if (element) return [element].concat($(element).nextSiblings());
    return [];
  },

  previousSiblings: function(element) {
    return $(element).recursivelyCollect('previousSibling');
  },

  nextSiblings: function(element) {
    return $(element).recursivelyCollect('nextSibling');
  },

  siblings: function(element) {
    element = $(element);
    return element.previousSiblings().reverse().concat(element.nextSiblings());
  },
*/
  match: function(element, selector) {
    if (typeof selector == 'string')
      selector = new Selector(selector);
    return selector.match($(element));
  },

/* Tom M. Yeh, Potix: remove unused codes
  up: function(element, expression, index) {
    return Selector.findElement($(element).ancestors(), expression, index);
  },
*/
  down: function(element, expression, index) {
    return Selector.findElement($(element).descendants(), expression, index);
  },

/* Tom M. Yeh, Potix: remove unused codes
  previous: function(element, expression, index) {
    return Selector.findElement($(element).previousSiblings(), expression, index);
  },

  next: function(element, expression, index) {
    return Selector.findElement($(element).nextSiblings(), expression, index);
  },

  getElementsBySelector: function() {
    var args = $A(arguments), element = $(args.shift());
    return Selector.findChildElements(element, args);
  },

  getElementsByClassName: function(element, className) {
    return document.getElementsByClassName(className, element);
  },
*/
  readAttribute: function(element, name) {
    element = $(element);
    if (document.all && !window.opera) {
      var t = Element._attributeTranslations;
      if (t.values[name]) return t.values[name](element, name);
      if (t.names[name])  name = t.names[name];
      var attribute = element.attributes[name];
      if(attribute) return attribute.nodeValue;
    }
    return element.getAttribute(name);
  },

/* Tom M. Yeh, Potix: remove unused codes
  getHeight: function(element) {
    return $(element).getDimensions().height;
  },

  getWidth: function(element) {
    return $(element).getDimensions().width;
  },
*/
  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    var elementClassName = element.className;
    if (elementClassName.length == 0) return false;
    if (elementClassName == className ||
        elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      return true;
    return false;
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).add(className);
    return element;
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element).remove(className);
    return element;
  },

/* Tom M. Yeh, Potix: remove unused codes
  toggleClassName: function(element, className) {
    if (!(element = $(element))) return;
    Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
    return element;
  },
*/
  observe: function() {
    Event.observe.apply(Event, arguments);
    return $A(arguments).first();
  },

  stopObserving: function() {
    Event.stopObserving.apply(Event, arguments);
    return $A(arguments).first();
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    var node = element.firstChild;
    while (node) {
      var nextNode = node.nextSibling;
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        element.removeChild(node);
      node = nextNode;
    }
    return element;
  },

/* Tom M. Yeh, Potix: remove unused codes
  empty: function(element) {
    return $(element).innerHTML.match(/^\s*$/);
  },
*/
  descendantOf: function(element, ancestor) {
    element = $(element), ancestor = $(ancestor);
    while (element = element.parentNode)
      if (element == ancestor) return true;
    return false;
  },

  scrollTo: function(element) {
    element = $(element);
    var pos = Position.cumulativeOffset(element);
    window.scrollTo(pos[0], pos[1]);
    return element;
  },

  getStyle: function(element, style) {
    element = $(element);
    if (['float','cssFloat'].include(style))
      style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
    style = style.camelize();
    var value = element.style[style];
    if (!value) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        var css = document.defaultView.getComputedStyle(element, null);
        value = css ? css[style] : null;
      } else if (element.currentStyle) {
        value = element.currentStyle[style];
      }
    }

    if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
      value = element['offset'+style.capitalize()] + 'px';

    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
      if (Element.getStyle(element, 'position') == 'static') value = 'auto';
    if(style == 'opacity') {
      if(value) return parseFloat(value);
      if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
        if(value[1]) return parseFloat(value[1]) / 100;
      return 1.0;
    }
    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style) {
    element = $(element);
    for (var name in style) {
      var value = style[name];
      if(name == 'opacity') {
        if (value == 1) {
          value = (/Gecko/.test(navigator.userAgent) &&
            !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
          if(/MSIE/.test(navigator.userAgent) && !window.opera)
            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
        } else if(value === '') {
          if(/MSIE/.test(navigator.userAgent) && !window.opera)
            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
        } else {
          if(value < 0.00001) value = 0;
          if(/MSIE/.test(navigator.userAgent) && !window.opera)
            element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
              'alpha(opacity='+value*100+')';
        }
      } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
      element.style[name.camelize()] = value;
    }
    return element;
  },

  getDimensions: function(element) {
    element = $(element);
    var display = $(element).getStyle('display');
    if (display != 'none' && display != null) // Safari bug
      return {width: zk.offsetWidth(element), height: zk.offsetHeight(element)}; //Tom M. Yeh, Potix: safari bug

    // All *Width and *Height properties give 0 on elements with display none,
    // so enable the element temporarily
    var els = element.style;
    var originalVisibility = els.visibility;
    var originalPosition = els.position;
    var originalDisplay = els.display;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = 'block';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = originalDisplay;
    els.position = originalPosition;
    els.visibility = originalVisibility;
    return {width: originalWidth, height: originalHeight};
  },

  makePositioned: function(element) {
    element = $(element);
    var pos = Element.getStyle(element, 'position');
    if (pos == 'static' || !pos) {
      element._madePositioned = true;
      element.style.position = 'relative';
      // Opera returns the offset relative to the positioning context, when an
      // element is position relative but top and left have not been defined
      if (window.opera) {
        element.style.top = 0;
        element.style.left = 0;
      }
    }
    return element;
  },

  undoPositioned: function(element) {
    element = $(element);
    if (element._madePositioned) {
      element._madePositioned = undefined;
      element.style.position =
        element.style.top =
        element.style.left =
        element.style.bottom =
        element.style.right = '';
    }
    return element;
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._clipping) return element;
	element._clipping = true;
    element._overflow = element.style.overflow;
	if (zk.ie && !element._overflow) element._overflow = 'visible';
    element._overflowX = element.style.overflowX;
	element._overflowY = element.style.overflowY;
//Tom M. Yeh, Potix: optimize it
//    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
    if (Element.getStyle(element, 'overflow') != 'hidden')
      element.style.overflow = 'hidden';
    return element;
  },

  undoClipping: function(element) {
    element = $(element);
    if (!element._clipping) return element;
//Tom M. Yeh, Potix
//Bug 1822717 and 1882277
    element.style.overflow = zk.ie && element._overflow == 'visible' ? 'auto' : element._overflow;
	element.style.overflowX = element._overflowX;
	element.style.overflowY = element._overflowY;
    element._clipping = element._overflow = element._overflowX = element._overflowY = undefined;
    return element;
  }
};

Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});

Element._attributeTranslations = {};

Element._attributeTranslations.names = {
  colspan:   "colSpan",
  rowspan:   "rowSpan",
  valign:    "vAlign",
  datetime:  "dateTime",
  accesskey: "accessKey",
  tabindex:  "tabIndex",
  enctype:   "encType",
  maxlength: "maxLength",
  readonly:  "readOnly",
  longdesc:  "longDesc"
};

Element._attributeTranslations.values = {
  _getAttr: function(element, attribute) {
    return element.getAttribute(attribute, 2);
  },

  _flag: function(element, attribute) {
    return $(element).hasAttribute(attribute) ? attribute : null;
  },

  style: function(element) {
    return element.style.cssText.toLowerCase();
  },

  title: function(element) {
    var node = element.getAttributeNode('title');
    return node.specified ? node.nodeValue : null;
  }
};

Object.extend(Element._attributeTranslations.values, {
  href: Element._attributeTranslations.values._getAttr,
  src:  Element._attributeTranslations.values._getAttr,
  disabled: Element._attributeTranslations.values._flag,
  checked:  Element._attributeTranslations.values._flag,
  readonly: Element._attributeTranslations.values._flag,
  multiple: Element._attributeTranslations.values._flag
});

/* Tom M. Yeh, Potix: remove unused codes
Element.Methods.Simulated = {
  hasAttribute: function(element, attribute) {
    var t = Element._attributeTranslations;
    attribute = t.names[attribute] || attribute;
    return $(element).getAttributeNode(attribute).specified;
  }
};

// IE is missing .innerHTML support for TABLE-related elements
if (document.all && !window.opera){
  Element.Methods.update = function(element, html) {
    element = $(element);
    html = typeof html == 'undefined' ? '' : html.toString();
    var tagName = element.tagName.toUpperCase();
    if (['THEAD','TBODY','TR','TD'].include(tagName)) {
      var div = document.createElement('div');
      switch (tagName) {
        case 'THEAD':
        case 'TBODY':
          div.innerHTML = '<table><tbody>' +  html.stripScripts() + '</tbody></table>';
          depth = 2;
          break;
        case 'TR':
          div.innerHTML = '<table><tbody><tr>' +  html.stripScripts() + '</tr></tbody></table>';
          depth = 3;
          break;
        case 'TD':
          div.innerHTML = '<table><tbody><tr><td>' +  html.stripScripts() + '</td></tr></tbody></table>';
          depth = 4;
      }
      $A(element.childNodes).each(function(node){
        element.removeChild(node)
      });
      depth.times(function(){ div = div.firstChild });

      $A(div.childNodes).each(
        function(node){ element.appendChild(node) });
    } else {
      element.innerHTML = html.stripScripts();
    }
    setTimeout(function() {html.evalScripts()}, 10);
    return element;
  }
};
*/
Object.extend(Element, Element.Methods);

var _nativeExtensions = false;

if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
  ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
    var className = 'HTML' + tag + 'Element';
    if(window[className]) return;
    var klass = window[className] = {};
    klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
  });

Element.addMethods = function(methods) {
  Object.extend(Element.Methods, methods || {});

  function copy(methods, destination, onlyIfAbsent) {
    onlyIfAbsent = onlyIfAbsent || false;
    var cache = Element.extend.cache;
    for (var property in methods) {
      var value = methods[property];
      if (!onlyIfAbsent || !(property in destination))
        destination[property] = cache.findOrStore(value);
    }
  }

  if (typeof HTMLElement != 'undefined') {
    copy(Element.Methods, HTMLElement.prototype);
/* Tom M. Yeh, Potix: remove unused codes
    copy(Element.Methods.Simulated, HTMLElement.prototype, true);
    copy(Form.Methods, HTMLFormElement.prototype);
    [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
      copy(Form.Element.Methods, klass.prototype);
    });
*/
    _nativeExtensions = true;
  }
}

/* Tom M. Yeh, Potix: remove unused codes
var Toggle = new Object();
Toggle.display = Element.toggle;
*/
/*--------------------------------------------------------------------------*/

/* Tom M. Yeh, Potix: remove unused codes
Abstract.Insertion = function(adjacency) {
  this.adjacency = adjacency;
}

Abstract.Insertion.prototype = {
  initialize: function(element, content) {
    this.element = $(element);
    this.content = content.stripScripts();

    if (this.adjacency && this.element.insertAdjacentHTML) {
      try {
        this.element.insertAdjacentHTML(this.adjacency, this.content);
      } catch (e) {
        var tagName = this.element.tagName.toUpperCase();
        if (['TBODY', 'TR'].include(tagName)) {
          this.insertContent(this.contentFromAnonymousTable());
        } else {
          throw e;
        }
      }
    } else {
      this.range = this.element.ownerDocument.createRange();
      if (this.initializeRange) this.initializeRange();
      this.insertContent([this.range.createContextualFragment(this.content)]);
    }

    setTimeout(function() {content.evalScripts()}, 10);
  },

  contentFromAnonymousTable: function() {
    var div = document.createElement('div');
    div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
    return $A(div.childNodes[0].childNodes[0].childNodes);
  }
}

var Insertion = new Object();

Insertion.Before = Class.create();
Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
  initializeRange: function() {
    this.range.setStartBefore(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment, this.element);
    }).bind(this));
  }
});

Insertion.Top = Class.create();
Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(true);
  },

  insertContent: function(fragments) {
    fragments.reverse(false).each((function(fragment) {
      this.element.insertBefore(fragment, this.element.firstChild);
    }).bind(this));
  }
});

Insertion.Bottom = Class.create();
Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
  initializeRange: function() {
    this.range.selectNodeContents(this.element);
    this.range.collapse(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.appendChild(fragment);
    }).bind(this));
  }
});

Insertion.After = Class.create();
Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
  initializeRange: function() {
    this.range.setStartAfter(this.element);
  },

  insertContent: function(fragments) {
    fragments.each((function(fragment) {
      this.element.parentNode.insertBefore(fragment,
        this.element.nextSibling);
    }).bind(this));
  }
});
*/
/*--------------------------------------------------------------------------*/

Element.ClassNames = Class.create();
Element.ClassNames.prototype = {
  initialize: function(element) {
    this.element = $(element);
  },

  _each: function(iterator) {
    this.element.className.split(/\s+/).select(function(name) {
      return name.length > 0;
    })._each(iterator);
  },

  set: function(className) {
    this.element.className = className;
  },

  add: function(classNameToAdd) {
    if (this.include(classNameToAdd)) return;
    this.set($A(this).concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set($A(this).without(classNameToRemove).join(' '));
  },

  toString: function() {
    return $A(this).join(' ');
  }
};

Object.extend(Element.ClassNames.prototype, Enumerable);
var Selector = Class.create();
Selector.prototype = {
  initialize: function(expression) {
    this.params = {classNames: []};
    this.expression = expression.toString().strip();
    this.parseExpression();
    this.compileMatcher();
  },

  parseExpression: function() {
    function abort(message) { throw 'Parse error in selector: ' + message; }

    if (this.expression == '')  abort('empty expression');

    var params = this.params, expr = this.expression, match, modifier, clause, rest;
    while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
      params.attributes = params.attributes || [];
      params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
      expr = match[1];
    }

    if (expr == '*') return this.params.wildcard = true;

    while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
      modifier = match[1], clause = match[2], rest = match[3];
      switch (modifier) {
        case '#':       params.id = clause; break;
        case '.':       params.classNames.push(clause); break;
        case '':
        case undefined: params.tagName = clause.toUpperCase(); break;
        default:        abort(expr.inspect());
      }
      expr = rest;
    }

    if (expr.length > 0) abort(expr.inspect());
  },

  buildMatchExpression: function() {
    var params = this.params, conditions = [], clause;

    if (params.wildcard)
      conditions.push('true');
    if (clause = params.id)
      conditions.push('element.readAttribute("id") == ' + clause.inspect());
    if (clause = params.tagName)
      conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
    if ((clause = params.classNames).length > 0)
      for (var i = 0, length = clause.length; i < length; i++)
        conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
    if (clause = params.attributes) {
      clause.each(function(attribute) {
        var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
        var splitValueBy = function(delimiter) {
          return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
        }

        switch (attribute.operator) {
          case '=':       conditions.push(value + ' == ' + attribute.value.inspect()); break;
          case '~=':      conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
          case '|=':      conditions.push(
                            splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
                          ); break;
          case '!=':      conditions.push(value + ' != ' + attribute.value.inspect()); break;
          case '':
          case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
          default:        throw 'Unknown operator ' + attribute.operator + ' in selector';
        }
      });
    }

    return conditions.join(' && ');
  },

// Tom M. Yeh, Potix: make it compressable with YUI compressor
  compileMatcher: function() {
    this.match = new Function('element', 'if (!element.tagName) return false; element = $(element); return ' + this.buildMatchExpression());
  },

  findElements: function(scope) {
    var element;

    if (element = $(this.params.id))
      if (this.match(element))
        if (!scope || Element.childOf(element, scope))
          return [element];

    scope = (scope || document).getElementsByTagName(this.params.tagName || '*');

    var results = [];
    for (var i = 0, length = scope.length; i < length; i++)
      if (this.match(element = scope[i]))
        results.push(Element.extend(element));

    return results;
  },

  toString: function() {
    return this.expression;
  }
}

Object.extend(Selector, {
  matchElements: function(elements, expression) {
    var selector = new Selector(expression);
    return elements.select(selector.match.bind(selector)).map(Element.extend);
  },

  findElement: function(elements, expression, index) {
    if (typeof expression == 'number') index = expression, expression = false;
    return Selector.matchElements(elements, expression || '*')[index || 0];
/* Tom M. Yeh, Potix: remove unused codes
  },

  findChildElements: function(element, expressions) {
    return expressions.map(function(expression) {
      return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*\/g).inject([null], function(results, expr) {
        var selector = new Selector(expr);
        return results.inject([], function(elements, result) {
          return elements.concat(selector.findElements(result || element));
        });
      });
    }).flatten();
*/
  }
});

/* Tom M. Yeh, Potix: remove unused codes
function $$() {
  return Selector.findChildElements(document, $A(arguments));
}

var Form = {
  reset: function(form) {
    $(form).reset();
    return form;
  },

  serializeElements: function(elements, getHash) {
    var data = elements.inject({}, function(result, element) {
      if (!element.disabled && element.name) {
        var key = element.name, value = $(element).getValue();
        if (value != undefined) {
          if (result[key]) {
            if (result[key].constructor != Array) result[key] = [result[key]];
            result[key].push(value);
          }
          else result[key] = value;
        }
      }
      return result;
    });

    return getHash ? data : Hash.toQueryString(data);
  }
};

Form.Methods = {
  serialize: function(form, getHash) {
    return Form.serializeElements(Form.getElements(form), getHash);
  },

  getElements: function(form) {
    return $A($(form).getElementsByTagName('*')).inject([],
      function(elements, child) {
        if (Form.Element.Serializers[child.tagName.toLowerCase()])
          elements.push(Element.extend(child));
        return elements;
      }
    );
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name) return $A(inputs).map(Element.extend);

    for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) || (name && input.name != name))
        continue;
      matchingInputs.push(Element.extend(input));
    }

    return matchingInputs;
  },

  disable: function(form) {
    form = $(form);
    form.getElements().each(function(element) {
      element.blur();
      element.disabled = 'true';
    });
    return form;
  },

  enable: function(form) {
    form = $(form);
    form.getElements().each(function(element) {
      element.disabled = '';
    });
    return form;
  },

  findFirstElement: function(form) {
    return $(form).getElements().find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    form = $(form);
    form.findFirstElement().activate();
    return form;
  }
}

Object.extend(Form, Form.Methods);
*/
/*--------------------------------------------------------------------------*/
/* Tom M. Yeh, Potix: remove unused codes
Form.Element = {
  focus: function(element) {
    $(element).focus();
    return element;
  },

  select: function(element) {
    $(element).select();
    return element;
  }
}

Form.Element.Methods = {
  serialize: function(element) {
    element = $(element);
    if (!element.disabled && element.name) {
      var value = element.getValue();
      if (value != undefined) {
        var pair = {};
        pair[element.name] = value;
        return Hash.toQueryString(pair);
      }
    }
    return '';
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    return Form.Element.Serializers[method](element);
  },

  clear: function(element) {
    $(element).value = '';
    return element;
  },

  present: function(element) {
    return $(element).value != '';
  },

  activate: function(element) {
    element = $(element);
    element.focus();
    if (element.select && ( element.tagName.toLowerCase() != 'input' ||
      !['button', 'reset', 'submit'].include(element.type) ) )
      element.select();
    return element;
  },

  disable: function(element) {
    element = $(element);
    element.disabled = true;
    return element;
  },

  enable: function(element) {
    element = $(element);
    element.blur();
    element.disabled = false;
    return element;
  }
}

Object.extend(Form.Element, Form.Element.Methods);
var Field = Form.Element;
var $F = Form.Element.getValue;
*/
/*--------------------------------------------------------------------------*/
/* Tom M. Yeh, Potix: remove unused codes
Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
      default:
        return Form.Element.Serializers.textarea(element);
    }
  },

  inputSelector: function(element) {
    return element.checked ? element.value : null;
  },

  textarea: function(element) {
    return element.value;
  },

  select: function(element) {
    return this[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var index = element.selectedIndex;
    return index >= 0 ? this.optionValue(element.options[index]) : null;
  },

  selectMany: function(element) {
    var values, length = element.length;
    if (!length) return null;

    for (var i = 0, values = []; i < length; i++) {
      var opt = element.options[i];
      if (opt.selected) values.push(this.optionValue(opt));
    }
    return values;
  },

  optionValue: function(opt) {
    // extend element because hasAttribute may not be native
    return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
  }
}
*/
/*--------------------------------------------------------------------------*/
/* Tom M. Yeh, Potix: remove unused codes
Abstract.TimedObserver = function() {}
Abstract.TimedObserver.prototype = {
  initialize: function(element, frequency, callback) {
    this.frequency = frequency;
    this.element   = $(element);
    this.callback  = callback;

    this.lastValue = this.getValue();
    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    var value = this.getValue();
    var changed = ('string' == typeof this.lastValue && 'string' == typeof value
      ? this.lastValue != value : String(this.lastValue) != String(value));
    if (changed) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  }
}

Form.Element.Observer = Class.create();
Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.Observer = Class.create();
Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
*/
/*--------------------------------------------------------------------------*/
/* Tom M. Yeh, Potix: remove unused codes
Abstract.EventObserver = function() {}
Abstract.EventObserver.prototype = {
  initialize: function(element, callback) {
    this.element  = $(element);
    this.callback = callback;

    this.lastValue = this.getValue();
    if (this.element.tagName.toLowerCase() == 'form')
      this.registerFormCallbacks();
    else
      this.registerCallback(this.element);
  },

  onElementEvent: function() {
    var value = this.getValue();
    if (this.lastValue != value) {
      this.callback(this.element, value);
      this.lastValue = value;
    }
  },

  registerFormCallbacks: function() {
    Form.getElements(this.element).each(this.registerCallback.bind(this));
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        default:
          Event.observe(element, 'change', this.onElementEvent.bind(this));
          break;
      }
    }
  }
}

Form.Element.EventObserver = Class.create();
Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.Element.getValue(this.element);
  }
});

Form.EventObserver = Class.create();
Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
  getValue: function() {
    return Form.serialize(this.element);
  }
});
*/
if (!window.Event) {
  var Event = new Object();
}

Object.extend(Event, {
/* Tom M. Yeh, Potix: remove unused codes
  KEY_BACKSPACE: 8,
  KEY_TAB:       9,
  KEY_RETURN:   13,
  KEY_ESC:      27,
  KEY_LEFT:     37,
  KEY_UP:       38,
  KEY_RIGHT:    39,
  KEY_DOWN:     40,
  KEY_DELETE:   46,
  KEY_HOME:     36,
  KEY_END:      35,
  KEY_PAGEUP:   33,
  KEY_PAGEDOWN: 34,
*/
  element: function(event) {
    return event.target || event.srcElement;
  },

  isLeftClick: function(event) {
    return (((event.which) && (event.which == 1)) ||
            ((event.button) && (event.button == 1)));
  },

  pointerX: function(event) {
    return event.pageX || (event.clientX +
      (document.documentElement.scrollLeft || document.body.scrollLeft));
  },

  pointerY: function(event) {
    return event.pageY || (event.clientY +
      (document.documentElement.scrollTop || document.body.scrollTop));
  },
/* Jumper Chen, Potix: add the code of event more controllable.*/
  safariKeys: {
    63234 : 37, // left
    63232 : 38, // up
    63235 : 39, // right
    63233 : 40, // down
    63276 : 33, // page up
    63277 : 34, // page down
    63272 : 46, // delete
    63273 : 36, // home
    63275 : 35  // end
  },
  charCode: function(evt) {
  	return evt.charCode || evt.keyCode;
  },

  keyCode: function(evt) {
    var k = evt.keyCode || evt.charCode;
    return zk.safari ? (this.safariKeys[k] || k) : k;
  },
  isSpecialKey: function(evt) {
    var k = evt.shiftKey ? evt.keyCode : this.keyCode(evt);
    return (evt.type == 'keypress' && evt.ctrlKey) || k == 0 || k == 9 || 
	k == 13 || k == 40 || k == 27 ||
    (k == 16) || (k == 17) ||
    (k >= 18 && k <= 20) ||
    (k >= 33 && k <= 35) ||
    (k >= 36 && k <= 39) ||
    (k == 44 && k == 45);
  },
/* Jumper Chen, Potix*/  
  
  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
	  event.keyCode = 0; //Jumper Chen, Potix: Bug #1834891
    }
  },
/* Tom M. Yeh, Potix: remove unused codes
  // find the first node with the given tagName, starting from the
  // node the event was triggered on; traverses the DOM upwards
  findElement: function(event, tagName) {
    var element = Event.element(event);
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },
*/
  observers: false,

  _observeAndCache: function(element, name, observer, useCapture) {
    if (!this.observers) this.observers = [];
    if (element.addEventListener) {
      this.observers.push([element, name, observer, useCapture]);
      element.addEventListener(name, observer, useCapture);
    } else if (element.attachEvent) {
      this.observers.push([element, name, observer, useCapture]);
      element.attachEvent('on' + name, observer);
    }
  },

  unloadCache: function() {
    if (!Event.observers) return;
    for (var i = 0, length = Event.observers.length; i < length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.attachEvent))
      name = 'keydown';

    Event._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.detachEvent))
      name = 'keydown';

    if (element.removeEventListener) {
      element.removeEventListener(name, observer, useCapture);
    } else if (element.detachEvent) {
      try {
        element.detachEvent('on' + name, observer);
      } catch (e) {}
    }
  }
});

/* prevent memory leaks in IE */
if (navigator.appVersion.match(/\bMSIE\b/))
  Event.observe(window, 'unload', Event.unloadCache, false);
var Position = {
  // set to true if needed, warning: firefox performance problems
  // NOT neeeded for page scrolling, only if draggable contained in
  // scrollable elements
  includeScrollOffsets: false,

  // must be called before calling withinIncludingScrolloffset, every time the
  // page is scrolled
  prepare: function() {
    this.deltaX =  window.pageXOffset
                || document.documentElement.scrollLeft
                || document.body.scrollLeft
                || 0;
    this.deltaY =  window.pageYOffset
                || document.documentElement.scrollTop
                || document.body.scrollTop
                || 0;
  },

  realOffset: function(element) {
    var valueT = 0, valueL = 0, tagName = element.tagName;
    do {
//Tom M. Yeh, Potix: fix opera bug (see the page function)
// If tagName is "IMG" or "TR", the "DIV" element's scrollTop should be ignored.
// Because the offsetTop of element "IMG" or "TR" is excluded its scrollTop.  
if (!window.opera || element.tagName == 'BODY' || (tagName != "TR" && tagName != "IMG"  && element.tagName == 'DIV') ) { 
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
}
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0, operaBug = false, el = element.parentNode;
//Jumper Chen, Poitx: fix gecko difference, the offset of gecko excludes its border-width when its CSS position is relative or absolute.	
	if (zk.gecko) {
		while (el && el != document.body) {
			var style = Element.getStyle(el, "position");
			if (style == "relative" || style == "absolute") {
				valueT += $int(Element.getStyle(el, "border-top-width"));
				valueL += $int(Element.getStyle(el, "border-left-width"));
			}
	        el = el.parentNode;
	    }
	}
	
    do {
//Tom M. Yeh, Potix: Bug 1577880: fix originated from http://dev.rubyonrails.org/ticket/4843
if (Element.getStyle(element, "position") == 'fixed') {
	valueT += zk.innerY() + element.offsetTop;
	valueL += zk.innerX() + element.offsetLeft;
	break;
} else {
//Jumper Chen, Poitx: fix opera bug. If the parent of "INPUT" or "SPAN" element is "DIV" 
// and the scrollTop of "DIV" element is more than 0, the offsetTop of "INPUT" or "SPAN" element always is wrong.
	if (window.opera) { 
		if (element.nodeName == "SPAN" || element.nodeName == "INPUT") operaBug = true;
		else if (element.nodeName == "DIV" && operaBug) {
			operaBug = false;
			if (element.scrollTop != 0) valueT += element.scrollTop  || 0;
		} else operaBug = false;			
	}
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
//Tom M. Yeh, Potix: Bug 1721158: In FF, element.offsetParent is null in this case
      element = zk.gecko && element != document.body ? Position.offsetParent(element): element.offsetParent;
}
    } while (element);
    return [valueL, valueT];
  },

  positionedOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
//Tom M. Yeh, Potix: Bug 1721158: In FF, element.offsetParent is null in this case
      element = zk.gecko && element != document.body ? Position.offsetParent(element): element.offsetParent;
      if (element) {
        if(element.tagName=='BODY') break;
        var p = Element.getStyle(element, 'position');
        if (p == 'relative' || p == 'absolute') break;
      }
    } while (element);
    return [valueL, valueT];
  },

  offsetParent: function(element) {
    if (element.offsetParent) return element.offsetParent;
    if (element == document.body) return element;

    while ((element = element.parentNode) && element != document.body)
//Tom M. Yeh, Potix: in IE, style might not be available
      if (element.style && Element.getStyle(element, 'position') != 'static')
        return element;

    return document.body;
  },

  // caches x/y coordinate pair to use with overlap
  within: function(element, x, y) {
    if (this.includeScrollOffsets)
//Tom Yeh, Potix: make the name shorter
//      return this.withinIncludingScrolloffsets(element, x, y);
      return this.withinScroll(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + zk.offsetHeight(element) && //Tom M. Yeh, Potix: safari bug
            x >= this.offset[0] &&
            x <  this.offset[0] + zk.offsetWidth(element)); //Tom M. Yeh, Potix: safari bug
  },

//Tom Yeh, Potix: make the name shorter
//  withinIncludingScrolloffsets: function(element, x, y) {
  withinScroll: function(element, x, y) {
  	/**
    var offsetcache = this.realOffset(element);

    this.xcomp = x + offsetcache[0] - this.deltaX;
    this.ycomp = y + offsetcache[1] - this.deltaY;
    this.offset = this.cumulativeOffset(element);*/ // Jumper Chen, Potix: bug #1692556
	this.xcomp = x;
	this.ycomp = y;
	this.offset = zk.revisedOffset(element);
    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + zk.offsetHeight(element) && //Tom M. Yeh, Potix: safari bug
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + zk.offsetWidth(element)); //Tom M. Yeh, Potix: safari bug
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + zk.offsetHeight(element)) - this.ycomp) / //Tom M. Yeh, Potix: safari bug
        zk.offsetHeight(element); //Tom M. Yeh, Potix: safari bug
    if (mode == 'horizontal')
      return ((this.offset[0] + zk.offsetWidth(element)) - this.xcomp) / //Tom M. Yeh, Potix: safari bug
        zk.offsetWidth(element); //Tom M. Yeh, Potix: safari bug
  },

  page: function(forElement) {
    var valueT = 0, valueL = 0;

    var element = forElement;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;

      // Safari fix
      if (element.offsetParent==document.body)
        if (Element.getStyle(element,'position')=='absolute') break;

    } while (element = element.offsetParent);

    element = forElement;
    do {
      if (!window.opera || element.tagName=='BODY') {
        valueT -= element.scrollTop  || 0;
        valueL -= element.scrollLeft || 0;
      }
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

/* Tom M. Yeh, Potix: remove unused codes
  clone: function(source, target) {
    var options = Object.extend({
      setLeft:    true,
      setTop:     true,
      setWidth:   true,
      setHeight:  true,
      offsetTop:  0,
      offsetLeft: 0
    }, arguments[2] || {})

    // find page position of source
    source = $(source);
    var p = Position.page(source);

    // find coordinate system to use
    target = $(target);
    var delta = [0, 0];
    var parent = null;
    // delta [0,0] will do fine with position: fixed elements,
    // position:absolute needs offsetParent deltas
    if (Element.getStyle(target,'position') == 'absolute') {
      parent = Position.offsetParent(target);
      delta = Position.page(parent);
    }

    // correct by body offsets (fixes Safari)
    if (parent == document.body) {
      delta[0] -= document.body.offsetLeft;
      delta[1] -= document.body.offsetTop;
    }

    // set position
    if(options.setLeft)   target.style.left  = (p[0] - delta[0] + options.offsetLeft) + 'px';
    if(options.setTop)    target.style.top   = (p[1] - delta[1] + options.offsetTop) + 'px';
    if(options.setWidth)  target.style.width = zk.offsetWidth(source) + 'px'; //Tom M. Yeh, Potix: safari bug
    if(options.setHeight) target.style.height = zk.offsetHeight(source) + 'px'; //Tom M. Yeh, Potix: safari bug
  },
*/
  absolutize: function(element) {
    element = $(element);
    if (element.style.position == 'absolute') return;
    Position.prepare();

    var offsets = Position.positionedOffset(element);
    var top     = offsets[1];
    var left    = offsets[0];
/* Tom M Yeh, Potix: Bug 1591389
    var width   = element.clientWidth;
    var height  = element.clientHeight;
*/

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
/* Tom M Yeh, Potix: Bug 1591389
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;
*/
    element.style.position = 'absolute';
    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
/* Tom M Yeh, Potix: Bug 1591389
    element.style.width  = width + 'px';
    element.style.height = height + 'px';
*/
  },

  relativize: function(element) {
    element = $(element);
    if (element.style.position == 'relative') return;
    Position.prepare();

    element.style.position = 'relative';
    var top  = parseFloat(element.style.top  || 0) - (element._originalTop || 0);
    var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);

    element.style.top    = top + 'px';
    element.style.left   = left + 'px';
/* Tom M Yeh, Potix: Bug 1591389
    element.style.height = element._originalHeight;
    element.style.width  = element._originalWidth;
*/
  }
}

// Safari returns margins on body which is incorrect if the child is absolutely
// positioned.  For performance reasons, redefine Position.cumulativeOffset for
// KHTML/WebKit only.
if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
  Position.cumulativeOffset = function(element) {
    var valueT = 0, valueL = 0, el = element.parentNode;
//Jumper Chen, Poitx: fix safari difference, the offset of safari excludes its border-width when its CSS position is relative or absolute.
	if (zk.safari) {
		while (el && el != document.body) {
			var style = Element.getStyle(el, "position");
			if (style == "relative" || style == "absolute") {
				valueT += $int(Element.getStyle(el, "border-top-width"));
				valueL += $int(Element.getStyle(el, "border-left-width"));
			} 
	        el = el.parentNode;
	    }
	}
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      if (element.offsetParent == document.body)
        if (Element.getStyle(element, 'position') == 'absolute') break;

      element = element.offsetParent;
    } while (element);

    return [valueL, valueT];
  }
}

Element.addMethods();

}//Tom M. Yeh, Potix :prevent it from load twice

// script.aculo.us effects.js v1.7.0, Fri Jan 19 19:16:36 CET 2007

// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// Contributors:
//  Justin Palmer (http://encytemedia.com/)
//  Mark Pilgrim (http://diveintomark.org/)
//  Martin Bialasinki
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/ 
//Tom M. Yeh, Potix: prevent it from load twice
if (!window.z_effects_js) {
	z_effects_js = true;

// converts rgb() and #xxx to #xxxxxx format,  
// returns self (or first argument) if not convertable  
String.prototype.parseColor = function() {  
  var color = '#';
  if(this.slice(0,4) == 'rgb(') {  
    var cols = this.slice(4,this.length-1).split(',');  
    var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3);  
  } else {  
    if(this.slice(0,1) == '#') {  
      if(this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase();  
      if(this.length==7) color = this.toLowerCase();  
    }  
  }  
  return(color.length==7 ? color : (arguments[0] || this));  
}

/*--------------------------------------------------------------------------*/

/* Tom M. Yeh, Potix: remove unused codes
Element.collectTextNodes = function(element) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      (node.hasChildNodes() ? Element.collectTextNodes(node) : ''));
  }).flatten().join('');
}

Element.collectTextNodesIgnoreClass = function(element, className) {  
  return $A($(element).childNodes).collect( function(node) {
    return (node.nodeType==3 ? node.nodeValue : 
      ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? 
        Element.collectTextNodesIgnoreClass(node, className) : ''));
  }).flatten().join('');
}
Element.setContentZoom = function(element, percent) {
  element = $(element);  
  element.setStyle({fontSize: (percent/100) + 'em'});   
  if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
  return element;
}
*/

Element.getOpacity = function(element){
  return $(element).getStyle('opacity');
}

Element.setOpacity = function(element, value){
  return $(element).setStyle({opacity:value});
}

Element.getInlineOpacity = function(element){
  return $(element).style.opacity || '';
}

Element.forceRerendering = function(element) {
  try {
    element = $(element);
    var n = document.createTextNode(' ');
    element.appendChild(n);
    element.removeChild(n);
  } catch(e) { }
};

/*--------------------------------------------------------------------------*/

Array.prototype.call = function() {
  var args = arguments;
  this.each(function(f){ f.apply(this, args) });
}

/*--------------------------------------------------------------------------*/

var Effect = {
  _elNotExistErr: {
    name: 'ElementDoesNotExistError',
    message: 'The specified DOM element does not exist, but is required for this effect to operate'
/* Tom M. Yeh, Potix: remove unused codes
  },
  tagifyText: function(element) {
    if(typeof Builder == 'undefined')
      throw("Effect.tagifyText requires including script.aculo.us' builder.js library");
      
    var tagifyStyle = 'position:relative';
    if(/MSIE/.test(navigator.userAgent) && !window.opera) tagifyStyle += ';zoom:1';
    
    element = $(element);
    $A(element.childNodes).each( function(child) {
      if(child.nodeType==3) {
        child.nodeValue.toArray().each( function(character) {
          element.insertBefore(
            Builder.node('span',{style: tagifyStyle},
              character == ' ' ? String.fromCharCode(160) : character), 
              child);
        });
        Element.remove(child);
      }
    });
  },
  multiple: function(element, effect) {
    var elements;
    if(((typeof element == 'object') || 
        (typeof element == 'function')) && 
       (element.length))
      elements = element;
    else
      elements = $(element).childNodes;
      
    var options = Object.extend({
      speed: 0.1,
      delay: 0.0
    }, arguments[2] || {});
    var masterDelay = options.delay;

    $A(elements).each( function(element, index) {
      new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay }));
    });
  },
  PAIRS: {
    'slide':  ['SlideDown','SlideUp'],
    'blind':  ['BlindDown','BlindUp'],
    'appear': ['Appear','Fade']
  },
  toggle: function(element, effect) {
    element = $(element);
    effect = (effect || 'appear').toLowerCase();
    var options = Object.extend({
      queue: { position:'end', scope:(element.id || 'global'), limit: 1 }
    }, arguments[2] || {});
    Effect[element.visible() ? 
      Effect.PAIRS[effect][1] : Effect.PAIRS[effect][0]](element, options);
*/
  }
};

/* Tom M. Yeh, Potix: remove unused codes
var Effect2 = Effect; // deprecated
*/
/* ------------- transitions ------------- */

Effect.Transitions = {
/* Tom M. Yeh, Potix: remove unused codes
  linear: Prototype.K,
*/
  sinoidal: function(pos) {
    return (-Math.cos(pos*Math.PI)/2) + 0.5;
  },
/* Tom M. Yeh, Potix: remove unused codes
  reverse: function(pos) {
    return 1-pos;
  },
*/
  flicker: function(pos) {
    return ((-Math.cos(pos*Math.PI)/4) + 0.75) + Math.random()/4;
  },
/* Tom M. Yeh, Potix: remove unused codes
  wobble: function(pos) {
    return (-Math.cos(pos*Math.PI*(9*pos))/2) + 0.5;
  },
*/
  pulse: function(pos, pulses) { 
    pulses = pulses || 5; 
    return (
      Math.round((pos % (1/pulses)) * pulses) == 0 ? 
            ((pos * pulses * 2) - Math.floor(pos * pulses * 2)) : 
        1 - ((pos * pulses * 2) - Math.floor(pos * pulses * 2))
      );
  },
  none: function(pos) {
    return 0;
  },
  full: function(pos) {
    return 1;
  }
};

/* ------------- core effects ------------- */

Effect.ScopedQueue = Class.create();
Object.extend(Object.extend(Effect.ScopedQueue.prototype, Enumerable), {
  initialize: function() {
    this.effects  = [];
    this.interval = null;
  },
  _each: function(iterator) {
    this.effects._each(iterator);
  },
  add: function(effect) {
    var timestamp = new Date().getTime();
    
    var position = (typeof effect.options.queue == 'string') ? 
      effect.options.queue : effect.options.queue.position;
    
    switch(position) {
      case 'front':
        // move unstarted effects after this effect  
        this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) {
            e.startOn  += effect.finishOn;
            e.finishOn += effect.finishOn;
          });
        break;
      case 'with-last':
        timestamp = this.effects.pluck('startOn').max() || timestamp;
        break;
      case 'end':
        // start effect after last queued effect has finished
        timestamp = this.effects.pluck('finishOn').max() || timestamp;
        break;
    }
    
    effect.startOn  += timestamp;
    effect.finishOn += timestamp;

    if(!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit))
      this.effects.push(effect);
    
    if(!this.interval) 
      this.interval = setInterval(this.loop.bind(this), 15);
  },
  remove: function(effect) {
    this.effects = this.effects.reject(function(e) { return e==effect });
    if(this.effects.length == 0) {
      clearInterval(this.interval);
      this.interval = null;
    }
  },
  loop: function() {
    var timePos = new Date().getTime();
    for(var i=0, len=this.effects.length;i<len;i++) 
      if(this.effects[i]) this.effects[i].loop(timePos);
  }
});

Effect.Queues = {
  instances: $H(),
  get: function(queueName) {
    if(typeof queueName != 'string') return queueName;
    
    if(!this.instances[queueName])
      this.instances[queueName] = new Effect.ScopedQueue();
      
    return this.instances[queueName];
  }
}
Effect.Queue = Effect.Queues.get('global');

Effect.DefaultOptions = {
  transition: Effect.Transitions.sinoidal,
  duration:   1.0,   // seconds
  fps:        60.0,  // max. 60fps due to Effect.Queue implementation
  sync:       false, // true for combining
  from:       0.0,
  to:         1.0,
  delay:      0.0,
  queue:      'parallel'
}

Effect.Base = function() {};
Effect.Base.prototype = {
  position: null,
  start: function(options) {
    this.options      = Object.extend(Object.extend({},Effect.DefaultOptions), options || {});
    this.currentFrame = 0;
    this.state        = 'idle';
    this.startOn      = this.options.delay*1000;
    this.finishOn     = this.startOn + (this.options.duration*1000);
    this.event('beforeStart');
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).add(this);
  },
  loop: function(timePos) {
    if(timePos >= this.startOn) {
      if(timePos >= this.finishOn) {
        this.render(1.0);
        this.cancel();
        this.event('beforeFinish');
        if(this.finish) this.finish(); 
        this.event('afterFinish');
        return;  
      }
      var pos   = (timePos - this.startOn) / (this.finishOn - this.startOn);
      var frame = Math.round(pos * this.options.fps * this.options.duration);
      if(frame > this.currentFrame) {
        this.render(pos);
        this.currentFrame = frame;
      }
    }
  },
  render: function(pos) {
    if(this.state == 'idle') {
      this.state = 'running';
      this.event('beforeSetup');
      if(this.setup) this.setup();
      this.event('afterSetup');
    }
    if(this.state == 'running') {
      if(this.options.transition) pos = this.options.transition(pos);
      pos *= (this.options.to-this.options.from);
      pos += this.options.from;
      this.position = pos;
      this.event('beforeUpdate');
      if(this.update) this.update(pos);
      this.event('afterUpdate');
    }
  },
  cancel: function() {
    if(!this.options.sync)
      Effect.Queues.get(typeof this.options.queue == 'string' ? 
        'global' : this.options.queue.scope).remove(this);
    this.state = 'finished';
  },
  event: function(eventName) {
    if(this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this);
    if(this.options[eventName]) this.options[eventName](this);
  },
  inspect: function() {
    var data = $H();
    for(property in this)
      if(typeof this[property] != 'function') data[property] = this[property];
    return '#<Effect:' + data.inspect() + ',options:' + $H(this.options).inspect() + '>';
  }
}

Effect.Parallel = Class.create();
Object.extend(Object.extend(Effect.Parallel.prototype, Effect.Base.prototype), {
  initialize: function(effects) {
    this.effects = effects || [];
    this.start(arguments[1]);
  },
  update: function(position) {
    this.effects.invoke('render', position);
  },
  finish: function(position) {
    this.effects.each( function(effect) {
      effect.render(1.0);
      effect.cancel();
      effect.event('beforeFinish');
      if(effect.finish) effect.finish(position);
      effect.event('afterFinish');
    });
  }
});

Effect.Event = Class.create();
Object.extend(Object.extend(Effect.Event.prototype, Effect.Base.prototype), {
  initialize: function() {
    var options = Object.extend({
      duration: 0
    }, arguments[0] || {});
    this.start(options);
  },
  update: Prototype.emptyFunction
});

Effect.Opacity = Class.create();
Object.extend(Object.extend(Effect.Opacity.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elNotExistErr);
    // make this work on IE on elements without 'layout'
    if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
      this.element.setStyle({zoom: 1});
    var options = Object.extend({
      from: this.element.getOpacity() || 0.0,
      to:   1.0
    }, arguments[1] || {});
    this.start(options);
  },
  update: function(position) {
    this.element.setOpacity(position);
  }
});

Effect.Move = Class.create();
Object.extend(Object.extend(Effect.Move.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elNotExistErr);
    var options = Object.extend({
      x:    0,
      y:    0,
      mode: 'relative'
    }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Bug in Opera: Opera returns the "real" position of a static element or
    // relative element that does not have top/left explicitly set.
    // ==> Always set top and left for position relative elements in your stylesheets 
    // (to 0 if you do not need them) 
    this.element.makePositioned();
    this.originalLeft = parseFloat(this.element.getStyle('left') || '0');
    this.originalTop  = parseFloat(this.element.getStyle('top')  || '0');
    if(this.options.mode == 'absolute') {
      // absolute movement, so we need to calc deltaX and deltaY
      this.options.x = this.options.x - this.originalLeft;
      this.options.y = this.options.y - this.originalTop;
    }
  },
  update: function(position) {
    this.element.setStyle({
      left: Math.round(this.options.x  * position + this.originalLeft) + 'px',
      top:  Math.round(this.options.y  * position + this.originalTop)  + 'px'
    });
  }
});

// for backwards compatibility
Effect.MoveBy = function(element, toTop, toLeft) {
  return new Effect.Move(element, 
    Object.extend({ x: toLeft, y: toTop }, arguments[3] || {}));
};

Effect.Scale = Class.create();
Object.extend(Object.extend(Effect.Scale.prototype, Effect.Base.prototype), {
  initialize: function(element, percent) {
    this.element = $(element);
    if(!this.element) throw(Effect._elNotExistErr);
    var options = Object.extend({
      scaleX: true,
      scaleY: true,
      scaleContent: true,
      scaleFromCenter: false,
      scaleMode: 'box',        // 'box' or 'contents' or {} with provided values
      scaleFrom: 100.0,
      scaleTo:   percent
    }, arguments[2] || {});
    this.start(options);
  },
  setup: function() {
    this.restoreAfterFinish = this.options.restoreAfterFinish || false;
    this.elementPositioning = this.element.getStyle('position');
    
    this.originalStyle = {};
    ['top','left','width','height','fontSize'].each( function(k) {
      this.originalStyle[k] = this.element.style[k];
    }.bind(this));
      
    this.originalTop  = this.element.offsetTop;
    this.originalLeft = this.element.offsetLeft;
    
    var fontSize = this.element.getStyle('font-size') || '100%';
    ['em','px','%','pt'].each( function(fontSizeType) {
      if(fontSize.indexOf(fontSizeType)>0) {
        this.fontSize     = parseFloat(fontSize);
        this.fontSizeType = fontSizeType;
      }
    }.bind(this));
    
    this.factor = (this.options.scaleTo - this.options.scaleFrom)/100;
    
    this.dims = null;
    if(this.options.scaleMode=='box')
      this.dims = [this.element.offsetHeight, this.element.offsetWidth];
    if(/^content/.test(this.options.scaleMode))
      this.dims = [this.element.scrollHeight, this.element.scrollWidth];
    if(!this.dims)
      this.dims = [this.options.scaleMode.originalHeight,
                   this.options.scaleMode.originalWidth];
  },
  update: function(position) {
    var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position);
    if(this.options.scaleContent && this.fontSize)
      this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType });
    this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale);
  },
  finish: function(position) {
    if(this.restoreAfterFinish) this.element.setStyle(this.originalStyle);
  },
  setDimensions: function(height, width) {
    var d = {};
    if(this.options.scaleX) d.width = Math.round(width) + 'px';
    if(this.options.scaleY) d.height = Math.round(height) + 'px';
    if(this.options.scaleFromCenter) {
      var topd  = (height - this.dims[0])/2;
      var leftd = (width  - this.dims[1])/2;
      if(this.elementPositioning == 'absolute') {
        if(this.options.scaleY) d.top = this.originalTop-topd + 'px';
        if(this.options.scaleX) d.left = this.originalLeft-leftd + 'px';
      } else {
        if(this.options.scaleY) d.top = -topd + 'px';
        if(this.options.scaleX) d.left = -leftd + 'px';
      }
    }
    this.element.setStyle(d);
  }
});

Effect.Highlight = Class.create();
Object.extend(Object.extend(Effect.Highlight.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elNotExistErr);
    var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || {});
    this.start(options);
  },
  setup: function() {
    // Prevent executing on elements not in the layout flow
    if(this.element.getStyle('display')=='none') { this.cancel(); return; }
    // Disable background image during the effect
    this.oldStyle = {};
    if (!this.options.keepBackgroundImage) {
      this.oldStyle.backgroundImage = this.element.getStyle('background-image');
      this.element.setStyle({backgroundImage: 'none'});
    }
    if(!this.options.endcolor)
      this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff');
    if(!this.options.restorecolor)
      this.options.restorecolor = this.element.getStyle('background-color');
    // init color calculations
    this._base  = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this));
    this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this));
  },
  update: function(position) {
    this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){
      return m+(Math.round(this._base[i]+(this._delta[i]*position)).toColorPart()); }.bind(this)) });
  },
  finish: function() {
    this.element.setStyle(Object.extend(this.oldStyle, {
      backgroundColor: this.options.restorecolor
    }));
  }
});

Effect.ScrollTo = Class.create();
Object.extend(Object.extend(Effect.ScrollTo.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    this.start(arguments[1] || {});
  },
  setup: function() {
    Position.prepare();
    var offsets = Position.cumulativeOffset(this.element);
    if(this.options.offset) offsets[1] += this.options.offset;
    var max = window.innerHeight ? 
      window.height - window.innerHeight :
      document.body.scrollHeight - 
        (document.documentElement.clientHeight ? 
          document.documentElement.clientHeight : document.body.clientHeight);
    this.scrollStart = Position.deltaY;
    this.delta = (offsets[1] > max ? max : offsets[1]) - this.scrollStart;
  },
  update: function(position) {
    Position.prepare();
    window.scrollTo(Position.deltaX, 
      this.scrollStart + (position*this.delta));
  }
});

/* ------------- combination effects ------------- */

Effect.Fade = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  var options = Object.extend({
  from: element.getOpacity() || 1.0,
  to:   0.0,
  afterFinishInternal: function(effect) { 
    if(effect.options.to!=0) return;
    effect.element.hide().setStyle({opacity: oldOpacity}); 
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

Effect.Appear = function(element) {
  element = $(element);
  var options = Object.extend({
  from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0),
  to:   1.0,
  // force Safari to render floated elements properly
  afterFinishInternal: function(effect) {
    effect.element.forceRerendering();
  },
  beforeSetup: function(effect) {
    effect.element.setOpacity(effect.options.from).show(); 
  }}, arguments[1] || {});
  return new Effect.Opacity(element,options);
}

Effect.Puff = function(element) {
  element = $(element);
  var oldStyle = { 
    opacity: element.getInlineOpacity(), 
    position: element.getStyle('position'),
    top:  element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height
  };
  return new Effect.Parallel(
   [ new Effect.Scale(element, 200, 
      { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), 
     new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], 
     Object.extend({ duration: 1.0, 
      beforeSetupInternal: function(effect) {
        Position.absolutize(effect.effects[0].element)
      },
      afterFinishInternal: function(effect) {
         effect.effects[0].element.hide().setStyle(oldStyle); }
     }, arguments[1] || {})
   );
}

Effect.BlindUp = function(element) {
  element = $(element);
  element.makeClipping();
  return new Effect.Scale(element, 0,
    Object.extend({ scaleContent: false, 
      scaleX: false, 
      restoreAfterFinish: true,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping();
      } 
    }, arguments[1] || {})
  );
}

Effect.BlindDown = function(element) {
  element = $(element);
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false,
    scaleFrom: 0,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.undoClipping();
    }
  }, arguments[1] || {}));
}

Effect.SwitchOff = function(element) {
  element = $(element);
  var oldOpacity = element.getInlineOpacity();
  return new Effect.Appear(element, Object.extend({
    duration: 0.4,
    from: 0,
    transition: Effect.Transitions.flicker,
    afterFinishInternal: function(effect) {
      new Effect.Scale(effect.element, 1, { 
        duration: 0.3, scaleFromCenter: true,
        scaleX: false, scaleContent: false, restoreAfterFinish: true,
        beforeSetup: function(effect) { 
          effect.element.makePositioned().makeClipping();
        },
        afterFinishInternal: function(effect) {
          effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity});
        }
      })
    }
  }, arguments[1] || {}));
}

Effect.DropOut = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left'),
    opacity: element.getInlineOpacity() };
  return new Effect.Parallel(
    [ new Effect.Move(element, {x: 0, y: 100, sync: true }), 
      new Effect.Opacity(element, { sync: true, to: 0.0 }) ],
    Object.extend(
      { duration: 0.5,
        beforeSetup: function(effect) {
          effect.effects[0].element.makePositioned(); 
        },
        afterFinishInternal: function(effect) {
          effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle);
        } 
      }, arguments[1] || {}));
}

/* Tom M. Yeh, Potix: remove unused codes
Effect.Shake = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.getStyle('top'),
    left: element.getStyle('left') };
    return new Effect.Move(element, 
      { x:  20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x:  40, y: 0, duration: 0.1,  afterFinishInternal: function(effect) {
    new Effect.Move(effect.element,
      { x: -20, y: 0, duration: 0.05, afterFinishInternal: function(effect) {
        effect.element.undoPositioned().setStyle(oldStyle);
  }}) }}) }}) }}) }}) }});
}
*/
Effect.SlideDown = function(element) {
  element = $(element).cleanWhitespace();
  // SlideDown need to have the content of the element wrapped in a container element with fixed height!
  var oldInnerBottom = element.down().getStyle('bottom');
  var elementDimensions = element.getDimensions();
  return new Effect.Scale(element, 100, Object.extend({ 
    scaleContent: false, 
    scaleX: false, 
    scaleFrom: window.opera ? 0 : 1,
    scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width},
    restoreAfterFinish: true,
    afterSetup: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if(window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().setStyle({height: '0px'}).show(); 
    },
    /**afterUpdateInternal: function(effect) { Jumper Chen, Potix: Bug #1752907
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' }); 
    },*/
    afterFinishInternal: function(effect) {
      effect.element.undoClipping().undoPositioned();
      effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); }
    }, arguments[1] || {})
  );
}

Effect.SlideUp = function(element) {
  element = $(element).cleanWhitespace();
  var oldInnerBottom = element.down().getStyle('bottom');
  return new Effect.Scale(element, window.opera ? 0 : 1,
   Object.extend({ scaleContent: false, 
    scaleX: false, 
    scaleMode: 'box',
    scaleFrom: 100,
    restoreAfterFinish: true,
    beforeStartInternal: function(effect) {
      effect.element.makePositioned();
      effect.element.down().makePositioned();
      if(window.opera) effect.element.setStyle({top: ''});
      effect.element.makeClipping().show();
    },  
    /**afterUpdateInternal: function(effect) { Jumper Chen, Potix: Bug #1752907
      effect.element.down().setStyle({bottom:
        (effect.dims[0] - effect.element.clientHeight) + 'px' });
    },*/
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping().undoPositioned().setStyle({bottom: oldInnerBottom});
      effect.element.down().undoPositioned();
    }
   }, arguments[1] || {})
  );
}

// Bug in opera makes the TD containing this element expand for a instance after finish 
/* Tom M. Yeh, Potix: remove unused codes
Effect.Squish = function(element) {
  return new Effect.Scale(element, window.opera ? 1 : 0, { 
    restoreAfterFinish: true,
    beforeSetup: function(effect) {
      effect.element.makeClipping(); 
    },  
    afterFinishInternal: function(effect) {
      effect.element.hide().undoClipping(); 
    }
  });
}
*/
/* Tom M. Yeh, Potix: remove unused codes
Effect.Grow = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.full
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();    
  var initialMoveX, initialMoveY;
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      initialMoveX = initialMoveY = moveX = moveY = 0; 
      break;
    case 'top-right':
      initialMoveX = dims.width;
      initialMoveY = moveY = 0;
      moveX = -dims.width;
      break;
    case 'bottom-left':
      initialMoveX = moveX = 0;
      initialMoveY = dims.height;
      moveY = -dims.height;
      break;
    case 'bottom-right':
      initialMoveX = dims.width;
      initialMoveY = dims.height;
      moveX = -dims.width;
      moveY = -dims.height;
      break;
    case 'center':
      initialMoveX = dims.width / 2;
      initialMoveY = dims.height / 2;
      moveX = -dims.width / 2;
      moveY = -dims.height / 2;
      break;
  }
  
  return new Effect.Move(element, {
    x: initialMoveX,
    y: initialMoveY,
    duration: 0.01, 
    beforeSetup: function(effect) {
      effect.element.hide().makeClipping().makePositioned();
    },
    afterFinishInternal: function(effect) {
      new Effect.Parallel(
        [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }),
          new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }),
          new Effect.Scale(effect.element, 100, {
            scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, 
            sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true})
        ], Object.extend({
             beforeSetup: function(effect) {
               effect.effects[0].element.setStyle({height: '0px'}).show(); 
             },
             afterFinishInternal: function(effect) {
               effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); 
             }
           }, options)
      )
    }
  });
}
*/
/* Tom M. Yeh, Potix: remove unused codes
Effect.Shrink = function(element) {
  element = $(element);
  var options = Object.extend({
    direction: 'center',
    moveTransition: Effect.Transitions.sinoidal,
    scaleTransition: Effect.Transitions.sinoidal,
    opacityTransition: Effect.Transitions.none
  }, arguments[1] || {});
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    height: element.style.height,
    width: element.style.width,
    opacity: element.getInlineOpacity() };

  var dims = element.getDimensions();
  var moveX, moveY;
  
  switch (options.direction) {
    case 'top-left':
      moveX = moveY = 0;
      break;
    case 'top-right':
      moveX = dims.width;
      moveY = 0;
      break;
    case 'bottom-left':
      moveX = 0;
      moveY = dims.height;
      break;
    case 'bottom-right':
      moveX = dims.width;
      moveY = dims.height;
      break;
    case 'center':  
      moveX = dims.width / 2;
      moveY = dims.height / 2;
      break;
  }
  
  return new Effect.Parallel(
    [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }),
      new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}),
      new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition })
    ], Object.extend({            
         beforeStartInternal: function(effect) {
           effect.effects[0].element.makePositioned().makeClipping(); 
         },
         afterFinishInternal: function(effect) {
           effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); }
       }, options)
  );
}
*/
/* Tom M. Yeh, Potix: remove unused codes
Effect.Pulsate = function(element) {
  element = $(element);
  var options    = arguments[1] || {};
  var oldOpacity = element.getInlineOpacity();
  var transition = options.transition || Effect.Transitions.sinoidal;
  var reverser   = function(pos){ return transition(1-Effect.Transitions.pulse(pos, options.pulses)) };
  reverser.bind(transition);
  return new Effect.Opacity(element, 
    Object.extend(Object.extend({  duration: 2.0, from: 0,
      afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); }
    }, options), {transition: reverser}));
}

Effect.Fold = function(element) {
  element = $(element);
  var oldStyle = {
    top: element.style.top,
    left: element.style.left,
    width: element.style.width,
    height: element.style.height };
  element.makeClipping();
  return new Effect.Scale(element, 5, Object.extend({   
    scaleContent: false,
    scaleX: false,
    afterFinishInternal: function(effect) {
    new Effect.Scale(element, 1, { 
      scaleContent: false, 
      scaleY: false,
      afterFinishInternal: function(effect) {
        effect.element.hide().undoClipping().setStyle(oldStyle);
      } });
  }}, arguments[1] || {}));
};
*/
/* Tom M. Yeh, Potix: remove unused codes
Effect.Morph = Class.create();
Object.extend(Object.extend(Effect.Morph.prototype, Effect.Base.prototype), {
  initialize: function(element) {
    this.element = $(element);
    if(!this.element) throw(Effect._elNotExistErr);
    var options = Object.extend({
      style: {}
    }, arguments[1] || {});
    if (typeof options.style == 'string') {
      if(options.style.indexOf(':') == -1) {
        var cssText = '', selector = '.' + options.style;
        $A(document.styleSheets).reverse().each(function(styleSheet) {
          if (styleSheet.cssRules) cssRules = styleSheet.cssRules;
          else if (styleSheet.rules) cssRules = styleSheet.rules;
          $A(cssRules).reverse().each(function(rule) {
            if (selector == rule.selectorText) {
              cssText = rule.style.cssText;
              throw $break;
            }
          });
          if (cssText) throw $break;
        });
        this.style = cssText.parseStyle();
        options.afterFinishInternal = function(effect){
          effect.element.addClassName(effect.options.style);
          effect.transforms.each(function(transform) {
            if(transform.style != 'opacity')
              effect.element.style[transform.style.camelize()] = '';
          });
        }
      } else this.style = options.style.parseStyle();
    } else this.style = $H(options.style)
    this.start(options);
  },
  setup: function(){
    function parseColor(color){
      if(!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff';
      color = color.parseColor();
      return $R(0,2).map(function(i){
        return parseInt( color.slice(i*2+1,i*2+3), 16 ) 
      });
    }
    this.transforms = this.style.map(function(pair){
      var property = pair[0].underscore().dasherize(), value = pair[1], unit = null;

      if(value.parseColor('#zzzzzz') != '#zzzzzz') {
        value = value.parseColor();
        unit  = 'color';
      } else if(property == 'opacity') {
        value = parseFloat(value);
        if(/MSIE/.test(navigator.userAgent) && !window.opera && (!this.element.currentStyle.hasLayout))
          this.element.setStyle({zoom: 1});
      } else if(Element.CSS_LENGTH.test(value)) 
        var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/),
          value = parseFloat(components[1]), unit = (components.length == 3) ? components[2] : null;

      var originalValue = this.element.getStyle(property);
      return $H({ 
        style: property, 
        originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), 
        targetValue: unit=='color' ? parseColor(value) : value,
        unit: unit
      });
    }.bind(this)).reject(function(transform){
      return (
        (transform.originalValue == transform.targetValue) ||
        (
          transform.unit != 'color' &&
          (isNaN(transform.originalValue) || isNaN(transform.targetValue))
        )
      )
    });
  },
  update: function(position) {
    var style = $H(), value = null;
    this.transforms.each(function(transform){
      value = transform.unit=='color' ?
        $R(0,2).inject('#',function(m,v,i){
          return m+(Math.round(transform.originalValue[i]+
            (transform.targetValue[i] - transform.originalValue[i])*position)).toColorPart() }) : 
        transform.originalValue + Math.round(
          ((transform.targetValue - transform.originalValue) * position) * 1000)/1000 + transform.unit;
      style[transform.style] = value;
    });
    this.element.setStyle(style);
  }
});

Effect.Transform = Class.create();
Object.extend(Effect.Transform.prototype, {
  initialize: function(tracks){
    this.tracks  = [];
    this.options = arguments[1] || {};
    this.addTracks(tracks);
  },
  addTracks: function(tracks){
    tracks.each(function(track){
      var data = $H(track).values().first();
      this.tracks.push($H({
        ids:     $H(track).keys().first(),
        effect:  Effect.Morph,
        options: { style: data }
      }));
    }.bind(this));
    return this;
  },
  play: function(){
    return new Effect.Parallel(
      this.tracks.map(function(track){
        var elements = [$(track.ids) || $$(track.ids)].flatten();
        return elements.map(function(e){ return new track.effect(e, Object.extend({ sync:true }, track.options)) });
      }).flatten(),
      this.options
    );
  }
});
*/
Element.CSS_PROPERTIES = $w(
  'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 
  'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' +
  'borderRightColor borderRightStyle borderRightWidth borderSpacing ' +
  'borderTopColor borderTopStyle borderTopWidth bottom clip color ' +
  'fontSize fontWeight height left letterSpacing lineHeight ' +
  'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+
  'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' +
  'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' +
  'right textIndent top width wordSpacing zIndex');
  
Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/;

String.prototype.parseStyle = function(){
  var element = Element.extend(document.createElement('div'));
  element.innerHTML = '<div style="' + this + '"></div>';
  var style = element.down().style, styleRules = $H();
  
  Element.CSS_PROPERTIES.each(function(property){
    if(style[property]) styleRules[property] = style[property]; 
  });
  if(/MSIE/.test(navigator.userAgent) && !window.opera && this.indexOf('opacity') > -1) {
    styleRules.opacity = this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1];
  }
  return styleRules;
};

/* Tom M. Yeh, Potix: remove unused codes
Element.morph = function(element, style) {
  new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || {}));
  return element;
};
*/
['setOpacity','getOpacity','getInlineOpacity','forceRerendering']
 .each( 
/* Tom M. Yeh, Potix: remove unused codes
['setOpacity','getOpacity','getInlineOpacity','forceRerendering','setContentZoom',
 'collectTextNodes','collectTextNodesIgnoreClass','morph'].each( 
*/
  function(f) { Element.Methods[f] = Element[f]; }
);

/* Tom M. Yeh, Potix: remove unused codes
Element.Methods.visualEffect = function(element, effect, options) {
  s = effect.gsub(/_/, '-').camelize();
  effect_class = s.charAt(0).toUpperCase() + s.substring(1);
  new Effect[effect_class](element, options);
  return $(element);
};
*/
Element.addMethods();

} //Tom M. Yeh, Potix: prevent it from load twice

// script.aculo.us dragdrop.js v1.7.0, Fri Jan 19 19:16:36 CET 2007

// Copyright (c) 2005, 2006 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
//           (c) 2005, 2006 Sammi Williams (http://www.oriontransfer.co.nz, sammi@oriontransfer.co.nz)
// 
// script.aculo.us is freely distributable under the terms of an MIT-style license.
// For details, see the script.aculo.us web site: http://script.aculo.us/

//Tom M. Yeh, Potix: prevent it from load twice
if (!window.z_dragdrop_js) {
	z_dragdrop_js = true;

/* Tom M. Yeh, Potix: remove unused codes
if(typeof Effect == 'undefined')
  throw("dragdrop.js requires including script.aculo.us' effects.js library");

var Droppables = {
  drops: [],

  remove: function(element) {
    this.drops = this.drops.reject(function(d) { return d.element==$(element) });
  },

  add: function(element) {
    element = $(element);
    var options = Object.extend({
      greedy:     true,
      hoverclass: null,
      tree:       false
    }, arguments[1] || {});

    // cache containers
    if(options.containment) {
      options._containers = [];
      var containment = options.containment;
      if((typeof containment == 'object') && 
        (containment.constructor == Array)) {
        containment.each( function(c) { options._containers.push($(c)) });
      } else {
        options._containers.push($(containment));
      }
    }
    
    if(options.accept) options.accept = [options.accept].flatten();

    Element.makePositioned(element); // fix IE
    options.element = element;

    this.drops.push(options);
  },
  
  findDeepestChild: function(drops) {
    deepest = drops[0];
      
    for (i = 1; i < drops.length; ++i)
      if (Element.isParent(drops[i].element, deepest.element))
        deepest = drops[i];
    
    return deepest;
  },

  isContained: function(element, drop) {
    var containmentNode;
    if(drop.tree) {
      containmentNode = element.treeNode; 
    } else {
      containmentNode = element.parentNode;
    }
    return drop._containers.detect(function(c) { return containmentNode == c });
  },
  
  isAffected: function(point, element, drop) {
    return (
      (drop.element!=element) &&
      ((!drop._containers) ||
        this.isContained(element, drop)) &&
      ((!drop.accept) ||
        (Element.classNames(element).detect( 
          function(v) { return drop.accept.include(v) } ) )) &&
      Position.within(drop.element, point[0], point[1]) );
  },

  deactivate: function(drop) {
    if(drop.hoverclass)
      Element.removeClassName(drop.element, drop.hoverclass);
    this.last_active = null;
  },

  activate: function(drop) {
    if(drop.hoverclass)
      Element.addClassName(drop.element, drop.hoverclass);
    this.last_active = drop;
  },

  show: function(point, element) {
    if(!this.drops.length) return;
    var affected = [];
    
    if(this.last_active) this.deactivate(this.last_active);
    this.drops.each( function(drop) {
      if(Droppables.isAffected(point, element, drop))
        affected.push(drop);
    });
        
    if(affected.length>0) {
      drop = Droppables.findDeepestChild(affected);
      Position.within(drop.element, point[0], point[1]);
      if(drop.onHover)
        drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element));
      
      Droppables.activate(drop);
    }
  },

  fire: function(event, element) {
    if(!this.last_active) return;
    Position.prepare();

    if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active))
      if (this.last_active.onDrop) 
        this.last_active.onDrop(element, this.last_active.element, event);
  },

  reset: function() {
    if(this.last_active)
      this.deactivate(this.last_active);
  }
}
*/
var Draggables = {
  drags: [],
  observers: [],
  
  register: function(draggable) {
    if(this.drags.length == 0) {
      this.eventMouseUp   = this.endDrag.bindAsEventListener(this);
      this.eventMouseMove = this.updateDrag.bindAsEventListener(this);
      this.eventKeypress  = this.keyPress.bindAsEventListener(this);
      
      Event.observe(document, "mouseup", this.eventMouseUp);
      Event.observe(document, "mousemove", this.eventMouseMove);
      Event.observe(document, "keypress", this.eventKeypress);
    }
    this.drags.push(draggable);
  },
  
  unregister: function(draggable) {
    this.drags = this.drags.reject(function(d) { return d==draggable });
    if(this.drags.length == 0) {
      Event.stopObserving(document, "mouseup", this.eventMouseUp);
      Event.stopObserving(document, "mousemove", this.eventMouseMove);
      Event.stopObserving(document, "keypress", this.eventKeypress);
    }
  },
  
  activate: function(draggable) {
    if(zk.opera || draggable.options.delay) { 
      this._timeout = setTimeout(function() { 
        Draggables._timeout = null; 
        window.focus(); 
        Draggables.activeDraggable = draggable; 
      }.bind(this), draggable.options.delay); 
    } else {
      window.focus(); // allows keypress events if window isn't currently focused, fails for Safari
      this.activeDraggable = draggable;
    }
  },
  
  deactivate: function() {
    this.activeDraggable = null;
  },
  
  updateDrag: function(event) {
    if(!this.activeDraggable) return;
    var pointer = [Event.pointerX(event), Event.pointerY(event)];
    // Mozilla-based browsers fire successive mousemove events with
    // the same coordinates, prevent needless redrawing (moz bug?)
    if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return;
    this._lastPointer = pointer;
    
    this.activeDraggable.updateDrag(event, pointer);
  },
  
  endDrag: function(event) {
    if(this._timeout) { 
      clearTimeout(this._timeout); 
      this._timeout = null; 
    }
    if(!this.activeDraggable) return;
    this._lastPointer = null;
    this.activeDraggable.endDrag(event);
    this.activeDraggable = null;
  },
  
  keyPress: function(event) {
    if(this.activeDraggable)
      this.activeDraggable.keyPress(event);
  },
  
  addObserver: function(observer) {
    this.observers.push(observer);
    this._cacheObserverCallbacks();
  },
  
  removeObserver: function(element) {  // element instead of observer fixes mem leaks
    this.observers = this.observers.reject( function(o) { return o.element==element });
    this._cacheObserverCallbacks();
  },
  
  notify: function(eventName, draggable, event) {  // 'onStart', 'onEnd', 'onDrag'
    if(this[eventName+'Count'] > 0)
      this.observers.each( function(o) {
        if(o[eventName]) o[eventName](eventName, draggable, event);
      });
    if(draggable.options[eventName]) draggable.options[eventName](draggable, event);
  },
  
  _cacheObserverCallbacks: function() {
    ['onStart','onEnd','onDrag'].each( function(eventName) {
      Draggables[eventName+'Count'] = Draggables.observers.select(
        function(o) { return o[eventName]; }
      ).length;
    });
  }
}

/*--------------------------------------------------------------------------*/

var Draggable = Class.create();
Draggable._dragging    = {};

Draggable.prototype = {
  initialize: function(element) {
 var zdd = zk.ie && arguments[1] && arguments[1].z_dragdrop; //Tom M. Yeh, Potix: Bug 1538506
    var defaults = {
      handle: false,
      reverteffect: function(element, top_offset, left_offset) {
var orgpos = element.style.position; //Tom M. Yeh, Potix: Bug 1538506
        var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02;
        new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur,
          queue: {scope:'_draggable', position:'end'}
        });
//Tom M. Yeh, Potix: Bug 1538506: a strange bar appear in IE
setTimeout(function () {
if (zdd && orgpos != 'absolute' && orgpos != 'relative')
	zkau._fixie4drop(element, orgpos);
else
	element.style.position = orgpos;
}, dur * 1000 + 10);
      },
      endeffect: function(element) {
        var toOpacity = typeof element._opacity == 'number' ? element._opacity : 1.0;
        new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, 
          queue: {scope:'_draggable', position:'end'},
          afterFinish: function(){ 
            Draggable._dragging[element] = false 
          }
        }); 
      },
      zindex: 1000,
      revert: false,
      scroll: false,
      scrollSensitivity: 20,
      scrollSpeed: 15,
      snap: false,  // false, or xy or [x,y] or function(x,y){ return [x,y] }
      delay: 0
    };
    
    if(!arguments[1] || typeof arguments[1].endeffect == 'undefined')
      Object.extend(defaults, {
        starteffect: function(element) {
          element._opacity = Element.getOpacity(element);
          Draggable._dragging[element] = true;
          new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); 
        }
      });
    
    var options = Object.extend(defaults, arguments[1] || {});

    this.element = $(element);
    
    if(options.handle && (typeof options.handle == 'string'))
      this.handle = this.element.down('.'+options.handle, 0);
    
    if(!this.handle) this.handle = $(options.handle);
    if(!this.handle) this.handle = this.element;
    
    if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) {
      options.scroll = $(options.scroll);
      this._isScrollChild = Element.childOf(this.element, options.scroll);
    }

if (zk.opera || !options.z_dragdrop) //Tom M. Yeh, Potix: Bug 1534426, 1535787 (ie: no makePositioned), 1647114 (opera: makePositioned required)
    Element.makePositioned(this.element); // fix IE    

    this.delta    = this.currentDelta();
    this.options  = options;
    this.dragging = false;   

    this.eventMouseDown = this.initDrag.bindAsEventListener(this);
    Event.observe(this.handle, "mousedown", this.eventMouseDown);
    
    Draggables.register(this);
  },
  
  destroy: function() {
    Event.stopObserving(this.handle, "mousedown", this.eventMouseDown);
    Draggables.unregister(this);
  },
  
  currentDelta: function() {
    return([
      $int(Element.getStyle(this.element,'left')),
      $int(Element.getStyle(this.element,'top'))]);
  },
  
  initDrag: function(event) {
    if(typeof Draggable._dragging[this.element] != 'undefined' &&
      Draggable._dragging[this.element]) return;
    if(Event.isLeftClick(event)) {    
      // abort on form elements, fixes a Firefox issue
      var src = Event.element(event);
      if((tag_name = src.tagName.toUpperCase()) && (
        tag_name=='INPUT' ||
        tag_name=='SELECT' ||
        tag_name=='OPTION' ||
        tag_name=='BUTTON' ||
        tag_name=='TEXTAREA')) return;
        
//Tom M. Yeh, Potix: skip popup/dropdown (of combobox and others)
for (var n = src; n && n != this.element; n = n.parentNode)
	if (Element.getStyle(n, 'position') == 'absolute')
		return;

      var pointer = [Event.pointerX(event), Event.pointerY(event)];
//Tom M. Yeh, Potix: give the element a chance to ignore dragging
if (this.options.ignoredrag && this.options.ignoredrag(this.element, pointer, event))
	return;
//Tom M. Yeh, Potix: disable selection
//zk.disableSelection(document.body); // Bug #1820433
      var pos     = Position.cumulativeOffset(this.element);
      this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
      
      Draggables.activate(this);
//Jumper Chen, Potix: Bug #1845026
//We need to ensure that the onBlur event is fired before the onSelect event for consistent among four browsers. 
	  if (zkau.currentFocus && Event.element(event) != zkau.currentFocus 
	  	&& typeof zkau.currentFocus.blur == "function") zkau.currentFocus.blur();
      Event.stop(event);
//Tom M. Yeh, Potix: mousedown is eaten above
zkau.autoZIndex(src, false, true);
    }
  },
  
  startDrag: function(event) {
//Tom M. Yeh, Potix: disable selection
zk.disableSelection(document.body); // Bug #1820433
  
    this.dragging = true;
    
    if(this.options.ghosting) {
//Tom M. Yeh, Potix: ghosting is controllable
var ghosting = true;
if (typeof this.options.ghosting == 'function') ghosting = this.options.ghosting(this, true, event);
if (ghosting) {
      this._clone = this.element.cloneNode(true);
this.z_orgpos = this.element.style.position; //Tom M. Yeh, Potix: Bug 1514789
if (this.z_orgpos != 'absolute')
      Position.absolutize(this.element);
      this.element.parentNode.insertBefore(this._clone, this.element);
}
    }
    
    if(this.options.zindex) { //Tom M. Yeh, Poitx: after ghosting
      this.originalZ = $int(Element.getStyle(this.element,'z-index'));
      this.element.style.zIndex = this.options.zindex;
    }
    
    if(this.options.scroll) {
      if (this.options.scroll == window) {
        var where = this._getWindowScroll(this.options.scroll);
        this.originalScrollLeft = where.left;
        this.originalScrollTop = where.top;
      } else {
        this.originalScrollLeft = this.options.scroll.scrollLeft;
        this.originalScrollTop = this.options.scroll.scrollTop;
      }
    }
    
    Draggables.notify('onStart', this, event);
    if(this.options.starteffect) this.options.starteffect(this.element, this.handle);
  },
  
  updateDrag: function(event, pointer) {
    if(!this.dragging) this.startDrag(event);
    Position.prepare();
/* Tom M. Yeh, Potix: remove unused codes
    Droppables.show(pointer, this.element);
*/
    Draggables.notify('onDrag', this, event);
    this.draw(pointer, event);
    if(this.options.change) this.options.change(this, pointer, event); //Tom M Yeh, Potix: add pointer
    
    if(this.options.scroll) {
      this.stopScrolling();
      
      var p;
      if (this.options.scroll == window) {
        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
      } else {
        p = Position.page(this.options.scroll);
        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
        p[1] += this.options.scroll.scrollTop + Position.deltaY;
        p.push(p[0]+this.options.scroll.offsetWidth);
        p.push(p[1]+this.options.scroll.offsetHeight);
      }
      var speed = [0,0];
      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
      this.startScrolling(speed);
    }
    
    // fix AppleWebKit rendering
    if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
	
    Event.stop(event);
  },
  
  finishDrag: function(event, success) {
    this.dragging = false;

//Tom M. Yeh, Potix: enable selection back and clear selection if any
zk.enableSelection(document.body);
setTimeout("zk.clearSelection()", 0);
    if(this.options.ghosting) {
//Tom M. Yeh: Potix: ghosting is controllable
var ghosting = true;
if (typeof this.options.ghosting == 'function') ghosting = this.options.ghosting(this, false);
if (ghosting) {
if (this.z_orgpos != "absolute") { //Tom M. Yeh, Potix: Bug 1514789
      Position.relativize(this.element);
this.element.style.position = this.z_orgpos;
}
      Element.remove(this._clone);
      this._clone = null;
}
    }

/* Tom M. Yeh, Potix: remove unused codes
    if(success) Droppables.fire(event, this.element);
*/
    Draggables.notify('onEnd', this, event);

	var pointer = [Event.pointerX(event), Event.pointerY(event)]; //Tom M. Yeh, Potix: add pointer
    var revert = this.options.revert;
    if(revert && typeof revert == 'function') revert = revert(this.element, pointer, event); //Tom M. Yeh, Potix: add pointer
    
    var d = this.currentDelta();
    if(revert && this.options.reverteffect) {
      this.options.reverteffect(this.element, 
        d[1]-this.delta[1], d[0]-this.delta[0]);
    } else {
      this.delta = d;
    }

    if(this.options.zindex)
      this.element.style.zIndex = this.originalZ;

    if(this.options.endeffect) 
      this.options.endeffect(this.element, event); //Tom M. Yeh, Potix: add event
      	
    Draggables.deactivate(this);
/* Tom M. Yeh, Potix: remove unused codes
    Droppables.reset();
*/
  },
  
  keyPress: function(event) {
    if(Event.keyCode(event)!=27/*Tom M. Yeh, Potix:Event.KEY_ESC*/) return;
    this.finishDrag(event, false);
    Event.stop(event);
  },
  
  endDrag: function(event) {
    if(!this.dragging) return;
    this.stopScrolling();
    this.finishDrag(event, true);
    Event.stop(event);
  },
  
  draw: function(point, event) {
    var pos = Position.cumulativeOffset(this.element);
    if(this.options.ghosting) {
      var r   = Position.realOffset(this.element);
      pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY;
    }
    
    var d = this.currentDelta();
    pos[0] -= d[0]; pos[1] -= d[1];
    
    if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) {
      pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft;
      pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop;
    }
    
    var p = [0,1].map(function(i){ 
      return (point[i]-pos[i]-this.offset[i]) 
    }.bind(this));
    
    if(this.options.snap) {
      if(typeof this.options.snap == 'function') {
        p = this.options.snap(p[0],p[1],this);
      } else {
      if(this.options.snap instanceof Array) {
        p = p.map( function(v, i) {
          return Math.round(v/this.options.snap[i])*this.options.snap[i] }.bind(this))
      } else {
        p = p.map( function(v) {
          return Math.round(v/this.options.snap)*this.options.snap }.bind(this))
      }
    }}
    
//Tom M. Yeh, Potix: resolve scrolling offset when DIV is used
if (this.z_scrl) {
	p[0] -= this.z_scrl[0]; p[1] -= this.z_scrl[1];
}

    var style = this.element.style;
//Tom M. Yeh, Potix: support function constraint
if (typeof this.options.constraint == 'function') {
	var np = this.options.constraint(this, p, event); //return null or [newx, newy]
	if (np) p = np;
	style.left = p[0] + "px";
	style.top  = p[1] + "px";
} else {
    if((!this.options.constraint) || (this.options.constraint=='horizontal'))
      style.left = p[0] + "px";
    if((!this.options.constraint) || (this.options.constraint=='vertical'))
      style.top  = p[1] + "px";
} //Tom M. Yeh, Potix
    
    if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering
  },
  
  stopScrolling: function() {
    if(this.scrollInterval) {
      clearInterval(this.scrollInterval);
      this.scrollInterval = null;
      Draggables._lastScrollPointer = null;
    }
  },
  
  startScrolling: function(speed) {
    if(!(speed[0] || speed[1])) return;
    this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed];
    this.lastScrolled = new Date();
    this.scrollInterval = setInterval(this.scroll.bind(this), 10);
  },
  
  scroll: function() {
    var current = new Date();
    var delta = current - this.lastScrolled;
    this.lastScrolled = current;
    if(this.options.scroll == window) {
      with (this._getWindowScroll(this.options.scroll)) {
        if (this.scrollSpeed[0] || this.scrollSpeed[1]) {
          var d = delta / 1000;
          this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] );
        }
      }
    } else {
      this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000;
      this.options.scroll.scrollTop  += this.scrollSpeed[1] * delta / 1000;
    }
    
    Position.prepare();
/* Tom M. Yeh, Potix: remove unused codes
    Droppables.show(Draggables._lastPointer, this.element);
*/
    Draggables.notify('onDrag', this);
    if (this._isScrollChild) {
      Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer);
      Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000;
      Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000;
      if (Draggables._lastScrollPointer[0] < 0)
        Draggables._lastScrollPointer[0] = 0;
      if (Draggables._lastScrollPointer[1] < 0)
        Draggables._lastScrollPointer[1] = 0;
      this.draw(Draggables._lastScrollPointer);
    }
    
    if(this.options.change) this.options.change(this);
  },
  
  _getWindowScroll: function(w) {
    var T, L, W, H;
    with (w.document) {
      if (w.document.documentElement && documentElement.scrollTop) {
        T = documentElement.scrollTop;
        L = documentElement.scrollLeft;
      } else if (w.document.body) {
        T = body.scrollTop;
        L = body.scrollLeft;
      }
      if (w.innerWidth) {
        W = w.innerWidth;
        H = w.innerHeight;
      } else if (w.document.documentElement && documentElement.clientWidth) {
        W = documentElement.clientWidth;
        H = documentElement.clientHeight;
      } else {
        W = body.offsetWidth;
        H = body.offsetHeight
      }
    }
    return { top: T, left: L, width: W, height: H };
  }
}

/*--------------------------------------------------------------------------*/

/* Tom M. Yeh, Potix: remove Sortable
var SortableObserver = Class.create();
SortableObserver.prototype = {
...
}
var Sortable = {
...
}
*/

/* Tom M. Yeh, Potix: remove unused codes
// Returns true if child is contained within element
Element.isParent = function(child, element) {
  if (!child.parentNode || child == element) return false;
  if (child.parentNode == element) return true;
  return Element.isParent(child.parentNode, element);
}

Element.findChildren = function(element, only, recursive, tagName) {    
  if(!element.hasChildNodes()) return null;
  tagName = tagName.toUpperCase();
  if(only) only = [only].flatten();
  var elements = [];
  $A(element.childNodes).each( function(e) {
    if(e.tagName && e.tagName.toUpperCase()==tagName &&
      (!only || (Element.classNames(e).detect(function(v) { return only.include(v) }))))
        elements.push(e);
    if(recursive) {
      var grandchildren = Element.findChildren(e, only, recursive, tagName);
      if(grandchildren) elements.push(grandchildren);
    }
  });

  return (elements.length>0 ? elements.flatten() : []);
}

Element.offsetSize = function (element, type) {
//Tom M. Yeh, Potix: safari bug
if (type == 'vertical' || type == 'height')
  return zk.offsetHeight(element);
else
  return zk.offsetWidth(element);
  //return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')];
}
*/
} //Tom M. Yeh, Potix: prevent it from load twice

/* boot.js

{{IS_NOTE
	Purpose:
		Bootstrap JavaScript
	Description:
		
	History:
		Sun Jan 29 11:43:45     2006, Created by tomyeh
}}IS_NOTE

Copyright (C) 2006 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under GPL Version 2.0 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
//zk//
if (!window.zk) { //avoid eval twice
zk = {};
zk.booting = true; //denote ZK is booting

////
//Customization
/** Creates the message box to notify the user that ZK client engine
 * is booting.
 * Developer can override this method to provide a customized message box.
 *
 * @param id the progress box's ID
 * @param msg the message
 * @param x the x-coordinate of the box
 * @param y the y-coordinate of the box
 * @param mask sets whether show the modal_mark (since 3.0.2)
 * @param center sets whether center the loading bar (since 3.0.2)
 */
if (!window.Boot_progressbox) { //not customized
	Boot_progressbox = function (id, msg, x, y, mask, center) {
		var n = document.createElement("DIV");
		document.body.appendChild(n);

		var html = '<div id="'+id+'"';
		var ix = zk.innerX(), iy = zk.innerY();
		if (mask || (zk.loading && !zk._prgsOnce)) {
			zk._prgsOnce = true; //do it only once
			html += '><div id="zk_mask" class="modal_mask" style="display:block;left:'+ ix + 'px;top:' + iy +	
				'px;" z.x="' + ix + '" z.y="' + iy + '"></div><div';
		} else html += "><div";

		if (typeof x != 'string' || x.indexOf("%") == -1) x += "px";
		if (typeof y != 'string' || y.indexOf("%") == -1) y += "px";

		html += ' id="zk_loading" class="z-loading" style="left:'+x+';top:'+y+';visibility: hidden;"'
		+' z.x="' + ix + '" z.y="' + iy + '"><div class="z-loading-indicator">'
		+'<img class="z-loading-icon" alt="..." src="'+zk.getUpdateURI('/web/img/spacer.gif')+'"/> '
		+msg+'</div></div></div>';

		zk._setOuterHTML(n, html);
		
		var el = $e("zk_loading");
		if (center) {
			if (el) {
				el.style.left = (zk.innerWidth() - el.offsetWidth) / 2 + ix + "px";
				el.style.top = (zk.innerHeight() - el.offsetHeight) / 2 + iy + "px";
				setZKAttr(el, "x", ix);
				setZKAttr(el, "y", iy);
			}
		}
		el.style.visibility = "visible";
		return $e(id);
	};
}
/** Creates the message box to notify the user that his request is in
 * processing.
 * Developer can override this method to provide a customized message box.
 * @param id the progress box's ID
 * @param msg the message
 * @since 3.0.6
 */
if (!window.AU_progressbox) {
	AU_progressbar = function (id, msg) {
		Boot_progressbox(id, msg, zk.innerX(), zk.innerY());
	};
}

/////
// zk

/** Browser info. */
zk.agent = navigator.userAgent.toLowerCase();
zk.safari = zk.agent.indexOf("safari") != -1;
zk.opera = zk.agent.indexOf("opera") != -1;
zk.ie = zk.agent.indexOf("msie") != -1 && !zk.opera;
zk.ie7 = zk.agent.indexOf("msie 7") != -1; //ie7 or later
zk.ie6Only =  zk.ie && !zk.ie7;
zk.gecko = zk.agent.indexOf("gecko/") != -1 && !zk.safari && !zk.opera;
zk.gecko3 = zk.gecko && zk.agent.indexOf("firefox/3") != -1;
zk.windows = zk.agent.indexOf("windows") != -1;
zk.mozilla = zk.gecko && zk.agent.indexOf("firefox/") == -1;
zk.air = zk.agent.indexOf("adobeair") != -1;
//zk.macintosh = zk.agent.indexOf("macintosh") != -1;
zk._js4ld = {}; //{name, [script]}
zk._ctpgs = []; //contained page IDs
zk.voidf = function () {return false;}; //always return false

/** Listen a browser event.
 * Why not to use prototype's Event.observe? Performance.
 */
zk.listen = function (el, evtnm, fn) {
	if (el.addEventListener)
		el.addEventListener(evtnm, fn, false);
	else /*if (el.attachEvent)*/
		el.attachEvent('on' + evtnm, fn);

	//Bug 1811352
	if ("submit" == evtnm && $tag(el) == "FORM") {
		if (!el._submfns) el._submfns = [];
		el._submfns.push(fn);
	}
};
/** Un-listen a browser event.
 */
zk.unlisten = function (el, evtnm, fn) {
	if (el.removeEventListener)
		el.removeEventListener(evtnm, fn, false);
	else if (el.detachEvent) {
		try {
			el.detachEvent('on' + evtnm, fn);
		} catch (e) {
		}
	}

	//Bug 1811352
	if ("submit" == evtnm && $tag(el) == "FORM" && el._submfns)
		el._submfns.remove(fn);
};

if (zk.ie) { //Bug 1741959: avoid memory leaks
	zk._ltns = {} // map(el, [evtnm, fn])
	zk._unltns = []; //array of [el, [evtnm, fn]]

	zk._listen = zk.listen;
	zk.listen = function (el, evtnm, fn) {
		zk._listen(el, evtnm, fn);

		var ls = zk._ltns[el];
		if (!ls) zk._ltns[el] = ls = {};
		var fns = ls[evtnm];
		if (!fns) ls[evtnm] = fns = [];
		fns.push(fn);
	};

	zk._unlisten = zk.unlisten;
	zk.unlisten = function (el, evtnm, fn) {
		zk._unlisten(el, evtnm, fn);

		var ls = zk._ltns[el];
		var fns = ls ? ls[evtnm]: null;
		if (fns) {
			fns.remove(fn);
			if (!fns.length) delete ls[evtnm];
		}
	};

	/** Unlisten events associated with the specified ID.
	 * Bug 1741959: IE meory leaks
	 */
	zk.unlistenAll = function (el) {
		if (el) {
			var ls = zk._ltns[el];
			if (ls) {
				zk._unltns.push([el, ls]);
				delete zk._ltns[el];
				setTimeout(zk._unlistenOne, 10000 + 20000*Math.random());
					//Note: the performance is not good, so delay 10~30s
			}
		} else {
			while (zk._unltns.length)
				zk._unlistenOne();

			for (var el in zk._ltns) {
				var ls = zk._ltns[el];
				if (ls) {
					delete zk._ltns[el];
					zk._unlistenNode(el, ls);
				}
			}
		}
	};
	zk._unlistenOne = function () {
		if (zk._unltns.length) {
			var inf = zk._unltns.shift();
			zk._unlistenNode(inf[0], inf[1]);
		}
	};
	zk._unlistenNode = function (el, ls) {
		for (var evtnm in ls) {
			var fns = ls[evtnm];
			delete ls[evtnm];
			for (var j = fns.length; --j >= 0;) {
				try {
					zk._unlisten(el, evtnm, fns[j]);
					fns[j] = null; //just in case
				} catch (e) { //ignore
				}
			}
			fns.length = 0; //just in case
		}
	};
} else {
	/** No function if not IE. */
	zk.unlistenAll = zk.voidf;
}

/** disable ESC to prevent user from pressing ESC to stop loading */
zk.disableESC = function () {
	if (!zk._noESC) {
		zk._noESC = function (evt) {
			if (!evt) evt = window.event;
			if (evt.keyCode == 27) {
				if (evt.preventDefault) {
					evt.preventDefault();
					evt.stopPropagation();
				} else {
					evt.returnValue = false;
					evt.cancelBubble = true;
				}
				return false;//eat
			}
			return true;
		};
		zk.listen(document, "keydown", zk._noESC);

		//FUTURE: onerror not working in Safari and Opera
		//if error occurs, loading will be never ended, so try to ignore
		//we cannot use zk.listen. reason: no way to get back msg...(FF)
		zk._oldOnErr = window.onerror;
		zk._onErrChanged = true;
		window.onerror =
	function (msg, url, lineno) {
		//We display errors only for local class web resource
		//It is annoying to show error if google analytics's js not found
		var au = zkau.uri();
		if (au && url.indexOf(location.host) >= 0) {
			var v = au.lastIndexOf(';');
			v = v >= 0 ? au.substring(0, v): au;
			if (url.indexOf(v + "/web/") >= 0) {
				msg = mesg.FAILED_TO_LOAD + url + "\n" + mesg.FAILED_TO_LOAD_DETAIL
					+ "\n" + mesg.CAUSE + msg+" (line "+lineno + ")";
				if (zk.error) zk.error(msg);
				else alert(msg);
				return true;
			}
		}
	};
	}
};
zk.disableESC(); //disable it as soon as possible
/** Enables ESC to back to the normal mode. */
zk.enableESC = function () {
	if (zk._noESC) {
		zk.unlisten(document, "keydown", zk._noESC);
		delete zk._noESC;
	}
	if (zk._onErrChanged) {
		window.onerror = zk._oldOnErr;
		if (zk._oldOnErr) delete zk._oldOnErr;
		delete zk._onErrChanged;
	}
};

//////////////////////////////////////
zk.mods = {}; //ZkFns depends on it

/** Returns the current time (new Date().getTime()) (since 01/01/1970).
 * @since 3.0.0
 */
function $now() {
	return new Date().getTime();
}
/** Note: it is easy to cause problem with EMBED, if we use prototype's $() since
 * it tried to extend the element.
 */
function $e(id) {
	return typeof id == 'string' ? id ? document.getElementById(id): null: id;
		//strange but getElementById("") fails in IE7
}
/** A control might be enclosed by other tag while event is sent from
 * the control directly, so... */
function $uuid(n) {
	if (typeof n != 'string') {
		for (; n; n = $parent(n))
			if (n.id) {
				n = n.id;
				break;
			}
	}
	if (!n) return "";
	var j = n.lastIndexOf('!');
	return j > 0 ? n.substring(0, j): n;
}
/**
 * Returns the id of the first element which can be found from its parent node, inclusive itself.
 * Otherwise, "" is assumed. 
 * @param {Object} n an element.
 * @since 3.0.6
 */
function $id(n) {
	for (; n; n = $parent(n))
		if (n.id) return n.id;
	return ""; 
}
/** Returns the real element (ends with !real).
 * If a component's attributes are located in the inner tag, i.e.,
 * you have to surround it with span or other tag, you have to place
 * uuid!real on the inner tag
 *
 * Note: !chdextr is put by the parent as the exterior of its children,
 * while !real is by the component itself
 */
function $real(cmp) {
	var id = $uuid(cmp);
	if (id) {
		var n = $e(id + "!real");
		if (n) return n;
		n = $e(id);
		if (n) return n;
	}
	return cmp;
}
/** Returns the enclosing element (not ends with !real).
 * If not found, cmp is returned.
 */
function $outer(cmp) {
	var id = $uuid(cmp);
	if (id) {
		var n = $e(id);
		if (n) return n;
	}
	return cmp;
}
/** Returns the type of a node without module. */
function $type(n) {
	var type = getZKAttr(n, "type");
	if (type) {
		var j = type.lastIndexOf('.');
		return j >= 0 ? type.substring(j + 1): type;
	}
	return null;
};
/** Returns the peer (xxx!real => xxx, xxx => xxx!real), or null if n/a.
 */
/*function $peer(id) {
	return id ? $e(
		id.endsWith("!real") ? id.substring(0, id.length-5): id+"!real"): null;
}*/
/** Returns the exterior of the specified component (ends with !chdextr).
 * Some components, hbox nad vbox, need to add exterior to child compoents,
 * and the exterior is named with "uuid!chdextr".
 */
function $childExterior(cmp) {
	var n = $e(cmp.id + "!chdextr");
	return n ? n: cmp;
}

/** Returns the parent node of the specified element.
 * It handles virtual parent.
 */
function $parent(n) {
	var p = zk._vpts[n.id];
	return p ? p: n.parentNode;
}
/** Sets virtual parent. It is used if a popup is limited (cropped) by a parent div.
 * @since 3.0.0
 */
zk.setVParent = function (n) {
	var id = n.id, p = n.parentNode;
	if (!id) {
		zk.error("id required, "+n);
		return;
	}
	if (zk.isVParent(id))
		return; //called twice

	var sib = n.nextSibling;
	if (sib) {
		var agtx = document.createElement("SPAN");
		agtx.id = id + "!agtx";
		agtx.style.display = "none";
		p.insertBefore(agtx, sib);
	}

	zk._vpts[id] = p;

	if (!getZKAttr(n, "dtid")) setZKAttr(n, "dtid", zkau.dtid(n));
	document.body.appendChild(n);
};
/**
 * Returns whether the element has a virtual parent.
 * @since 3.0.0
 */
zk.isVParent = function (n) {
	return zk._vpts[n && n.id ? n.id: n];
};
/** Unsets virtual parent.
 * @since 3.0.0
 */
zk.unsetVParent = function (n) {
	var id = n.id, p = zk._vpts[id];
	delete zk._vpts[id];
	if (p) {
		var sib = $e(id + "!agtx");
		if (sib) {
			p.insertBefore(n, sib);
			zk.remove(sib);
		} else
			p.appendChild(n);
	}
};
/** unsetVParent if it is a child of the specified node, n.
 * 	Note: including itself.
 * @param hide to avoid some annoying effect you can specify whether
 * to hide before unsetting the parent. Note: since it is hidden,
 * x.style.display will be changed -- use this option with a lot of cares
 * @since 3.0.0
 */
zk.unsetChildVParent = function (n, hide) {
	var bo = [];
	for (var id in zk._vpts)
		if (zk.isAncestor(n, id))
			bo.push(id);

	for (var j = bo.length; --j >= 0;) {
		n = $e(bo[j]);
		if (hide) n.style.display = "none";
		zk.unsetVParent(n);
	}
	return bo;
};
//Note: we have to use string to access {}. Otherwise, the behavior is strange
zk._vpts = {}; //a map of virtual parent (n.id, n's parent)

/** Returns the nearest parent element, including el itself, with the specified type.
 */
function $parentByType(el, type) {
	for (; el; el = $parent(el))
		if ($type(el) == type)
			return el;
	return null;
};
/** Returns the tag name in the upper case. */
function $tag(el) {
	return el && el.tagName ? el.tagName.toUpperCase(): "";
};
/** Returns the nearest parent element, including el itself, with the specified tag.
 */
function $parentByTag(el, tagName) {
	for (; el; el = $parent(el))
		if ($tag(el) == tagName)
			return el;
	return null;
};
/** Returns whether an element is visible.
 * Returns false if none-existence.
 * Returns true if no style.
 * @param {Boolean} strict if true, it also checks the visibility property.(since 3.0.4)
 */
function $visible(el, strict) {
	return el && (!el.style || (el.style.display != "none" && (!strict || el.style.visibility != "hidden")));
}

/** Converts to an integer. It handles null and "07" */
function $int(v, b) {
	v = v ? parseInt(v, b || 10): 0;
	return isNaN(v) ? 0: v;
};

/** Returns the ZK attribute of the specified name.
 * Note: the name space of ZK attributes is "http://www.zkoss.org/2005/zk"
 */
function getZKAttr(el, nm) {
	//20061120:
	//1) getAttributeNS doesn't work properly to retrieve attribute back
	//2) setAttribute("z:nm", val) doesn't work in Safari
	try {
		return el && el.getAttribute ? el.getAttribute("z." + nm): null;
	} catch (e) {
		return null; //IE6: failed if el is TABLE and attribute not there
	}
};
/** Sets the ZK attribute of the specified name with the specified value.
 */
function setZKAttr(el, nm, val) {
	if (el && el.setAttribute) el.setAttribute("z." + nm, val);
};
function rmZKAttr(el, nm) {
	if (el && el.removeAttribute) el.removeAttribute("z." + nm);
	else setZKAttr(el, nm, "");
};

/** Returns the version of the specified module name.
 */
zk.getBuild = function (nm) {
	return zk.mods[nm] || zk.build || "0";
};

/** Adds a function that will be invoked after all components are
 * initialized.
 * <p>Note: it is called after all components are initialized
 * (init, beforeSize and onSize),
 * so it might be better to be called as addAfterInit
 * <p>The function is removed from the list right before invoked,
 * so it won't be called twice (unless you call zk.addInit again).
 * @param front whether to add the function to the front of the list
 * @param {String} unique whether not to add if redundant. If any, fn is added
 * only if fn was not added before.
 */
zk.addInit = function (fn, front, unique) {
	if (typeof unique == "string") {
		if(zk._initids[unique]) return;	
		zk._initids[unique] = true;
	}
	zk._addfn(zk._initfns, fn, front);
};
/** Adds a function that will be invoked 25 milliseconds, after
 * all components are initialized.
 * <p>Like zk.addInit, the function is called after all components are
 * initialized, so it might be better to be called as addAfterInitLater.
 * However, the function added by addInitLater is invoked
 * with a timer that is called 25 milliseconds.
 * Thus, it is designed to add functions that cannot be called
 * immediately after initialization (zkType.init).
 *
 * <p>The function is removed from the list right before invoked,
 * so it won't be called twice (unless you call zk.addInitLater again).
 *
 * @param front whether to add the function to the front of the list
 * @param {String} unique whether not to add if redundant. If any, fn is added
 * only if fn was not added before.
 * @since 3.0.0
 */
zk.addInitLater = function (fn, front, unique) {
	if (typeof unique == "string") {
		if(zk._inLatids[unique]) return;
		zk._inLatids[unique] = true;
	}
	zk._addfn(zk._inLatfns, fn, front);
};
zk._addfn = function (fns, fn, front) {
	if (front) fns.unshift(fn);
	else fns.push(fn);
};
/** Adds a function for module initialization.
 * It is called after all javascript fies are loaded, and before
 * initializing the components.
 *
 * <p>In other words, ZK invokes functions added by zk.addBeforeInit,
 * then initializes all components, and finally invokes functions added
 * by zk.addInit.
 *
 * <p>The function is removed from the list right before invoked,
 * so it won't be called twice (unless you call zk.addBeforeInit again).
 */
zk.addBeforeInit = zk.addModuleInit = function (fn) { //addModuleInit is for backward compatible to 3.0.3 and earlier
	zk._bfinits.push(fn);
};
/** Adds a component that must be initialized after
 * all modules are loaded and initialized.
 */
zk.addInitCmp = function (cmp) {
	zk._initcmps.push(cmp);
};

/** Adds a function that will be invoked after all components are
 * cleaned up.
 * Unlike zk.addCleanupLater, the components being cleaned up are
 * still available when fn is called.
 * <p>Note: it is called after all components are initialized.
 * <p>The function is removed from the list right before invoked,
 * so it won't be called twice (unless you call zk.addInit again).
 * @param front whether to add the function to the front of the list
 * @param {String} unique whether not to add if redundant. If any, fn is added
 * only if fn was not added before.
 */
zk.addCleanup = function (fn, front, unique) {
	if (typeof unique == "string") {
		if(zk._cuids[unique]) return;	
		zk._cuids[unique] = true;
	}
	zk._addfn(zk._cufns, fn, front);
};
/** Adds a function that will be invoked 25 milliseconds, after
 * all components are cleaned up.
 * Note: when fn is called, the component being cleaned up may be removed.
 *
 * <p>The function is removed from the list right before invoked,
 * so it won't be called twice (unless you call zk.addInitLater again).
 *
 * @param front whether to add the function to the front of the list
 * @param {String} unique whether not to add if redundant. If any, fn is added
 * only if fn was not added before.
 * @since 3.0.0
 */
zk.addCleanupLater = function (fn, front, unique) {
	if (typeof unique == "string") {
		if(zk._cuLatids[unique]) return;	
		zk._cuLatids[unique] = true;
	}
	zk._addfn(zk._cuLatfns, fn, front);
};

/** Adds a function that will be invoked before the browser is unloading
 * the page.
 * If the function returns a string, then the whole execution will stop
 * and the string is returned to browser (to warning the user).
 * If nothing is returned, the following functions will be invoked.
 *
 * @param front whether to add the function to the front of the list
 * @since 3.0.0
 */
zk.addBeforeUnload = function (fn, front) {
	if (front) zk._bfunld.unshift(fn);
	else zk._bfunld.push(fn);
};
/** Removes the function added by zk.addBeforeUnload.
 * @since 3.0.0
 */
zk.rmBeforeUnload = function (fn) {
	zk._bfunld.remove(fn);
};
/** Called when window.onbeforeunload is called.
 * Note: you rarely need to invoke this directly (except au.js).
 * @since 3.0.0
 */
zk.beforeUnload = function () {
	for (var j = 0, bl = zk._bfunld.length; j < bl; ++j) {
		var s = zk._bfunld[j]();
		if (s) return s;
	}
};

/** Unwatches a list of ZK callbacks.
 * Example, zk.unwatch(n, "onVisi", "onSize"), and then zkType.onVisi
 * and zkType.onSize will be ignored for the specified component
 * Note: it cannot be called in zkType.init().
 * @since 3.0.5
 */
zk.unwatch = function (n) {
	if (typeof n != "string") n = n.id;
	for (var as = arguments, j = as.length; --j > 0;)
		switch (as[j]) {
		case "onVisi": zk._visicmps.remove(n); break;
		case "onHide": zk._hidecmps.remove(n); break;
		case "onSize": zk._szcmps.remove(n); break;
		case "beforeSize": zk._bfszcmps.remove(n); break;
		case "onScroll": zk._scrlcmps.remove(n);
		}
};
/** Watches a list of ZK callbacks.
 * Example, zk.watch(n, "onVisi", "onSize"), and then zkType.onVisi
 * and zkType.onSize will be called back for the specified component.
 * By default, they will be called back, so you don't need to invoke
 * this method unless you call zk.unwatch() to stop callback.
 * Note: it cannot be called in zkType.init().
 * @since 3.0.5
 */
zk.watch = function (n) {
	n = $e(n);
	for (var as = arguments, j = as.length; --j > 0;)
		switch (as[j]) {
		case "onVisi": zk._watch(n, zk._visicmps); break;
		case "onHide": zk._watch(n, zk._hidecmps); break;
		case "onSize": zk._watch(n, zk._szcmps); break;
		case "beforeSize": zk._watch(n, zk._bfszcmps); break;
		case "onScroll": zk._watch(n, zk._scrlcmps);
		}
};
zk._watch = function (n, cmps) {
	for (var j = 0; j < cmps.length; ++j) {
		var c = cmps[j];
		if (zk.isAncestor(c, n)) {
			cmps.splice(j, 0, n.id);
			return;
		}
	}
	cmps.unshift(n.id);
};

/** Invokes the specified function that depends on the specified module.
 * If the module is not loaded yet, it will be loaded first.
 * If it is loaded, the function executes directly.
 * @since 3.0.0
 */
zk.invoke = function (nm, fn, dtid) {
	if (!zk._modules[nm]) zk.load(nm, fn, null, null, dtid);
	else if (zk.loading) zk.addBeforeInit(fn);
	else fn();
};

/** Registers a script that will be evaluated when the specified module
 * is loaded.
 * @param script a piece of JavaScript, or a function
 * @since 3.0.6
 */
zk.addOnLoad = function (nm, script) {
	if (zk._modules[nm]) {
		setTimeout(script, 0);
	} else {
		var ary = zk._js4ld[nm] = [];
		ary.push(script);
	}
};

/** Loads the specified module (JS). If a feature is called "a.b.c", then
 * zkau.uri() + "/web/js" + "a/b/c.js" is loaded.
 *
 * <p>To load a JS file that other modules don't depend on, use zk.loadJS.
 *
 * @param nm the module name if no / is specified, or filename if / is
 * specified, or URL if :// is specified.
 * @param initfn the function that will be added to zk.addBeforeInit
 * @param ckfn used ONLY if URL (i.e., xxx://) is used as nm,
 * and the file being loaded doesn't invoke zk.ald().
 * @param modver the version of the module, or null to use zk.getBuild(nm)
 */
zk.load = function (nm, initfn, ckfn, modver, dtid) {
	if (!nm) {
		zk.error("Module name must be specified");
		return;
	}

	if (!zk._modules[nm]) {
		zk._modules[nm] = true;
		if (initfn) zk.addBeforeInit(initfn);
		zk._load(nm, modver, dtid);
		if (ckfn) zk._ckfns.push(ckfn);
	}
};
zk._loadByType = function (nm, n) {
	if (!zk._modules[nm]) {
		zk._modules[nm] = true;
		zk._load(nm, null, zkau.dtid(n));
	}
};
/** Loads the required module for the specified component.
 * Note: it DOES NOT check any of its children.
 * @return true if z.type is defined.
 */
zk.loadByType = function (n) {
	var type = getZKAttr(n, "type");
	if (type) {
		var j = type.lastIndexOf('.');
		if (j > 0) zk._loadByType(type.substring(0, j), n);
		return true;
	}
	return false;
};

/** Loads the javascript. It invokes _bld before loading.
 *
 * <p>The JavaScript file being loaded must<br/>
 * 1) call zk.ald() after loaded<br/>
 * 2) pass ckfn to test whether it is loaded.
 */
zk._load = function (nm, modver, dtid) {
	zk._bld();

	var e = document.createElement("script");
	e.type = "text/javascript" ;

	var zcb;
	if (zk.gecko) {
		e.onload = zk.ald;
		zcb = "";
	} else {
		zcb = "/_zcbzk.ald";
			//Note: we use /_zcb to enforce callback of zk.ald
	}

	var uri = nm;
	if (uri.indexOf("://") > 0) {
		e.src = uri;
	} else if (uri.indexOf('/') >= 0) {
		if (uri.charAt(0) != '/') uri = '/' + uri;
		e.charset = "UTF-8";
		e.src = zk.getUpdateURI("/web" + zcb + uri, false, modver, dtid);
	} else { //module name
		uri = uri.replace(/\./g, '/');
		var j = uri.lastIndexOf('!');
		uri = j >= 0 ?
			uri.substring(0, j) + ".js." + uri.substring(j + 1):
			uri + ".js";
		if (uri.charAt(0) != '/') uri = '/' + uri;
		e.charset = "UTF-8";
		if (!modver) modver = zk.getBuild(nm);
		e.src = zk.getUpdateURI("/web" + zcb + "/js" + uri, false, modver, dtid);
	}
	document.getElementsByTagName("HEAD")[0].appendChild(e);
		//Bug 1815074: IE bug:
		//zk.ald might be called before returning from appendChild
};
/** before load. */
zk._bld = function () {
	if (zk.loading ++) {
		zk._updCnt();
	} else {
		zk.disableESC();

		zk._ckload = setInterval(function () {
			for (var j = 0, cl = zk._ckfns.length; j < cl; ++j)
				if (zk._ckfns[j]()) {
					zk._ckfns.splice(j--, 1);
					zk.ald();
				} else return; //wait a while
		}, 10);

		setTimeout(function () {
			if (zk.loading || window.dbg_progressbox) {
				var n = $e("zk_loadprog");
				if (!n)
					Boot_progressbox("zk_loadprog",
						'Loading (<span id="zk_loadcnt">'+zk.loading+'</span>)',
						"45%", "40%");
			}
		}, 350);
	}
};
/** after load. */
zk.ald = function () {
	if (--zk.loading) {
		try {
			zk._updCnt();
		} catch (ex) {
			zk.error("Failed to count. "+ex.message);
		}
	} else {
		try {
			zk.enableESC();

			if (zk._ckload) {
				clearInterval(zk._ckload);
				delete zk._ckload;
			}

			//dispatch zk._js4ld
			for (var nm in zk._js4ld)
				if (zk._modules[nm]) {
					var ary = zk._js4ld[nm];
					if (ary) {
						delete zk._js4ld[nm];
						while (ary.length)
							setTimeout(ary.shift(), 0);
					}
				}

			var n = $e("zk_loadprog");
			if (n) n.parentNode.removeChild(n);
		} catch (ex) {
			zk.error("Failed to stop counting. "+ex.message);
		}
		
		if (zk._ready) zk._evalInit(); //zk._loadAndInit might not finish
	}
};
zk._updCnt = function () {
	var n = $e("zk_loadcnt");
	if (n) n.innerHTML = "" + zk.loading;
};

/** Initializes the dom tree.
 */
zk.initAt = function (node) {
	if (!node) return;

	var stk = [];
	stk.push(node);

	zk._loadAndInit({stk: stk, nosibling: true});
};

/** Loads all required module and initializes components. */
zk._loadAndInit = function (inf) {
	zk._ready = false;

	//The algorithm here is to mimic deep-first tree traversal
	//We cannot use recursive algorithm because it might take too much time
	//to execute and browser will alert users for aborting!
	for (var j = 0; inf.stk.length;) {
		if (++j > 1000) {
			setTimeout(function() {zk._loadAndInit(inf);}, 10);
			return; //let browser breath
		}

		var n = inf.stk.pop();
		if (n.nodeType == 1) {
			try { 
				if (zk.gecko) {
	//FF remembers the previous value that user entered when reload
	//We have to reset them because the server doesn't know any of them
					switch ($tag(n)) {
					case "INPUT":
						if (n.type == "checkbox" || n.type == "radio") {
							if (n.checked != n.defaultChecked)
								n.checked = n.defaultChecked;
							break;
						}
						if (n.type != "text" && n.type != "password") break;
						//fall thru
					case "TEXTAREA":
						if (n.value != n.defaultValue
						&& n.defaultValue != "zk_wrong!~-.zk_pha!6")
							n.value = n.defaultValue;
						break;
					case "OPTION":
						if (n.selected != n.defaultSelected)
							n.selected = n.defaultSelected;
						//break;
					}
				} else if (zk.ie) {
					switch ($tag(n)) {
					case "A": //Bug 1635685 and 1612312
					case "AREA": //Bug 1896749
						if (n.href.indexOf("javascript:") >= 0)
							zk.listen(n, "click", zk._ieFixBfUnload);
						break;
					case "FORM":
						//Bug 1811352
						zk.fixSubmit(n);
						//break;
					}
				}
			} catch (e) {} // IE7 failed if href contains incorrect encoding

			var v = getZKAttr(n, "dtid");
			if (v) zkau.addDesktop(v); //desktop's ID found

			if (zk.loadByType(n) || getZKAttr(n, "drag")
			|| getZKAttr(n, "drop") || getZKAttr(n, "zid"))
				zk._initcmps.push(n);

			//Test if a (non-owned) page included by other content (e.g. JSP)
			if (getZKAttr(n, "zidsp") == "ctpage")
				zk._ctpgs.push(n.id);
		}

		//if nosibling, don't process its sibling (only process children)
		if (inf.nosibling) inf.nosibling = false;
		else if (n.nextSibling && !getZKAttr(n, "skipsib"))
			inf.stk.push(n.nextSibling);

		//Since 3.0.2, we introduce z.skipdsc to stop parsing the descendants.
		//It improves the performance for the sophisticated component
		//that want to initialize children in a custom way.
		if (n.firstChild && !getZKAttr(n, "skipdsc"))
			inf.stk.push(n.firstChild);
	}

	zk._evalInit();
	zk._ready = true;
};
/** Fix bug 1635685 and 1612312 (IE/IE7 only):
 * IE invokes onbeforeunload if <a href="javascript;"> is clicked (sometimes)
 * It actually ignores window.beforeunload temporary by
 * set zk.skipBfUnload.
 */
if (zk.ie) {
	zk._ieFixBfUnload = function () {
		zk.skipBfUnload = true;
		setTimeout(zk._skipBackBF, 0); //restore
	};
	zk._skipBackBF = function () {
		zk.skipBfUnload = false;
	};
}

/** Initial components and init functions. */
zk._evalInit = function () {
	do {
		while (!zk.loading && zk._bfinits.length)
			(zk._bfinits.shift())();

		//Note: if loading, zk._doLoad will execute zk._evalInit after finish
		for (var j = 0; zk._initcmps.length && !zk.loading;) {
			var n = zk._initcmps.pop(); //reverse-order (child first)

			var m = zk.eval(n, "init");
			if (m) n = m; //it might be transformed

			if (getZKAttr(n, "zid")) zkau.initzid(n);
			if (getZKAttr(n, "drag")) zkau.initdrag(n);
			if (getZKAttr(n, "drop")) zkau.initdrop(n);

			var type = $type(n);
			if (type) {
				var o = window["zk" + type];
				if (o) {
					//We put child in front of parent (by use of push)
					//note: init is called child child-first, but
					//onVisi/onHide is called parent-first
					if (o["onVisi"]) zk._tvisicmps.push(n.id); //child-first
					if (o["onHide"]) zk._thidecmps.push(n.id); //child-first
					if (o["onSize"]) zk._tszcmps.push(n.id); //child-first
					if (o["beforeSize"]) zk._tbfszcmps.push(n.id); //child-first
					if (o["onScroll"]) zk._tscrlcmps.push(n.id); //child-first
				}
			}

			if (zk.loading || ++j > 1000) {
				if (!zk.loading)
					setTimeout(zk._evalInit, 10); //let browser breath
				return;
			}
		}

		if (!zk.loading) {
			//put _tvisicmps at the head of _visicmps and keep child-first
			for (var es = zk._tvisicmps; es.length;)
				zk._visicmps.unshift(es.pop());
			for (var es = zk._thidecmps; es.length;)
				zk._hidecmps.unshift(es.pop());
			for (var es = zk._tscrlcmps; es.length;)
				zk._scrlcmps.unshift(es.pop());

			//since beforeSize/onSize might zk.unwatch, add to _szcmps first
			for (var es = zk._tbfszcmps, j = es.length; --j >= 0;)
				zk._bfszcmps.unshift(es[j]);
			for (var es = zk._tszcmps, j = es.length; --j >= 0;)
				zk._szcmps.unshift(es[j]);

			for (var es = zk._tbfszcmps; es.length;) {
				var n = $e(es.pop()); //parent at the end, so pop the end first
				if ($visible(n)) zk.eval(n, "beforeSize");
			}
			for (var es = zk._tszcmps; es.length;) {
				var n = $e(es.pop());
				if ($visible(n)) zk.eval(n, "onSize");
			}
		}

		while (!zk.loading && zk._initfns.length)
			(zk._initfns.shift())();

		if (!zk.loading && !zk._initfns.length) {
			zk._initids = {}; //cleanup

			setTimeout(zk._initLater, 25);
		}
	} while (!zk.loading && (zk._bfinits.length || zk._initcmps.length
	|| zk._initfns.length));
	//Bug 1815074: _initfns might cause _bfinits to be added

	zkau.doQueResps(); //since responses might not be processed yet
};
zk._initLater = function () {
	while (!zk.loading && zk._inLatfns.length)
		(zk._inLatfns.shift())();
	if (!zk.loading && !zk._inLatfns.length)
		zk._inLatids = {};
};

/** Evaluate a method of the specified component.
 *
 * It assumes fn is a method name of a object called "zk" + type
 * (in window).
 * Nothing happens if no such object or no such method.
 *
 * @param n the component
 * @param fn the method name, e.g., "init"
 * @param type the component type. If omitted, $type(n)
 * is assumed.
 * @return the result
 */
zk.eval = function (n, fn, type) {
	if (!type) type = $type(n);
	if (type) {
		var o = window["zk" + type];
		if (o) {
			var f = o[fn];
			if (f) {
				try {
					var args = [n];
					for (var j = arguments.length - 2; --j > 0;) //3->1, 4->2...
						args[j] = arguments[j + 2];
					return f.apply(n, args);
				} catch (ex) {
					zk.error("Failed to invoke zk"+type+"."+fn+"\n"+ex.message);
					if (zk.debugJS) throw ex;
				}
			}
		}
	}
	return false;
};

/** Check z.type and invoke zkxxx.cleanup if declared.
 */
zk.cleanupAt = function (n) {
	zk._cleanupAt(n);

	while (zk._cufns.length)
		(zk._cufns.shift())();
		
	zk._cuids = {};
	setTimeout(zk._cleanLater, 25);
};
zk._cleanLater = function () {
	while (zk._cuLatfns.length)
		(zk._cuLatfns.shift())();
	zk._cuLatids = {};
};
zk._cleanupAt = function (n) {
	if (getZKAttr(n, "zid")) zkau.cleanzid(n);
	if (getZKAttr(n, "zidsp")) zkau.cleanzidsp(n);
	if (getZKAttr(n, "drag")) zkau.cleandrag(n);
	if (getZKAttr(n, "drop")) zkau.cleandrop(n);

	var type = $type(n);
	if (type) {
		zk.eval(n, "cleanup", type);
		zkau.cleanupMeta(n); //note: it is called only if type is defined
		zk.unlistenAll(n); //Bug 1741959: memory leaks
		zk._visicmps.remove(n.id);
		zk._hidecmps.remove(n.id);
		zk._szcmps.remove(n.id);
		zk._bfszcmps.remove(n.id);
		zk._scrlcmps.remove(n.id);
	}

	for (n = n.firstChild; n; n = n.nextSibling)
		if (n.nodeType == 1) zk._cleanupAt(n); //recursive for child component
};

/** To notify a component that it becomes visible because one its ancestors
 * becomes visible. All descendants of n is invoked if onVisi is declared.
 * The invocation of onVisi is parent-first (and then child).
 *@param n the topmost element that has become visible.
 * Note: n has become visible when this method is called.
 * If null, all elements will be handled
 */
zk.onVisiAt = function (n) {
	//Note: process from last since zk.unwatch assumes it
	for (var elms = zk._visicmps, j = elms.length; --j >= 0;) { //parent first
		var elm = $e(elms[j]);
		for (var e = elm; e; e = $parent(e)) {
			if (!$visible(e))
				break;
			if (e == n || !n) { //elm is a child of n
				zk.fixOverflow(elm);
				zk.eval(elm, "onVisi");
				break;
			}
		}
	}
};
/** To notify a component that it becomes invisible because one its ancestors
 * becomes invisible. All descendants of n is invoked if onHide is declared.
 * The invocation of onHide is parent-first (and then child).
 *@param n the topmost element that will become invisible.
 * Note: n is still visible when this method is called.
 * If null, all elements will be handled.
 */
zk.onHideAt = function (n) {
	//Bug 1526542: we have to blur if we want to hide a focused control in gecko and IE
	var f = zkau.currentFocus;
	if (f && zk.isAncestor(n, f)) {
		zkau.currentFocus = null;
		try {f.blur();} catch (e) {}
	}

	//Note: process from last since zk.unwatch assumes it
	for (var elms = zk._hidecmps, j = elms.length; --j >= 0;) { //parent first
		var elm = $e(elms[j]);
		for (var e = elm; e; e = $parent(e)) {
			if (!$visible(e)) //yes, ignore hidden ones
				break;
			if (e == n || !n) { //elm is a child of n
				zk.eval(elm, "onHide");
				break;
			}
		}
	}
};
/** To notify a component that its parent's size is changed.
 * All descendants of n is invoked if onSize is declared.
 * The invocation of onSize is parent-first (and then child).
 * @param n the topmost element whose size is changed.
 * If null, the browser's size is changed and all elements will be handled.
 * @since 3.0.4
 */
zk.onSizeAt = function (n) {
	//Note: process from last since zk.unwatch assumes it
	for (var elms = zk._szcmps, j = elms.length; --j >= 0;) { //parent first
		var elm = $e(elms[j]);
		for (var e = elm; e; e = $parent(e)) {
			if (!$visible(e))
				break;
			if (!n || e == n) { //elm is a child of n
				zk.eval(elm, "onSize");
				break;
			}
		}
	}
};
/** To notify a component that its parent's size WILL be changed.
 * All descendants of n is invoked if beforeSize is declared.
 * The invocation of beforeSize is parent-first (and then child).
 *
 * <p>The typical use is: call beforeSizeAt first, adjust the width/height
 * and then call onSizeAt.
 *
 * <p>The component usually cleans up in zkXxx.beforeSize, if necessary, and
 * does the sizing in zkXxx.onSize, if necessary.
 *
 * @param n the topmost element whose size is changed.
 * If null, the browser's size is changed and all elements will be handled.
 * @since 3.0.4
 */
zk.beforeSizeAt = function (n) {
	//Note: process from last since zk.unwatch assumes it
	for (var elms = zk._bfszcmps, j = elms.length; --j >= 0;) { //parent first
		var elm = $e(elms[j]);
		for (var e = elm; e; e = $parent(e)) {
			if (!$visible(e))
				break;
			if (!n || e == n) { //elm is a child of n
				zk.eval(elm, "beforeSize");
				break;
			}
		}
	}
};
/** To notify a component that the parent is scrolled.
 * All descendants of n is invoked if onScroll is declared.
 * The invocation of onScroll is parent-first (and then child).
 * @param n the topmost element which is scrolled.
 * If null, the browser's size is changed and all elements will be handled.
 * @since 3.0.5
 */
zk.onScrollAt = function (n) {
	if (zkau.valid) zkau.valid.onScrollAt(n); // Bug #1819264
	//Note: process from last since zk.unwatch assumes it
	for (var elms = zk._scrlcmps, j = elms.length; --j >= 0;) { //parent first
		var elm = $e(elms[j]);
		for (var e = elm; e; e = $parent(e)) {
			if (!$visible(e))
				break;
			if (!n || e == n) { //elm is a child of n
				zk.eval(elm, "onScroll");
				break;
			}
		}
	}
};

//extra//
/** Loads the specified style sheet (CSS).
 * @param uri Example, "/a/b.css". It will be prefixed with zkau.uri() + "/web",
 * unless http:// or https:// is specified
 */
zk.loadCSS = function (uri, dtid) {
	if (uri.indexOf("://") < 0) {
		if (uri.charAt(0) != '/') uri = '/' + uri;
		uri = zk.getUpdateURI("/web" + uri, false, null, dtid);
	}
	zk.loadCSSDirect(uri);
};
/**Loads the specified style sheet (CSS) without prefixing with /web.
 *
 * @param uri the URI. Note: it is assigned to the href attribute directly
 * without prefix with /web
 * @param id the identifier (the id attribute). Optional.
 * @since 3.0.2
 */
zk.loadCSSDirect = function (uri, id) {
	var e = document.createElement("LINK");
	if (id) e.id = id;
	e.rel = "stylesheet";
	e.type = "text/css";
	e.href = uri;
	document.getElementsByTagName("HEAD")[0].appendChild(e);
};
/** Loads the specified JavaScript file directly.
 * @param uri Example, "/a/b.css". It will be prefixed with zkau.uri() + "/web",
 * unless http:// or https:// is specified
 * @param fn the function to execute after loading. It is optional.
 * Not function under safari
 */
zk.loadJS = function (uri, fn, dtid) {
	var e = document.createElement("script");
	e.type	= "text/javascript" ;
	e.charset = "UTF-8";
	if (fn)
		e.onload = e.onreadystatechange = function() {
			if (!e.readyState || e.readyState == 'loaded') fn();
		};

	if (uri.indexOf("://") < 0) {
		if (uri.charAt(0) != '/') uri = '/' + uri;
		uri = zk.getUpdateURI("/web" + uri, false, null, dtid);
	}
	e.src = uri;
	document.getElementsByTagName("HEAD")[0].appendChild(e);
};

/** Returns the proper URI.
 * @param ignoreSessId whether not to append session ID.
 * @param modver the module version to insert into uri, or null to use zk.build.
 * Note: modver is used if uri starts with /uri
 */
zk.getUpdateURI = function (uri, ignoreSessId, modver, dtid) {
	var au = zkau.uri(dtid);
	if (!uri) return au;

	if (uri.charAt(0) != '/') uri = '/' + uri;
	if (modver && uri.length >= 5 && uri.substring(0, 5) == "/web/")
		uri = "/web/_zv" + modver + uri.substring(4);

	var j = au.lastIndexOf(';'), k = au.lastIndexOf('?');
	if (j < 0 && k < 0) return au + uri;

	if (k >= 0 && (j < 0 || k < j)) j = k;
	var prefix = au.substring(0, j);

	if (ignoreSessId)
		return prefix + uri;

	var suffix = au.substring(j);
	var l = uri.indexOf('?');
	return l >= 0 ?
		k >= 0 ?
		  prefix + uri.substring(0, l) + suffix + '&' + uri.substring(l+1):
		  prefix + uri.substring(0, l) + suffix + uri.substring(l):
		prefix + uri + suffix;
};

//-- progress --//
/** Turn on the progressing dialog after the specified timeout. */
zk.progress = function (timeout) {
	zk.progressing = true;
	if (timeout > 0) setTimeout(zk._progress, timeout);
	else zk._progress();
};
zk.progressDone = function() {
	zk.progressing = zk.progressPrompted = false;
	var n = $e("zk_prog");
	if (n) n.parentNode.removeChild(n);
};
/** Generates the progressing dialog. */
zk._progress = function () {
	if (zk.progressing && !zk.loading) {
		var n = $e("zk_showBusy");
		if (n) return;
		n = $e("zk_prog");
		if (!n) {
			var msg;
			try {msg = mesg.PLEASE_WAIT;} catch (e) {msg = "Processing...";}
				//when the first boot, mesg might not be ready

			AU_progressbar("zk_prog", msg);
			zk.progressPrompted = true;
		}
	}
};

//-- utilities --//
zk.https = function () {
	var p = location.protocol;
	return p && "https:" == p.toLowerCase();
};
/** Returns the x coordination of the visible part. */
zk.innerX = function () {
    return window.pageXOffset
		|| document.documentElement.scrollLeft
		|| document.body.scrollLeft || 0;
};
/** Returns the y coordination of the visible part. */
zk.innerY = function () {
    return window.pageYOffset
		|| document.documentElement.scrollTop
		|| document.body.scrollTop || 0;
};

zk.innerWidth = function () {
	return typeof window.innerWidth == "number" ? window.innerWidth:
		document.compatMode == "CSS1Compat" ?
			document.documentElement.clientWidth: document.body.clientWidth;
};
zk.innerHeight = function () {
	return typeof window.innerHeight == "number" ? window.innerHeight:
		document.compatMode == "CSS1Compat" ?
			document.documentElement.clientHeight: document.body.clientHeight;
};
zk.pageWidth = function () {
	var a = document.body.scrollWidth, b = document.body.offsetWidth;
	return a > b ? a: b;
};
zk.pageHeight = function () {
	var a = document.body.scrollHeight, b = document.body.offsetHeight;
	return a > b ? a: b;
};

zk._setOuterHTML = function (n, html) {
	if (n.outerHTML) n.outerHTML = html;
	else { //non-IE
		var range = document.createRange();
		range.setStartBefore(n);
		var df = range.createContextualFragment(html);
		n.parentNode.replaceChild(df, n);
	}
};

/** Pause milliseconds. */
zk.pause = function (millis) {
	if (millis) {
		var d = $now(), n;
		do {
			n = $now();
		} while (n - d < millis);
	}
};

//-- HTML/XML --//
zk.encodeXML = function (txt, multiline) {
	var out = "";
	if (txt)
		for (var j = 0, tl = txt.length; j < tl; ++j) {
			var cc = txt.charAt(j);
			switch (cc) {
			case '<': out += "&lt;"; break;
			case '>': out += "&gt;"; break;
			case '&': out += "&amp;"; break;
			case '"': out += "&quot;"; break;
			case '\n':
				if (multiline) {
					out += "<br/>";
					break;
				}
			default:
				out += cc;
			}
		}
	return out
};

//-- debug --//
/** Generates a message for debugging. */
zk.message = function () {
	var msg = "", a = arguments;
	if (a.length > 1) {
		for (var i = 0, len = a.length; i < len; i++)
			msg += "[" + a[i] + "] ";
	} else msg = arguments[0];
	zk._msg = zk._msg ? zk._msg + msg: msg;
	zk._msg +=  '\n';
	setTimeout(zk._domsg, 600);
		//for better performance and less side effect, execute later
};
zk._domsg = function () {
	if (zk._msg) {
		var console = $e("zk_msg");
		if (!console) {
			console = document.createElement("DIV");
			document.body.appendChild(console);
			var html = '<div id="zk_debugbox" class="debugbox" style="visibility:hidden">'
+'<table cellpadding="0" cellspacing="0" width="100%"><tr>'
+'<td width="20pt"><button onclick="zk._msgclose(this)">close</button><br/>'
+'<button onclick="$e(\'zk_msg\').value = \'\'">clear</button></td>'
+'<td><textarea id="zk_msg" style="width:99%" rows="10"></textarea></td></tr></table></div>';
			zk._setOuterHTML(console, html);
			console = $e("zk_msg");
			var d = $e("zk_debugbox");
			d.style.top = zk.innerY() + zk.innerHeight() - d.offsetHeight - 20 + "px";
			d.style.left = zk.innerX() + zk.innerWidth() - d.offsetWidth - 20 + "px";
			d.style.visibility = "visible";
		}
		console.value = console.value + zk._msg + '\n';
		zk._msg = null;
	}
};
zk._msgclose = function (n) {
	while ((n = n.parentNode) != null)
		if ($tag(n) == "DIV") {
			n.parentNode.removeChild(n);
			return;
		}
};
//FUTURE: developer could control whether to turn on/off
zk.debug = zk.message;

/** Error message must be a popup. */
zk.error = function (msg) {
	if (zk.booting) {
		setTimeout(function () {zk.error(msg)}, 100);
		return;
	}

	if (!zk._errcnt) zk._errcnt = 1;
	var id = "zk_err_" + zk._errcnt++;
	var box = document.createElement("DIV");
	document.body.appendChild(box);
	var html =
 '<div style="position:absolute;z-index:99000;padding:3px;left:'
+(zk.innerX()+50)+'px;top:'+(zk.innerY()+20)
+'px;width:550px;border:1px solid #963;background-color:#fc9" id="'
+id+'"><table cellpadding="2" cellspacing="2" width="100%"><tr valign="top">'
+'<td width="20pt"><button onclick="zkau.sendRedraw()">redraw</button>'
+'<button onclick="zk._msgclose(this)">close</button></td>'
+'<td style="border:1px inset">'+zk.encodeXML(msg, true) //Bug 1463668: security
+'</td></tr></table></div>';
	zk._setOuterHTML(box, html);
	box = $e(id); //we have to retrieve back

	try {
		new Draggable(box, {
			handle: box, zindex: box.style.zIndex,
			starteffect: zk.voidf, starteffect: zk.voidf, endeffect: zk.voidf});
	} catch (e) {
	}
};
/** Closes all error box (zk.error).
 * @since 3.0.6
 */
zk.errorDismiss = function () {
	for (var j = zk._errcnt; j; --j)
		zk.remove($e("zk_err_" + j));
};

//-- bootstrapping --//
zk.loading = 0;
zk._modules = {}; //Map(String nm, boolean loaded)
zk._initfns = []; //used by addInit
zk._initids = {};
zk._inLatfns = []; //used by addInitLater
zk._inLatids = {};
zk._bfinits = []; //used by addBeforeInit
zk._cufns = []; //used by addCleanup
zk._cuids = {};
zk._cuLatfns = []; //used by addCleanupLater
zk._cuLatids = {};
zk._bfunld = []; //used by addBeforeUnload
zk._initcmps = []; //comps to init
zk._ckfns = []; //functions called to check whether a module is loaded (zk._load)
zk._visicmps = []; //an array of component's ID that requires zkType.onVisi; the child is in front of the parent
zk._hidecmps = []; //an array of component's ID that requires zkType.onHide; the child is in front of the parent
zk._szcmps = []; //an array of component's ID that requires zkType.onSize; the child is in front of the parent
zk._bfszcmps = []; //an array of component's ID that requires zkType.beforeSize; the child is in front of the parent
zk._scrlcmps = []; //an array of component's ID that requires zkType.onScroll; the child is in front of the parent
zk._tszcmps = [], zk._tbfszcmps = [], zk._tscrlcmps = [],
zk._tvisicmps = [], zk._thidecmps = []; //temporary array
function myload() {
	var f = zk._onload;
	if (f) {
		zk._onload = null; //called only once
		f();
	}
}
zk._onload = function () {
	//It is possible to move javascript defined in zul's language.xml
	//However, IE has bug to order JavaScript properly if zk._load is used
	zk.progress(600);
	zk.addInitLater(zk.progressDone);
	zk.addInitLater(function() {zk.booting = false;});
	zk.initAt(document.body);
};

//Source: http://dean.edwards.name/weblog/2006/06/again/
if (zk.ie && !zk.https()) {
	//IE consider the following <script> insecure, so skip is https
	document.write('<script id="_zie_load" defer src="javascript:void(0)"><\/script>');
	var e = $e("_zie_load");
	e.onreadystatechange = function() {
		if ("complete" == this.readyState) //don't check loaded!
	        myload(); // call the onload handler
	};
	e.onreadystatechange();
} else if (zk.safari) {
    var timer = setInterval(function() {
		if (/loaded|complete/.test(document.readyState)) {
			clearInterval(timer);
			delete timer;
			myload();
		}
	}, 10);
} else {
	//Bug 1619959: FF not always fire DOMContentLoaded (such as in 2nd iframe),
	//so we have to use onload in addition to register DOMContentLoaded
	if (zk.gecko)
		zk.listen(document, "DOMContentLoaded", myload)

	zk._oldOnload = window.onload;
	window.onload = function () {
		myload();
		if (zk._oldOnload)
			zk._oldOnload.apply(window, arguments);
	}
}
} //if (!window.zk)

/* mesg.js "charset=utf-8"

{{IS_NOTE
	Purpose:
		Locale dependent message
	Description:
		
	History:
		Fri Jun 10 15:56:48     2005, Created by tomyeh
}}IS_NOTE

Copyright (C) 2005 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under GPL Version 2.0 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
mesg = {};
mesg.NOT_FOUND = "Not found: ";
mesg.UNSUPPORTED = "Not supported yet: ";
mesg.FAILED_TO_SEND = "Failed to send requests to server.";
mesg.FAILED_TO_RESPONSE = "The server is temporarily out of service.";
mesg.TRY_AGAIN = "Would you like to try again?";
mesg.UNSUPPORTED_BROWSER = "Unsupported browser: ";
mesg.ILLEGAL_RESPONSE = "Unknown response sent from the server. Please reload and try again.\n";
mesg.FAILED_TO_PROCESS = "Failed to process ";
mesg.UUID_REQUIRED = "UUID is required";
mesg.INVALID_STRUCTURE = "Invalid structure: ";
mesg.COMP_OR_UUID_REQUIRED = "Component or its UUID is required";
mesg.NUMBER_REQUIRED = "You must specify a number, rather than ";
mesg.INTEGER_REQUIRED = "You must specify an integer, rather than ";
mesg.EMPTY_NOT_ALLOWED = "Empty is not allowed.\nYou cannot specify nothing but spaces, either";
mesg.GOTO_ERROR_FIELD = "Go to the wrong field";
mesg.PLEASE_WAIT = "Processing...";
mesg.VALUE_NOT_MATCHED = "You must specify one of values in the drop-down list.";

mesg.FILE_SIZE = "File size: ";
mesg.KBYTES = "KB";

mesg.CANCEL="Cancel";

mesg.FAILED_TO_LOAD = "Failed to load ";
mesg.FAILED_TO_LOAD_DETAIL = "It may be caused by bad traffic. You could reload this page and try again.";
mesg.CAUSE = "Cause: ";

/* common.js

{{IS_NOTE
	Purpose:
		Common utiltiies.
	Description:
		
	History:
		Fri Jun 10 18:16:11     2005, Created by tomyeh
}}IS_NOTE

Copyright (C) 2005 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under GPL Version 2.0 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
if (!window.anima) { //avoid eval twice

// Standard //
String.prototype.startsWith = function (prefix) {
	return this.substring(0,prefix.length) == prefix;
};
String.prototype.endsWith = function (suffix) {
	return this.substring(this.length-suffix.length) == suffix;
};
String.prototype.trim = function () {
	var j = 0, tl = this.length, k = tl - 1;
	while (j < tl && this.charAt(j) <= ' ')
		++j;
	while (k >= j && this.charAt(k) <= ' ')
		--k;
	return j > k ? "": this.substring(j, k + 1);
};
String.prototype.skipWhitespaces = function (j) {
	for (var tl = this.length;j < tl; ++j) {
		var cc = this.charAt(j);
		if (cc != ' ' && cc != '\t' && cc != '\n' && cc != '\r')
			break;
	}
	return j;
};
String.prototype.nextWhitespace = function (j) {
	for (var tl = this.length;j < tl; ++j) {
		var cc = this.charAt(j);
		if (cc == ' ' || cc == '\t' || cc == '\n' || cc == '\r')
			break;
	}
	return j;
};

/** Removes the specified object from the array if any.
 * Returns false if not found.
 */
Array.prototype.remove = function (o) {
	for (var j = 0, tl = this.length; j < tl; ++j) {
		if (o == this[j]) {
			this.splice(j, 1);
			return true;
		}
	}
	return false;
};
/** Returns whether the array contains the specified object.
 */
Array.prototype.contains = function (o) {
	for (var j = 0, tl = this.length; j < tl; ++j) {
		if (o == this[j])
			return true;
	}
	return false;
};

////
//Form//
function z_fmsubm(a, b, c) {
	var fns = this._submfns;
	for (var j = 0, fl = (fns ? fns.length: 0); j < fl; ++j)
		fns[j].apply(this, arguments);
	return this._ogsubm(a, b, c);
		//If IE, we cannot use _ogsubm.apply. Reason unknown.
};
if (zk.ie) {
	zk.fixSubmit = function (n) {
		n._ogsubm = n.submit;
		n.submit = z_fmsubm;
	}

	//Step 1. Override document.createElement
	zk._newElem = document.createElement;
	document.createElement = function (tag) {
		var n = zk._newElem(tag);
			//we cannot use zk._newElem.apply. Reason unknown.
		if (tag.toUpperCase() == "FORM")
			zk.fixSubmit(n);
		return n;
	};

	//Step 2: HTC (http://delete.me.uk/2004/09/addbehaviour.html)
	//Due to performance issue and unable to really make it work
	//we change submit in zk.init

} else {
	HTMLFormElement.prototype._ogsubm = HTMLFormElement.prototype.submit;
	HTMLFormElement.prototype.submit = z_fmsubm;
}

//////
// More zk utilities (defined also in boot.js) //
/** Override a method of the specified object.
 *
 * Example:
zk.override(zkau.cmd1, "outer", mine, function (uuid, cmp, html) {
	mine.outer(uuid, cmp, html);
});
 *
 * @param obj the object containing the method
 * @param fn the method name
 * @param supobj the object to have the super method (i.e., previous method)
 * @since 3.0.5
 */
zk.override = function (obj, fn, supobj, func) {
	supobj[fn] = obj[fn];
	obj[fn] = func;
};

/**
 * Fixs the layout position of the element when the style of element is "overflow:hidden" or
 * "position:relative" in IE. Because, sometimes the layout position of the element
 * will be gone or go away its original place. 
 * @param {Object} el
 * @since 3.0.5
 */
zk.fixOverflow = zk.ie ? function (el){
	if (el) {
		var of = el.style.overflow;
		el.style.overflow = "hidden";
		if(el.offsetWidth){} // this is a trick to re-calc
		el.style.overflow = of;
	}
}: zk.voidf;
/**
 * Redraws the all node tree.
 * @since 3.0.4
 */
zk.redraw = function (cmp) {
	if (cmp) {
		cmp = $outer(cmp);
		zkau.cmd1.outer(cmp.id, cmp, zk.getOuterHTML(cmp));
	}
};
/**
 * Returns the outerHTML of the element.
 * @since 3.0.4
 */
zk.getOuterHTML = function (cmp) {
	if (cmp.outerHTML) return cmp.outerHTML;
	var div = document.createElement("DIV");
	var clone = cmp.cloneNode(true);
	div.appendChild(clone);
	return div.innerHTML;
}
/** To prevent onblur if alert is shown.
 * Note: browser will change the focus back, so it is safe to ingore.
 * @since 3.0.5
 */
zk.alert = function (msg) {
	zk.alerting = true;
	try {
		alert(msg);
	} finally {
		zk.alerting = false;
	}
};
/** To confirm the user for an activity.
 * @since 3.0.6
 */
zk.confirm = function (msg) {
	zk.alerting = true;
	try {
		return confirm(msg);
	} finally {
		zk.alerting = false;
	}
};

/** Returns whether it is part of the class name
 * of the specified element.
 */
zk.hasClass = function (el, clsnm) {
	var cn = el.className;
	return cn && (' '+cn+' ').indexOf(' '+clsnm+' ') != -1;
};

/** Adds the specified class name to the class name of the specified element.
 * @since 3.0.0
 */
zk.addClass = function (el, clsnm, bAdd) {
	if (bAdd == false) {
		zk.rmClass(el, clsnm);
		return;
	}

	if (!zk.hasClass(el, clsnm)) {
		var cn = el.className;
		if (cn.length) cn += ' ';
		el.className = cn + clsnm;
	}
};
/** Removes the specified class name from the the class name of the specified
 * element.
 * @since 3.0.0
 */
zk.rmClass = function (el, clsnm, bRemove) {
	if (bRemove == false) {
		zk.addClass(el, clsnm);
		return;
	}

	if (zk.hasClass(el, clsnm)) {
    	var re = new RegExp('(?:^|\\s+)' + clsnm + '(?:\\s+|$)', "g");
        el.className = el.className.replace(re, " ");            
	}
};

/** Sets the offset height. */
zk.setOffsetHeight = function (el, hgh) {
	hgh = hgh
		- $int(Element.getStyle(el, "padding-top"))
		- $int(Element.getStyle(el, "padding-bottom"))
		- $int(Element.getStyle(el, "margin-top"))
		- $int(Element.getStyle(el, "margin-bottom"))
		- $int(Element.getStyle(el, "border-top-width"))
		- $int(Element.getStyle(el, "border-bottom-width"));
	el.style.height = (hgh > 0 ? hgh: 0) + "px";
};

/** Return el.offsetWidth, which solving Safari's bug. */
zk.offsetWidth = function (el) {
	if (!el) return 0;
	if (!zk.safari || $tag(el) != "TR") return el.offsetWidth;

	var wd = 0;
	for (var j = el.cells.length; --j >= 0;)
		wd += el.cells[j].offsetWidth;
	return wd;
};
/** Return el.offsetHeight, which solving Safari's bug. */
zk.offsetHeight = function (el) {
	if (!el) return 0;
	if (!zk.safari || $tag(el) != "TR") return el.offsetHeight;

	var hgh = 0;
	for (var j = el.cells.length; --j >= 0;) {
		var h = el.cells[j].offsetHeight;
		if (h > hgh) hgh = h;
	}
	return hgh;
};
/** Returns el.offsetTop, which solving Safari's bug. */
zk.offsetTop = function (el) {
	if (!el) return 0;
	if (zk.safari && $tag(el) === "TR" && el.cells.length)
		el = el.cells[0];
	return el.offsetTop;
};
/** Returns el.offsetLeft, which solving Safari's bug. */
zk.offsetLeft = function (el) {
	if (!el) return 0;
	if (zk.safari && $tag(el) === "TR" && el.cells.length)
		el = el.cells[0];
	return el.offsetLeft;
};
zk.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
zk.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
/** Returns the summation of the specified styles.
 *  For example,
 *  zk.sumStyles(el, "lr", zk.paddings) sums the style values of
 * zk.paddings['l'] and zk.paddings['r'].
 *
 * @param {String} areas the areas is abbreviation for left "l", right "r", top "t", and bottom "b".
 * So you can specify to be "lr" or "tb" or more.
 * @param styles {zk.paddings} or {zk.borders}. 
 * @return {Number}
 * @since 3.0.0
 */
zk.sumStyles = function (el, areas, styles) {
	var val = 0;
    for (var i = 0, l = areas.length; i < l; i++){
		 var w = $int(Element.getStyle(el, styles[areas.charAt(i)]));
         if (!isNaN(w)) val += w;
    }
    return val;
};
/**
 * Returns the revised size, which subtracted the size of its CSS border or padding, for the specified element.
 * @param {Number} size original size of the specified element. 
 * @param {Boolean} isHgh if true it will be "tb" top and bottom.
 * @return {Number}
 * @since 3.0.0
 */
zk.revisedSize = function (el, size, isHgh) {
	var areas = "lr";
	if (isHgh) areas = "tb";
    size -= (zk.sumStyles(el, areas, zk.borders) + zk.sumStyles(el, areas, zk.paddings));
    if (size < 0) size = 0;
	return size;
};
/**
 * Returns the revised position, which subtracted the offset of its scrollbar,
 * for the specified element.
 * @param {Object} el
 * @param {Array} ofs [left, top];
 * @return {Array} [left, top];
 * @since 3.0.0
 */
zk.revisedOffset = function (el, ofs) {
	if(!ofs) {
		if (el.getBoundingClientRect){ // IE and FF3
			var b = el.getBoundingClientRect();
			return [b.left + zk.innerX() - el.ownerDocument.documentElement.clientLeft,
				b.top + zk.innerY() - el.ownerDocument.documentElement.clientTop];
			// IE adds the HTML element's border, by default it is medium which is 2px
			// IE 6 and 7 quirks mode the border width is overwritable by the following css html { border: 0; }
			// IE 7 standards mode, the border is always 2px
			// This border/offset is typically represented by the clientLeft and clientTop properties
			// However, in IE6 and 7 quirks mode the clientLeft and clientTop properties are not updated when overwriting it via CSS
			// Therefore this method will be off by 2px in IE while in quirksmode
		}
		ofs = Position.cumulativeOffset(el);
	}
	var scrolls = Position.realOffset(el);
	scrolls[0] -= zk.innerX(); scrolls[1] -= zk.innerY(); 
	return [ofs[0] - scrolls[0], ofs[1] - scrolls[1]];
};
if (zk.safari) {
	//fix safari's bug
	zk._oldposofs = Position.positionedOffset;
	Position.positionedOffset = function (el) {
		if ($tag(el) === "TR" && el.cells.length)
			el = el.cells[0];
		return zk._oldposofs(el);
	};
}
if (zk.gecko || zk.safari) {
	zk._oldcumofs = Position.cumulativeOffset;
	Position.cumulativeOffset = function (el) {
		//fix safari's bug: TR has no offsetXxx
		if (zk.safari && $tag(el) === "TR" && el.cells.length)
			el = el.cells[0];

		//fix gecko and safari's bug: if not visible before, offset is wrong
		var ofs;
		if (!$visible(el) && !zk.offsetWidth(el)) {
			el.style.display = "";
			ofs = zk._oldcumofs(el);
			el.style.display = "none";
		} else {
			ofs = zk._oldcumofs(el);
		}
		return ofs;
	};
}

/** Center the specified element.
 * @param flags a combination of center, left, right, top and bottom.
 * If omitted, center is assigned.
 */
zk.center = function (el, flags) {
	var wdgap = zk.offsetWidth(el),
		hghgap = zk.offsetHeight(el);

	if ((!wdgap || !hghgap) && !$visible(el)) {
		el.style.top = "-10000px"; //avoid annoying effect
		el.style.display = "block"; //we need to calculate the size
		wdgap = zk.offsetWidth(el);
		hghgap = zk.offsetHeight(el),
		el.style.display = "none"; //avoid Firefox to display it too early
	}

	var left = zk.innerX(), top = zk.innerY();
	var x, y, skipx, skipy;

	wdgap = zk.innerWidth() - wdgap;
	if (!flags) x = left + wdgap / 2;
	else if (flags.indexOf("left") >= 0) x = left;
	else if (flags.indexOf("right") >= 0) x = left + wdgap - 1; //just in case
	else if (flags.indexOf("center") >= 0) x = left + wdgap / 2;
	else {
		x = 0; skipx = true;
	}

	hghgap = zk.innerHeight() - hghgap;
	if (!flags) y = top + hghgap / 2;
	else if (flags.indexOf("top") >= 0) y = top;
	else if (flags.indexOf("bottom") >= 0) y = top + hghgap - 1; //just in case
	else if (flags.indexOf("center") >= 0) y = top + hghgap / 2;
	else {
		y = 0; skipy = true;
	}

	if (x < left) x = left;
	if (y < top) y = top;
	
	var ofs = zk.toStyleOffset(el, x, y);	
	
	if (!skipx) el.style.left = ofs[0] + "px";
	if (!skipy) el.style.top =  ofs[1] + "px";
};
/** Returns the width and height.
 * In additions, it fixes brwoser's bugs, so call it as soon as possible.
 */
zk.getDimension = function (el) {
	var wd = zk.offsetWidth(el), hgh;
	if (!$visible(el) && !wd) {
		var fixleft = el.style.left == "" || el.style.left == "auto";
		if (fixleft) el.style.left = "0";
		var fixtop = el.style.top == "" || el.style.top == "auto";
		if (fixtop) el.style.top = "0";
			//IE6/gecko: otherwise, cumulativeOffset is wrong

		el.style.display = "";
		wd = zk.offsetWidth(el);
		hgh = zk.offsetHeight(el);
		el.style.display = "none";

		if (fixleft) el.style.left = "";
		if (fixtop) el.style.top = "";
	} else {
		hgh = zk.offsetHeight(el);
	}
	return [wd, hgh];
};
/** Position a component being releted to another. */
zk.position = function (el, ref, type) {
	var refofs = zk.getDimension(el);
	var wd = refofs[0], hgh = refofs[1];
	refofs = zk.revisedOffset(ref); 
	
	var x, y;
	var scx = zk.innerX(), scy = zk.innerY(),
		scmaxx = scx + zk.innerWidth(), scmaxy = scy + zk.innerHeight();

	if (type == "end_before") { //el's upper-left = ref's upper-right
		x = refofs[0] + zk.offsetWidth(ref);
		y = refofs[1];

		if (zk.ie) {
			var diff = $int(Element.getStyle(ref, "margin-top"));
			if (!isNaN(diff)) y += diff;
			diff = $int(Element.getStyle(ref, "margin-right"));
			if (!isNaN(diff)) x += diff;
		}

		if (x + wd > scmaxx)
			x = refofs[0] - wd;
		if (y + hgh > scmaxy)
			y = scmaxy - hgh;
	} else { //after-start: el's upper-left = ref's lower-left
		x = refofs[0];
		y = refofs[1] + zk.offsetHeight(ref);

		if (zk.ie) {
			var diff = $int(Element.getStyle(ref, "margin-bottom"));
			if (!isNaN(diff)) y += diff;
			diff = $int(Element.getStyle(ref, "margin-left"));
			if (!isNaN(diff)) x += diff;
		}

		if (y + hgh > scmaxy)
			y = refofs[1] - hgh;
		if (x + wd > scmaxx)
			x = scmaxx - wd;
	}

	if (x < scx) x = scx;
	if (y < scy) y = scy;
	refofs = zk.toStyleOffset(el, x, y);
	el.style.left = refofs[0] + "px"; el.style.top = refofs[1] + "px";
};

/** Returns the maximal allowed height of the specified element.
 * In other words, it is the client height of the parent minus all sibling's.
 * @since 3.0.3
 */
zk.getVflexHeight = function (el) {
	var hgh = el.parentNode.clientHeight;
	if (zk.ie6Only) { //IE6's clientHeight is wrong
		var ref = el.parentNode;
		var h = ref.style.height;
		if (h && h.endsWith("px")) {
			h = zk.revisedSize(ref, $int(h), true);
			if (h && h < hgh) hgh = h;
		}
	}

	for (var p = el, q; q = p.previousSibling;) {
		if (q.offsetHeight && $visible(q)) hgh -= q.offsetHeight; //may undefined
		p = q;
	}
	for (var p = el, q; q = p.nextSibling;) {
		if (q.offsetHeight && $visible(q)) hgh -= q.offsetHeight; //may undefined
		p = q;
	}
	return hgh;
};

/** Returns the style's coordination in [integer, integer].
 * Note: it ignores the unit and assumes px (so pt or others will be wrong)
 */
zk.getStyleOffset = function (el) {
	return [$int(el.style.left), $int(el.style.top)];
};
/** Converts from absolute coordination to style's coordination.
 * It is only useful for table's cell.
 * We cannot use zk.toParentCoord, because
 * after calling Draggable, offsetParent becomes BODY but
 * style.left/top is still relevant to original offsetParent
 */
zk.toStyleOffset = function (el, x, y) {
	var oldx = el.style.left, oldy = el.style.top;
	if (zk.opera || zk.air) {
		//Opera:
		//1)we have to reset left/top. Or, the second call position wrong
		//test case: Tooltips and Popups
		//2)we cannot assing "", either
		//test case: menu
		el.style.left = el.style.top = "0";
	} else {
		//IE/gecko fix: otherwise, zk.toStyleOffset won't correct
		if (el.style.left == "" || el.style.left == "auto") el.style.left = "0";
		if (el.style.top == "" || el.style.top == "auto") el.style.top = "0";
	}

	var ofs1 = Position.cumulativeOffset(el);
	var ofs2 = zk.getStyleOffset(el);
	ofs1 = [x - ofs1[0] + ofs2[0], y  - ofs1[1] + ofs2[1]];
	el.style.left = oldx;
	el.style.top = oldy;
	return ofs1;
};

/** Whether el1 and el2 are overlapped. */
zk.isOverlapped = function (el1, el2) {
	return zk.isOffsetOverlapped(
		Position.cumulativeOffset(el1), [el1.offsetWidth, el1.offsetHeight],
		Position.cumulativeOffset(el2), [el2.offsetWidth, el2.offsetHeight]);
};
/** Whether ofs1/dim1 is overlapped with ofs2/dim2. */
zk.isOffsetOverlapped = function (ofs1, dim1, ofs2, dim2) {
	var o1x1 = ofs1[0], o1x2 = dim1[0] + o1x1,
		o1y1 = ofs1[1], o1y2 = dim1[1] + o1y1;
	var o2x1 = ofs2[0], o2x2 = dim2[0] + o2x1,
		o2y1 = ofs2[1], o2y2 = dim2[1] + o2y1;
	return o2x1 <= o1x2 && o2x2 >= o1x1 && o2y1 <= o1y2 && o2y2 >= o1y1;
};

/** Whether an element is really visible.
 * @param {Boolean} strict if true, it also checks the visibility property.(since 3.0.4)
 */
zk.isRealVisible = function (e, strict) {
	if (!e) return false;
	do {
		if (!$visible(e, strict)) return false;
		//note: document is the top parent and has NO style
	} while (e = $parent(e)); //yes, assign
	return true;
};
zk.isVisible = $visible; //backward compatible

/** Focus the specified element and any of its child. */
zk.focusDown = function (el) {
	return zk._focusDown(el, ["INPUT", "SELECT", "BUTTON"], true)
		|| zk._focusDown(el, ["A"], false);
};
/** checkA whether to check the A tag specially (i.e., focus if one ancestor
 * has z.type).
 */
zk._focusDown = function (el, match, checkA) {
	if (!el) return false;
	if (el.focus) {
		var tn = $tag(el);
		if (match.contains(tn)) {
			zk.focus(el);
			return true;
		}
		if (checkA && tn == "A") {
			for (var n = el; (n = $parent(n))/*yes, assign*/;) {
				if (getZKAttr(n, "type")) {
					zk.focus(el);
					return true;
				}
			}
		}
	}
	for (el = el.firstChild; el; el = el.nextSibling) {
		if (zk._focusDown(el, match))
			return true;
	}
	return false;
};
/** Focus the element with the specified ID and do it timeout later. */
zk.asyncFocusDown = function (id, timeout) {
	++zk.inAsyncFocus;
	setTimeout("--zk.inAsyncFocus; if (!zk.focusDown($e('"+id+"'))) window.focus();",
		timeout > 0? timeout: 0);
};
/** Focus the element without looking down, and do it timeout later. */
zk.asyncFocus = function (id, timeout) {
	++zk.inAsyncFocus;
	setTimeout("--zk.inAsyncFocus; zk.focus($e('"+id+"'));",
		timeout > 0? timeout: 0);
		//Workaround for an IE bug: we have to set focus twice since
		//the first one might fail (even we prolong the timeout to 1 sec)
};
zk.inAsyncFocus = 0;

/** Focus to the specified component w/o throwing exception. */
zk.focus = function (cmp) {
	if (cmp && cmp.focus)
		try {
			cmp.focus();
		} catch (e) {
			setTimeout(function() {
				try {
					cmp.focus();
				} catch (e) {
					setTimeout(function() {try {cmp.focus();} catch (e) {}}, 100);
				}
			}, 0);
		}
		//IE throws exception if failed to focus in some cases
};

/** Select the text of the element, and do it timeout later. */
zk.asyncSelect = function (id, timeout) {
	++zk.inAsyncSelect;
	setTimeout("--zk.inAsyncSelect; zk.select($e('"+id+"'));",
		timeout > 0? timeout: 0);
};
zk.inAsyncSelect = 0;

/** Select to the specified component w/o throwing exception. */
zk.select = function (cmp) {
	if (cmp && cmp.select)
		try {
			cmp.select();
		} catch (e) {
			setTimeout(function() {
				try {cmp.select();} catch (e) {}
			}, 0);
		}
		//IE throws exception when focus() in some cases
};

/** Returns the selection range of the specified control.
 * Note: if the function occurs some error, it always return [0, 0];
 */
zk.getSelectionRange = function(inp) {	
	try {
		if (document.selection != null && inp.selectionStart == null) { //IE		
			var range = document.selection.createRange(); 
			var rangetwo = inp.createTextRange(); 
			var stored_range = ""; 
			if(inp.type.toLowerCase() == "text"){
				stored_range = rangetwo.duplicate();
			}else{
				 stored_range = range.duplicate(); 
				 stored_range.moveToElementText(inp); 
			}
			stored_range.setEndPoint('EndToEnd', range); 
			var start = stored_range.text.length - range.text.length;			
			return [start, start + range.text.length];
		} else { //Gecko
			return [inp.selectionStart, inp.selectionEnd];
		}
	} catch (e) {
		return [0, 0];
	}
}

/** Inserts a node after another.
 */
zk.insertAfter = function (el, ref) {
	var sib = ref.nextSibling;
	if (sib) ref.parentNode.insertBefore(el, sib);
	else ref.parentNode.appendChild(el);
};
/** Inserts a node before another.
 */
zk.insertBefore = function (el, ref) {
	ref.parentNode.insertBefore(el, ref);
};
/** Inserts an unparsed HTML immediately before the specified element.
 * @param el the sibling before which to insert
 */
zk.insertHTMLBefore = function (el, html) {
	if (zk.ie || zk.opera) {
		switch ($tag(el)) { //exclude TABLE
		case "TD": case "TH": case "TR": case "CAPTION": case "COLGROUP":
		case "TBODY": case "THEAD": case "TFOOT":
			var ns = zk._tblCreateElements(html);
			var p = el.parentNode;
			for (var j = 0, nl = ns.length; j < nl; ++j)
				p.insertBefore(ns[j], el);
			return;
		}
	}
	el.insertAdjacentHTML('beforeBegin', html);
};
/** Inserts an unparsed HTML immediately before the ending element.
 */
zk.insertHTMLBeforeEnd = function (el, html) {
	if (zk.ie || zk.opera) {
		var tn = $tag(el);
		switch (tn) {
		case "TABLE": case "TR":
		case "TBODY": case "THEAD": case "TFOOT": case "COLGROUP":
		/*case "TH": case "TD": case "CAPTION":*/ //no need to handle them
			var ns = zk._tblCreateElements(html);
			if (tn == "TABLE" && ns.length && $tag(ns[0]) == "TR") {
				var bd = el.tBodies;
				if (!bd || !bd.length) {
					bd = document.createElement("TBODY");
					el.appendChild(bd);
					el = bd;
				} else {
					el = bd[bd.length - 1];
				}
			}
			for (var j = 0, nl = ns.length; j < nl; ++j)
				el.appendChild(ns[j]);
			return;
		}
	}
	el.insertAdjacentHTML("beforeEnd", html);
};
/** Inserts an unparsed HTML immediately after the specified element.
 * @param el the sibling after which to insert
 */
zk.insertHTMLAfter = function (el, html) {
	if (zk.ie || zk.opera) {
		switch ($tag(el)) { //exclude TABLE
		case "TD": case "TH": case "TR": case "CAPTION":
		case "TBODY": case "THEAD": case "TFOOT":
		case "COLGROUP": case "COL":
			var ns = zk._tblCreateElements(html);
			var sib = el.nextSibling;
			var p = el.parentNode;
			for (var j = 0, nl = ns.length; j < nl; ++j)
				if (sib != null) p.insertBefore(ns[j], sib);
				else p.appendChild(ns[j]);
			return;
		}
	}
	el.insertAdjacentHTML('afterEnd', html);
};

/** Sets the inner HTML.
 */
zk.setInnerHTML = function (el, html) {
	if (zk.ie || zk.opera) {
		var tn = $tag(el);
		if (tn == "TR" || tn == "TABLE" || tn == "TBODY" || tn == "THEAD"
		|| tn == "TFOOT" || tn == "COLGROUP" || tn == "COL") { //ignore TD/TH/CAPTION
			var ns = zk._tblCreateElements(html);
			if (tn == "TABLE" && ns.length && $tag(ns[0]) == "TR") {
				var bd = el.tBodies;
				if (!bd || !bd.length) {
					bd = document.createElement("TBODY");
					el.appendChild(bd);
					el = bd;
				} else {
					el = bd[0];
					while (el.nextSibling)
						el.parentNode.removeChild(el.nextSibling);
				}
			}
			while (el.firstChild)
				el.removeChild(el.firstChild);
			for (var j = 0, nl = ns.length; j < nl; ++j)
				el.appendChild(ns[j]);
			return;
		}
	}
	el.innerHTML = html;
};
/** Sets the outer HTML.
 */
zk.setOuterHTML = function (el, html) {
	//NOTE: Safari doesn't support __defineSetter__
	var p = el.parentNode;
	if (zk.ie || zk.opera) {
		var tn = $tag(el);
		if (tn == "TD" || tn == "TH" || tn == "TABLE" || tn == "TR"
		|| tn == "CAPTION" || tn == "TBODY" || tn == "THEAD"
		|| tn == "TFOOT" || tn == "COLGROUP" || tn == "COL") {
			var ns = zk._tblCreateElements(html);
			var sib = el.nextSibling;
			p.removeChild(el);
			for (var j = 0, nl = ns.length; j < nl; ++j)
				if (sib) p.insertBefore(ns[j], sib);
				else p.appendChild(ns[j]);
		} else {
			el.outerHTML = html;
		}
	} else {
		var r = el.ownerDocument.createRange();
		r.setStartBefore(el);
		var df = r.createContextualFragment(html);
		p.replaceChild(df, el);
	}

	for (p = p.firstChild; p; p = p.nextSibling) {
		if ($tag(p)) { //skip Text
			if (!$visible(p)) zk._hideExtr(p);
			else zk._showExtr(p);
			break;
		}
	}
};

/** Returns the next sibling with the specified tag name, or null if not found.
 */
zk.nextSibling = function (el, tagName) {
	while (el && (el = el.nextSibling) != null && $tag(el) != tagName)
		;
	return el;
};
/** Returns the next sibling with the specified tag name, or null if not found.
 */
zk.previousSibling = function (el, tagName) {
	while (el && (el = el.previousSibling) != null && $tag(el) != tagName)
		;
	return el;
};
/** Returns the parent with the specified tag name, or null if not found.
 * <p>Unlike parentByTag, the search excludes el
 */
zk.parentNode = function (el, tagName) {
	while (el && (el = $parent(el))/*yes,assign*/ && $tag(el) != tagName)
		;
	return el;
};
/** Returns the first child of the specified node. */
zk.firstChild = function (el, tagName, descendant) {
	for (var n = el.firstChild; n; n = n.nextSibling)
		if ($tag(n) == tagName)
			return n;

	if (descendant) {
		for (var n = el.firstChild; n; n = n.nextSibling) {
			var chd = zk.firstChild(n, tagName, descendant);
			if (chd)
				return chd;
		}
	}
	return null;
};

/** Returns whether a node is an ancestor of another (including itself).
 *
 * @param ckuuid whether to check UUID is the same (i.e., whether
 * they are different part of the same component).
 */
zk.isAncestor = function (p, c, ckuuid) {
	if (ckuuid && $uuid(p) == $uuid(c))
		return true;

	p = $e(p);
	c = $e(c);
	for (; c; c = $parent(c))
		if (p == c)
			return true;
	return false;
};
/** Returns whether a node is an ancestor of one of an array of elements.
 *
 * @param ckuuid whether to check UUID is the same (i.e., whether
 * they are different part of the same component).
 * @param ckowner whether to check p's owner (z.owner) (3.1.0)
 */
zk.isAncestorX = function (p, ary, ckuuid, ckowner) {
	for (var j = 0, al = ary.length; j < al; ++j)
		if (zk.isAncestor(p, ary[j], ckuuid))
			return true;

	if (ckowner) {
		var owner = $e(getZKAttr(p, "owner"));
		return owner && zk.isAncestorX(owner, ary, ckuuid, ckowner);
	}
	return false;
};
/** Returns whether any of an array of elments is an ancestor of another.
 * @since 3.0.2
 * @param ckowner whether to check c's owner (z.owner) (3.1.0)
 */
zk.isAncestorX1 = function (ary, c, ckuuid, ckowner) {
	for (var j = 0, al = ary.length; j < al; ++j)
		if (zk.isAncestor(ary[j], c, ckuuid))
			return true;

	if (ckowner) {
		var owner = $e(getZKAttr(c, "owner"));
		return owner && zk.isAncestorX1(ary, owner, ckuuid, ckowner);
	}
	return false;
};

/** Returns the enclosing tag for the specified HTML codes.
 */
zk.tagOfHtml = function (html) {
	if (!html) return "";

	var j = html.indexOf('>'), k = html.lastIndexOf('<');
	if (j < 0 || k < 0) {
		zk.error("Unknown tag: "+html);
		return "";
	}
	var head = html.substring(0, j);
	j = head.indexOf('<') + 1;
	j = head.skipWhitespaces(j);
	k = head.nextWhitespace(j);
	return head.substring(j, k).toUpperCase();
};

/** Appends an unparsed HTML immediately after the last child.
 * @param el the parent
 */
//zk.appendHTMLChild = function (el, html) {
//	el.insertAdjacentHTML('beforeEnd', html);
//};

///// fix inserting/updating TABLE/TR/TD ////
if (zk.ie || zk.opera) {
//IE don't support TABLE/TR/TD well.

//20061109: Tom M. Yeh:
//Browser: Opera:
//Issue: When append TD with insertAdjacentHTML, it creates extra sibling,
//TextNode.
//Test: Live data of listbox in ZkDEMO
	/** Creates TABLE/TD/TH/TR... with the specified HTML text.
	 *
	 * Thanks the contribution of Ilian Ianev, Barclays Global Investors,
	 * for the following fix.
	 */
	zk._tblCreateElements = function (html) {
		var level;
		html = html.trim(); //If not trim, Opera will create TextNode!
		var tag = zk.tagOfHtml(html)
		switch (tag) {
		case "TABLE":
			level = 0;
			break;
		case "TR":
			level = 2;
			html = '<table>' + html + '</table>';
			break;
		case "TH": case "TD":
			level = 3;
			html = '<table><tr>' + html + '</tr></table>';
			break;
		case "COL":
			level = 2;
			html = '<table><colgroup>'+html+'</colgroup></table>';
			break;
		default://case "THEAD": case "TBODY": case "TFOOT": case "CAPTION": case "COLGROUP":
			level = 1;
			html = '<table>' + html + '</table>';
			break;
		}

		//get the correct node
		var el = document.createElement('DIV');
		el.innerHTML = html;
		while (--level >= 0)
			el = el.firstChild;
		
		//detach from parent and return
		var ns = [];
		for (var n; n = el.firstChild;) {
			//IE creates extra tbody if add COLGROUP
			//However, the following skip is dirty-fix, assuming html doesn't
			//contain TBODY (unless it is the first tag)
			var nt = $tag(n);
			if (nt == tag || nt != "TBODY")
				ns.push(n);
			el.removeChild(n);
		}
		return ns;
	};
}

/** Returns the element's value (by catenate all CDATA and text).
 */
zk.getElementValue = function (el) {
	var txt = ""
	for (el = el.firstChild; el; el = el.nextSibling)
		if (el.data) txt += el.data;
	return txt;
};

/** Extends javascript for Non-IE
 */
if (!zk.ie && !HTMLElement.prototype.insertAdjacentHTML) {
	//insertAdjacentHTML
	HTMLElement.prototype.insertAdjacentHTML = function (sWhere, sHTML) {
		var df;   // : DocumentFragment
		var r = this.ownerDocument.createRange();

		switch (String(sWhere).toLowerCase()) {  // convert to string and unify case
		case "beforebegin":
			r.setStartBefore(this);
			df = r.createContextualFragment(sHTML);
			this.parentNode.insertBefore(df, this);
			break;

		case "afterbegin":
			r.selectNodeContents(this);
			r.collapse(true);
			df = r.createContextualFragment(sHTML);
			this.insertBefore(df, this.firstChild);
			break;

		case "beforeend":
			r.selectNodeContents(this);
			r.collapse(false);
			df = r.createContextualFragment(sHTML);
			this.appendChild(df);
			break;

		case "afterend":
			r.setStartAfter(this);
			df = r.createContextualFragment(sHTML);
			zk.insertAfter(df, this);
			break;
		}
	};
};

//-- Image utilities --//
/** Rename by changing the type (after -).
 * It works with url(/x/y.gif), too
 *url: the original URL
 *type: the type to rename to: open or closed
 *todo: support _zh_TW
*/
zk.renType = function (url, type) {
	var j = url.lastIndexOf(';');
	var suffix;
	if (j >= 0) {
		suffix = url.substring(j);
		url = url.substring(0, j);
	} else
		suffix = "";

	j = url.lastIndexOf('.');
	if (j < 0) j = url.length; //no extension at all
	var	k = url.lastIndexOf('-'),
		m = url.lastIndexOf('/'),
		ext = j <= m ? "": url.substring(j),
		pref = k <= m ? j <= m ? url: url.substring(0, j): url.substring(0, k);
	if (type) type = "-" + type;
	else type = "";
	return pref + type + ext + suffix;
};
/** Rename between / and .
 */
zk.rename = function (url, name) {
	var j = url.lastIndexOf(';');
	var suffix;
	if (j >= 0) {
		suffix = url.substring(j);
		url = url.substring(0, j);
	} else
		suffix = "";

	j = url.lastIndexOf('.');
	var k = url.lastIndexOf('/'),
		ext = j <= k ? "": url.substring(j);
	return url.substring(0, k + 1) + name + ext + suffix;
};

//-- special routines --//
if (!zk._actg1) {
	zk._actg1 = ["IFRAME","EMBED","APPLET"];
	zk._actg2 = ["A","BUTTON","TEXTAREA","INPUT"];
	if (zk.ie6Only) { //ie7 solves the z-order issue of SELECT
		zk._actg1.unshift("SELECT"); //change visibility is required
	} else
		zk._actg2.unshift("SELECT");

	zk.coveredTagnames = zk._actg1; //backward compatible 2.4 or before

	zk._disTags = []; //A list of {element: xx, what: xx}
	zk._hidCvred = []; //A list of {element: xx, visibility: xx}
}

/** Disables all active tags. */
zk.disableAll = function (parent) {
	for (var j = 0, al1 = zk._actg1.length; j < al1; j++)
		zk._dsball(parent, document.getElementsByTagName(zk._actg1[j]), true);

	if (zk.dbModal) //not disable-behind-modal
		for (var j = 0, al2 = zk._actg2.length; j < al2; j++)
			zk._dsball(parent, document.getElementsByTagName(zk._actg2[j]));
};
zk._dsball = function (parent, els, visibility) {
	l_els:
	for (var k = 0, elen = els.length; k < elen; k++) {
		var el = els[k];
		if (zk.isAncestor(parent, el))
			continue;
		for(var m = 0, dl = zk._disTags.length; m < dl; ++m) {
			var info = zk._disTags[m];
			if (info.element == el)
				continue l_els;
		}

		var tn = $tag(el), what;
		if (visibility) { //_actg1
			if (!zk.shallHideDisabled(el)) continue;

			what = el.style.visibility;
			el.style.visibility = "hidden";
		} else if (zk.gecko && tn == "A") {
//Firefox doesn't support the disable of A
			what = "h:" + zkau.getStamp(el, "tabIndex") + ":" +
				(el.tabIndex ? el.tabIndex: 0); //just in case (if null)
			el.tabIndex = -1;
		} else {
			what = "d:" + zkau.getStamp(el, "disabled") + ":" + el.disabled;
			el.disabled = true;
		}
		zk._disTags.push({element: el, what: what});
	}
};
/** Whether an element belonging to zk._disTags shall be handled.
 * @since 3.0.4
 */
zk.shallHideDisabled = function (el) {
	var tn = $tag(el);
	return (tn != "IFRAME" && tn != "EMBED" && tn != "APPLET")
		|| (getZKAttr(el, "autohide") == "true" && $visible(el, true));
};
/** Restores tags being disabled by previous disableAll. If el is not null,
 * only el's children are enabled
 */
zk.restoreDisabled = function (n) {
	var skipped = [];
	for (var bug1498895 = zk.ie, dlen = zk._disTags.length; dlen; --dlen) {
		var info = zk._disTags.shift();
		var el = info.element;
		if (el && el.tagName) { //still exists
			if (n && !zk.isAncestor(n, el)) { //not processed yet
				skipped.push(info);
				continue;
			}
			var what = info.what;
			if (what.startsWith("d:")) {
				var j = what.indexOf(':', 2);
				if (what.substring(2, j) == zkau.getStamp(el, "disabled"))
					el.disabled = what.substring(j + 1) == "true";
			} else if (what.startsWith("h:")) {
				var j = what.indexOf(':', 2);
				if (what.substring(2, j) == zkau.getStamp(el, "href"))
					el.tabIndex = what.substring(j + 1);
			} else 
				el.style.visibility = what;

			//Workaround IE: Bug 1498895
			/**if (bug1498895) { disable by the bug #1884111, 
			 // because we had the new concept that restores the previous focus, 
			 // we don't need to find which input element needs to be focused.
				var tn = $tag(el);
				if ((tn == "INPUT" && (el.type == "text" || el.type == "password"))
				||  tn == "TEXTAREA"){
				//focus only visible (to prevent scroll)
					try {
						var ofs = Position.cumulativeOffset(el);
						if (ofs[0] >= zk.innerX() && ofs[1] >= zk.innerY()
						&& (ofs[0]+20) <= (zk.innerX()+zk.innerWidth())
						&& (ofs[1]+20) <= (zk.innerY()+zk.innerHeight())) {
							el.focus();
							bug1498895 = false;
						}
					} catch (e) {
					}
				}
			}*/
		}
	}
	zk._disTags = skipped;
};
/** Hide select, iframe and applet if it is covered by any of ary
 * and not belonging to any of ary.
 * If ary is empty, it restores what have been hidden by last invocation
 * to this method.
 */
zk.hideCovered = function (ary) {
	if (!ary || ary.length == 0) {
		var hl = zk._hidCvred.length;
		while (hl) {
			var info = zk._hidCvred.shift();
			if (info.element.style)
				info.element.style.visibility = info.visibility;
			--hl;
		}
		return;
	}

	var cts = zk._actg1;
	for (var j = 0, clen = cts.length; j < clen; ++j) {
		var els = document.getElementsByTagName(cts[j]);
		loop_els:
		for (var k = 0, elen = els.length; k < elen; k++) {
			var el = els[k];
			if (!zk.isRealVisible(el)) continue;

			for (var m = 0, al = ary.length; m < al; ++m) {
				if (zk.isAncestor(ary[m], el))
					continue loop_els;
			}

			var overlapped = false;
			if (zk.shallHideDisabled(el))
				for (var m = 0, al = ary.length; m < al; ++m) {
					if (zk.isOverlapped(ary[m], el)) {
						overlapped = true;
						break;
					}
				}

			if (overlapped) {
				for (var m = 0, hl = zk._hidCvred.length; m < hl; ++m) {
					if (el == zk._hidCvred[m].element)
						continue loop_els;
				}
				zk._hidCvred
					.push({element: el, visibility: el.style.visibility});
				el.style.visibility = "hidden";
			} else {
				for (var m = 0, hl = zk._hidCvred.length; m < hl; ++m) {
					if (el == zk._hidCvred[m].element) {
						el.style.visibility = zk._hidCvred[m].visibility;
						zk._hidCvred.splice(m, 1);
						break;
					}
				}
			}
		}
	}
};

/** Retrieve a member by use of a.b.c */
zk.resolve = function (fullnm) {
	for (var j = 0, v = window;;) {
		var k = fullnm.indexOf('.', j);
		var nm = k >= 0 ? fullnm.substring(j, k): fullnm.substring(j);
		v = v[nm];
		if (k < 0 || !v) return v;
		j = k + 1;
	}
};

/** Sets the style. */
zk.setStyle = function (el, style) {
	for (var j = 0, k = 0; k >= 0; j = k + 1) {
		k = style.indexOf(';', j);
		var s = k >= 0 ? style.substring(j, k): style.substring(j);
		var l = s.indexOf(':');
		var nm, val;
		if (l < 0) {
			nm = s.trim(); val = "";
		} else {
			nm = s.substring(0, l).trim();
			val = s.substring(l + 1).trim();
		}

		if (nm) el.style[nm.camelize()] = val;
	}
};

/** Returns the text-relevant style (same as HTMLs.getTextRelevantStyle).
 * @param incwd whether to include width
 * @param inchgh whether to include height
 */
zk.getTextStyle = function (style, incwd, inchgh) {
	var ts = "";
	for (var j = 0, k = 0; k >= 0; j = k + 1) {
		k = style.indexOf(';', j);
		var s = k >= 0 ? style.substring(j, k): style.substring(j);
		var l = s.indexOf(':');
		var nm = l < 0 ? s.trim(): s.substring(0, l).trim();

		if (nm.startsWith("font")  || nm.startsWith("text")
		|| zk._txtstyles.contains(nm)
		|| (incwd && nm == "width") || (inchgh && nm == "height"))
			ts += s + ';';
	}
	return ts;
};
if (!zk._txtstyles)
	zk._txtstyles = ["color", "background-color", "background",
		"white-space"];

/** Backup a style of the specified name.
 * The second call to backupStyle is ignored until zk.restoreStyle is called.
 * Usually used with onmouseover.
 */
zk.backupStyle = function (el, nm) {
	var bknm = "zk_bk" + nm;
	if (!el.getAttribute(bknm))
		el.setAttribute(bknm, el.style[nm] || "_zk_none_");
};
/** Restore the style of the specified name.
 * Usually used with onover.
 */
zk.restoreStyle = function (el, nm) {
	if (el && el.getAttribute && el.style) { //el might be removed!
		var bknm = "zk_bk" + nm;
		var val = el.getAttribute(bknm);
		if (val) {
			el.removeAttribute(bknm);
			el.style[nm] = val == "_zk_none_" ? "": val;
		}
	}
};

/** Scroll inner into visible, assuming outer has a scrollbar. */
zk.scrollIntoView = function (outer, inner) {
	if (outer && inner) {
		var padding = $int(Element.getStyle(inner, "padding-top"));
		var limit = inner.offsetTop - padding;
		if (limit < outer.scrollTop) {
			outer.scrollTop = limit;
		} else {
			limit = 3 + inner.offsetTop + inner.offsetHeight
				- outer.scrollTop - outer.clientHeight;
			if (limit > 0) outer.scrollTop += limit;
		}
	}
};

/** Go to the specified uri.
 * @param overwrite whether to overwrite the history
 * @param target the target frame (ignored if overwrite is true
 */
zk.go = function (url, overwrite, target) {
	var bProgress = !zk.opera && !zk.keepDesktop
		&& window.location.href.indexOf('#') < 0; //whether to show progress
		//we don't show progress for opera, since user might press BACK to
		//return this page (and found the progress dlg remains on browse)
		//
		//Bug 1773575: with # and the same url, no redraw
	if (bProgress && url) {
		bProgress =	url.indexOf("://") < 0 && !url.startsWith("mailto:")
			&& !url.startsWith("javascript:") && !url.startsWith("about:");
	}
	if (!url) {
		if (bProgress) zk.progress(); //BACK button issue
		window.location.reload();
	} else if (overwrite) {
		if (bProgress) zk.progress();
		window.location.replace(url);
	} else if (target) {
		//we have to process query string because browser won't do it
		//even if we use insertHTMLBeforeEnd("<form...")
		var frm = document.createElement("FORM");
		document.body.appendChild(frm);
		var j = url.indexOf('?');
		if (j > 0) {
			var qs = url.substring(j + 1);
			url = url.substring(0, j);
			zk.queryToHiddens(frm, qs);
		}
		frm.name = "go";
		frm.action = url;
		frm.method = "GET";
		frm.target = target;
		if (url && !zk.isNewWindow(url, target) && bProgress)
			zk.progress();
		frm.submit();
	} else {
		if (bProgress) zk.progress();
		window.location.href = url;
	}
	if (bProgress) zk.progressDone(); // Bug #1843032
};
/** Tests whether a new window will be opened.
 */
zk.isNewWindow = function (url, target) {
	return url.startsWith("mailto:") || url.startsWith("javascript:")
		|| (target && target != "_self");
};

/* Convert query string (a=b&c=d) to hiddens of the specified form.
 */
zk.queryToHiddens = function (frm, qs) {
	for(var j = 0;;) {
		var k = qs.indexOf('=', j);
		var l = qs.indexOf('&', j);

		var nm, val;
		if (k < 0 || (k > l && l >= 0)) { //no value part
			nm = l >= 0 ? qs.substring(j, l): qs.substring(j);
			val = "";
		} else {
			nm = qs.substring(j, k);
			val = l >= 0 ? qs.substring(k + 1, l): qs.substring(k + 1);
		}
		zk.newHidden(nm, val, frm);

		if (l < 0) return; //done
		j = l + 1;
	}
};

/** Creates a frame if it is not created yet. */
zk.newFrame = function (name, src, style) {
	var frm = $e(name);
	if (frm) return frm;

	if (!src) src = zk.getUpdateURI('/web/img/spacer.gif');
		//IE with HTTPS: we must specify the src

	var html = '<iframe id="'+name+'" name="'+name+'" src="'+src+'"';
	if (style) html += ' style="'+style+'"';
	html += '></iframe>';
	zk.insertHTMLBeforeEnd(document.body, html);
	return $e(name);
};

/** Returns the nearest form, or null if not available.
 * @since 3.0.0
 */
zk.formOf = function (n) {
	for (; n; n = n.parentNode)
		if ($tag(n) == "FORM")
			return n;
};

/** Creates a hidden field.
 * @param parent to assign the hidden to. Ignored if null.
 * @since 3.0.0
 */
zk.newHidden = function (nm, val, parent) {
	var inp = document.createElement("INPUT");
	inp.type = "hidden";
	inp.name = nm;
	inp.value = val;
	if (parent) parent.appendChild(inp);
	return inp;
};

/** Returns the number of columns (considering colSpan)
 */
zk.ncols = function (cells) {
	var cnt = 0;
	if (cells) {
		for (var j = 0, cl = cells.length; j < cl; ++j) {
			var span = cells[j].colSpan;
			if (span >= 1) cnt += span;
			else ++cnt;
		}
	}
	return cnt;
};
/**
 * Retrieves the index of the object in the cells collection of a row.
 * Note: The function fixed the problem of IE that the cell.cellIndex returns a wrong index 
 * if there is a hidden cell in the table. So, the behavior is difference among others.
 * @param {Object} cell
 * @since 3.0.1
 */
zk.cellIndex = function (cell) {
	var i = 0; 
	if (zk.ie) {
		var cells = cell.parentNode.cells;
		for(var j = 0, cl = cells.length; j < cl; j++) {
			if (cells[j] == cell) {
				i = j;
				break;
			}
		}
	} else i = cell.cellIndex;
	return i; 
};


/** Returns the number of columns (considering colSpan)
 */
zk.ncols = function (cells) {
	var cnt = 0;
	if (cells) {
		for (var j = 0; j < cells.length; ++j) {
			var span = cells[j].colSpan;
			if (span >= 1) cnt += span;
			else ++cnt;
		}
	}
	return cnt;
};

/** Copies the width of each cell from one row to another.
 * It handles colspan of srcrows, but not dst's colspan, nor rowspan
 *
 * @param srcrows all rows from the source table. Don't pass just one row
 * because a row might not have all cells.
 */
zk.cpCellWidth = function (dst, srcrows, mate) {
	if (dst == null || srcrows == null || !srcrows.length
	|| !dst.cells || !dst.cells.length)
		return;

	var ncols = dst.cells.length; //TODO: handle colspan for dst: ncols = zk.ncols(dst.cells);
	var src, maxnc = 0, loadIdx = getZKAttr(mate.element, "lastLoadIdx");
	for (var j = 0, len = $int(loadIdx) || srcrows.length; j < len; ++j) {
		var row = srcrows[j];
		if (!zk.isVisible(row) || getZKAttr(row, "loaded") == "false") continue;
		var cells = row.cells;
		var nc = zk.ncols(cells);
		var valid = cells.length == nc && $visible(row);
			//skip with colspan and invisible
		if (valid && nc >= ncols) {
			maxnc = ncols;
			src = row;
			break;
		}
		if (nc > maxnc) {
			src = valid ? row: null;
			maxnc = nc;
		} else if (nc == maxnc && !src && valid) {
			src = row;
		}
	}
	if (!maxnc) return;

	var fakeRow = !src;
	if (fakeRow) { //the longest row containing colspan
		src = document.createElement("TR");
		src.style.height = "0px";
			//Note: we cannot use display="none" (offsetWidth won't be right)
		for (var j = 0; j < maxnc; ++j)
			src.appendChild(document.createElement("TD"));
		srcrows[0].parentNode.appendChild(src);
	}

	//we have to clean up first, since, in FF, if dst contains %
	//the copy might not be correct
	for (var j = maxnc; --j >=0;)
		dst.cells[j].style.width = "";

	var sum = 0;
	for (var j = maxnc; --j >= 0;) {
		var d = dst.cells[j], s = src.cells[j];
		if (zk.opera) {
			sum += s.offsetWidth;
			d.style.width = zk.revisedSize(s, s.offsetWidth);
		} else {
			d.style.width = s.offsetWidth + "px";
			if (maxnc > 1) { //don't handle single cell case (bug 1729739)
				var v = s.offsetWidth - d.offsetWidth;
				if (v != 0) {
					v += s.offsetWidth;
					if (v < 0) v = 0;
					d.style.width = v + "px";
				}
			}
		}
	}

	if (zk.opera && getZKAttr(mate.element, "fixed") != "true")
		dst.parentNode.parentNode.style.width = sum + "px";

	if (fakeRow)
		src.parentNode.removeChild(src);
};
//Number//
/** digits specifies at least the number of digits must be ouput. */
zk.formatFixed = function (val, digits) {
	var s = "" + val;
	for (var j = digits - s.length; --j >= 0;)
		s = "0" + s;
	return s;
};

//Date//
/** Parses a string into a Date object.
 * @param strict whether not to lenient
 */
zk.parseDate = function (txt, fmt, strict) {
	if (!fmt) fmt = "yyyy/MM/dd";
	var val = new Date();
	var y = val.getFullYear(), m = val.getMonth(), d = val.getDate();

	var ts = txt.split(/\W+/);
	for (var i = 0, j = 0, fl = fmt.length; j < fl; ++j) {
		var cc = fmt.charAt(j);
		if ((cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')) {
			var len = 1;
			for (var k = j; ++k < fl; ++len)
				if (fmt.charAt(k) != cc)
					break;

			var nosep; //no separator
			if (k < fl) {
				var c2 = fmt.charAt(k);
				nosep = c2 == 'y' || c2 == 'M' || c2 == 'd' || c2 == 'E';
			}

			var token = ts[i++];
			switch (cc) {
			case 'y':
				if (nosep) {
					if (len <= 3) len = 2;
					if (token.length > len) {
						ts[--i] = token.substring(len);
						token = token.substring(0, len);
					}
				}
				y = $int(token);
				if (isNaN(y)) return null; //failed
				if (y < 100) y += y > 29 ? 1900 : 2000;
				break;
			case 'M':
				if (len <= 2) {
					if (nosep && token.length > 2) {
						ts[--i] = token.substring(2);
						token = token.substring(0, 2);
					}
					m = $int(token) - 1;
					if (isNaN(m)) return null; //failed
				} else {
					for (var l = 0;; ++l) {
						if (l == 12) return null; //failed
						if (len == 3) {
							if (zk.SMON[l].split(/\W+/)[0] == token) {
								m = l;
								break;
							}
						} else {
							if (zk.FMON[l].split(/\W+/)[0] == token) {
								m = l;
								break;
							}
						}
					}
				}
				break;
			case 'd':
				if (nosep) {
					if (len < 2) len = 2;
					if (token.length > len) {
						ts[--i] = token.substring(len);
						token = token.substring(0, len);
					}
				}
				d = $int(token);
				if (isNaN(d)) return null; //failed
				break;
			//default: ignored
			}
			j = k - 1;
		}
	}

	var dt = new Date(y, m, d);
	if (strict) {
		if (dt.getFullYear() != y || dt.getMonth() != m || dt.getDate() != d)
			return null; //failed

		txt = txt.trim();
		txt = zk._ckDate(zk.SDOW, txt);
		txt = zk._ckDate(zk.S2DOW, txt);
		txt = zk._ckDate(zk.FDOW, txt);
		txt = zk._ckDate(zk.SMON, txt);
		txt = zk._ckDate(zk.S2MON, txt);
		txt = zk._ckDate(zk.FMON, txt);
		txt = zk._ckDate(zk.APM, txt);
		for (var j = txt.length; --j >= 0;) {
			var cc = txt.charAt(j);
			if ((cc > '9' || cc < '0') && fmt.indexOf(cc) < 0)
				return null; //failed
		}
	}
	return dt;
};
zk._ckDate = function (ary, txt) {
	if (txt.length)
		for (var j = ary.length; --j >= 0;) {
			var k = txt.indexOf(ary[j]);
			if (k >= 0)
				txt = txt.substring(0, k) + txt.substring(k + ary[j].length);
		}
	return txt;
};

/** Generates a formated string for the specified Date object. */
zk.formatDate = function (val, fmt) {
	if (!fmt) fmt = "yyyy/MM/dd";

	var txt = "";
	for (var j = 0, fl = fmt.length; j < fl; ++j) {
		var cc = fmt.charAt(j);
		if ((cc >= 'a' && cc <= 'z') || (cc >= 'A' && cc <= 'Z')) {
			var len = 1;
			for (var k = j; ++k < fl; ++len)
				if (fmt.charAt(k) != cc)
					break;

			switch (cc) {
			case 'y':
				if (len <= 3) txt += zk.formatFixed(val.getFullYear() % 100, 2);
				else txt += zk.formatFixed(val.getFullYear(), len);
				break;
			case 'M':
				if (len <= 2) txt += zk.formatFixed(val.getMonth()+1, len);
				else if (len == 3) txt += zk.SMON[val.getMonth()];
				else txt += zk.FMON[val.getMonth()];
				break;
			case 'd':
				txt += zk.formatFixed(val.getDate(), len);
				break;
			case 'E':
				if (len <= 3) txt += zk.SDOW[val.getDay()];
				else txt += zk.FDOW[val.getDay()];
				break;
			case 'D':
				txt += zk.dayInYear(val);
				break;
			case 'd':
				txt += zk.dayInMonth(val);
				break;
			case 'w':
				txt += zk.weekInYear(val);
				break;
			case 'W':
				txt += zk.weekInMonth(val);
				break;
			case 'G':
				txt += "AD";
				break;
			case 'F':
				txt += zk.dayOfWeekInMonth(val);
				break;
			default:
				txt += '1';
					//fake; SimpleDateFormat.parse might ignore it
					//However, it must be an error if we don't generate a digit
			}
			j = k - 1;
		} else {
			txt += cc;
		}
	}
	return txt;
};
/** Converts milli-second to day. */
zk.ms2day = function (t) {
	return Math.round(t / 86400000);
};
/** Day in year (starting at 1). */
zk.dayInYear = function (d, ref) {
	if (!ref) ref = new Date(d.getFullYear(), 0, 1);
	return 1 + zk.ms2day(d - ref);
};
/** Day in month (starting at 1). */
zk.dayInMonth = function (d) {
	return zk.dayInYear(d, new Date(d.getFullYear(), d.getMonth(), 1));
};
/** Week in year (starting at 1). */
zk.weekInYear = function (d, ref) {
	if (!ref) ref = new Date(d.getFullYear(), 0, 1);
	var wday = ref.getDay();
	if (wday == 7) wday = 0;
	return 1 + Math.floor((zk.ms2day(d - ref) + wday) / 7);
};
/** Week in month (starting at 1). */
zk.weekInMonth = function (d) {
	return zk.weekInYear(d, new Date(d.getFullYear(), d.getMonth(), 1));
};
/** Day of week in month. */
zk.dayOfWeekInMonth = function (d) {
	return 1 + Math.floor(zk.ms2day(d - new Date(d.getFullYear(), d.getMonth(), 1)) / 7);
};

/** Returns an integer of the attribute of the specified element. */
zk.getIntAttr = function (el, nm) {
	return $int(el.getAttribute(nm));
};

//selection//
zk.clearSelection = function(){
	try{
		if(window["getSelection"]){ 
			if(zk.safari){
				window.getSelection().collapse();
			}else{
				window.getSelection().removeAllRanges();
			}
		}else if(document.selection){
			if(document.selection.empty){
				document.selection.empty();
			}else if(document.selection.clear){
				document.selection.clear();
			}
		}
		return true;
	} catch (e){
		return false;
	}
}
/** Disable whether the specified element is selectable. */
zk.disableSelection = function (el) {
	el = $e(el);
	if (el)
		if (zk.gecko)
			el.style.MozUserSelect = "none";
		else if (zk.safari)
			el.style.KhtmlUserSelect = "none"; 
		else if (zk.ie)
			el.onselectstart = function (evt) {
				if (!evt) evt = window.event;
				var n = Event.element(evt), tag = $tag(n);
				return tag == "TEXTAREA" || tag == "INPUT" && (n.type == "text" || n.type == "password");
			};
};
/** Enables whether the specified element is selectable. */
zk.enableSelection = function (el) {
	el = $e(el);
	if (el)
		if (zk.gecko)
			el.style.MozUserSelect = ""; 
		else if (zk.safari)
			el.style.KhtmlUserSelect = "";
		else if (zk.ie)
			el.onselectstart = null;
};
/** Clears selection, if any. */
zk.clearSelection = function (){
	try {
		if (window["getSelection"]){ 
			if (zk.safari) window.getSelection().collapse();
			else window.getSelection().removeAllRanges();
		} else if (document.selection){
			if (document.selection.empty) document.selection.empty();
			else if(document.selection.clear) document.selection.clear();
		}
	} catch (e){ //ignore
	}
}


/*Float: used to be added to zkau.floats
 * Derives must provide an implementation of _close(el).
 */
zk.Float = Class.create();
zk.Float.prototype = {
	initialize: function () {
	},
	/** returns true if no float at all. */
	empty: function () {
		return !this._ftid;
	},
	/** Closes this float if the specified ID is matched.
	 * @return whether it is closed
	 */
	close: function (id) {
		if (this._ftid == id)
			this.closeFloats();
	},
	/** Closes (hides) all floats unless it is an ancestor of any of arguments.
	 * @param arguments a list of components that shall be closed
	 */
	closeFloats: function () {
		return this._closeFloats(false, zkau._shallCloseBut, arguments);
	},
	/** Closes all floats when a component is getting the focus.
	 * @param arguments a list of components that shall be closed
	 */
	closeFloatsOnFocus: function () {
		return this._closeFloats(true, zkau._shallCloseBut, arguments);
	},
	/** Closes all floats if it belongs to any of arguments.
	 * @since 3.0.2
	 */
	closeFloatsOf: function () {
		return this._closeFloats(false, zkau._shallCloseOf, arguments);
	},
	_closeFloats: function (onfocus, shallClose, ancestors) {
		if (this._ftid) {
			var n = $e(this._ftid);
			if ($visible(n) && getZKAttr(n, "animating") != "hide"
			&& (!onfocus || shallClose(n, ancestors))) {
				this._close(n);
				this._ftid = null;
				return true;
			}
		}
		return false;
	},
	/** Adds elements that we have to hide what they covers.
	 */
	addHideCovered: function (ary) {
		if (this._ftid) {
			var el = $e(this._ftid);
			if (el) ary.push(el);
		}
	},
//zk.Float doesn't support asPopup. Reason: if asPopup is true, there must
//be multiple floats, i.e., zk.Floats shall be used instead
	/** Sets the popup ID.
	 */
	setFloatId: function (id) {
		this._ftid = id;
	}
};

/*Floats: used to be added to zkau.floats
 * Derives must provide an implementation of _close(el).
 */
zk.Floats = Class.create();
zk.Floats.prototype = {
	initialize: function () {
		this._ftids = [];
		this._aspps = {}; //(id, whether a float behaves like a popup)
	},
	/** returns true if no float at all. */
	empty: function () {
		return !this._ftids.length;
	},
	/** Closes this float if the specified ID is matched.
	 * @return whether it is closed
	 */
	close: function (id) {
		for (var j = this._ftids.length; j;)
			if (this._ftids[--j] == id) {
				this.closeFloats();
				return true;
			}
		return false;
	},
	/** Closes (hides) all floats unless it is an ancestor of any of arguments.
	 * @param arguments a list of components that shall be closed
	 */
	closeFloats: function () {
		return this._closeFloats(false, zkau._shallCloseBut, arguments);
	},
	/** Closes all floats when a component is getting the focus.
	 * @param arguments a list of components that shall be closed
	 */
	closeFloatsOnFocus: function () {
		return this._closeFloats(true, zkau._shallCloseBut, arguments);
	},
	/** Closes all floats if it belongs to any of arguments.
	 * @since 3.0.2
	 */
	closeFloatsOf: function () {
		return this._closeFloats(false, zkau._shallCloseOf, arguments);
	},
	_closeFloats: function (onfocus, shallClose, ancestors) {
		var closed;
		for (var j = this._ftids.length; --j >= 0;) {
			var id = this._ftids[j];
			var n = $e(id);
			if ($visible(n) && getZKAttr(n, "animating") != "hide"
			&& ((!onfocus && !this._aspps[id]) || shallClose(n, ancestors))) {
				this._ftids.splice(j, 1);
				this._close(n);
				closed = true;
			}
		}
		return closed;
	},
	/** Adds elements that we have to hide what they covers.
	 */
	addHideCovered: function (ary) {
		for (var j = 0, fl = this._ftids.length; j < fl; ++j) {
			var el = $e(this._ftids[j]);
			if (el) ary.push(el);
		}
	},

	getFloatIds: function () {
		return this._ftids;
	},
	/** Adds the float ID.
	 *
	 * @param asPopup whether the float behaves like a popup window
	 * (i.e., it remains open if closeFloats is called due to
	 * the activities of its child),
	 * Otherwise, the float is always closed when closeFloats is called.
	 */
	addFloatId: function (id, asPopup) {
		this._ftids.push(id);
		if (asPopup) this._aspps[id] = true;
	},
	removeFloatId: function (id) {
		this._ftids.remove(id);
		delete this._aspps[id];
	}
};

//Histroy//
zk.History = Class.create();
zk.History.prototype = {
	initialize: function () {
		this.curbk = "";
		zk.addBeforeInit(function () { // Bug #1847708
			zkau.history.checkBookmark(); // We don't need to wait for the first time.
			setInterval("zkau.history.checkBookmark()", 520);
		});
			//Though IE use history.html, timer is still required 
			//because user might specify URL directly
	},
	/** Sets a bookmark that user can use forward and back buttons */
	bookmark: function (nm) {
		if (this.curbk != nm) {
			this.curbk = nm; //to avoid loop back the server
			var encnm = encodeURIComponent(nm);
			window.location.hash = zk.safari ? encnm: '#' + encnm;
			if (zk.ie /*|| zk.safari*/) this.bkIframe(nm);
		}
	},
	/** Checks whether the bookmark is changed. */
	checkBookmark: function() {
		var nm = this.getBookmark();
		if (nm != this.curbk) {
			this.curbk = nm;
			zkau.send({uuid: '', cmd: "onBookmarkChanged", data: [nm]}, 50);
		}
	},
	getBookmark: function () {
		var nm = window.location.hash;
		var j = nm.indexOf('#');
		return j >= 0 ? decodeURIComponent(nm.substring(j + 1)): '';
	}
};
if (zk.ie /*|| zk.safari*/) {
	/** bookmark iframe */
	zk.History.prototype.bkIframe = function (nm) {
		var url = zk.getUpdateURI("/web/js/zk/html/history.html", true);
		if (nm) url += '?' +encodeURIComponent(nm);

		var ifr = $e('zk_histy');
		if (ifr) {
			ifr.src = url;
		} else {
			zk.newFrame('zk_histy', url,
				/*zk.safari ? "width:0;height:0;display:inline":*/ "display:none");
		}
	};
	/** called when history.html is loaded*/
	zk.History.prototype.onHistoryLoaded = function (src) {
		var j = src.indexOf('?');
		var nm = j >= 0 ? src.substring(j + 1): '';
		window.location.hash = nm ? /*zk.safari ? nm:*/ '#' + nm: '';
		this.checkBookmark();
	};
}

/** Removes a node. */
zk.remove = function (n) {
	if (n) Element.remove(n);
};

/** An event listener that does nothing but stop event propogation.
 * @since 3.0.4
 */
zk.doEventStop = function (evt) {
	if (!evt) evt = window.event;
	Event.stop(evt);
};
/**
 * Sets the visibility property of the specified cmp.
 * @param {Boolean} alwaysAnima if true, always invoke zk.show().
 * @since 3.0.5
 */
zk.setVisible = function (cmp, visible, alwaysAnima) {
	//Bug 1896588: if cmp invisible, just don't do animation (performance in IE)
	if (alwaysAnima || zk.isRealVisible(cmp, true)) zk.show(cmp, visible);
	else if (visible) action.show(cmp);
	else action.hide(cmp);
};
////
//show & hide
/** Shows the specified element with the effect specified in conshow,
 * if any. It will call action.show if no effect is specified.
 * CSA shall not call this method. Rather, call action.show instead.
 */
zk.show = function (id, bShow) {
	if (bShow == false) {
		zk.hide(id);
		return;
	}

	var n = $e(id);
	if (n) {
		var js = getZKAttr(n, "conshow");
		if (js) {
			rmZKAttr(n, "conshow"); //avoid dead loop
			try {
				eval(js);
			} finally {
				setZKAttr(n, "conshow", js);
			}
		} else {
			action.show(n);
		}
	}
};
/** Hides the specified element with the effect specified in conhide,
 * if any. It will call action.hide if no effect is specified.
 * CSA shall not call this method. Rather, call action.hide instead.
 */
zk.hide = function (id, bHide) {
	if (bHide == false) {
		zk.show(id);
		return;
	}

	var n = $e(id);
	if (n) {
		var js = getZKAttr(n, "conhide");
		if (js) {
			rmZKAttr(n, "conhide"); //avoid dead loop
			try {
				eval(js);
			} finally {
				setZKAttr(n, "conhide", js);
			}
		} else {
			action.hide(n);
		}
	}
};
/** Shows the exterior. */
zk._showExtr = function (n) {
	if (!getZKAttr(n, "float")) {
		var ext = $e(n.id + "!chdextr");
		if (ext && "true" == getZKAttr(ext, "coexist")) {
			ext.style.display = "";
			ext = $e(n.id + "!chdextr2"); //hbox/vbox's space
			if (ext && ext.style.width != "0"
			&& ext.style.height != "0") //box use hidden to solve some browser bugs
				ext.style.display = "";
		}
	}
};
/** Hides the exterior. */
zk._hideExtr = function (n) {
	if (!getZKAttr(n, "float")) {
		var ext = $e(n.id + "!chdextr");
		if (ext && "true" == getZKAttr(ext, "coexist")) {
			ext.style.display = "none";
			ext = $e(n.id + "!chdextr2"); //hbox/vbox's space
			if (ext) ext.style.display = "none";
		}
	}
};

///////////////////
// Communication //
comm = {}
/** Sends the onClick event to the server.
 * @param cmp the component's UUID, a child element's ID (xxx!yyy),
 * or a child element
 * @param area a string to identify this click
 * @since 3.0.5
 */
comm.sendClick = function (cmp, area) {
	cmp = $outer(cmp);
	if (cmp)
		zkau.send({uuid: cmp.id, cmd: "onClick", data: [area], ctl: true});
};
/** Sends the onUser event to the server.
 * @param cmp the component's UUID, a child element's ID (xxx!yyy),
 * or a child element
 * @param arguments[1-n] data (Event.getData)
 * @since 3.0.5
 */
comm.sendUser = function (cmp) {
	cmp = $outer(cmp);
	if (cmp) {
		var len = arguments.length, data;
		if (len > 1) {
			data = [];
			for (var j = 1; j < len; ++j)
				data[j - 1] = arguments[j];
		}
		zkau.send({uuid: cmp.id, cmd: "onUser", data: data, ctl: true});
	}
};
/** Sends the specified event to the server.
 * @param cmp the component's UUID, a child element's ID (xxx!yyy),
 * or a child element
 * @param evt the event name, e.g., onMyEvent
 * @param arguments[1-n] data (Event.getData)
 * @since 3.0.5
 */
comm.sendEvent = function (cmp, evt) {
	cmp = $outer(cmp);
	if (cmp) {
		var len = arguments.length, data;
		if (len > 2) {
			data = [];
			for (var j = 2; j < len; ++j)
				data[j - 2] = arguments[j];
		}
		zkau.send({uuid: cmp.id, cmd: evt, data: data, ctl: true});
	}
};

//////////////
/// Action ///
/** Basic utilities for Client Side Action.
 */
action = {};
/** Makes a component visible.
 * @param noVisiAt whether not to call onVisiAt
 */
action.show = function (id, noVisiAt) {
	var n = $e(id);
	if (n)
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "zk.show");
		} else {
			zk._showExtr(n);  //parent visible first
			n.style.display = "";
			if (!noVisiAt && zk.isRealVisible(n)) zk.onVisiAt(n); //callback later
				//Bug 1896588: don't do onVisiAt if not visible
		}
};

/** Makes a component invisible.
 * @param noHideAt whether not to call onHideAt
 */
action.hide = function (id, noHideAt) {
	var n = $e(id);
	if (n)
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "zk.hide");
		} else {
			if (!noHideAt && zk.isRealVisible(n)) zk.onHideAt(n); //callback first
				//Bug 1896588: don't do onHideAt if not visible
			n.style.display = "none";
			zk._hideExtr(n); //hide parent later
		}
};

///////////
// anima //
/* Animation effects. It requires the component to have the <div><div>
 * structure.
 */
anima = {}
/** @since 3.0.1 */
anima.count = 0;

/** Make a component visible by increasing the opacity.
 * @param id component or its ID
 */
anima.appear = function (id, dur) {
	var n = $e(id);
	if (n) {
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "anima.appear");
		} else {
			++anima.count;
			setZKAttr(n, "animating", "show");
			zk._showExtr(n);  //parent visible first
			Effect.Appear(n, {duration:dur ? dur/1000: 0.8, afterFinish: anima._afterVisi});
		}
	}
};
/** Make a component visible by sliding down.
 * @param id component or its ID
 */
anima.slideDown = function (id, dur) {
	var n = $e(id);
	if (n) {
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "anima.slideDown");
		} else {
			++anima.count;
			setZKAttr(n, "animating", "show");
			zk._showExtr(n);  //parent visible first
			Effect.SlideDown(n, {duration:dur ? dur/1000: 0.4, afterFinish: anima._afterVisi, y :0});
				//duration must be less than 0.5 since other part assumes it
		}
	}
};
/**
 * Make a component visible by moving down.
 * @param {Object} id
 * @since 3.0.2
 */
anima.moveDown = function (id) {
	anima.moveBy(id, 'top');
};
/**
 * Make a component visible by moving right.
 * @param {Object} id
 * @since 3.0.2
 */
anima.moveRight = function (id) {
	anima.moveBy(id, 'left');
};
/**
 * Make a component visible by moving diagonal.
 * @param {Object} id
 * @since 3.0.2
 */
anima.moveDiagonal = function (id) {
	anima.moveBy(id);
};
/** Make a component visible by moving.
 * @param id component or its ID
 * @param pos the move position. "top" means from 0 to the original top, 
 *  "left" means from 0 to the original left.
 * @since 3.0.2
 */
anima.moveBy = function (id, pos, dur) {
	var n = $e(id);
	if (n) {
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "anima." + (pos == "top" ? "moveDown" : pos == "left" ? 
				"moveRight" : "moveBy"));
		} else {
			++anima.count;
			setZKAttr(n, "animating", "show");
			zk._showExtr(n);  //parent visible first
			if (!pos) pos = "topleft"
			Effect.MoveBy(n, 0, 0, {duration:dur ? dur/1000: 0.8, afterFinish: anima._afterHide, afterSetup: function(effect) {
				 if (pos.indexOf("left") > -1) {
					 effect.options.x = effect.originalLeft;
					 effect.originalLeft = 0;
				 }
				 if (pos.indexOf("top") > -1) {
					 effect.options.y = effect.originalTop;
					 effect.originalTop = 0;
				 }
     			 effect.element.show();
    		}});
		}
	}
};
/** Make a component invisible by sliding up.
 * @param id component or its ID
 */
anima.slideUp = function (id, dur) {
	var n = $e(id);
	if (n) {
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "anima.slideUp");
		} else {
			++anima.count;
			setZKAttr(n, "animating", "hide");
			zk.onHideAt(n); //callback first
			Effect.SlideUp(n, {duration:dur ? dur/1000: 0.4, afterFinish: anima._afterHide});
				//duration must be less than 0.5 since other part assumes it
		}
	}
};
/** Make a component invisible by fading it out.
 * @param id component or its ID
 */
anima.fade = function (id, dur) {
	var n = $e(id);
	if (n) {
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "anima.fade");
		} else {
			++anima.count;
			setZKAttr(n, "animating", "hide");
			zk.onHideAt(n); //callback first
			Effect.Fade(n, {duration:dur ? dur/1000: 0.55, afterFinish: anima._afterHide});
		}
	}
};
/** Make a component invisible by puffing away.
 * @param id component or its ID
 */
anima.puff = function (id, dur) {
	var n = $e(id);
	if (n) {
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "anima.puff");
		} else {
			++anima.count;
			setZKAttr(n, "animating", "hide");
			zk.onHideAt(n); //callback first
			Effect.Puff(n, {duration:dur ? dur/1000: 0.7, afterFinish: anima._afterHide0});
		}
	}
};
/** Make a component invisible by fading and dropping out.
 * @param id component or its ID
 */
anima.dropOut = function (id, dur) {
	var n = $e(id);
	if (n) {
		if (getZKAttr(n, "animating")) {
			zk._addAnique(n.id, "anima.dropOut");
		} else {
			++anima.count;
			setZKAttr(n, "animating", "hide");
			zk.onHideAt(n); //callback first
			Effect.DropOut(n, {duration:dur ? dur/1000: 0.7, afterFinish: anima._afterHide0});
		}
	}
};
anima._afterVisi = function (ef) {
	var n = ef.element;
	if (n) {
		--anima.count;
		rmZKAttr(n, "animating");
		zk.onVisiAt(n);
		zk._doAnique(n.id);
	}
};
anima._afterHide = function (ef) {
	var n = ef.element;
	if (n) {
		zk._hideExtr(n); //hide parent later
		--anima.count;
		rmZKAttr(n, "animating");
		zk._doAnique(n.id);
	}
};
anima._afterHide0 = function (ef) {
	var n = ef.effects[0].element;
	if (n) {
		zk._hideExtr(n); //hide parent later
		--anima.count;
		rmZKAttr(n, "animating");
		zk._doAnique(n.id);
	}
};

//animation queue
zk._anique = {};
	//queue for waiting animating to clear: map(id, array(js_func_name))
zk._addAnique = function(id, funcnm) {
	var ary = zk._anique[id];
	if (!ary)
		ary = zk._anique[id] = [];
	ary.push(funcnm);
};
zk._doAnique = function (id) {
	var ary = zk._anique[id];
	if (ary) {
		var n = $e(id), al = ary.length;
		while (al) {
			if (getZKAttr(n, "animating"))
				break;
			var js = ary.shift();
			eval(js+"('"+id+"')");
			al--;
		}
			
		if (!al)
			delete zk._anique[id];
	}
};

} //if (!window.anima)
/* au.js

{{IS_NOTE
	Purpose:
		JavaScript for asynchronous updates
	Description:
		
	History:
		Fri Jun 10 15:04:31     2005, Created by tomyeh
}}IS_NOTE

Copyright (C) 2005 Potix Corporation. All Rights Reserved.

{{IS_RIGHT
	This program is distributed under GPL Version 2.0 in the hope that
	it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
if (!window.zkau) { //avoid eval twice
////
//Customization
/** Returns the background color for a list item or tree item.
 * Developer can override this method by providing a different background.
 * @param e the element
 * @param undo whether to undo the effect (false to set effect)
 */
if (!window.Droppable_effect) { //define it only if not customized
	Droppable_effect = function (e, undo) {
		if (undo)
			zk.restoreStyle(e, "backgroundColor");
		else {
			zk.backupStyle(e, "backgroundColor");
			e.style.backgroundColor = "#80ADE7";			
		}
	};
}
/** Handles the error caused by processing the response.
 * @param msgCode the error message code.
 * It is either an index of mesg (e.g., "FAILED_TO_PROCESS"),
 * or an error message
 * @param msg2 the additional message (optional)
 * @param cmd the command (optional)
 * @param ex the exception (optional)
 * @since 3.0.6
 */
if (!window.onProcessError) {
	onProcessError = function (msgCode, msg2, cmd, ex) {
		var msg = mesg[msgCode];
		zk.error((msg?msg:msgCode)+'\n'+(msg2?msg2:"")+(cmd?cmd:"")+(ex?"\n"+ex.message:""));
	};
}
/** Confirms the user how to handle an error.
 * Default: it shows up a message asking the user whether to retry.
 * @since 3.0.6
 */
if (!window.confirmRetry) {
	confirmRetry = function (msgCode, msg2) {
		var msg = mesg[msgCode];
		return zk.confirm((msg?msg:msgCode)+'\n'+mesg.TRY_AGAIN+(msg2?"\n\n("+msg2+")":""));
	};
}

//au//
zkau = {};

zkau._respQue = []; //responses in XML
zkau._evts = {}; //(dtid, Array()): events that are not sent yet
zkau._js4resps = []; //JS to eval upon response
zkau._metas = {}; //(id, meta)
zkau._drags = {}; //(id, Draggable): draggables
zkau._drops = []; //dropables
zkau._zidsp = {}; //ID spaces: {owner's uuid, {id, uuid}}
zkau._stamp = 0; //used to make a time stamp
zkau.topZIndex = 12; //topmost z-index for overlap/popup/modal
zkau.floats = []; //popup of combobox, bandbox, datebox...
zkau._onsends = []; //JS called before zkau._sendNow
zkau._seqId = 1; //1-999
zkau._dtids = []; //an array of desktop IDs
zkau._uris = {}; //a map of update engine's URIs ({dtid, uri})
zkau._spushInfo = {} //the server-push info: Map(dtid, {min, max, factor})
var undef; //an undefined variable

/** Adds a desktop. */
zkau.addDesktop = function (dtid) {
	var ds = zkau._dtids;
	for (var j = ds.length; --j >= 0;)
		if (ds[j] == dtid)
			return; //nothing to do
	ds.push(dtid);
};
/** Returns the desktop's ID.
 * @param {String or Element} n the component to look for its desktop ID.
 * @since 3.0.0
 */
zkau.dtid = function (n) {
	if (zkau._dtids.length == 1) return zkau._dtids[0];

	for (n = $e(n); n; n = $parent(n)) {
		var id = getZKAttr(n, "dtid");
		if (id) return id;
	}
	return null;
};
/** Returns the URI of the update engine.
 * @since 3.0.6
 */
zkau.uri = function (dtid) {
	return zkau._dtids.length <= 1 || !dtid ? zkau._uri: zkau._uris[dtid];
};
/** Adds the update engine's UIR for the specified destkop.
 * @since 3.0.6
 */
zkau.addURI = function (dtid, uri) {
	zkau._uris[dtid] = uri;
	if (!zkau._uri) zkau._uri = uri; //performance fine tune
};

zk.addInit(function () {
	zk.listen(document, "keydown", zkau._onDocKeydown);
	zk.listen(document, "mousedown", zkau._onDocMousedown);
	zk.listen(document, "mouseover", zkau._onDocMouseover);
	zk.listen(document, "mouseout", zkau._onDocMouseout);

	zk.listen(document, "contextmenu", zkau._onDocCtxMnu);
	zk.listen(document, "click", zkau._onDocLClick);
	zk.listen(document, "dblclick", zkau._onDocDClick);
	zk.listen(window, "scroll", zkau._onDocScroll);
	zk.listen(window, "resize", zkau._onResize);

	zkau._oldUnload = window.onunload;
	window.onunload = zkau._onUnload; //unable to use zk.listen

	zkau._oldBfUnload = window.onbeforeunload;
	window.onbeforeunload = zkau._onBfUnload;
});
zkau._onDocScroll = function () {
	var ix = zk.innerX(), iy = zk.innerY();
	zkau._fixOffset($e("zk_mask"), ix, iy);
	zkau._fixOffset($e("zk_loading"), ix, iy);
	zkau._fixOffset($e("zk_loadprog"), ix, iy);
	zkau._fixOffset($e("zk_prog"), ix, iy);
	zkau._fixOffset($e("zk_prog"), ix, iy);
	var d = $e("zk_debugbox");
	if (d) {
		d.style.top = iy + zk.innerHeight() - d.offsetHeight - 20 + "px";
		d.style.left = ix + zk.innerWidth() - d.offsetWidth - 20 + "px";
	}

	zk.onScrollAt();
};
zkau._fixOffset = function (el, x, y) {
	if (!el) return;
	var ix = $int(getZKAttr(el, "x")), iy = $int(getZKAttr(el, "y"));
	var top = $int(el.style.top) + (y - iy), left = $int(el.style.left) + (x - ix);
	el.style.top = top + "px";
	el.style.left = left + "px";
	setZKAttr(el, "x", x);
	setZKAttr(el, "y", y);
};
/** Handles onclick for button-type.
 */
zkau.onclick = function (evt) {
	if (typeof evt == 'string') {
		zkau.send({uuid: $uuid(evt), cmd: "onClick", ctl: true});
		return;
	}

	if (!evt) evt = window.event;
	var target = Event.element(evt);

	//it might be clicked on the inside element
	for (;; target = $parent(target))
		if (!target) return;
		else if (target.id) break;

	var href = getZKAttr(target, "href");
	if (href) {
		zk.go(href, false, getZKAttr(target, "target"));
		Event.stop(evt); //prevent _onDocLClick
		return; //done
	}
	zkau._lastClickId = target.id;
	zkau.send({uuid: $uuid(target.id),
		cmd: "onClick", data: zkau._getMouseData(evt, target), ctl: true});
	//Don't stop event so popup will work (bug 1734801)
	zkau.addOnSend(zkau._resetLastClickId);
};
zkau._resetLastClickId = function () {zkau._lastClickId = null;};
/** Handles ondblclick for button (for non-FF).
 * Note: double clicks are handled by zkau._onDocDClick, but
 * some tags (button and checkbox) eat the event, so _onDocDClick won't
 * get the event.
 */
zkau.ondblclick = function (evt) {
	if (!evt) evt = window.event;
	var cmp = Event.element(evt);

	//it might be clicked on the inside element
	for (;; cmp = $parent(cmp))
		if (!cmp) return;
		else if (cmp.id) break;

	cmp = $outer(cmp);
	if (cmp && getZKAttr(cmp, "dbclk")) {
		zkau.send({uuid: cmp.id,
			cmd: "onDoubleClick", data: zkau._getMouseData(evt, cmp), ctl: true});
		Event.stop(evt); //just in case: prevent _onDocDClick to run again
		return false;
	}
};

/** Returns the data for onClick. */
zkau._getMouseData = function (evt, target) {
	var extra = "";
	if (evt.altKey) extra += "a";
	if (evt.ctrlKey) extra += "c";
	if (evt.shiftKey) extra += "s";

	var ofs = Position.cumulativeOffset(target);
	var x = Event.pointerX(evt) - ofs[0];
	var y = Event.pointerY(evt) - ofs[1];
	return [x, y, extra];
};

/** Asks the server to update a component (for file uploading). */
zkau.sendUpdateResult = function (uuid, updatableId) {
	zkau.send({uuid: uuid, cmd: "updateResult", data: [updatableId]}, -1);
}
/** Asks the server to remove a component. */
zkau.sendRemove = function (uuid) {
	if (!uuid) {
		zk.error(mesg.UUID_REQUIRED);
		return;
	}
	zkau.send({uuid: uuid, cmd: "remove"}, 5);
};

////ajax resend mechanism////
/** IE6 sometimes remains readyState==1 (reason unknown), so resend. */
zkau._areqTmout = function () {
	//Note: we don't resend if readyState >= 3, since the server is already
	//processing it
	var req = zkau._areq, reqInf = zkau._areqInf;
	if (req && req.readyState < 3) {
		zkau._areq = zkau._areqInf = null;
		try {
			if(typeof req.abort == "function") req.abort();
		} catch (e2) {
		}
		if (reqInf.tmout < 60000) reqInf.tmout += 3000;
			//sever might be busy, so prolong next timeout
		zkau._areqResend(reqInf);
	}
};

zkau._areqResend = function (reqInf, timeout) {
	if (zkau._seqId == reqInf.sid) {//skip if the response was recived
		zkau._preqInf = reqInf; //store as a pending request info
		setTimeout("zkau._areqResend2()", timeout ? timeout: 0);
	}
};
zkau._areqResend2 = function () {
	var reqInf = zkau._preqInf;
	if (reqInf) {
		zkau._preqInf = null;
		if (zkau._seqId == reqInf.sid)
			zkau._sendNow2(reqInf);
	}
};
/** Called when the response is received from _areq.
 */
zkau._onRespReady = function () {
	try {
		var req = zkau._areq, reqInf = zkau._areqInf;
		if (req && req.readyState == 4) {
			zkau._areq = zkau._areqInf = null;
			if (reqInf.tfn) clearTimeout(reqInf.tfn); //stop timer

			if (zk.pfmeter) zkau._pfrecv(req);

			if (zkau._revertpending) zkau._revertpending();
				//revert any pending when the first response is received

			var sid = req.getResponseHeader("ZK-SID");
			if (req.status == 200) { //correct
				if (sid && sid != zkau._seqId) {
					zkau._errcode = "ZK-SID " + (sid ? "mismatch": "required");
					return;
				} //if sid null, always process (usually for error msg)

				var cmds = zkau.parseXmlResp(req.responseXML);
				if (cmds) { //valid response
					zkau._respQue.push(cmds);

					//advance SID to avoid receive the same response twice
					if (sid && ++zkau._seqId > 999) zkau._seqId = 1;
					zkau._areqTry = 0;
					zkau._preqInf = null;
				}
			} else if (!sid || sid == zkau._seqId) { //ignore only if out-of-seq (note: 467 w/o sid)
				zkau._errcode = req.status;
				var eru = zk.eru['e' + req.status];
				if (typeof eru == "string") {
					zk.go(eru);
				} else {
				//handle MSIE's buggy HTTP status codes
				//http://msdn2.microsoft.com/en-us/library/aa385465(VS.85).aspx
					switch (req.status) { //auto-retry for certain case
					default:
						if (!zkau._areqTry) break;
						//fall thru
					case 12002: //server timeout
					case 12030: //http://danweber.blogspot.com/2007/04/ie6-and-error-code-12030.html
					case 12031:
					case 12152: // Connection closed by server.
					case 12159:
					case 13030:
					case 503: //service unavailable
						if (!zkau._areqTry) zkau._areqTry = 3; //two more try
						if (--zkau._areqTry) {
							zkau._areqResend(reqInf, 200);
							return;
						}
					}

					if (!zkau._ignorable && !zkau._unloading) {
						var msg = req.statusText;
						if (confirmRetry("FAILED_TO_RESPONSE", req.status+(msg?": "+msg:""))) {
							zkau._areqTry = 2; //one more try
							zkau._areqResend(reqInf);
							return;
						}
					}

					zkau._cleanupOnFatal(zkau._ignorable);
				}
			}
		}
	} catch (e) {
		zkau._areq = zkau._areqInf = null;
		try {
			if(req && typeof req.abort == "function") req.abort();
		} catch (e2) {
		}

		//NOTE: if connection is off and req.status is accessed,
		//Mozilla throws exception while IE returns a value
		if (!zkau._ignorable && !zkau._unloading) {
			var msg = e.message;
			zkau._errcode = "[Receive] " + msg;
			//if (e.fileName) zkau._errcode += ", "+e.fileName;
			//if (e.lineNumber) zkau._errcode += ", "+e.lineNumber;
			if (confirmRetry("FAILED_TO_RESPONSE", (msg&&msg.indexOf("NOT_AVAILABLE")<0?msg:""))) {
				zkau._areqResend(reqInf);
				return;
			}
		}
		zkau._cleanupOnFatal(zkau._ignorable);
	}

	//handle pending ajax send
	if (zkau._sendPending && !zkau._areq && !zkau._preqInf) {
		zkau._sendPending = false;
		var ds = zkau._dtids;
		for (var j = ds.length; --j >= 0;)
			zkau._send2(ds[j], 0);
	}

	zkau.doQueResps();
	zkau._checkProgress();
};
/** Parses a XML response.
 * @since 3.0.6
 */
zkau.parseXmlResp = function (xml) {
	if (!xml) return null; //invalid

	var cmds = [],
		rs = xml.getElementsByTagName("r");
	for (var j = 0, rl = rs ? rs.length: 0; j < rl; ++j) {
		var cmd = rs[j].getElementsByTagName("c")[0],
			data = rs[j].getElementsByTagName("d");

		if (!cmd) {
			zk.error(mesg.ILLEGAL_RESPONSE+"Command required");
			continue;
		}

		cmds.push(cmd = {cmd: zk.getElementValue(cmd)});
		cmd.data = [];
		for (var k = data ? data.length: 0; --k >= 0;)
			cmd.data[k] = zk.getElementValue(data[k]);
	}
	return cmds;
};
/** Checks whether to turn off the progress prompt.
 * @return true if the processing is done
 */
zkau._checkProgress = function () {
	if (zkau.processing())
		return false;
	zk.progressDone();
	return true;
};
/** Returns whether any request is in processing.
 * @since 3.0.0
 */
zkau.processing = function () {
	return zkau._respQue.length || zkau._areq || zkau._preqInf;
};

/** Returns the timeout of the specified event.
 * It is mainly used to generate the timeout argument of zkau.send.
 *
 * @param timeout if non-negative, it is used when zkau.asap is true.
 */
zkau.asapTimeout = function (cmp, evtnm, timeout) {
	return zkau.asap(cmp, evtnm) ? timeout >= 0 ? timeout: 38: -1;
};
/** Returns whether any non-deferrable listener is registered for
 * the specified event.
 */
zkau.asap = function (cmp, evtnm) {
	return getZKAttr($e(cmp), evtnm) == "true" ;
};

/** Returns the event list of the specified desktop ID.
 */
zkau._events = function (dtid) {
	var es = zkau._evts;
	if (!es[dtid])
		es[dtid] = [];
	return es[dtid];
};

/** Adds a callback to be called before sending ZK request.
 * @param func the function call
 */
zkau.addOnSend = function (func) {
	zkau._onsends.push(func);
};
zkau.removeOnSend = function (func) {
	zkau._onsends.remove(func);
};
/** Returns an array of queued events.
 * @since 3.0.0
 */
zkau.events = function (uuid) {
	return zkau._events(zkau.dtid(uuid));
};
/** Sends a request to the client
 * @param timout milliseconds.
 * If negative, it won't be sent until next non-negative event
 */
zkau.send = function (evt, timeout) {
	if (timeout < 0) evt.implicit = true;

	if (evt.uuid) {
		zkau._send(zkau.dtid(evt.uuid), evt, timeout);
	} else if (evt.dtid) {
		zkau._send(evt.dtid, evt, timeout);
	} else {
		var ds = zkau._dtids;
		for (var j = 0, dl = ds.length; j < dl; ++j)
			zkau._send(ds[j], evt, timeout);
	}
};
/** A shortcut of zkau.send(evt, zkau.asapTimeout(evt.uuid, evt.cmd, timeout)).
 * @since 3.0.5
 */
zkau.sendasap = function (evt, timeout) {
	zkau.send(evt, zkau.asapTimeout(evt.uuid, evt.cmd, timeout));
};
zkau._send = function (dtid, evt, timeout) {
	if (evt.ctl) {
		//Don't send the same request if it is in processing
		if (zkau._areqInf && zkau._areqInf.ctli == evt.uuid
		&& zkau._areqInf.ctlc == evt.cmd)
			return;

		var t = $now();
		if (zkau._ctli == evt.uuid && zkau._ctlc == evt.cmd //Bug 1797140
		&& t - zkau._ctlt < 390)
			return; //to prevent key stroke are pressed twice (quickly)

		//Note: it is still possible to queue two ctl with same uuid and cmd,
		//if the first one was not sent yet and the second one is generated
		//after 390ms.
		//However, it is rare so no handle it

		zkau._ctlt = t;
		zkau._ctli = evt.uuid;
		zkau._ctlc = evt.cmd;
	}

	zkau._events(dtid).push(evt);

	//Note: we don't send immediately (Bug 1593674)
	//Note: Unlike sendAhead and _send2, if timeout is undefined,
	//it is considered as 0.
	zkau._send2(dtid, timeout ? timeout: 0);
};
/** @param timeout if undefined or negative, it won't be sent. */
zkau._send2 = function (dtid, timeout) {
	if (dtid && timeout >= 0) setTimeout("zkau._sendNow('"+dtid+"')", timeout);
};
/** Sends a request before any pending events.
 * @param timout milliseconds.
 * If undefined or negative, it won't be sent until next non-negative event
 * Note: Unlike zkau.send, it considered undefined as not sending now
 * (reason: backward compatible)
 */
zkau.sendAhead = function (evt, timeout) {
	var dtid;
	if (evt.uuid) {
		zkau._events(dtid = zkau.dtid(evt.uuid)).unshift(evt);
	} else if (evt.dtid) {
		zkau._events(dtid = evt.dtid).unshift(evt);
	} else {
		var ds = zkau._dtids;
		for (var j = ds.length; --j >= 0; ++j) {
			zkau._events(ds[j]).unshift(evt);
			zkau._send2(ds[j], timeout); //Spec: don't convert unefined to 0 for timeout
		}
		return;
	}
	zkau._send2(dtid, timeout);
};
zkau._sendNow = function (dtid) {
	var es = zkau._events(dtid);
	if (es.length == 0)
		return; //nothing to do

	if (zk.loading) {
		zk.addInit(function () {zkau._sendNow(dtid);});
		return; //wait
	}

	if (zkau._areq || zkau._preqInf) { //send ajax request one by one
		zkau._sendPending = true;
		return;
	}

	//callback (fckez uses it to ensure its value is sent back correctly
	for (var j = 0, ol = zkau._onsends.length; j < ol; ++j) {
		try {
			zkau._onsends[j](implicit); //it might add more events
		} catch (e) {
			zk.error(e.message);
		}
	}

	//bug 1721809: we cannot filter out ctl even if zkau.processing

	//decide implicit and ignorable
	var implicit = true, ignorable = true, ctli, ctlc;
	for (var j = es.length; --j >= 0;) {
		var evt = es[j];
		if (implicit && !evt.ignorable) { //ignorable implies implicit
			ignorable = false;
			if (!evt.implicit)
				implicit = false;
		}
		if (evt.ctl && !ctli) {
			ctli = evt.uuid;
			ctlc = evt.cmd;
		}
	}
	zkau._ignorable = ignorable;

	//Consider XML (Pros: ?, Cons: larger packet)
	var content = "";
	for (var j = 0, el = es.length; el; ++j, --el) {
		var evt = es.shift();
		content += "&cmd."+j+"="+evt.cmd+"&uuid."+j+"="+(evt.uuid?evt.uuid:'');
		if (evt.data)
			for (var k = 0, dl = evt.data.length; k < dl; ++k) {
				var data = evt.data[k];
				content += "&data."+j+"="
					+ (data != null ? encodeURIComponent(data): '_z~nil');
			}
	}

	if (content)
		zkau._sendNow2({
			sid: zkau._seqId, uri: zkau.uri(dtid),
			dtid: dtid, content: "dtid=" + dtid + content,
			ctli: ctli, ctlc: ctlc, implicit: implicit, ignorable: ignorable,
			tmout: 0
		});
};
zkau._sendNow2 = function(reqInf) {
	var req = zkau.ajaxRequest(),
		uri = zkau._useQS(reqInf) ? reqInf.uri + '?' + reqInf.content: null;
	zkau.sentTime = $now(); //used by server-push (zkex)
	try {
		req.onreadystatechange = zkau._onRespReady;
		req.open("POST", uri ? uri: reqInf.uri, true);
		req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
		req.setRequestHeader("ZK-SID", reqInf.sid);
		if (zkau._errcode) {
			req.setRequestHeader("ZK-Error-Report", zkau._errcode);
			delete zkau._errcode;
		}

		if (zk.pfmeter) zkau._pfsend(req, reqInf.dtid);

		zkau._areq = req;
		zkau._areqInf = reqInf;
		if (zk_resndto > 0)
			zkau._areqInf.tfn = setTimeout(zkau._areqTmout, zk_resndto + reqInf.tmout);

		if (uri) req.send();
		else req.send(reqInf.content);

		if (!reqInf.implicit) zk.progress(zk_procto); //wait a moment to avoid annoying
	} catch (e) {
		//handle error
		try {
			if(typeof req.abort == "function") req.abort();
		} catch (e2) {
		}

		if (!reqInf.ignorable && !zkau._unloading) {
			var msg = e.message;
			zkau._errcode = "[Send] " + msg;
			if (confirmRetry("FAILED_TO_SEND", msg)) {
				zkau._areqResend(reqInf);
				return;
			}
		}
		zkau._cleanupOnFatal(reqInf.ignorable);
	}
};
//IE: use query string if possible to avoid IE incomplete-request problem
zkau._useQS = zk.ie ? function (reqInf) {
	var s = reqInf.content, j = s.length, prev, cc;
	if (j + reqInf.uri.length < 2000) {
		while (--j >= 0) {
			cc = s.charAt(j);
			if (cc == '%' && prev >= '8') //%8x, %9x...
				return false;
			prev = cc;
		}
		return true;
	}
	return false;
}: zk.voidf;

/** Registers a script that will be evaluated when the next response is back.
 * Note: it executes only once, so you have to register again if necessary.
 */
zkau.addOnResponse = function (script) {
	zkau._js4resps.push(script);
};
/** Evaluates scripts registered by addOnResponse. */
zkau._evalOnResponse = function () {
	while (zkau._js4resps.length)
		setTimeout(zkau._js4resps.shift(), 0);
};

/** Process the responses queued in zkau._respQue. */
zkau.doQueResps = function () {
	var ex, que = zkau._respQue, breath = $now() + 6000;
	while (que.length) {
		if (zk.loading) {
			zk.addInit(zkau.doQueResps); //Note: when callback, zk.loading is false
			break; //wait until the loading is done
		}

		try {
			var cmds = que.shift();
			if (!zkau._doResps(cmds))
				que.unshift(cmds); //handle it later
		} catch (e) {
			if (!ex) ex = e;
		}

		if (!ex && $now() > breath) {
			setTimeout(zkau.doQueResps, 10); //let browser breath
			return;
		}
	}

	if (zkau._checkProgress())
		zkau.doneTime = $now();
	if (ex) throw ex;
};
/** Process the specified response in XML. */
zkau._doResps = function (cmds) {
	var processed;
	try {
		while (cmds && cmds.length) {
			if (zk.loading)
				return false;

			processed = true;
			var cmd = cmds.shift();
			try {
				zkau.process(cmd.cmd, cmd.data);
			} catch (e) {
				onProcessError("FAILED_TO_PROCESS", null, cmd.cmd, e);
				throw e;
			}
		}
	} finally {
		if (processed && (!cmds || !cmds.length))
			zkau._evalOnResponse();
	}
	return true;
};
/** Process a command.
 */
zkau.process = function (cmd, data) {
	//I. process commands that data[0] is not UUID
	var fn = zkau.cmd0[cmd];
	if (fn) {
		fn.apply(zkau, data);
		return;
	}

	//I. process commands that require uuid
	if (!data || !data.length) {
		onProcessError("ILLEGAL_RESPONSE", "uuid is required for ", cmd);
		return;
	}

	fn = zkau.cmd1[cmd];
	if (fn) {
		data.splice(1, 0, $e(data[0])); //insert cmp
		fn.apply(zkau, data);
		return;
	}

	onProcessError("ILLEGAL_RESPONSE", "Unknown command: ", cmd);
};
/** Used by ZkFns. */
zk.process = function (cmd) {
	var args = [];
	for (var j = arguments.length; --j > 0;)
		args[j - 1] = arguments[j];
	zkau.process(cmd, args);
};

/** Cleans up if we detect obsolete or other severe errors. */
zkau._cleanupOnFatal = function (ignorable) {
	for (var uuid in zkau._metas) {
		var meta = zkau._metas[uuid];
		if (meta && meta.cleanupOnFatal)
			meta.cleanupOnFatal(ignorable);
	}
};

/** Invoke zk.initAt for siblings. Note: from and to are excluded. */
zkau._initSibs = function (from, to, next) {
	for (;;) {
		from = next ? from.nextSibling: from.previousSibling;
		if (!from || from == to) break;
		zk.initAt(from);
	}
};
/** Invoke zk.initAt for all children. Note: to is excluded. */
zkau._initChildren = function (n, to) {
	for (n = n.firstChild; n && n != to; n = n.nextSibling)
		zk.initAt(n);
};
/** Invoke inserHTMLBeforeEnd and then zk.initAt.
 */
zkau._insertAndInitBeforeEnd = function (n, html) {
	if ($tag(n) == "TABLE" && zk.tagOfHtml(html) == "TR") {
		if (!n.tBodies || !n.tBodies.length) {
			var m = document.createElement("TBODY");
			n.appendChild(m);
			n = m;
		} else {
			n = n.tBodies[0];
		}
	}

	var lc = n.lastChild;
	zk.insertHTMLBeforeEnd(n, html);		
	if (lc) zkau._initSibs(lc, null, true);
	else zkau._initChildren(n);
};

/** Sets an attribute (the default one). */
zkau.setAttr = function (cmp, name, value) {
	cmp = zkau._attr(cmp, name);

	if ("visibility" == name) {
		zk.setVisible(cmp, value == "true");
	} else if ("value" == name) {
		if (value != cmp.value) {
			cmp.value = value;
			if (cmp == zkau.currentFocus && cmp.select) cmp.select();
				//fix a IE bug that cursor disappear if input being
				//changed is onfocus
		}
		if (cmp.defaultValue != cmp.value)
			cmp.defaultValue = cmp.value;
	} else if ("checked" == name) {
		value = "true" == value || "checked" == value;
		if (value != cmp.checked)
			cmp.checked = value;
		if (cmp.defaultChecked != cmp.checked)
			cmp.defaultChecked = cmp.checked;
		//we have to update defaultChecked because click a radio
		//might cause another to unchecked, but browser doesn't
		//maintain defaultChecked
	} else if ("selectAll" == name && $tag(cmp) == "SELECT") {
		value = "true" == value;
		for (var j = 0, ol = cmp.options.length; j < ol; ++j)
			cmp.options[j].selected = value;
	} else if ("style" == name) {
		zk.setStyle(cmp, value);
	} else if (name.startsWith("z.")) { //ZK attributes
		setZKAttr(cmp, name.substring(2), value);
	} else {
		var j = name.indexOf('.'); 
		if (j >= 0) {
			if ("style" != name.substring(0, j)) {
				zk.error(mesg.UNSUPPORTED+name);
				return;
			}
			name = name.substring(j + 1).camelize();
			if (typeof(cmp.style[name]) == "boolean") //just in case
				value = "true" == value || name == value;
			cmp.style[name] = value;

			if ("width" == name && (!value || value.indexOf('%') < 0) //don't handle width with %
			&& !getZKAttr(cmp, "float")) {
				var ext = $e(cmp.id + "!chdextr");
				if (ext && $tag(ext) == "TD" && ext.colSpan == 1)
					ext.style.width = value;
			}
			return;
		}

		if (name == "disabled" || name == "href")
			zkau.setStamp(cmp, name);
			//mark when this attribute is set (change or not), so
			//modal dialog and other know how to process it
			//--
			//Better to call setStamp always but, to save memory,...

		//Firefox cannot handle many properties well with getAttribute/setAttribute,
		//such as selectedIndex, scrollTop...
		var old = "class" == name ? cmp.className:
			"selectedIndex" == name ? cmp.selectedIndex:
			"disabled" == name ? cmp.disabled:
			"readOnly" == name ? cmp.readOnly:
			"scrollTop" == name ? cmp.scrollTop:
			"scrollLeft" == name ? cmp.scrollLeft:
				cmp.getAttribute(name);

		//Note: "true" != true (but "123" = 123)
		//so we have take care of boolean
		if (typeof(old) == "boolean")
			value = "true" == value || name == value; //e.g, reaonly="readOnly"

		if (old != value) {
			if ("selectedIndex" == name) cmp.selectedIndex = value;
			else if ("class" == name) cmp.className = value;
			else if ("disabled" == name) cmp.disabled = value;
			else if ("readOnly" == name) cmp.readOnly = value;
			else if ("scrollTop" == name) cmp.scrollTop = value;
			else if ("scrollLeft" == name) cmp.scrollLeft = value;
			else cmp.setAttribute(name, value);
		}
	}
};
zkau._attr = function (cmp, name) {
	var real = $real(cmp);
	if (real != cmp && real) {
		if (name.startsWith("on")) return real;
			//Client-side-action must be done at the inner tag

		switch ($tag(real)) {
		case "INPUT":
		case "TEXTAREA":
			switch(name) {
			case "name": case "value": case "defaultValue":
			case "checked": case "defaultChecked":
			case "cols": case "size": case "maxlength":
			case "type": case "disabled": case "readOnly":
			case "rows":
				return real;
			}
			break;
		case "IMG":
			switch (name) {
			case "align": case "alt": case "border":
			case "hspace": case "vspace": case "src":
				return real;
			}
		}
	}
	return cmp;
};
/** Returns the time stamp. */
zkau.getStamp = function (cmp, name) {
	var stamp = getZKAttr(cmp, "stm" + name);
	return stamp ? stamp: "";
};
/** Sets the time stamp. */
zkau.setStamp = function (cmp, name) {
	setZKAttr(cmp, "stm" + name, "" + ++zkau._stamp);
};
zkau.rmAttr = function (cmp, name) {
	cmp = zkau._attr(cmp, name);

	if ("class" == name) {
		if (cmp.className) cmp.className = "";
	} else if (name.startsWith("z.")) { //ZK attributes
		rmZKAttr(cmp, name.substring(2));
		return;
	} else {
		var j = name.indexOf('.'); 
		if (j >= 0) {
			if ("style" != name.substring(0, j)) {
				zk.error(mesg.UNSUPPORTED+name);
				return;
			}
			cmp.style[name.substring(j + 1)] = "";
		} else if (!cmp.hasAttriute || cmp.hasAttribute(name)) {
			cmp.setAttribute(name, "");
		}
	}
};

/** Corrects zIndex of the specified component, which must be absolute.
 * @param silent whether to send onZIndex
 * @param autoz whether to adjust zIndex only if necessary.
 * If false (used when creating a window), it always increases zIndex
 */
zkau.fixZIndex = function (cmp, silent, autoz) {
	if (!zkau._popups.length && !zkau._overlaps.length && !zkau._modals.length)
		zkau.topZIndex = 12; //reset it!

	var zi = $int(cmp.style.zIndex);
	if (zi > zkau.topZIndex) {
		zkau.topZIndex = zi;
	} else if (!autoz || zi < zkau.topZIndex) {
		cmp.style.zIndex = ++zkau.topZIndex;
		if (!silent && cmp.id) {
			cmp = $outer(cmp);
			zkau.sendOnZIndex(cmp);
		}
	}
};
/** Automatically adjust z-index if node is part of popup/overalp/...
 */
zkau.autoZIndex = function (node) {
	for (; node; node = $parent(node)) {
		if (node.style && node.style.position == "absolute") {
			if (getZKAttr(node, "autoz"))
				zkau.fixZIndex(node, false, true); //don't inc if equals
		}
	}
};

//-- popup --//
if (!zkau._popups) {
	zkau._popups = []; //uuid
	zkau._overlaps = []; //uuid
	zkau._modals = []; //uuid (used zul.js or other modal)
}

/** Returns the current modal window's ID, or null.
 * @since 3.0.4
 */
zkau.currentModalId = function () {
	var modals = zkau._modals;
	return modals.length ? modals[modals.length - 1]: null;
};
/** Checks if we can move focus to the specified element.
 * If it is not in the current modal, false is returned and
 * focus is moved back to the current modal.
 *
 * @param checkOnly if true, the focus won't be changed.
 * @since 3.0.4
 */
zkau.canFocus = function (el, checkOnly) {
	var modalId = zkau.currentModalId();
	if (modalId && !zk.isAncestor(modalId, el)) {
		if (!checkOnly) {
			//Note: we cannot change focus to SPAN/DIV, but they might
			//gain focus (such as selecting a piece of text)
			var cf = zkau.currentFocus, cftn = $tag(cf);
			if (cf && cf.id && cftn != "SPAN" && cftn != "DIV"
			&& zk.isAncestor(modalId, cf.id))
				zk.asyncFocus(cf.id);
			else
				zk.asyncFocusDown(modalId);
		}
		return false;
	}
	return true;
};

//-- utilities --//
/** Returns the element of the specified element.
 * It is the same as Event.elemet(evt), but
 * it is smart enough to know whether evt is an element.
 * It is used to make a method able to accept either event or element.
 */
zkau.evtel = function (evtel) {
	if (!evtel) evtel = window.event;
	else if (evtel.parentNode) return evtel;
	return Event.element(evtel);
};

zkau.onfocus = function (evtel) { //accept both evt and cmp
	zkau.onfocus0(evtel);
};
/** When a component implements its own onfocus, it shall call back this
 * method and ignore the event if this method returns false.
 * Like zkau.onfocus except returns false if it shall be ignored.
 * @since 3.0.4
 */
zkau.onfocus0 = function (evtel, silent) { //accept both evt and cmp
	var el = zkau.evtel(evtel);
	if (!zkau.canFocus(el)) return false;

	zkau.currentFocus = el; //_onDocMousedown doesn't take care all cases
	zkau.closeFloatsOnFocus(el);
	if (zkau.valid) zkau.valid.uncover(el);

	zkau.autoZIndex(el);

	var cmp = $outer(el);
	if (!silent && zkau.asap(cmp, "onFocus"))
		zkau.send({uuid: cmp.id, cmd: "onFocus"}, 100);
	return true;
};
/**
 * @param noonblur not to send the onblur event (3.0.5)
 */
zkau.onblur = function (evtel, noonblur) {
	var el = zkau.evtel(evtel);
	if (el == zkau.currentFocus) zkau.currentFocus = null;
		//Note: _onDocMousedown is called before onblur, so we have to
		//prevent it from being cleared

	if (!noonblur && !zk.alerting) {
		var cmp = $outer(el);
		if (zkau.asap(cmp, "onBlur"))
			zkau.send({uuid: cmp.id, cmd: "onBlur"}, 100);
	}
};

zkau.onimgover = function (evtel) {
	var el = zkau.evtel(evtel);
	if (el && el.src.indexOf("-off") >= 0)
		el.src = zk.renType(el.src, "on");
};
zkau.onimgout = function (evtel) {
	var el = zkau.evtel(evtel);
	if (el && el.src.indexOf("-on") >= 0)
		el.src = zk.renType(el.src, "off");
};

/** Returns the Ajax request. */
zkau.ajaxRequest = function () {
	if (window.XMLHttpRequest) {
		return new XMLHttpRequest();
	} else {
		try {
			return new ActiveXObject('Msxml2.XMLHTTP');
		} catch (e2) {
			return new ActiveXObject('Microsoft.XMLHTTP');
		}
	}
};

/** Handles window.unload. */
zkau._onUnload = function () {
	zkau._unloading = true; //to disable error message

	if (zk.gecko) zk.restoreDisabled(); //Workaround Nav: Bug 1495382

	//20061109: Tom Yeh: Failed to disable Opera's cache, so it's better not
	//to remove the desktop.
	//Good news: Opera preserves the most udpated content, when BACK to
	//a cached page, its content. OTOH, IE/FF/Safari cannot.
	//Note: Safari won't send rmDesktop when onunload is called
	if (!zk.opera && !zk.keepDesktop) {
		try {
			var ds = zkau._dtids;
			for (var j = 0, dl = ds.length; j < dl; ++j) {
				var req = zkau.ajaxRequest(),
					content = "dtid="+ds[j]+"&cmd.0=rmDesktop",
					uri = zkau.uri(ds[j]);
				req.open("POST", zk.ie ? uri+"?"+content: uri, true);
				req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
				if (zk.ie) req.send();
				else req.send(content);
			}
		} catch (e) { //silent
		}
	}

	if (zkau._oldUnload) zkau._oldUnload.apply(window, arguments);
	zk.unlistenAll();
};
/** Handles window.onbeforeunload. */
zkau._onBfUnload = function () {
	if (!zk.skipBfUnload) {
		if (zkau.confirmClose)
			return zkau.confirmClose;

		var s = zk.beforeUnload();
		if (s) return s;
	}

	if (zkau._oldBfUnload)
		return zkau._oldBfUnload.apply(window, arguments);
	//Return nothing
};

/** Handle document.onmousedown. */
zkau._onDocMousedown = function (evt) {
	if (!evt) evt = window.event;

	var el = Event.element(evt);
	if (!zkau.canFocus(el)) return;

	zkau._savepos(evt);

	zkau.currentFocus = el;

	zkau.closeFloatsOnFocus(el);
	zkau.autoZIndex(el);
};
/** Handles the left click. */
zkau._onDocLClick = function (evt) {
	if (!evt) evt = window.event;

	if (evt.which == 1 || (evt.button == 0 || evt.button == 1)) {
		var target = Event.element(evt), cmp = zkau._parentByZKAttr(target, "lfclk", "pop");
		if (cmp) {
			var ctx = getZKAttr(cmp, "pop");
			if (ctx) {
				ctx = zkau.getByZid(cmp, ctx);
				if (ctx && (!zkau._lastClickId || zkau._lastClickId == $id(target))) {
					var type = $type(ctx);
					if (type) {
						zkau.closeFloats(ctx, cmp);

						ctx.style.position = "absolute";
						zk.setVParent(ctx); //FF: Bug 1486840, IE: Bug 1766244
						zkau._autopos(ctx, Event.pointerX(evt), Event.pointerY(evt));
						zk.eval(ctx, "context", type, cmp);
						if ($visible(ctx)) setZKAttr(ctx, "owner", cmp.id);
							//bookmark owner, so closeFloats know not to close
					}
				}
			}

			if (getZKAttr(cmp, "lfclk") && zkau.insamepos(evt) && !zkau._lastClickId)
				zkau.send({uuid: $uuid(cmp),
					cmd: "onClick", data: zkau._getMouseData(evt, cmp), ctl: true});

			//no need to Event.stop
		}
	}
	//don't return anything. Otherwise, it replaces event.returnValue in IE (Bug 1541132)
};
/** Saves the mouse position to be used with insamepos. */
zkau._savepos = function (evt) {
	if (evt)
		zkau._mspos = [Event.pointerX(evt), Event.pointerY(evt), Event.element(evt)];
};
/** Checks whether the position of the specified event is the same the one
 * stored with zkau._savepos.
 * Note: if the target element is different, it is considered as IN THE SAME POSITION.
 */
zkau.insamepos = function (evt) {
	if (!evt || !zkau._mspos) return true; //yes, true

	if (Event.element(evt) != zkau._mspos[2]) return true; //yes, true

	var x = Event.pointerX(evt) - zkau._mspos[0];
	var y = Event.pointerY(evt) - zkau._mspos[1];
	return x > -3 && x < 3 && y > -3 && y < 3;
};
/** Autoposition by the specified (x, y). */
zkau._autopos = function (el, x, y) {
	var ofs = zk.getDimension(el);
	var wd = ofs[0], hgh = ofs[1];

	var scx = zk.innerX(), scy = zk.innerY(),
		scmaxx = scx + zk.innerWidth(), scmaxy = scy + zk.innerHeight();
	if (x + wd > scmaxx) {
		x = scmaxx - wd;
		if (x < scx) x = scx;
	}
	if (y + hgh > scmaxy) {
		y = scmaxy - hgh;
		if (y < scy) y = scy;
	}

	ofs = zk.toStyleOffset(el, x, y);
	el.style.left = ofs[0] + "px";
	el.style.top = ofs[1] + "px";
};

/** Handles the double click. */
zkau._onDocDClick = function (evt) {
	if (!evt) evt = window.event;

	var cmp = Event.element(evt);
	cmp = zkau._parentByZKAttr(cmp, "dbclk");
	if (cmp/* no need since browser handles it: && zkau.insamepos(evt)*/) {
		var uuid = getZKAttr(cmp, "item"); //treerow (and other transparent)
		if (!uuid) uuid = $uuid(cmp);
		zkau.send({uuid: uuid,
			cmd: "onDoubleClick", data: zkau._getMouseData(evt, cmp), ctl: true});
		//no need to Event.stop
	}
};
/** Handles the right click (context menu). */
zkau._onDocCtxMnu = function (evt) {
	if (!evt) evt = window.event;

	var target = Event.element(evt);
	var cmp = zkau._parentByZKAttr(target, "ctx", "rtclk");

	if (cmp) {
		var ctx = getZKAttr(cmp, "ctx");
		var rtclk = getZKAttr(cmp, "rtclk");
		if (ctx || rtclk) {
			//Give the component a chance to handle right-click
			for (var n = target; n; n = $parent(n)) {
				var type = $type(n);
				if (type) {
					var o = window["zk" + type];
					if (o && o.onrtclk)
						if (o.onrtclk(n))
							ctx = rtclk = null;
				}
				if (n == cmp) break; //only up to the one with right click
			}
		}

		if (ctx) {
			ctx = zkau.getByZid(cmp, ctx);
			if (ctx) {
				var type = $type(ctx);
				if (type) {
					zkau.closeFloats(ctx, cmp);

					ctx.style.position = "absolute";
					zk.setVParent(ctx); //FF: Bug 1486840, IE: Bug 1766244
					zkau._autopos(ctx, Event.pointerX(evt), Event.pointerY(evt));
					zk.eval(ctx, "context", type, cmp);
					if ($visible(ctx)) setZKAttr(ctx, "owner", cmp.id);
						//bookmark owner, so closeFloats know not to close
				}
			}
		}

		if (rtclk/*no need since oncontextmenu: && zkau.insamepos(evt)*/) {
			var uuid = getZKAttr(cmp, "item"); //treerow (and other transparent)
			if (!uuid) uuid = $uuid(cmp);
			zkau.send({uuid: uuid,
				cmd: "onRightClick", data: zkau._getMouseData(evt, cmp), ctl: true});
		}

		Event.stop(evt);
		return false;
	}
	return !zk.ie || evt.returnValue;
};
zkau._onDocMouseover = function (evt) {
	if (!evt) evt = window.event;

	var cmp = Event.element(evt);
	/** Request 1628075: give up.
	    Why? the wait cursor won't disappear until users move the cursor
	if (cmp && cmp.style && cmp.getAttribute && $tag(cmp) != "HTML") {
		var bk = cmp.getAttribute("z_bk4wait");
		if (zk.progressPrompted) {
			if (!bk) {
				var cr = cmp.style.cursor;
				cmp.setAttribute("z_bk4wait", cr ? cr: "nil");
				cmp.style.cursor = "wait";
			}
		} else if (bk) {
			cmp.removeAttribute("z_bk4wait");
			cmp.style.cursor = bk == "nil" ? "": bk;
		}
	}*/

	cmp = zkau._parentByZKAttr(cmp, "tip");
	if (cmp && !zk.progressing) { //skip tip if in processing
		var tip = getZKAttr(cmp, "tip");
		tip = zkau.getByZid(cmp, tip);
		if (tip) {
			var open = zkau._tipz && zkau._tipz.open;
			if (!open || zkau._tipz.cmpId != cmp.id) {
				if (zkau._tipz) {
					zkau._tipz.shallClose = true;
					zkau._tryCloseTip();
				}
				zkau._tipz = {
					tipId: tip.id, cmpId: cmp.id,
					x: Event.pointerX(evt) + 1, y: Event.pointerY(evt) + 2
					 //Bug 1572286: position tooltip with some offset to allow
				};
				if (open) zkau._openTip(cmp.id, true);
				else setTimeout("zkau._openTip('"+cmp.id+"')", zk_tipto);
			} else {
				zkau._openTip(cmp.id, true);
			}
			return; //done
		}
	}
	if (zkau._tipz) {
		if (zkau._tipz.open) {
			var tip = $e(zkau._tipz.tipId);
			if (tip && zk.isAncestor(tip, Event.element(evt))) {
				zkau._tipz.shallClose = false; //don't close it
			} else {
				zkau._tipz.shallClose = true;
				setTimeout(zkau._tryCloseTip, 300);
			}
		} else
			zkau._tipz = null;
	}
};
/** document.onmouseout */
zkau._onDocMouseout = function (evt) {
	if (!evt) evt = window.event;

	if (zkau._tipz)
		if (zkau._tipz.open) {
			zkau._tipz.shallClose = true;
			setTimeout(zkau._tryCloseTip, 300);
		} else
			zkau._tipz = null;
};
/** window.onresize */
zkau._onResize = function () {
	if (zkau._cInfoReg) {
		//since IE keeps sending onresize when dragging the browser border,
		//we reduce # of packs sent to the server by use of timeout
		zkau._cInfoPend = true;
		setTimeout(zkau._doClientInfo, 150);
	}

	zkau._onResize1();
}
zkau._onResize1 = function () {
	if (zk.booting)
		return; //IE6: it sometimes fires an "extra" onResize in loading

	//Tom Yeh: 20051230:
	//In certain case, IE will keep sending onresize (because
	//grid/listbox may adjust size, which causes IE to send onresize again)
	//To avoid this endless loop, we ignore onresize a whilf if _reszfn
	//is called
	if (!zkau._tmResz || $now() > zkau._tmResz) {
		++zkau._reszcnt;
		setTimeout(zkau._onResize2, zk.ie && zkau._reszcnt < 5 ? 200: 35);
			//IE keeps sending onresize when dragging the browser's border,
			//so we have to filter (most of) them out

	} else setTimeout(zkau._onResize1, 200);
};
zkau._onResize2 = function () {
	if (!--zkau._reszcnt) {
		if (zk.loading || anima.count) {
			zkau._onResize1();
			return;
		}

		if (zk.ie) zkau._tmResz = $now() + 1500;
			//IE keeps sending onresize when dragging the browser's border,
			//so we have to filter (most of) them out

		zk.beforeSizeAt();
		zk.onSizeAt();
	}
};
zkau._reszcnt = 0;

/** send clientInfo to the server ontimeout. */
zkau._doClientInfo = function () {
	if (zkau._cInfoPend) {
		zkau._cInfoPend = false;
		zkau.cmd0.clientInfo();
	}
};

zkau._openTip = function (cmpId, enforce) {
	if (!zkau._tipz || (zkau._tipz.open && !enforce))
		return;

 	if (!cmpId || cmpId == zkau._tipz.cmpId) {
	//We have to filter out non-matched cmpId because user might move
	//from one component to another
		var tip = $e(zkau._tipz.tipId);
		if (tip) {
			var cmp = $e(cmpId);
			zkau._tipz.open = true;

			tip.style.position = "absolute";
			zk.setVParent(tip); //FF: Bug 1486840, IE: Bug 1766244
			zkau._autopos(tip, zkau._tipz.x, zkau._tipz.y);
			zk.eval(tip, "context", null, cmp);
			//not setZKAttr(... "owner") since it is OK to close
		} else {
			zkau._tipz = null;
		}
	}
};
/** Closes tooltip if _tipz.shallClose is set. */
zkau._tryCloseTip = function () {
	if (zkau._tipz && zkau._tipz.shallClose) {
		if (zkau._tipz.open) {
			for (var close, n = $e(zkau._tipz.tipId), fts = zkau.floats, j = fts.length; --j >= 0;) {
				if (typeof fts[j].getFloatIds != "function") continue;
				if (!$visible(n) || getZKAttr(n, "animating") == "hide") break;
				for (var f = fts[j].getFloatIds(), len = f.length; --len >= 0;) {
					if (zk.isAncestor(n, f[len])) {
						fts[j]._close($e(f[len]));
						f.splice(len, 1);
						close = true;
					}
				}
				
				if (close) {
					zkau._tipz = null;
					break;
				}
			}
		}
	}
};

/** Returns the target of right-click, or null if not found. */
zkau._parentByZKAttr = function (n, attr1, attr2) {
	for (; n; n = $parent(n)) {
		if (attr1 && getZKAttr(n, attr1)) return n;
		if (attr2 && getZKAttr(n, attr2)) return n;
		if (getZKAttr(n, "float")) break;
			//tooltip/popup/context might be inside the component
	}
	return null;
};

/** Handles document.onkeydown. */
zkau._onDocKeydown = function (evt) {
	if (!evt) evt = window.event;
	var target = Event.element(evt),
		zkAttrSkip, evtnm, ctkeys, shkeys, alkeys, exkeys,
		keycode = Event.keyCode(evt), zkcode; //zkcode used to search z.ctkeys
	switch (keycode) {
	case 13: //ENTER
		var tn = $tag(target);
		if (tn == "TEXTAREA" || tn == "BUTTON"
		|| (tn == "INPUT" && target.type.toLowerCase() == "button"))
			return true; //don't change button's behavior (Bug 1556836)
		//fall thru
	case 27: //ESC
		if (zkau.closeFloats(target)) {
			Event.stop(evt);
			return false; //eat
		}
		if (keycode == 13) {
			zkAttrSkip = "skipOK"; evtnm = "onOK";
		} else {
			zkAttrSkip = "skipCancel"; evtnm = "onCancel";
		}
		break;
	case 16: //Shift
	case 17: //Ctrl
	case 18: //Alt
		return true;
	case 45: //Ins
	case 46: //Del
		zkcode = keycode == 45 ? 'I': 'J';
		break;
	default:
		if (keycode >= 33 && keycode <= 40) { //PgUp, PgDn, End, Home, L, U, R, D
			zkcode = String.fromCharCode('A'.charCodeAt(0) + (keycode - 33));
				//A~H: PgUp, ...
			break;
		} else if (keycode >= 112 && keycode <= 123) { //F1: 112, F12: 123
			zkcode = String.fromCharCode('P'.charCodeAt(0) + (keycode - 112));
				//M~Z: F1~F12
			break;
		} else if (evt.ctrlKey || evt.altKey) {
			zkcode = String.fromCharCode(keycode).toLowerCase();
			break;
		}
		return true;
	}

	if (zkcode) evtnm = "onCtrlKey";

	for (var n = target, ref; n; n = $parent(n)) {
		if (n.id && n.getAttribute) {
			if (!ref && n.id.indexOf("!") == -1)
				ref = n.id;
			if (getZKAttr(n, evtnm) == "true"
			&& (!zkcode || zkau._inCtkeys(evt, zkcode, getZKAttr(n, "ctkeys")))) {
				var bSend = true;
				if (zkau.currentFocus) {
					var inp = zkau.currentFocus;
					switch ($tag(inp)) {
					case "INPUT":
						var type = inp.type.toLowerCase();
						if (type != "text" && type != "password")
							break; //ignore it
						//fall thru
					case "TEXTAREA":
						bSend = zkau.textbox && zkau.textbox.updateChange(inp, false);
					}
				}

				var req = {uuid: n.id, cmd: evtnm, ctl: true,
					data: [keycode, evt.ctrlKey, evt.shiftKey, evt.altKey, ref]};
				if (zk.gecko && $tag(inp) == "SELECT" && $type(inp) && zkau.asap(inp, "onSelect"))
					zkau.lateReq = req; //Bug 1756559:let SELECT to send (see sel.js)
				else
					zkau.send(req, 38);
				Event.stop(evt);
				return false;
			}
			if ("onCancel" == evtnm && $type(n) == "Wnd") {
				if (getZKAttr(n, "closable") == "true") {
					zkau.sendOnClose(n);
					Event.stop(evt);
					return false;
					//20060504: Bug 1481676: Tom Yeh
					//We have to stop ESC event. Otherwise, it terminates
					//Ajax connection (issue by close)
				}
				break;
			}
			if (zkAttrSkip && getZKAttr(n, zkAttrSkip) == "true")
				break; //nothing to do
		}
	}

	if (keycode == 27 && zkau._areq) { //Bug 1927788: prevent FF from closing connection
		Event.stop(evt);
		return false; //eat
	}
	return true; //no special processing
};
/** returns whether a key code is specified in keys. */
zkau._inCtkeys = function (evt, zkcode, keys) {
	if (keys) {
		//format: ctl+k;alt+k;shft+k;k
		var cc = evt.ctrlKey ? '^': evt.altKey ? '@': evt.shiftKey ? '$': '#';
		var j = keys.indexOf(cc), k = keys.indexOf(';', j + 1);
		if (j >=0 && k >= 0) {
			keys = keys.substring(j + 1, k);
			return keys.indexOf(zkcode) >= 0;
		}
	}
	return false;
};

zkau.sendOnMove = function (cmp, keys) {
	var offset = getZKAttr(cmp, "offset");
	var left = cmp.style.left, top = cmp.style.top;
	if (offset && getZKAttr(cmp, "pos") == "parent") {
		var xy = offset.split(",");
		left = $int(left) - $int(xy[0]) + "px";
		top = $int(top) - $int(xy[1]) + "px";
	}
	zkau.sendasap({uuid: cmp.id, cmd: "onMove",
		data: [left, top, keys ? keys: ""], ignorable: true}); //yes, ignorable since it is implicit for modal window
};
zkau.sendOnZIndex = function (cmp) {
	zkau.sendasap({uuid: cmp.id, cmd: "onZIndex",
		data: [cmp.style.zIndex], ignorable: true}); //yes, ignorable since it is implicit for modal window
};
zkau.sendOnSize = function (cmp, keys) {
	zkau.sendasap({uuid: cmp.id, cmd: "onSize",
		data: [cmp.style.width, cmp.style.height, keys]});

	setTimeout(function () {zk.beforeSizeAt(cmp); zk.onSizeAt(cmp);},
		zk.ie6Only ? 800: 0);
	// If the vflex component in the window component, the offsetHeight of the specific component is wrong at the same time on IE6.
	// Thus, we have to invoke the zk.onSizeAt function again.
};
zkau.sendOnClose = function (uuid, closeFloats) {
	var el = $e(uuid);
	if (closeFloats) zkau.closeFloats(el);
	zkau.send({uuid: el.id, cmd: "onClose"}, 5);
};
/** Ask the server to redraw all desktops on the browser.
 * @since 3.0.6
 */
zkau.sendRedraw = function () {
	zk.errorDismiss();
	for (var ds = zkau._dtids, j = ds.length; --j >= 0;)
		zkau.send({dtid: ds[j], cmd: "redraw"});
};

/** Test if any float is opened.
 * @since 3.0.4
 */
zkau.anyFloat = function () {
	for (var fts = zkau.floats, j = fts.length; --j >= 0;)
		if (!fts[j].empty())
			return true;
	return false;
};

/** Closes popups and floats except any of the specified components
 * is an ancestor of popups and floats.
 *
 * Maybe it shall be named as closeFloatsBut, but we cannot due to backward
 * compatible issues.
 *
 * @param arguments a list of component (or its ID) to exclude if
 * a popup contains any of them
 * @return false if nothing changed.
 */
zkau.closeFloats = function () {
	return zkau._closeFloats("closeFloats", zkau._shallCloseBut, arguments);
};
/** Similar to zkau.closeFloats, except it is called when a component
 * is getting the focus.
 * More precisely, it treats all floats as popup windows, i.e.,
 * floats remains if it is an ancestor of aruments.
 */
zkau.closeFloatsOnFocus = function () {
	return zkau._closeFloats("closeFloatsOnFocus", zkau._shallCloseBut, arguments);
};
zkau._shallCloseBut = function (n, ancestors) {
	return !zk.isAncestorX(n, ancestors, true, true);
};
/** Closes popups and floats if they belongs to any of the specified component.
 * By belong we mean a component is a descendant of another.
 * @return false if nothing changed.
 * @since 3.0.2
 */
zkau.closeFloatsOf = function () {
	return zkau._closeFloats("closeFloatsOf", zkau._shallCloseOf, arguments);
};
zkau._shallCloseOf = function (n, ancestors) {
	return zk.isAncestorX1(ancestors, n, true, true);
}
zkau._closeFloats = function (method, shallClose, ancestors) {
	var closed;
	for (var j = zkau._popups.length; --j >=0;) {
	//reverse order is important if popup contains another
	//otherwise, IE seem have bug to handle them correctly
		var n = $e(zkau._popups[j]);
		if ($visible(n) && getZKAttr(n, "animating") != "hide"
		&& shallClose(n, ancestors)) {
		//we avoid hiding twice we have to check animating
			closed = true;
			zk.unsetVParent(n);
			zk.hide(n);
			zkau.sendasap({uuid: n.id, cmd: "onOpen", data: [false]});
				//We have to send onOpen since the server need to know
				//whether the popup becomes invsibile
		}
	}

	//floats: combobox, context menu...
	for (var fts = zkau.floats, j = fts.length; --j >= 0;) {
		var ft = fts[j];
		if (ft[method].apply(ft, ancestors))
			closed = true;
	}

	if (closed)
		zkau.hideCovered();
	return closed;
};

zkau.hideCovered = function() {
	var ary = [];
	for (var j = 0, pl = zkau._popups.length; j < pl; ++j) {
		var el = $e(zkau._popups[j]);
		if ($visible(el)) ary.push(el);
	}

	for (var j = 0, fl = zkau.floats.length; j < fl; ++j)
		zkau.floats[j].addHideCovered(ary);

	for (var j = 0, ol = zkau._overlaps.length; j < ol; ++j) {
		var el = $e(zkau._overlaps[j]);
		if ($visible(el)) ary.push(el);
	}
	zk.hideCovered(ary);

	if (zkau.valid) zkau.valid.uncover();
};

/** Returns the meta info associated with the specified cmp or its UUID.
 */
zkau.getMeta = function (cmp) {
	var id = typeof cmp == 'string' ? cmp: cmp ? cmp.id: null;
	if (!id) return null;
	return zkau._metas[$uuid(id)];
};
/** Returns the meta info associated with the specified cmp or its UUID.
 */
zkau.setMeta = function (cmp, info) {
	var id = typeof cmp == 'string' ? cmp: cmp ? cmp.id: null;
	if (!id) {
		zk.error(mesg.COMP_OR_UUID_REQUIRED);
		return;
	}
	if (info) zkau._metas[$uuid(id)] = info;
	else delete zkau._metas[$uuid(id)]; //save memory
};
/** Returns the info by specified any child component and the type.
 */
zkau.getMetaByType = function (el, type) {
	el = $parentByType(el, type);
	return el != null ? zkau.getMeta(el): null;
};

/** Cleans up meta of the specified component.
 * <p>Note: this method is called automatically if z.type is defined.
 * So, you need to call this method only if no z.type -- very rare.
 */
zkau.cleanupMeta = function (cmp) {
	var meta = zkau.getMeta(cmp);
	if (meta) {
		if (meta.cleanup) meta.cleanup();
		zkau.setMeta(cmp, null);
	}
};

//Server Push//
/** Sets the info of the server push.
 * @since 3.0.0
 */
zkau.setSPushInfo = function (dtid, info) {
	var i = zkau._spushInfo[dtid];
	if (!i) i = zkau._spushInfo[dtid] = {};

	if (info.min != null) i.min = info.min;
	if (info.max != null) i.max = info.max;
	if (info.factor != null) i.factor = info.factor;
};
/** Returns the info of the server push.
 * @since 3.0.0
 */
zkau.getSPushInfo = function (dtid) {
	return zkau._spushInfo[dtid];
};

////
//ID Space//
/** Returns element of the specified zid. */
zkau.getByZid = function (n, zid) {
	if (zid.startsWith("uuid(") && zid.endsWith(')'))
		return $e(zid.substring(5, zid.length - 1));

	var oid = zkau._zidOwner(n);
	var v = zkau._zidsp[oid];
	if (v) {
		v = v[zid];
		if (v) return $e(v);
	}
};
zkau.initzid = function (n, zid) {
	var oid = zkau._zidOwner(n);
	var ary = zkau._zidsp[oid];
	if (!ary) ary = zkau._zidsp[oid] = {};
	if (!zid) zid = getZKAttr(n, "zid");
	ary[zid] = n.id;
};
zkau.cleanzid = function (n) {
	var oid = zkau._zidOwner(n);
	var ary = zkau._zidsp[oid];
	if (ary) delete ary[getZKAttr(n, "zid")];
};
/** Clean an ID space. */
zkau.cleanzidsp = function (n) {
	delete zkau._zidsp[n.id];
};
/** Returns the space owner that n belongs to, or null if not found. */
zkau._zidOwner = function (n) {
	//zidsp currently applied only to page, since we'd like
	//developers easy to reference other component in the same page
	//If you want to support a new space, just generae zidsp="true"
	for (var p = n; p; p = $parent(p)) {
		if (getZKAttr(p, "zidsp"))
			return p.id;
	}
	return "_zdt_" + zkau.dtid(n);
};

///////////////
//Drag & Drop//
zkau.initdrag = function (n) {
	zkau._drags[n.id] = new Draggable(n, {
		starteffect: zk.voidf, // bug #1886342: we cannot use the zkau.closeFloats function in this situation.
		endeffect: zkau._enddrag, change: zkau._dragging,
		ghosting: zkau._ghostdrag, z_dragdrop: true,
		constraint: zkau._constraint,
		revert: zkau._revertdrag, ignoredrag: zkau._ignoredrag, zindex: 88800
	});
	zk.eval(n, "initdrag");
};
zkau.cleandrag = function (n) {
	if (zkau._drags[n.id]) {
		zkau._drags[n.id].destroy();
		delete zkau._drags[n.id];
	}
	zk.eval(n, "cleandrag");
};
zkau.initdrop = function (n) {
	zkau._drops.unshift(n); //last created, first matched
};
zkau.cleandrop = function (n) {
	zkau._drops.remove(n);
};

zkau._ignoredrag = function (el, pointer) {
	return zk.eval(el, "ignoredrag", null, pointer);
};
zkau._dragging = function (dg, pointer, evt) {
	var target = Event.element(evt);	
	if (target == dg.zk_lastTarget) return;
		
	var e = zkau._getDrop(dg.z_elorg || dg.element, pointer, evt);
	var flag = e && e == dg.zk_lastDrop;
	if (!e || e != dg.zk_lastDrop) {
		zkau._cleanLastDrop(dg);
		if (e) {			
			dg.zk_lastDrop = e;
			Droppable_effect(e);
			flag = true;
		}
	}
	if (flag && dg.element._img) {
		if (dg.element._img.className != "drop-allow")
			dg.element._img.className = "drop-allow";
	} else if (dg.element._img) {
		if (dg.element._img.className != "drop-disallow")
		dg.element._img.className = "drop-disallow";
	}
	dg.zk_lastTarget = target;
};
zkau._revertdrag = function (cmp, pointer, evt) {
	if (zkau._getDrop(cmp, pointer, evt) == null)
		return true;

	//Note: we hve to revert when zkau._onRespReady called, since app might
	//change cmp's position
	var dg = zkau._drags[cmp.id];
	var orgpos = cmp.style.position;
	zkau._revertpending = function () {
		//Bug 1599737: a strange bar appears
		if (zk.ie && orgpos != 'absolute' && orgpos != 'relative')
			zkau._fixie4drop(cmp, orgpos);
		if (dg.z_x != null) {
			cmp.style.left = dg.z_x;
			cmp.style.top = dg.z_y;
			delete dg.z_x;
			delete dg.z_y;
		}
		delete zkau._revertpending; //exec once
	};
	return false;
};
if (zk.ie) {
//In IE, we have to detach and attach. We cannot simply restore position!!
//Otherwise, a strange bar appear
	zkau._fixie4drop = function (el, orgpos) {
		var p = el.parentNode;
		var n = el.nextSibling;
		zk.remove(el);
		el.style.position = orgpos;
		if (n) p.insertBefore(el, n);
		else p.appendChild(el);
	};
}

zkau._enddrag = function (cmp, evt) {
	zkau._cleanLastDrop(zkau._drags[cmp.id]);
	var pointer = [Event.pointerX(evt), Event.pointerY(evt)];
	var e = zkau._getDrop(cmp, pointer, evt);
	if (e) {
		var keys = "";
		if (evt) {
			if (evt.altKey) keys += 'a';
			if (evt.ctrlKey) keys += 'c';
			if (evt.shiftKey) keys += 's';
		}
		setTimeout("zkau._sendDrop('"+cmp.id+"','"+e.id+"','"+pointer[0]+"','"+pointer[1]+"','"+keys+"')", 38);
			//In IE, listitem is selected after _enddrag, so we have to
			//delay the sending of onDrop
	}
};
zkau._sendDrop = function (dragged, dropped, x, y, keys) {
	zkau.send({uuid: dropped, cmd: "onDrop", data: [dragged, x, y, keys]});
};
zkau._getDrop = function (cmp, pointer, evt) {
	var dragType = getZKAttr(cmp, "drag");
	var el = Event.element(evt);
	l_next:
	for (; el; el = $parent(el)) {
		if (el == cmp) return; //dropping to itself not allowed
		var dropTypes = getZKAttr(el, "drop");	
		if (dropTypes) {
			if (dropTypes != "true") {
				if (dragType == "true") continue; //anonymous drag type
				for (var k = 0;;) {
					var l = dropTypes.indexOf(',', k);
					var s = l >= 0 ? dropTypes.substring(k, l): dropTypes.substring(k);
					if (s.trim() == dragType) break; //found
					if (l < 0) continue l_next;
					k = l + 1;
				}
			}
			return el; //found;
		}
	}
	return null;
};
zkau._cleanLastDrop = function (dg) {
	if (!dg) return;
	if (dg.zk_lastDrop) {
		Droppable_effect(dg.zk_lastDrop, true);
		dg.zk_lastDrop = null;
	}
	dg.zk_lastTarget = null;
};
zkau._proxyXY = function (evt) {
	return [Event.pointerX(evt) + 10, Event.pointerY(evt) + 10];
};
zkau._constraint = function (dg, p, evt) {
	return zkau._proxyXY(evt);
};
zkau._ghostdrag = function (dg, ghosting, evt) {
//Tom Yeh: 20060227: Use a 'fake' DIV if
//1) FF cannot handle z-index well if listitem is dragged across two listboxes
//2) Safari's ghosting position is wrong
//3) Opera's width is wrong if cloned

//Bug 1783363: Due to the use of "position:relative",
//a side effect of Bug 1766244, we no longer clone even if zk.ie
	var special;
	if (ghosting) {
		var tn = $tag(dg.element);
		zk.zk_special = special = "TR" == tn || "TD" == tn || "TH" == tn;
	} else {
		special = zk.zk_special;
	}
	if (ghosting) {
		zkau.beginGhostToDIV(dg);
		var ofs = zkau._proxyXY(evt);		
		if (special) {
			var msg = "";
			var target = Event.element(evt);
			if (target.id.indexOf("!cave") > 0) 
				msg = target.textContent || target.innerText;
			else 
				if (target.id.indexOf("!cell") > 0) {
					var real = $real(target.id);
					msg = real.textContent || real.innerText;
				}
				else 
					msg = target.textContent || target.innerText;
			if (!msg) msg = "";
			if (msg.length > 10) msg = msg.substring(0,10) + "...";
			var el = dg.element;
			document.body.insertAdjacentHTML("beforeend",	
				'<div id="zk_ddghost" class="drop-ghost" style="position:absolute;top:'
				+ofs[1]+'px;left:'+ofs[0]+'px;"><div class="drop-content"><span id="zk_ddghost!img" class="drop-disallow"></span>&nbsp;'+msg+'</div></div>');				
		}else {
			var el  = dg.element.cloneNode(true);
			el.id = "zk_ddghost";
			el.style.position = "absolute";
			var xy = zkau._proxyXY(evt);
			el.style.top = xy[1] + "px";
			el.style.left = xy[0] + "px";
			document.body.appendChild(el);
		}
		dg.element = $e("zk_ddghost");
		if (special) dg.element._img = $e(dg.element.id + "!img");
		document.body.style.cursor = "pointer";
	} else {
		dg.element._img = null;
		zkau.endGhostToDIV(dg);
		document.body.style.cursor = "";
	}
	return false	
};
/** Prepares to ghost dg.element to a DIV.
 * It is used when you want to ghost with a div.
 * @return the offset of dg.element.
 */
zkau.beginGhostToDIV = function (dg) {
	zk.dragging = true;
	dg.delta = dg.currentDelta();
	dg.z_elorg = dg.element;
	
	var ofs = Position.cumulativeOffset(dg.element);
	dg.z_scrl = Position.realOffset(dg.element);
	dg.z_scrl[0] -= zk.innerX(); dg.z_scrl[1] -= zk.innerY();
		//Store scrolling offset since Draggable.draw not handle DIV well
	
	ofs[0] -= dg.z_scrl[0]; ofs[1] -= dg.z_scrl[1];	
	return ofs;
};
/** Returns the origin element before ghosted.
 * <p>Note: the ghosted DIV is dg.element.
 * It is called between beginGhostToDIV and endGhostToDIV
 */
zkau.getGhostOrgin = function (dg) {
	return dg.z_elorg;
};
/** Clean and remove the ghosted DIV.
 */
zkau.endGhostToDIV = function (dg) {
	setTimeout("zk.dragging=false", 0);
		//we have to reset it later since onclick is fired later (after onmouseup)
	if (dg.z_elorg && dg.element != dg.z_elorg) {
		zk.remove(dg.element);
		dg.element = dg.z_elorg;
		delete dg.z_elorg;
	}
};

//Perfomance Meter//
zkau._pfj = 0; //an index
zkau._pfIds = ""; //what are processed
zkau._pfsend = function (req, dtid) {
	req.setRequestHeader("ZK-Client-Start",
		dtid + "-" + zkau._pfj++ + "=" + Math.round($now()));

	if (zkau._pfIds) {
		req.setRequestHeader("ZK-Client-Complete", zkau._pfIds);
		zkau._pfIds = "";
	}
};
zkau._pfrecv = function (req) {
	//ZK-Client-Complete from the server is a list of requestId
	//separated with ' '
	var ids = req.getResponseHeader("ZK-Client-Complete");
	if (ids && (ids = ids.trim())) {
		if (zkau._pfIds) zkau._pfIds += ',';
		zkau._pfIds += ids + "=" + Math.round($now());
	}
};

//Upload//
/** Begins upload (called when the submit button is pressed)
 * @param wndid id of window to close, if any
 */
zkau.beginUpload = function (wndid) {
	zkau.endUpload();
	zkau._upldWndId = wndid;
	zkau._tmupload = setInterval(function () {
		zkau.send({dtid: zkau.dtid(wndid), cmd: "getUploadInfo", ignorable: true});
	}, 1000);
};
zkau.updateUploadInfo = function (p, cb) {
	if (cb <= 0) zkau.endUpload();
	else if (zkau._tmupload) {
		var img = $e("zk_upload!img");
		if (!img) {
			var html = '<div id="zk_upload" style="position:absolute;border:1px solid #77a;padding:9px;background-color:#fec;z-index:79000">'
				+'<div style="width:202px;border:1px inset"><img id="zk_upload!img" src="'+zk.getUpdateURI('/web/zk/img/prgmeter.gif')
				+'"/></div><br/>'+mesg.FILE_SIZE+Math.round(cb/1024)+mesg.KBYTES
				+'<br/><input type="button" value="'+mesg.CANCEL+'" onclick="zkau._cancelUpload()"</div>';
			document.body.insertAdjacentHTML("afterbegin", html);
			zk.center($e("zk_upload"));
			img = $e("zk_upload!img");
		}
		if (p >= 0 && p <= 100) {
			img.style.height = "10px"; //avoid being scaled when setting width
			img.style.width = (p * 2) + "px";
		}
	}
};
zkau._cancelUpload = function () {
	zkau.endUpload();

	if (zkau._upldWndId) {
		zkau.sendOnClose(zkau._upldWndId);
		zkau._upldWndId = null;
	}
};
/** Called to end the upload. It must be called if beginUpload is called.
 */
zkau.endUpload = function () {
	zk.focus(window);
		//focus might be in iframe of fileupload dlg, so get it back
		//otherwise, IE might lose focus forever (see also Bug 1526542)

	zk.remove($e("zk_upload"));
	if (zkau._tmupload) {
		clearInterval(zkau._tmupload);
		zkau._tmupload = null;
	}
};

//Miscellanous//
zkau.history = new zk.History();

//Commands//
zkau.cmd0 = { //no uuid at all
	bookmark: function (dt0) {
		zkau.history.bookmark(dt0);
	},
	obsolete: function (dt0, dt1) { //desktop timeout
		zkau._cleanupOnFatal();
		zk.error(dt1);
	},
	alert: function (msg) {
		zk.alert(msg);
	},
	redirect: function (url, target) {
		try {
			zk.go(url, false, target);
		} catch (ex) {
			if (!zkau.confirmClose) throw ex;
		}
	},
	title: function (dt0) {
		document.title = dt0;
	},
	script: function (dt0) {
		eval(dt0);
	},
	echo: function (dtid) {
		zkau.send({dtid: dtid, cmd: "dummy", ignorable: true});
	},
	clientInfo: function (dtid) {
		zkau._cInfoReg = true;
		zkau.send({dtid: dtid, cmd: "onClientInfo", data: [
			new Date().getTimezoneOffset(),
			screen.width, screen.height, screen.colorDepth,
			zk.innerWidth(), zk.innerHeight(), zk.innerX(), zk.innerY()
		]});
	},
	download: function (url) {
		if (url) {
			var ifr = $e('zk_download');
			if (ifr) {
				ifr.src = url; //It is OK to reuse the same iframe
			} else {
				var html = '<iframe src="'+url+'" id="zk_download" name="zk_download" style="display:none;width:0;height:0;border:0"></iframe>';
				zk.insertHTMLBeforeEnd(document.body, html);
			}
		}
	},
	print: function () {
		window.print();
	},
	scrollBy: function (x, y) {
		window.scrollBy(x, y);
	},
	scrollTo: function (x, y) {
		window.scrollTo(x, y);
	},
	resizeBy: function (x, y) {
		window.resizeBy(x, y);
	},
	resizeTo: function (x, y) {
		window.resizeTo(x, y);
	},
	moveBy: function (x, y) {
		window.moveBy(x, y);
	},
	moveTo: function (x, y) {
		window.moveTo(x, y);
	},
	cfmClose: function (msg) {
		zkau.confirmClose = msg;
	},
	showBusy: function (msg, open) {
		//close first (since users might want close and show diff message)
		var n = $e("zk_showBusy");
		if (n) {
			n.parentNode.removeChild(n);
			zk.restoreDisabled();
		}

		if (open == "true") {
			n = $e("zk_loadprog");
			if (n) n.parentNode.removeChild(n);
			n = $e("zk_prog");
			if (n) n.parentNode.removeChild(n);
			n = $e("zk_showBusy");
			if (!n) {
				msg = msg == "" ? mesg.PLEASE_WAIT : msg;
				Boot_progressbox("zk_showBusy", msg,
					0, 0, true, true);
				zk.disableAll();
			}
		}
	}
};
zkau.cmd1 = {
	wrongValue: function (uuid, cmp, dt1) {
		if (cmp) {
			cmp = $real(cmp); //refer to INPUT (e.g., datebox)

			//we have to update default value so validation will be done again
			var old = cmp.value;
			cmp.defaultValue = old + "_err"; //enforce to validate
			if (old != cmp.value) cmp.value = old; //Bug 1490079 (FF only)

			if (zkau.valid) zkau.valid.errbox(cmp.id, dt1);
			else zk.alert(dt1);
		} else if (!uuid) { //keep silent if component (of uuid) not exist (being detaced)
			zk.alert(dt1);
		}
	},
	setAttr: function (uuid, cmp, nm, val) {
		if (nm == "z.init" || nm == "z.chchg") { //initialize
			//Note: cmp might be null because it might be removed
			if (cmp) {
				var type = $type(cmp);
				if (type) {
					zk.loadByType(cmp);
					if (zk.loading) {
						zk.addInitCmp(cmp);
					} else {
						zk.eval(cmp, nm == "z.init" ? "init": "childchg", type);
					}
				}
			}
			return; //done
		}

		if (val == null && arguments.length <= 4) { //single null value
			zkau.cmd1.rmAttr(uuid, cmp, nm);
			return;
		}

		var done = false;
		if ("z.drag" == nm) {
			if (!getZKAttr(cmp, "drag")) zkau.initdrag(cmp);
			zkau.setAttr(cmp, nm, val);
			done = true;
		} else if ("z.drop" == nm) {
			if (!getZKAttr(cmp, "drop")) zkau.initdrop(cmp);
			zkau.setAttr(cmp, nm, val);
			done = true;
		} else if ("zid" == nm) {
			zkau.cleanzid(cmp);
			if (val) zkau.initzid(cmp, val);
		}

		var args = [cmp, "setAttr", null, nm, val];
		for (var j = arguments.length - 4; --j >= 0;)
			args[j + 5] = arguments[j + 4];
		if (zk.eval.apply(cmp, args))
			return; //done

		if (!done)
			zkau.setAttr(cmp, nm, val);
	},
	rmAttr: function (uuid, cmp, nm) {
		var done = false;
		if ("z.drag" == nm) {
			zkau.cleandrag(cmp);
			zkau.rmAttr(cmp, nm);
			done = true;
		} else if ("z.drop" == nm) {
			zkau.cleandrop(cmp);
			zkau.rmAttr(cmp, nm);
			done = true;
		}

		if (zk.eval(cmp, "rmAttr", null, nm)) //NOTE: cmp is NOT converted to real!
			return; //done

		if (!done)
			zkau.rmAttr(cmp, nm);
	},
	outer: function (uuid, cmp, html) {
		zk.unsetChildVParent(cmp, true); //OK to hide since it will be replaced

		zk.cleanupAt(cmp);
		var from = cmp.previousSibling, from2 = cmp.parentNode,
			to = cmp.nextSibling;
		zk.setOuterHTML(cmp, html);
		if (from) zkau._initSibs(from, to, true);
		else zkau._initChildren(from2, to);

		if (zkau.valid) zkau.valid.fixerrboxes();
	},
	addAft: function (uuid, cmp, html) {
		//Bug 1939059: This is a dirty fix. Refer to AuInsertBefore
		//Format: comp-uuid:pg-uuid (if native root)
		if (!cmp) {
			var j = uuid.indexOf(':');
			if (j >= 0) { //native root
				cmp = $e(uuid.substring(0, j)); //try comp (though not possible)
				if (!cmp) {
					uuid = uuid.substring(j + 1); //try page
					cmp = $e(uuid);
					if (!cmp) cmp = document.body;
					zkau.cmd1.addChd(uuid, cmp, html);
					return;
				}
			}
		}

		var v = zk.isVParent(cmp);
		if (v) zk.unsetVParent(cmp);
		var n = $childExterior(cmp);
		var to = n.nextSibling;
		zk.insertHTMLAfter(n, html);
		zkau._initSibs(n, to, true);
		if (v) zk.setVParent(cmp);
	},
	addBfr: function (uuid, cmp, html) {
		var v = zk.isVParent(cmp);
		if (v) zk.unsetVParent(cmp);
		var n = $childExterior(cmp);
		var to = n.previousSibling;
		zk.insertHTMLBefore(n, html);
		zkau._initSibs(n, to, false);
		if (v) zk.setVParent(cmp);
	},
	addChd: function (uuid, cmp, html) {
		/* To add the first child properly, it checks as follows.
		//1) a function called addFirstChild
		2) uuid + "!cave" (as parent)
		3) an attribute called z.cave to hold id (as parent)
		4) uuid + "!child" (as next sibling)
		5) uuid + "!real" (as parent)
		 */
		//if (zk.eval(cmp, "addFirstChild", html))
		//	return;

		var n = $e(uuid + "!cave");
		if (!n) {
			n = getZKAttr(cmp, "cave");
			if (n) n = $e(n);
		}
		if (n) { //as last child of n
			zkau._insertAndInitBeforeEnd(n, html);
			return;
		}

		n = $e(uuid + "!child");
		if (n) { //as previous sibling of n
			var to = n.previousSibling;
			zk.insertHTMLBefore(n, html);
			zkau._initSibs(n, to, false);
			return;
		}

		cmp = $real(cmp); //go into the real tag (e.g., tabpanel)
		zkau._insertAndInitBeforeEnd(cmp, html);
	},
	rm: function (uuid, cmp) {
		//NOTE: it is possible the server asking removing a non-exist cmp
		//so keep silent if not found
		if (cmp) {
			zk.unsetChildVParent(cmp, true); //OK to hide since it will be removed

			zk.cleanupAt(cmp);
			cmp = $childExterior(cmp);
			zk.remove(cmp);
			zkau.hideCovered(); // Bug #1858838
		}
		if (zkau.valid) zkau.valid.fixerrboxes();
	},
	focus: function (uuid, cmp) {
		if (!zk.eval(cmp, "focus")) {
			//Bug 1936366: endModal uses timer, so canFocus might be false
			//when this method is called
			setTimeout(function (){
				if (!zkau.canFocus(cmp, true)) return;

				zkau.autoZIndex(cmp); //some, say, window, not listen to onfocus
				cmp = $real(cmp); //focus goes to inner tag
				zk.asyncFocus(cmp.id, 35);
				}, 30); //wnd.js uses 20
		}
	},
	closeErrbox: function (uuid, cmp) {
		if (zkau.valid)
			zkau.valid.closeErrbox(uuid, false, true);
	},
	submit: function (uuid, cmp) {
		setTimeout(function (){if (cmp && cmp.submit) cmp.submit();}, 50);
	},
	invoke: function (uuid, cmp, func, arg0, arg1, arg2) {
		zk.eval(cmp, func, null, arg0, arg1, arg2);
	},
	popup: function (uuid, cmp, mode, x, y) {
		var type = $type(cmp);
		if (type) {
			if (mode == "0") { //close
				zkau.closeFloatsOf(cmp);
			} else {
				var ref;
				if (mode == "1") { //ref
					ref = $e(x);
					if (ref) {
						var ofs = Position.cumulativeOffset($e(x));
						x = ofs[0];
						y = ofs[1] + zk.offsetHeight(ref);
					}
				}
				cmp.style.position = "absolute";
				zk.setVParent(cmp); //FF: Bug 1486840, IE: Bug 1766244
				zkau._autopos(cmp, $int(x), $int(y));
				zk.eval(cmp, "context", type, ref);
			}
		}
	},
	echo2: function (uuid, cmp, evtnm, data) {
		zkau.send(
			{uuid: uuid, cmd: "echo",
				data: data != null ? [evtnm, data]: [evtnm], ignorable: true});
	}
};
zkau.cmd1.cmd = zkau.cmd1.invoke; //backward compatibility (2.4.1 or before)

} //if (!window.zkau)

zk.GROUPING=",";
zk.DECIMAL=".";
zk.PERCENT="%";
zk.MINUS="-";
zk.DOW_1ST=0;
zk.SDOW=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
zk.S2DOW=zk.SDOW;
zk.FDOW=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];
zk.SMON=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
zk.S2MON=zk.SMON;
zk.FMON=["January","February","March","April","May","June","July","August","September","October","November","December"];
zk.APM=["AM","PM"];

