/********** prototype */

/*  Prototype JavaScript framework, version 1.4.0
 *  (c) 2005 Sam Stephenson <sam@conio.net>
 *
 *  Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the Prototype web site: http://prototype.conio.net/
 *
/*--------------------------------------------------------------------------*/

var Prototype = {
  Version: '1.4.0',
  ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',

  emptyFunction: function() {},
  K: function(x) {return x}
  }

var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var Abstract = new Object();

Object.extend = function(destination, source) {
  for (property in source) {
    destination[property] = source[property];
  }
  return destination;
}

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;
  }
}

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;
  return function(event) {
    return __method.call(object, event || window.event);
  }
}

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;
  }
});

var Try = {
  these: function() {
    var returnValue;

    for (var i = 0; i < arguments.length; i++) {
      var lambda = arguments[i];
      try {
        returnValue = lambda();
        break;
      } catch (e) {}
    }

    return returnValue;
  }
}

/*--------------------------------------------------------------------------*/

var PeriodicalExecuter = Class.create();
PeriodicalExecuter.prototype = {
  initialize: function(callback, frequency) {
    this.callback = callback;
    this.frequency = frequency;
    this.currentlyExecuting = false;

    this.registerCallback();
  },

  registerCallback: function() {
    setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
  },

  onTimerEvent: function() {
    if (!this.currentlyExecuting) {
      try {
        this.currentlyExecuting = true;
        this.callback();
      } finally {
        this.currentlyExecuting = false;
      }
    }
  }
}

/*--------------------------------------------------------------------------*/

function $() {
  var elements = new Array();

  for (var i = 0; i < arguments.length; i++) {
    var element = arguments[i];
    if (typeof element == 'string')
      element = document.getElementById(element);

    if (arguments.length == 1)
      return element;

    elements.push(element);
  }

  return elements;
}
Object.extend(String.prototype, {
  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(eval);
  },

  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[0].nodeValue : '';
  },

  toQueryParams: function() {
    var pairs = this.match(/^\??(.*)$/)[1].split('&');
    return pairs.inject({}, function(params, pairString) {
      var pair = pairString.split('=');
      params[pair[0]] = pair[1];
      return params;
    });
  },

  toArray: function() {
    return this.split('');
  },

  camelize: function() {
    var oStringList = this.split('-');
    if (oStringList.length == 1) return oStringList[0];

    var camelizedString = this.indexOf('-') == 0
      ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
      : oStringList[0];

    for (var i = 1, len = oStringList.length; i < len; i++) {
      var s = oStringList[i];
      camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
    }

    return camelizedString;
  },

  inspect: function() {
    return "'" + this.replace('\\', '\\\\').replace("'", '\\\'') + "'";
  }
});

String.prototype.parseQuery = String.prototype.toQueryParams;

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;
    }
  },

  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 = true;
    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(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;
  },

  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;
  },

  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.collect(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 (value >= (result || value))
        result = value;
    });
    return result;
  },

  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value <= (result || value))
        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;
  },

  sortBy: function(iterator) {
    return this.collect(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.collect(Prototype.K);
  },

  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) {
      iterator(value = collections.pluck(index));
      return value;
    });
  },

  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; i < iterable.length; i++)
      results.push(iterable[i]);
    return results;
  }
}

Object.extend(Array.prototype, Enumerable);

Array.prototype._reverse = Array.prototype.reverse;

Object.extend(Array.prototype, {
  _each: function(iterator) {
    for (var i = 0; i < this.length; i++)
      iterator(this[i]);
  },

  clear: function() {
    this.length = 0;
    return this;
  },

  first: function() {
    return this[0];
  },

  last: function() {
    return this[this.length - 1];
  },

  compact: function() {
    return this.select(function(value) {
      return value != undefined || value != null;
    });
  },

  flatten: function() {
    return this.inject([], function(array, value) {
      return array.concat(value.constructor == Array ?
        value.flatten() : [value]);
    });
  },

  without: function() {
    var values = $A(arguments);
    return this.select(function(value) {
      return !values.include(value);
    });
  },

  indexOf: function(object) {
    for (var i = 0; i < this.length; i++)
      if (this[i] == object) return i;
    return -1;
  },

  reverse: function(inline) {
    return (inline !== false ? this : this.toArray())._reverse();
  },

  shift: function() {
    var result = this[0];
    for (var i = 0; i < this.length - 1; i++)
      this[i] = this[i + 1];
    this.length--;
    return result;
  },

  inspect: function() {
    return '[' + this.map(Object.inspect).join(', ') + ']';
  }
});
var Hash = {
  _each: function(iterator) {
    for (key in this) {
      var value = this[key];
      if (typeof value == 'function') 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');
  },

  merge: function(hash) {
    return $H(hash).inject($H(this), function(mergedHash, pair) {
      mergedHash[pair.key] = pair.value;
      return mergedHash;
    });
  },

  toQueryString: function() {
    return this.map(function(pair) {
      return pair.map(encodeURIComponent).join('=');
    }).join('&');
  },

  inspect: function() {
    return '#<Hash:{' + this.map(function(pair) {
      return pair.map(Object.inspect).join(': ');
    }).join(', ') + '}>';
  }
}

function $H(object) {
  var hash = Object.extend({}, object || {});
  Object.extend(hash, Enumerable);
  Object.extend(hash, Hash);
  return hash;
}
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;
    do {
      iterator(value);
      value = value.succ();
    } while (this.include(value));
  },

  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);
}

var Ajax = {
  getTransport: function() {
    return Try.these(
      function() {return new ActiveXObject('Msxml2.XMLHTTP')},
      function() {return new ActiveXObject('Microsoft.XMLHTTP')},
      function() {return new XMLHttpRequest()}
    ) || false;
  },

  activeRequestCount: 0
}

Ajax.Responders = {
  responders: [],

  _each: function(iterator) {
    this.responders._each(iterator);
  },

  register: function(responderToAdd) {
    if (!this.include(responderToAdd))
      this.responders.push(responderToAdd);
  },

  unregister: function(responderToRemove) {
    this.responders = this.responders.without(responderToRemove);
  },

  dispatch: function(callback, request, transport, json) {
    this.each(function(responder) {
      if (responder[callback] && typeof responder[callback] == 'function') {
        try {
          responder[callback].apply(responder, [request, transport, json]);
        } catch (e) {}
      }
    });
  }
};

Object.extend(Ajax.Responders, Enumerable);

Ajax.Responders.register({
  onCreate: function() {
    Ajax.activeRequestCount++;
  },

  onComplete: function() {
    Ajax.activeRequestCount--;
  }
});

Ajax.Base = function() {};
Ajax.Base.prototype = {
  setOptions: function(options) {
    this.options = {
      method:       'post',
      asynchronous: true,
      parameters:   ''
    }
    Object.extend(this.options, options || {});
  },

  responseIsSuccess: function() {
    return this.transport.status == undefined
        || this.transport.status == 0
        || (this.transport.status >= 200 && this.transport.status < 300);
  },

  responseIsFailure: function() {
    return !this.responseIsSuccess();
  }
}

Ajax.Request = Class.create();
Ajax.Request.Events =
  ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);
    this.request(url);
  },

  request: function(url) {
    var parameters = this.options.parameters || '';
    if (parameters.length > 0) parameters += '&_=';

    try {
      this.url = url;
      if (this.options.method == 'get' && parameters.length > 0)
        this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;

      Ajax.Responders.dispatch('onCreate', this, this.transport);

      this.transport.open(this.options.method, this.url,
        this.options.asynchronous);

      if (this.options.asynchronous) {
        this.transport.onreadystatechange = this.onStateChange.bind(this);
        setTimeout((function() {this.respondToReadyState(1)}).bind(this), 10);
      }

      this.setRequestHeaders();

      var body = this.options.postBody ? this.options.postBody : parameters;
      this.transport.send(this.options.method == 'post' ? body : null);

    } catch (e) {
      this.dispatchException(e);
    }
  },

  setRequestHeaders: function() {
    var requestHeaders =
      ['X-Requested-With', 'XMLHttpRequest',
       'X-Prototype-Version', Prototype.Version];

    if (this.options.method == 'post') {
      requestHeaders.push('Content-type',
        'application/x-www-form-urlencoded');

      /* Force "Connection: close" for Mozilla browsers to work around
       * a bug where XMLHttpReqeuest sends an incorrect Content-length
       * header. See Mozilla Bugzilla #246651.
       */
      if (this.transport.overrideMimeType)
        requestHeaders.push('Connection', 'close');
    }

    if (this.options.requestHeaders)
      requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

    for (var i = 0; i < requestHeaders.length; i += 2)
      this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
  },

  onStateChange: function() {
    var readyState = this.transport.readyState;
    if (readyState != 1)
      this.respondToReadyState(this.transport.readyState);
  },

  header: function(name) {
    try {
      return this.transport.getResponseHeader(name);
    } catch (e) {}
  },

  evalJSON: function() {
    try {
      return eval(this.header('X-JSON'));
    } catch (e) {}
  },

  evalResponse: function() {
    try {
      return eval(this.transport.responseText);
    } catch (e) {
      this.dispatchException(e);
    }
  },

  respondToReadyState: function(readyState) {
    var event = Ajax.Request.Events[readyState];
    var transport = this.transport, json = this.evalJSON();

    if (event == 'Complete') {
      try {
        (this.options['on' + this.transport.status]
         || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
         || Prototype.emptyFunction)(transport, json);
      } catch (e) {
        this.dispatchException(e);
      }

      if ((this.header('Content-type') || '').match(/^text\/javascript/i))
        this.evalResponse();
    }

    try {
      (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
      Ajax.Responders.dispatch('on' + event, this, transport, json);
    } catch (e) {
      this.dispatchException(e);
    }

    /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
    if (event == 'Complete')
      this.transport.onreadystatechange = Prototype.emptyFunction;
  },

  dispatchException: function(exception) {
    (this.options.onException || Prototype.emptyFunction)(this, exception);
    Ajax.Responders.dispatch('onException', this, exception);
  }
});

Ajax.Updater = Class.create();

Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
  initialize: function(container, url, options) {
    this.containers = {
      success: container.success ? $(container.success) : $(container),
      failure: container.failure ? $(container.failure) :
        (container.success ? null : $(container))
    }

    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, object) {
      this.updateContent();
      onComplete(transport, object);
    }).bind(this);

    this.request(url);
  },

  updateContent: function() {
    var receiver = this.responseIsSuccess() ?
      this.containers.success : this.containers.failure;
    var response = this.transport.responseText;

    if (!this.options.evalScripts)
      response = response.stripScripts();

    if (receiver) {
      if (this.options.insertion) {
        new this.options.insertion(receiver, response);
      } else {
        Element.update(receiver, response);
      }
    }

    if (this.responseIsSuccess()) {
      if (this.onComplete)
        setTimeout(this.onComplete.bind(this), 10);
    }
  }
});

Ajax.PeriodicalUpdater = Class.create();
Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
  initialize: function(container, url, options) {
    this.setOptions(options);
    this.onComplete = this.options.onComplete;

    this.frequency = (this.options.frequency || 2);
    this.decay = (this.options.decay || 1);

    this.updater = {};
    this.container = container;
    this.url = url;

    this.start();
  },

  start: function() {
    this.options.onComplete = this.updateComplete.bind(this);
    this.onTimerEvent();
  },

  stop: function() {
    this.updater.onComplete = undefined;
    clearTimeout(this.timer);
    (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
  },

  updateComplete: function(request) {
    if (this.options.decay) {
      this.decay = (request.responseText == this.lastText ?
        this.decay * this.options.decay : 1);

      this.lastText = request.responseText;
    }
    this.timer = setTimeout(this.onTimerEvent.bind(this),
      this.decay * this.frequency * 1000);
  },

  onTimerEvent: function() {
    this.updater = new Ajax.Updater(this.container, this.url, this.options);
  }
});
document.getElementsByClassName = function(className, parentElement) {
  var children = ($(parentElement) || document.body).getElementsByTagName('*');
  return $A(children).inject([], function(elements, child) {
    if (child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
      elements.push(child);
    return elements;
  });
}

/*--------------------------------------------------------------------------*/

if (!window.Element) {
  var Element = new Object();
}

Object.extend(Element, {
  visible: function(element) {
    return $(element).style.display != 'none';
  },

  toggle: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      Element[Element.visible(element) ? 'hide' : 'show'](element);
    }
  },

  hide: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = 'none';
    }
  },

  show: function() {
    for (var i = 0; i < arguments.length; i++) {
      var element = $(arguments[i]);
      element.style.display = '';
    }
  },

  remove: function(element) {
    element = $(element);
    element.parentNode.removeChild(element);
  },

  update: function(element, html) {
    $(element).innerHTML = html.stripScripts();
    setTimeout(function() {html.evalScripts()}, 10);
  },

  getHeight: function(element) {
    element = $(element);
    return element.offsetHeight;
  },

  classNames: function(element) {
    return new Element.ClassNames(element);
  },

  hasClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).include(className);
  },

  addClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).add(className);
  },

  removeClassName: function(element, className) {
    if (!(element = $(element))) return;
    return Element.classNames(element).remove(className);
  },

  // removes whitespace-only text node children
  cleanWhitespace: function(element) {
    element = $(element);
    for (var i = 0; i < element.childNodes.length; i++) {
      var node = element.childNodes[i];
      if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
        Element.remove(node);
    }
  },

  empty: function(element) {
    return $(element).innerHTML.match(/^\s*$/);
  },

  scrollTo: function(element) {
    element = $(element);
    var x = element.x ? element.x : element.offsetLeft,
        y = element.y ? element.y : element.offsetTop;
    window.scrollTo(x, y);
  },

  getStyle: function(element, style) {
    element = $(element);
    var value = element.style[style.camelize()];
    if (!value) {
      if (document.defaultView && document.defaultView.getComputedStyle) {
        var css = document.defaultView.getComputedStyle(element, null);
        value = css ? css.getPropertyValue(style) : null;
      } else if (element.currentStyle) {
        value = element.currentStyle[style.camelize()];
      }
    }

    if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
      if (Element.getStyle(element, 'position') == 'static') value = 'auto';

    return value == 'auto' ? null : value;
  },

  setStyle: function(element, style) {
    element = $(element);
    for (name in style)
      element.style[name.camelize()] = style[name];
  },

  getDimensions: function(element) {
    element = $(element);
    if (Element.getStyle(element, 'display') != 'none')
      return {width: element.offsetWidth, height: element.offsetHeight};

    // 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;
    els.visibility = 'hidden';
    els.position = 'absolute';
    els.display = '';
    var originalWidth = element.clientWidth;
    var originalHeight = element.clientHeight;
    els.display = 'none';
    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;
      }
    }
  },

  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 = '';
    }
  },

  makeClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element._overflow = element.style.overflow;
    if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
      element.style.overflow = 'hidden';
  },

  undoClipping: function(element) {
    element = $(element);
    if (element._overflow) return;
    element.style.overflow = element._overflow;
    element._overflow = undefined;
  }
});

var Toggle = new Object();
Toggle.display = Element.toggle;

/*--------------------------------------------------------------------------*/

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) {
        if (this.element.tagName.toLowerCase() == 'tbody') {
          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(this.toArray().concat(classNameToAdd).join(' '));
  },

  remove: function(classNameToRemove) {
    if (!this.include(classNameToRemove)) return;
    this.set(this.select(function(className) {
      return className != classNameToRemove;
    }).join(' '));
  },

  toString: function() {
    return this.toArray().join(' ');
  }
}

Object.extend(Element.ClassNames.prototype, Enumerable);
var Field = {
  clear: function() {
    for (var i = 0; i < arguments.length; i++)
      $(arguments[i]).value = '';
  },

  focus: function(element) {
    $(element).focus();
  },

  present: function() {
    for (var i = 0; i < arguments.length; i++)
      if ($(arguments[i]).value == '') return false;
    return true;
  },

  select: function(element) {
    $(element).select();
  },

  activate: function(element) {
    element = $(element);
    element.focus();
    if (element.select)
      element.select();
  }
}

/*--------------------------------------------------------------------------*/

var Form = {
  serialize: function(form) {
    var elements = Form.getElements($(form));
    var queryComponents = new Array();

    for (var i = 0; i < elements.length; i++) {
      var queryComponent = Form.Element.serialize(elements[i]);
      if (queryComponent)
        queryComponents.push(queryComponent);
    }

    return queryComponents.join('&');
  },

  getElements: function(form) {
    form = $(form);
    var elements = new Array();

    for (tagName in Form.Element.Serializers) {
      var tagElements = form.getElementsByTagName(tagName);
      for (var j = 0; j < tagElements.length; j++)
        elements.push(tagElements[j]);
    }
    return elements;
  },

  getInputs: function(form, typeName, name) {
    form = $(form);
    var inputs = form.getElementsByTagName('input');

    if (!typeName && !name)
      return inputs;

    var matchingInputs = new Array();
    for (var i = 0; i < inputs.length; i++) {
      var input = inputs[i];
      if ((typeName && input.type != typeName) ||
          (name && input.name != name))
        continue;
      matchingInputs.push(input);
    }

    return matchingInputs;
  },

  disable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.blur();
      element.disabled = 'true';
    }
  },

  enable: function(form) {
    var elements = Form.getElements(form);
    for (var i = 0; i < elements.length; i++) {
      var element = elements[i];
      element.disabled = '';
    }
  },

  findFirstElement: function(form) {
    return Form.getElements(form).find(function(element) {
      return element.type != 'hidden' && !element.disabled &&
        ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
    });
  },

  focusFirstElement: function(form) {
    Field.activate(Form.findFirstElement(form));
  },

  reset: function(form) {
    $(form).reset();
  }
}

Form.Element = {
  serialize: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter) {
      var key = encodeURIComponent(parameter[0]);
      if (key.length == 0) return;

      if (parameter[1].constructor != Array)
        parameter[1] = [parameter[1]];

      return parameter[1].map(function(value) {
        return key + '=' + encodeURIComponent(value);
      }).join('&');
    }
  },

  getValue: function(element) {
    element = $(element);
    var method = element.tagName.toLowerCase();
    var parameter = Form.Element.Serializers[method](element);

    if (parameter)
      return parameter[1];
  }
}

Form.Element.Serializers = {
  input: function(element) {
    switch (element.type.toLowerCase()) {
      case 'submit':
      case 'hidden':
      case 'password':
      case 'text':
        return Form.Element.Serializers.textarea(element);
      case 'checkbox':
      case 'radio':
        return Form.Element.Serializers.inputSelector(element);
    }
    return false;
  },

  inputSelector: function(element) {
    if (element.checked)
      return [element.name, element.value];
  },

  textarea: function(element) {
    return [element.name, element.value];
  },

  select: function(element) {
    return Form.Element.Serializers[element.type == 'select-one' ?
      'selectOne' : 'selectMany'](element);
  },

  selectOne: function(element) {
    var value = '', opt, index = element.selectedIndex;
    if (index >= 0) {
      opt = element.options[index];
      value = opt.value;
      if (!value && !('value' in opt))
        value = opt.text;
    }
    return [element.name, value];
  },

  selectMany: function(element) {
    var value = new Array();
    for (var i = 0; i < element.length; i++) {
      var opt = element.options[i];
      if (opt.selected) {
        var optValue = opt.value;
        if (!optValue && !('value' in opt))
          optValue = opt.text;
        value.push(optValue);
      }
    }
    return [element.name, value];
  }
}

/*--------------------------------------------------------------------------*/

var $F = Form.Element.getValue;

/*--------------------------------------------------------------------------*/

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();
    if (this.lastValue != value) {
      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);
  }
});

/*--------------------------------------------------------------------------*/

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() {
    var elements = Form.getElements(this.element);
    for (var i = 0; i < elements.length; i++)
      this.registerCallback(elements[i]);
  },

  registerCallback: function(element) {
    if (element.type) {
      switch (element.type.toLowerCase()) {
        case 'checkbox':
        case 'radio':
          Event.observe(element, 'click', this.onElementEvent.bind(this));
          break;
        case 'password':
        case 'text':
        case 'textarea':
        case 'select-one':
        case 'select-multiple':
          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, {
  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,

  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));
  },

  stop: function(event) {
    if (event.preventDefault) {
      event.preventDefault();
      event.stopPropagation();
    } else {
      event.returnValue = false;
      event.cancelBubble = true;
    }
  },

  // 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; i < Event.observers.length; i++) {
      Event.stopObserving.apply(this, Event.observers[i]);
      Event.observers[i][0] = null;
    }
    Event.observers = false;
  },

  observe: function(element, name, observer, useCapture) {
    var element = $(element);
    useCapture = useCapture || false;

    if (name == 'keypress' &&
        (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
        || element.attachEvent))
      name = 'keydown';

    this._observeAndCache(element, name, observer, useCapture);
  },

  stopObserving: function(element, name, observer, useCapture) {
    var 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) {
      element.detachEvent('on' + name, observer);
    }
  }
});

/* prevent memory leaks in IE */
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;
    do {
      valueT += element.scrollTop  || 0;
      valueL += element.scrollLeft || 0;
      element = element.parentNode;
    } while (element);
    return [valueL, valueT];
  },

  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      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;
      element = element.offsetParent;
      if (element) {
        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)
      if (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)
      return this.withinIncludingScrolloffsets(element, x, y);
    this.xcomp = x;
    this.ycomp = y;
    this.offset = this.cumulativeOffset(element);

    return (y >= this.offset[1] &&
            y <  this.offset[1] + element.offsetHeight &&
            x >= this.offset[0] &&
            x <  this.offset[0] + element.offsetWidth);
  },

  withinIncludingScrolloffsets: 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);

    return (this.ycomp >= this.offset[1] &&
            this.ycomp <  this.offset[1] + element.offsetHeight &&
            this.xcomp >= this.offset[0] &&
            this.xcomp <  this.offset[0] + element.offsetWidth);
  },

  // within must be called directly before
  overlap: function(mode, element) {
    if (!mode) return 0;
    if (mode == 'vertical')
      return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
        element.offsetHeight;
    if (mode == 'horizontal')
      return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
        element.offsetWidth;
  },

  clone: function(source, target) {
    source = $(source);
    target = $(target);
    target.style.position = 'absolute';
    var offsets = this.cumulativeOffset(source);
    target.style.top    = offsets[1] + 'px';
    target.style.left   = offsets[0] + 'px';
    target.style.width  = source.offsetWidth + 'px';
    target.style.height = source.offsetHeight + 'px';
  },

  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 {
      valueT -= element.scrollTop  || 0;
      valueL -= element.scrollLeft || 0;
    } while (element = element.parentNode);

    return [valueL, valueT];
  },

  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 = source.offsetWidth + 'px';
    if(options.setHeight) target.style.height = source.offsetHeight + 'px';
  },

  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];
    var width   = element.clientWidth;
    var height  = element.clientHeight;

    element._originalLeft   = left - parseFloat(element.style.left  || 0);
    element._originalTop    = top  - parseFloat(element.style.top || 0);
    element._originalWidth  = element.style.width;
    element._originalHeight = element.style.height;

    element.style.position = 'absolute';
    element.style.top    = top + 'px';;
    element.style.left   = left + 'px';;
    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';
    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;
    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];
  }
}


// util.js

/*
 * Copyright 2005 Joe Walker
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Declare a constructor function to which we can add real functions.
 * @constructor
 */
function DWRUtil() { }

/**
 * Enables you to react to return being pressed in an input
 * For example:
 * <code>&lt;input type="text" onkeypressed="DWRUtil.onReturn(event, methodName)"/&gt;</code>
 * @param event The event object for Netscape browsers
 * @param action Method name to execute when return is pressed
 */
DWRUtil.onReturn = function(event, action) {
  if (!event) {
    event = window.event;
  }
  if (event && event.keyCode && event.keyCode == 13) {
    action();
  }
};

/**
 * Select a specific range in a text box.
 * This is useful for 'google suggest' type functionallity.
 * @param ele The id of the text input element or the HTML element itself
 * @param start The beginning index
 * @param end The end index 
 */
DWRUtil.selectRange = function(ele, start, end) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    alert("selectRange() can't find an element with id: " + orig + ".");
    return;
  }
  if (ele.setSelectionRange) {
    ele.setSelectionRange(start, end);
  }
  else if (ele.createTextRange) {
    var range = ele.createTextRange();
    range.moveStart("character", start);
    range.moveEnd("character", end - ele.value.length);
    range.select();
  }
  ele.focus();
};

/**
 * Find the element in the current HTML document with the given id, or if more
 * than one parameter is passed, return an array containing the found elements.
 * Any non-string arguments are left as is in the reply.
 * This function is inspired by the prototype library however it probably works
 * on more browsers than the original.
 * Technically speaking this will not work on IE5.0 because it uses Array.push
 * however it is expected that this will only be used in conjunction with
 * engine.js (which makes up for this omission). If you are using this function
 * without engine.js and want IE5.0 compatibility then you should arrange for
 * a replacement for Array.push.
 */
var $;
if (!$ && document.getElementById) {
  $ = function() {
    var elements = new Array();
    for (var i = 0; i < arguments.length; i++) {
      var element = arguments[i];
      if (typeof element == 'string') {
        element = document.getElementById(element);
      }
      if (arguments.length == 1) {
        return element;
      }
      elements.push(element);
    }
    return elements;
  }
}
else if (!$ && document.all) {
  $ = function() {
    var elements = new Array();
    for (var i = 0; i < arguments.length; i++) {
      var element = arguments[i];
      if (typeof element == 'string') {
        element = document.all[element];
      }
      if (arguments.length == 1) {
        return element;
      }
      elements.push(element);
    }
    return elements;
  }
}

/**
 * A better toString than the default for an Object
 * @param data The object to describe
 * @param level 0 = Single line of debug, 1 = Multi-line debug that does not
 *        dig into child objects, 2 = Multi-line debug that digs into the
 *        2nd layer of child objects
 * @param depth How much do we indent this item?
 */
DWRUtil.toDescriptiveString = function(data, level, depth) {
  var reply = "";
  var i = 0;
  var value;
  var obj;
  if (level == null) level = 0;
  if (depth == null) depth = 0;
  if (data == null) return "null";
  if (DWRUtil._isArray(data)) {
    if (data.length == 0) reply += "[]";
    else {
      if (level != 0) reply += "[\n";
      else reply = "[";
      for (i = 0; i < data.length; i++) {
        try {
          obj = data[i];
          if (obj == null || typeof obj == "function") {
            continue;
          }
          else if (typeof obj == "object") {
            if (level > 0) value = DWRUtil.toDescriptiveString(obj, level - 1, depth + 1);
            else value = DWRUtil._detailedTypeOf(obj);
          }
          else {
            value = "" + obj;
            value = value.replace(/\/n/g, "\\n");
            value = value.replace(/\/t/g, "\\t");
          }
        }
        catch (ex) {
          value = "" + ex;
        }
       if (level != 0)  {
          reply += DWRUtil._indent(level, depth + 2) + value + ", \n";
       }
        else {
          if (value.length > 13) value = value.substring(0, 10) + "...";
          reply += value + ", ";
          if (i > 5) {
            reply += "...";
            break;
          }
        }
      }
      if (level != 0) reply += DWRUtil._indent(level, depth) + "]";
      else reply += "]";
    }
    return reply;
  }
  if (typeof data == "string" || typeof data == "number" || DWRUtil._isDate(data)) {
    return data.toString();
  }
  if (typeof data == "object") {
    var typename = DWRUtil._detailedTypeOf(data);
    if (typename != "Object")  reply = typename + " ";
    if (level != 0) reply += "{\n";
    else reply = "{";
    var isHtml = DWRUtil._isHTMLElement(data);
    for (var prop in data) {
      if (isHtml) {
        // HTML nodes have far too much stuff. Chop out the constants
        if (prop.toUpperCase() == prop || prop == "title" ||
          prop == "lang" || prop == "dir" || prop == "className" ||
          prop == "form" || prop == "name" || prop == "prefix" ||
          prop == "namespaceURI" || prop == "nodeType" ||
          prop == "firstChild" || prop == "lastChild" ||
          prop.match(/^offset/)) {
          continue;
        }
      }
      value = "";
      try {
        obj = data[prop];
        if (obj == null || typeof obj == "function") {
          continue;
        }
        else if (typeof obj == "object") {
          if (level > 0) {
            value = "\n";
            value += DWRUtil._indent(level, depth + 2);
            value = DWRUtil.toDescriptiveString(obj, level - 1, depth + 1);
          }
          else {
            value = DWRUtil._detailedTypeOf(obj);
          }
        }
        else {
          value = "" + obj;
          value = value.replace(/\/n/g, "\\n");
          value = value.replace(/\/t/g, "\\t");
        }
      }
      catch (ex) {
        value = "" + ex;
      }
      if (level == 0 && value.length > 13) value = value.substring(0, 10) + "...";
      var propStr = prop;
      if (propStr.length > 30) propStr = propStr.substring(0, 27) + "...";
      if (level != 0) reply += DWRUtil._indent(level, depth + 1);
      reply += prop + ":" + value + ", ";
      if (level != 0) reply += "\n";
      i++;
      if (level == 0 && i > 5) {
        reply += "...";
        break;
      }
    }
    reply += DWRUtil._indent(level, depth);
    reply += "}";
    return reply;
  }
  return data.toString();
};

/**
 * Indenting for DWRUtil.toDescriptiveString
 * @private
 */
DWRUtil._indent = function(level, depth) {
  var reply = "";
  if (level != 0) {
    for (var j = 0; j < depth; j++) {
      reply += "\u00A0\u00A0";
    }
    reply += " ";
  }
  return reply;
};

/**
 * Setup a GMail style loading message.
 */
DWRUtil.useLoadingMessage = function(message) {
  var loadingMessage;
  if (message) loadingMessage = message;
  else loadingMessage = "Loading";
  DWREngine.setPreHook(function() {
    var disabledZone = $('disabledZone');
    if (!disabledZone) {
      disabledZone = document.createElement('div');
      disabledZone.setAttribute('id', 'disabledZone');
      disabledZone.style.position = "absolute";
      disabledZone.style.zIndex = "1000";
      disabledZone.style.left = "0px";
      disabledZone.style.top = "0px";
      disabledZone.style.width = "100%";
      disabledZone.style.height = "100%";
      document.body.appendChild(disabledZone);
      var messageZone = document.createElement('div');
      messageZone.setAttribute('id', 'messageZone');
      messageZone.style.position = "absolute";
      messageZone.style.top = "0px";
      messageZone.style.right = "0px";
      messageZone.style.background = "red";
      messageZone.style.color = "white";
      messageZone.style.fontFamily = "Arial,Helvetica,sans-serif";
      messageZone.style.padding = "4px";
      disabledZone.appendChild(messageZone);
      var text = document.createTextNode(loadingMessage);
      messageZone.appendChild(text);
    }
    else {
      $('messageZone').innerHTML = loadingMessage;
      disabledZone.style.visibility = 'visible';
    }
  });
  DWREngine.setPostHook(function() {
    $('disabledZone').style.visibility = 'hidden';
  });
}

/**
 * Set the value for the given id to the specified val.
 * This method works for selects (where the option with a matching value and
 * not text is selected), input elements (including textareas) divs and spans.
 * @param ele The id of the element or the HTML element itself
 */
DWRUtil.setValue = function(ele, val) {
  if (val == null) val = "";

  var orig = ele;
  var nodes, i;

  ele = $(ele);
  // We can work with names and need to sometimes for radio buttons
  if (ele == null) {
    nodes = document.getElementsByName(orig);
    if (nodes.length >= 1) {
      ele = nodes.item(0);
    }
  }
  if (ele == null) {
    alert("setValue() can't find an element with id/name: " + orig + ".");
    return;
  }

  if (DWRUtil._isHTMLElement(ele, "select")) {
    if (ele.type == "select-multiple" && DWRUtil._isArray(val)) {
      DWRUtil._selectListItems(ele, val);
    }
    else {
      DWRUtil._selectListItem(ele, val);
    }
    return;
  }

  if (DWRUtil._isHTMLElement(ele, "input")) {
    if (nodes && ele.type == "radio") {
      for (i = 0; i < nodes.length; i++) {
        if (nodes.item(i).type == "radio") {
          nodes.item(i).checked = (nodes.item(i).value == val);
        }
      }
    }
    else {
      switch (ele.type) {
      case "checkbox":
      case "check-box":
      case "radio":
        ele.checked = (val == true);
        return;
      default:
        ele.value = val;
        return;
      }
    }
  }

  if (DWRUtil._isHTMLElement(ele, "textarea")) {
    ele.value = val;
    return;
  }

  // If the value to be set is a DOM object then we try importing the node
  // rather than serializing it out
  if (val.nodeType) {
    if (val.nodeType == 9 /*Node.DOCUMENT_NODE*/) {
      val = val.documentElement;
    }

    val = DWRUtil._importNode(ele.ownerDocument, val, true);
    ele.appendChild(val);
    return;
  }

  // Fall back to innerHTML
  ele.innerHTML = val;
};

/**
 * Find multiple items in a select list and make them selected
 * @param ele The select list item
 * @param val The array of values to select
 */
DWRUtil._selectListItems = function(ele, val) {
  // We deal with select list elements by selecting the matching option
  // Begin by searching through the values
  var found  = false;
  var i;
  var j;
  for (i = 0; i < ele.options.length; i++) {
    ele.options[i].selected = false;
    for (j = 0; j < val.length; j++) {
      if (ele.options[i].value == val[j]) {
        ele.options[i].selected = true;
      }
    }
  }
  // If that fails then try searching through the visible text
  if (found) return;

  for (i = 0; i < ele.options.length; i++) {
    for (j = 0; j < val.length; j++) {
      if (ele.options[i].text == val[j]) {
        ele.options[i].selected = true;
      }
    }
  }
};

/**
 * Find an item in a select list and make it selected
 * @param ele The select list item
 * @param val The value to select
 */
DWRUtil._selectListItem = function(ele, val) {
  // We deal with select list elements by selecting the matching option
  // Begin by searching through the values
  var found  = false;
  var i;
  for (i = 0; i < ele.options.length; i++) {
    if (ele.options[i].value == val) {
      ele.options[i].selected = true;
      found = true;
    }
    else {
      ele.options[i].selected = false;
    }
  }
  // If that fails then try searching through the visible text
  if (found) return;

  for (i = 0; i < ele.options.length; i++) {
    if (ele.options[i].text == val) {
      ele.options[i].selected = true;
      break;
    }
  }
}

/**
 * The counterpart to setValue() - read the current value for a given element.
 * This method works for selects (where the option with a matching value and
 * not text is selected), input elements (including textareas) divs and spans.
 * @param ele The id of the element or the HTML element itself
 */
DWRUtil.getValue = function(ele) {
  var nodes;
  var orig = ele;
  ele = $(ele);
  // We can work with names and need to sometimes for radio buttons
  if (ele == null) {
    nodes = document.getElementsByName(orig);
    if (nodes.length >= 1) {
      ele = nodes.item(0);
    }
  }
  if (ele == null) {
    alert("getValue() can't find an element with id/name: " + orig + ".");
    return "";
  }

  if (DWRUtil._isHTMLElement(ele, "select")) {
    // This is a bit of a scam because it assumes single select
    // but I'm not sure how we should treat multi-select.
    var sel = ele.selectedIndex;
    if (sel != -1) {
      var reply = ele.options[sel].value;
      /*if (reply == null || reply == "") {
        reply = ele.options[sel].text;
      }*/

      return reply;
    }
    else {
      return "";
    }
  }

  if (DWRUtil._isHTMLElement(ele, "input")) {
    if (nodes && ele.type == "radio") {
      for (i = 0; i < nodes.length; i++) {
        if (nodes.item(i).type == "radio") {
          if (nodes.item(i).checked) {
            return nodes.item(i).value;
          }
        }
      }
    }
    switch (ele.type) {
    case "checkbox":
    case "check-box":
    case "radio":
      if(ele.checked) return ele.checked;
      else return "";
    default:
      return ele.value;
    }
  }

  if (DWRUtil._isHTMLElement(ele, "textarea")) {
    return ele.value;
  }

  return ele.innerHTML;
};

/**
 * getText() is like getValue() with the except that it only works for selects
 * where it reads the text of an option and not it's value.
 * @param ele The id of the element or the HTML element itself
 */
DWRUtil.getText = function(ele) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    alert("getText() can't find an element with id: " + orig + ".");
    return "";
  }

  if (!DWRUtil._isHTMLElement(ele, "select")) {
    alert("getText() can only be used with select elements. Attempt to use: " + DWRUtil._detailedTypeOf(ele) + " from  id: " + orig + ".");
    return "";
  }

  // This is a bit of a scam because it assumes single select
  // but I'm not sure how we should treat multi-select.
  var sel = ele.selectedIndex;
  if (sel != -1) {
    return ele.options[sel].text;
  }
  else {
    return "";
  }
};

/**
 * Given a map, call setValue() for all the entries in the map using the key
 * of each entry as an id.
 * @param map The map of values to set to various elements
 */
DWRUtil.setValues = function(map) {
  for (var property in map) {
    var ele = $(property);
    if (ele != null) {
      var value = map[property];
      DWRUtil.setValue(property, value);
    }
  }
};

/**
 * Given a map, call getValue() for all the entries in the map using the key
 * of each entry as an id.
 * @param map The map of values to set to various elements
 */
DWRUtil.getValues = function(map) {
  for (var property in map) {
    var ele = $(property);
    if (ele != null) {
      map[property] = DWRUtil.getValue(property);
    }
  }
};

/**
 * Add options to a list from an array or map.
 * DWRUtil.addOptions has 5 modes:
 * <p><b>Array</b><br/>
 * DWRUtil.addOptions(selectid, array) and a set of options are created with the
 * text and value set to the string version of each array element.
 * </p>
 * <p><b>Array of objects, using option text = option value</b><br/>
 * DWRUtil.addOptions(selectid, data, prop) creates an option for each array
 * element, with the value and text of the option set to the given property of
 * each object in the array.
 * </p>
 * <p><b>Array of objects, with differing option text and value</b><br/>
 * DWRUtil.addOptions(selectid, array, valueprop, textprop) creates an option
 * for each object in the array, with the value of the option set to the given
 * valueprop property of the object, and the option text set to the textprop
 * property.
 * </p>
 * <p><b>Map (object)</b><br/>
 * DWRUtil.addOptions(selectid, map, reverse) creates an option for each
 * property. The property names are used as option values, and the property
 * values are used as option text, which sounds wrong, but is actually normally
 * the right way around. If reverse evaluates to true then the property values
 * are used as option values.
 * <p><b>ol or ul list</b><br/>
 * DWRUtil.addOptions(ulid, array) and a set of li elements are created with the
 * innerHTML set to the string value of the array elements. This mode works
 * with ul and ol lists.
 * </p>
 * @param ele The id of the list element or the HTML element itself
 * @param data An array or map of data items to populate the list
 * @param valuerev (optional) If data is an array of objects, an optional
 *    property name to use for option values. If the data is a map then this
 *    boolean property allows you to swap keys and values.
 * @param textprop (optional) Only for use with arrays of objects - an optional
 *    property name for use as the text of an option.
 */
DWRUtil.addOptions = function(ele, data) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    alert("addOptions() can't find an element with id: " + orig + ".");
    return;
  }
  var useOptions = DWRUtil._isHTMLElement(ele, "select");
  var useLi = DWRUtil._isHTMLElement(ele, ["ul", "ol"]);
  if (!useOptions && !useLi) {
    alert("addOptions() can only be used with select elements. Attempt to use: " + DWRUtil._detailedTypeOf(ele));
    return;
  }
  if (data == null) return;

  var text;
  var value;
  var opt;
  if (DWRUtil._isArray(data)) {
    // Loop through the data that we do have
    for (var i = 0; i < data.length; i++) {
      if (useOptions) {
        if (arguments[2] != null) {
          if (arguments[3] != null) {
            text = DWRUtil._getValueFrom(data[i], arguments[3]);
            value = DWRUtil._getValueFrom(data[i], arguments[2]);
          }
          else {
            value = DWRUtil._getValueFrom(data[i], arguments[2]);
            text = value;
          }
        }
        else
        {
          text = DWRUtil._getValueFrom(data[i], arguments[3]);
          value = text;
        }
        if (text || value) {
          opt = new Option(text, value);
          ele.options[ele.options.length] = opt;
        }
      }
      else {
        li = document.createElement("li");
        value = DWRUtil._getValueFrom(data[i], arguments[2]);
        if (value != null) {
          value = ""+new String(value);
          if(value.indexOf("<li>")==0){
          	value = value.substring("<li>".length);
          }
          if(value.indexOf("</li>")!=-1){
          	value = value.substring(0,value.indexOf("</li>"));
          }
          li.innerHTML = value;
          ele.appendChild(li);
        }
      }
    }
  }
  else
  {
    for (var prop in data) {
      if (!useOptions) {
        alert("DWRUtil.addOptions can only create select lists from objects.");
        return;
      }
      if (arguments[2]) {
        text = prop;
        value = data[prop];
      }
      else {
        text = data[prop];
        value = prop;
      }
      if (text || value) {
        opt = new Option(text, value);
        ele.options[ele.options.length] = opt;
      }
    }
  }
};

/**
 * Get the data from an array function for DWRUtil.addOptions
 * @private
 */
DWRUtil._getValueFrom = function(data, method) {
  if (method == null) return data;
  else if (typeof method == 'function') return method(data);
  else return data[method];
}

/**
 * Remove all the options from a select list (specified by id)
 * @param ele The id of the list element or the HTML element itself
 */
DWRUtil.removeAllOptions = function(ele) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    alert("removeAllOptions() can't find an element with id: " + orig + ".");
    return;
  }
  var useOptions = DWRUtil._isHTMLElement(ele, "select");
  var useLi = DWRUtil._isHTMLElement(ele, ["ul", "ol"]);
  if (!useOptions && !useLi) {
    alert("removeAllOptions() can only be used with select, ol and ul elements. Attempt to use: " + DWRUtil._detailedTypeOf(ele));
    return;
  }
  if (useOptions) {
    ele.options.length = 0;
  }
  else {
    while (ele.childNodes.length > 0) {
      ele.removeChild(ele.firstChild);
    }
  }
};

/**
 * Create rows inside a the table, tbody, thead or tfoot element (given by id).
 * The normal case would be to use tbody since that allows you to keep header
 * lines separate, but this function should work with and table element above
 * tr.
 * <p>This function creates a row for each element in the <code>data</code>
 * array and for that row create one cell for each function in the
 * <code>cellFuncs</code> array by passing the element from the
 * <code>data</code> array to the given function.
 * <p>The return from the function is used to populate the cell.
 * <p>The pseudo code looks something like this:
 * <pre>
 *   for each member of the data array
 *   for function in the cellFuncs array
 *     create cell from cellFunc(data[i])
 * </pre>
 * <p>One slight modification to this is that any members of the cellFuncs array
 * that are strings instead of functions, the strings are used as cell contents
 * directly.
 * <p>There are 2 current options:<ul>
 * <li>rowCreator: a function that will create a row for you (e.g. you wish to
 *   add css to the tr). The default returns document.createElement("tr")</li>
 * <li>cellCreator: a function to create a cell, (e.g. to use a th in place of a
 *   td). The default returns document.createElement("td")</li>
 * </ul>
 * @param ele The id of the tbody element
 * @param data Array containing one entry for each row in the updated table
 * @param cellFuncs An array of functions (one per column) for extracting cell
 *  data from the passed row data
 * @param options An object containing various options. See above for options.
 */
DWRUtil.addRows = function(ele, data, cellFuncs, options) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    alert("addRows() can't find an element with id: " + orig + ".");
    return;
  }
  if (!DWRUtil._isHTMLElement(ele, ["table", "tbody", "thead", "tfoot"])) {
    alert("addRows() can only be used with table, tbody, thead and tfoot elements. Attempt to use: " + DWRUtil._detailedTypeOf(ele));
    return;
  }
  if (!options) options = {};
  if (!options.rowCreator) options.rowCreator = DWRUtil._defaultRowCreator;
  if (!options.cellCreator) options.cellCreator = DWRUtil._defaultCellCreator;
  // TODO: remove the frag if it does not cause bugs: var frag = document.createDocumentFragment();
  var tr, i;
  if (DWRUtil._isArray(data)) {
    for (i = 0; i < data.length; i++) {
      tr = DWRUtil._addRowInner(data[i], cellFuncs, options);
      if (tr != null) ele.appendChild(tr);
    }
  }
  else if (typeof data == "object") {
    i = 0;
    for (var row in data) {
      tr = DWRUtil._addRowInner(row, cellFuncs, options, i);
      if (tr != null) ele.appendChild(tr);
      i++;
    }
  }
  //ele.appendChild(frag);
};

/**
 * Internal function to draw a single row of a table.
 * @private
 */
DWRUtil._addRowInner = function(row, cellFuncs, options, i) {
  var tr = options.rowCreator(row, i);
  if (tr == null) return null;
  for (var j = 0; j < cellFuncs.length; j++) {
    var func = cellFuncs[j];
    var td;
    if (typeof func == "string") {
      td = options.cellCreator();
      td.appendChild(document.createTextNode(func));
    }
    else {
      var reply = func(row);
      td = options.cellCreator(reply, j);
      if (DWRUtil._isHTMLElement(reply, "td")) td = reply;
      else if (DWRUtil._isHTMLElement(reply)) td.appendChild(reply);
      else td.innerHTML = reply;
    }
    tr.appendChild(td);
  }
  return tr;
};

/**
 * Default row creation function
 * @private
 */
DWRUtil._defaultRowCreator = function(row, i) {
  return document.createElement("tr");
};

/**
 * Default cell creation function
 * @private
 */
DWRUtil._defaultCellCreator = function(data, j) {
  return document.createElement("td");
};

/**
 * Remove all the children of a given node.
 * Most useful for dynamic tables where you clearChildNodes() on the tbody
 * element.
 * @param ele The id of the element or the HTML element itself
 */
DWRUtil.removeAllRows = function(ele) {
  var orig = ele;
  ele = $(ele);
  if (ele == null) {
    alert("removeAllRows() can't find an element with id: " + orig + ".");
    return;
  }
  if (!DWRUtil._isHTMLElement(ele, ["table", "tbody", "thead", "tfoot"])) {
    alert("removeAllRows() can only be used with table, tbody, thead and tfoot elements. Attempt to use: " + DWRUtil._detailedTypeOf(ele));
    return;
  }
  while (ele.childNodes.length > 0) {
    ele.removeChild(ele.firstChild);
  }
};

/**
 * Is the given node an HTML element (optionally of a given type)?
 * @param ele The element to test
 * @param nodeName eg "input", "textarea" - check for node name (optional)
 *         if nodeName is an array then check of a match.
 * @private
 */
DWRUtil._isHTMLElement = function(ele, nodeName) {
  if (ele == null || typeof ele != "object" || ele.nodeName == null) {
    return false;
  }

  if (nodeName != null) {
    var test = ele.nodeName.toLowerCase();

    if (typeof nodeName == "string") {
      return test == nodeName.toLowerCase();
    }

    if (DWRUtil._isArray(nodeName)) {
      var match = false;
      for (var i = 0; i < nodeName.length && !match; i++) {
        if (test == nodeName[i].toLowerCase()) {
          match =  true;
        }
      }
      return match;
    }

    alert("DWRUtil._isHTMLElement was passed test node name that is neither a string or array of strings");
    return false;
  }

  return true;
};

/**
 * Like typeOf except that more information for an object is returned other
 * than "object"
 * @private
 */
DWRUtil._detailedTypeOf = function(x) {
  var reply = typeof x;
  if (reply == "object") {
    reply = Object.prototype.toString.apply(x);  // Returns "[object class]"
    reply = reply.substring(8, reply.length-1);  // Just get the class bit
  }
  return reply;
};

/**
 * Array detector.
 * This is an attempt to work around the lack of support for instanceof in
 * some browsers.
 * @param data The object to test
 * @returns true iff <code>data</code> is an Array
 * @private
 */
DWRUtil._isArray = function(data) {
  return (data && data.join) ? true : false;
};

/**
 * Date detector.
 * This is an attempt to work around the lack of support for instanceof in
 * some browsers.
 * @param data The object to test
 * @returns true iff <code>data</code> is a Date
 * @private
 */
DWRUtil._isDate = function(data) {
  return (data && data.toUTCString) ? true : false;
};

/**
 * document.importNode is used by setValue.
 * This gets around the missing functionallity in IE.
 * @private
 */
DWRUtil._importNode = function(doc, importedNode, deep) {
  var newNode;

  if (importedNode.nodeType == 1 /*Node.ELEMENT_NODE*/) {
    newNode = doc.createElement(importedNode.nodeName);

    for (var i = 0; i < importedNode.attributes.length; i++) {
      var attr = importedNode.attributes[i];
      if (attr.nodeValue != null && attr.nodeValue != '') {
        newNode.setAttribute(attr.name, attr.nodeValue);
      }
    }

    if (typeof importedNode.style != "undefined") {
      newNode.style.cssText = importedNode.style.cssText;
    }
  }
  else if (importedNode.nodeType == 3 /*Node.TEXT_NODE*/) {
    newNode = doc.createTextNode(importedNode.nodeValue);
  }

  if (deep && importedNode.hasChildNodes()) {
    for (i = 0; i < importedNode.childNodes.length; i++) {
      newNode.appendChild(DWRUtil._importNode(doc, importedNode.childNodes[i], true));
    }
  }

  return newNode;
}
if (typeof document.importNode != "function") {
  document.importNode = function(importedNode, deep) {
    DWRUtil._importNode(this, importedNode, deep);
  };
}

// xControlMen.js

function xControlMen(id,idKapa,estilos,tim){
	xCMObj= new xControlMen.create(id,idKapa,estilos,tim);
	eval('xCM'+id+'=xCMObj');
	return xCMObj;
}

xControlMen.create=function(id,idKapa,estilos,tim){
	this.arg=arguments;
	this.tiempo=0;
	this.actvFun=0;
	this.classElement=[];
	this.id='xCM'+id;

	for(var x=0;x<=this.arg[2].length;x++){
		this.classElement[x]=this.arg[2].split("/")[x];
	}
}

xControlMen.create.prototype.actvOpc=function(idTd,idHref,ev){
	var classHref=0;
	//farem un tractament especial per a la primera opcio
	//perque quan no estigui en rollover el text no quedi en gris

	if (((idTd.charAt(3)) == "1")&&(idTd.charCodeAt(4) > 58)){
		classHref=this.classElement[2];
	}
	else
	{
		classHref=this.classElement[3];
	}

	if (document.getElementById) { /* Navegadores con DOM- IE5.5,NS6*/
		if(this.actvFun==1){
			if(ev==0){
				var elem = document.getElementById(this.arg[1]);
				document.getElementById('om101Kapa').style.visibility='hidden';
				document.getElementById('om102Kapa').style.visibility='hidden';
				document.getElementById('om103Kapa').style.visibility='hidden';
				document.getElementById('om104Kapa').style.visibility='hidden';
				document.getElementById('om105Kapa').style.visibility='hidden';
				document.getElementById('om106Kapa').style.visibility='hidden';
				document.getElementById('om107Kapa').style.visibility='hidden';
				
				//$showCovered(document.getElementById('om105Kapa'));
				$hideCovered(elem);
				elem.style.visibility='visible';
				document.getElementById(idTd).className=this.classElement[0];
				document.getElementById(idHref).className=this.classElement[2];
				if(this.tiempo!=0){
					clearTimeout(this.tiempo);
				}
			}else if(ev==1){
				document.getElementById(idTd).className=this.classElement[1];
				//document.getElementById(idHref).className=this.classElement[3];
				document.getElementById(idHref).className=classHref;
				this.tiempo=setTimeout(this.id+'.actvOpc("'+idTd+'","'+idHref+'",2)',this.arg[3]);
			}else if(ev==2){
				var elem = document.getElementById(this.arg[1]);
				if(elem.style.visibility!='hidden'){
					$showCovered(elem);
					elem.style.visibility='hidden';
				}
			}else{
				//No fem re
				
			}
		}else{
			var elem = document.getElementById(this.arg[1]);
			this.actvFun=1;
			document.getElementById(this.arg[1]).style.visibility='visible';
			$hideCovered(elem);
		}
	}else if (document.all ) { /* Navegadores IE*/
		if(this.actvFun==1){
					if(ev==0){
						findObj(this.arg[1]).style.visibility='visible';
						findObj(idTd).className=this.classElement[0];
						findObj(idHref).className=this.classElement[2];
						if(this.tiempo!=0){
							clearTimeout(this.tiempo);
						}
					}else if(ev==1){
						findObj(idTd).className=this.classElement[1];
						//findObj(idHref).className=this.classElement[3];
						findObj(idHref).className=classHref;
						this.tiempo=setTimeout(this.id+'.actvOpc("'+idTd+'","'+idHref+'",2)',this.arg[3]);
					}else{
						findObj(this.arg[1]).style.visibility='hidden';
					}
				}else{
					this.actvFun=1;
					findObj(this.arg[1]).style.visibility='visible';
		}

	}
}


xControlMen.create.prototype.showOpc=function(idTd,idHref,ev){
	//if (document.layers) { /* Navegadores NS4.5*/
		if(this.actvFun==1){
			if(ev==0){
				var arrayDivs = document.getElementsByTagName("div");
				for(i=0;i<arrayDivs.lenght;i++) arrayDivs[i].visibility="hidden";
				findObj(this.arg[1]).visibility="visible";
				if(this.tiempo!=0){
					clearTimeout(this.tiempo);
				}
			}else if(ev==1){
				this.tiempo=setTimeout(this.id+'.showOpc("'+idTd+'","'+idHref+'",2)',this.arg[3]);
			}else if(ev==2){
				findObj(this.arg[1]).visibility="hidden";
			}else{
			}
		}else{
			this.actvFun=1;
			findObj(this.arg[1]).visibility="visible";
		}
	//}
}

function findObj(n, d) { //v4.0
  var p,i,x;  if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) {
    d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);}
  if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n];
  for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=findObj(n,d.layers[i].document);
  if(!x && document.getElementById) x=document.getElementById(n); return x;
}

//AFEGIT PER POSICIONA ELS LAYERS


var hide  = true;

function showhide(obj)
{
	var x = new getObj('testP');
	hide = !hide;
	x.style.visibility = (hide) ? 'hidden' : 'visible';
	setLyr(obj,'testP');
}

function setLyr(obj,lyr,OffsX,OffsY)
{
    var newX = findPosX(obj);
    var newY = findPosY(obj);
    if(OffsX==null) OffsX=0;
    if(OffsY==null) OffsY=0;
    if (lyr == 'testP') newY -= 50;
    var ObjRetorn = new getObj(lyr);
    ObjRetorn.style.left = newX+OffsX + "px";
    ObjRetorn.style.top = newY+OffsY +"px";
    var elem = $(lyr);
    //$hideCovered(elem);
}


function findPosX(obj)
{
	var curleft = 0;
	if (document.getElementById || document.all)
	{
		while (obj.offsetParent)
		{
			curleft += obj.offsetLeft
			obj = obj.offsetParent;
		}
	}
	else if (document.layers)
		curleft += obj.x;
	return curleft;
}

function findPosY(obj)
{
	var curtop = 0;
	var printstring = '';
	if (document.getElementById || document.all)
	{
		while (obj.offsetParent)
		{
			printstring += ' element ' + obj.tagName + ' has ' + obj.offsetTop;
			curtop += obj.offsetTop
			obj = obj.offsetParent;
		}
	}
	else if (document.layers)
		curtop += obj.y;
//	window.status = printstring;
	return curtop;
}


function getObj(name)
{
 if (document.getElementById)
 {
	   this.obj = document.getElementById(name);
	   this.style = document.getElementById(name).style;
 }
 else if (document.all)
 {
	   this.obj = document.all[name];
	   this.style = document.all[name].style;
 }
 else if (document.layers)
 {
	   if (document.layers[name])
	   {
	   	this.obj = document.layers[name];
	   	this.style = document.layers[name];
	   }
	   else
	   {
	    this.obj = document.layers.testP.layers[name];
	    this.style = document.layers.testP.layers[name];
	   }
 }
}


// AFEGIT PER CREAR FINESTRES


var NewWindow = null;
function tancar_finestra()
{                         
 if (NewWindow != null)
  {
   NewWindow.close();
   var NewWindow = null;
  }  
}
function openWindow(URL,Title,Width,Height)
{                         
 var htmlpage = " ";
 var win_opt = "toolbar=0,location=0,directories=0,status=0,menubar=0,";
 win_opt += "scrollbars=0,resizable=0,copyhistory=0,";
 win_opt += "width=" + Width + ",height=" + Height;
// Creacio de la finestra

    NewWindow = window.open(URL,"Title",win_opt);
    NewWindow.creator = self;NewWindow.moveTo(20,25);
}




// FUNCIONES PARA OCULTAR LOS SELECTS

function $hideCovered(el)
{
	
    var ie_opera = ( /msie/i.test(navigator.userAgent) ||
           !/opera/i.test(navigator.userAgent) );
    if (!$isExplorer(document))
        return;
    var tags = new Array(/*"applet", "iframe", */"select");

    var p = $getAbsolutePos(el);
    
    var EX1 = p.x;
    var EX2 = el.offsetWidth + EX1;
    var EY1 = p.y;
    var EY2 = el.offsetHeight + EY1 +15;
    x_min = EX1;
    x_max = EX2;
    y_min = EY1;
    y_max = EY2;

    var debug = 'Ocultar lo relativo a '+el.id + '('+EX1+','+EY1+')' + '\n('+EX2+','+EY2+')\n';

/*    for (var k = tags.length; k > 0; ) {
        var ar = document.getElementsByTagName(tags[--k]);
        var cc = null;

        for (var i = ar.length; i > 0; ) {
            cc = ar[--i];
            var pp = $getAbsolutePos(cc);
            var CX1 = pp.x;
            var CX2 = cc.offsetWidth + CX1;
            var CY1 = pp.y;
            var CY2 = cc.offsetHeight + CY1;
            cc.style.visibility = 'visible';
        }
    }*/


    for (var k = tags.length; k > 0; ) {
        var ar = document.getElementsByTagName(tags[--k]);
        var cc = null;

        for (var i = ar.length; i > 0; ) {
            cc = ar[--i];

            var pp = $getAbsolutePos(cc);
            var CX1 = pp.x;
            var CX2 = cc.offsetWidth + CX1;
            var CY1 = pp.y;
            var CY2 = cc.offsetHeight + CY1;
            
            // Por si nos movemos por el menu
            cc.style.visibility = 'visible';
            
           debug += '\nencontrado a: '+cc.id+ '\n('+CX1+','+CY1+')' + '\n('+CX2+','+CY2+')';
            
            // La condicion de que el elemento este por debajo del menu que desplega
            if (((CX1 >= EX1 && CX1 <= EX2) && ((CY1 >= EY1 && CY1 <= EY2)
            								 || (CY2 >= EY1 && CY2 <= EY2)
            								 || (CY1 < EY1 && CY2 > EY2)))
             || ((CX2 >= EX1 && CX2 <= EX2) && ((CY1 >= EY1 && CY1 <= EY2)
            								 || (CY2 >= EY1 && CY2 <= EY2)
            								 || (CY1 < EY1 && CY2 > EY2)))
             || ((CX1 < EX1 && CX2 > EX2) && ((CY1 >= EY1 && CY1 <= EY2)
            								 || (CY2 >= EY1 && CY2 <= EY2)
            								 || (CY1 < EY1 && CY2 > EY2))))
			{
                debug += ' y lo oculto';
                cc.style.visibility = 'hidden';
	        }
	    }
    }
    
    //alert(debug);
}

function $showCovered(el)
{
	    var ie_opera = ( /msie/i.test(navigator.userAgent) ||
	           !/opera/i.test(navigator.userAgent) );
	    if (!$isExplorer(document))
	        return;
	    var tags = new Array(/*"applet", "iframe", */"select");
	
	    var p = $getAbsolutePos(el);
	    var EX1 = p.x;
	    var EX2 = el.offsetWidth + EX1;
	    var EY1 = p.y;
	    var EY2 = el.offsetHeight + EY1+15;
	
	    for (var k = tags.length; k > 0; ) {
	        var ar = document.getElementsByTagName(tags[--k]);
	        var cc = null;
	
	        for (var i = ar.length; i > 0; ) {
	            cc = ar[--i];
	            p = $getAbsolutePos(cc);
	            var CX1 = p.x;
	            var CX2 = cc.offsetWidth + CX1;
	            var CY1 = p.y;
	            var CY2 = cc.offsetHeight + CY1;
	            if (((CX1 >= EX1 && CX1 <= EX2) && ((CY1 >= EY1 && CY1 <= EY2)
	            								 || (CY2 >= EY1 && CY2 <= EY2)
	            								 || (CY1 < EY1 && CY2 > EY2)))
	             || ((CX2 >= EX1 && CX2 <= EX2) && ((CY1 >= EY1 && CY1 <= EY2)
	            								 || (CY2 >= EY1 && CY2 <= EY2)
	            								 || (CY1 < EY1 && CY2 > EY2)))
	             || ((CX1 < EX1 && CX2 > EX2) && ((CY1 >= EY1 && CY1 <= EY2)
	            								 || (CY2 >= EY1 && CY2 <= EY2)
	            								 || (CY1 < EY1 && CY2 > EY2))))
				{
	                cc.style.visibility = 'visible';
	            } 
	        }
	    }
	   
}

function $getVisib(obj)
{
    var value = obj.style.visibility;
    if (!value) {
        if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
            if (!Calendar.is_khtml)
                value = document.defaultView.
                    getComputedStyle(obj, "").getPropertyValue("visibility");
            else
                value = '';
        } else if (obj.currentStyle) { // IE
            value = obj.currentStyle.visibility;
        } else
            value = '';
    }
    return value;
}

function $getAbsolutePos(el)
{
    var SL = 0, ST = 0;
    var is_div = /^div$/i.test(el.tagName);
    if (is_div && el.scrollLeft)
        SL = el.scrollLeft;
    if (is_div && el.scrollTop)
        ST = el.scrollTop;
    var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
    if (el.offsetParent) {
        var tmp = $getAbsolutePos(el.offsetParent);
        r.x += tmp.x;
        r.y += tmp.y;
    }
    return r;
    /*var aux = domLib_getOffsets(el);
    return {x: aux.get('left'), y: aux.get('top')};
    return {x: findPosX(el), y: findPosY(el)};*/
}


// menuCapcalera_e.js

// CAPAS DE MENU DE NAVEGACION SUPERIOR
xControlMen('pc1','om101Kapa','textBlauOnFixe/textBlauOffFixe/b10Fixe/tg10Fixe',0);
xControlMen('pc2','om102Kapa','textVermellOnFixe/textVermellOffFixe/b10Fixe/tg10Fixe',0);
xControlMen('pc3','om103Kapa','textLilaOnFixe/textLilaOffFixe/b10Fixe/tg10Fixe',0);
xControlMen('pc4','om104Kapa','textVerdOnFixe/textVerdOffFixe/b10Fixe/tg10Fixe',0);
xControlMen('pc5','om105Kapa','textMarroOnFixe/textMarroOffFixe/b10Fixe/tg10Fixe',0);
xControlMen('pc6','om106Kapa','textTaronjaOnFixe/textTaronjaOffFixe/b10Fixe/tg10Fixe',0);
xControlMen('pc7','om107Kapa','textMoradoOnFixe/textMoradoOffFixe/b10Fixe/tg10Fixe',0);


//general.js

function $ImgChangeSrc(id, sourceImg) {
	$(id).src = sourceImg;
}

function $ImgSwap(id, sourceImg1, sourceImg2) {
	if ($(id).src.indexOf(sourceImg1) != -1)
		$ImgChangeSrc(id, sourceImg2)
	else
		$ImgChangeSrc(id, sourceImg1)
}

function $Parent(id){
	if(window.parent){
	return  window.parent.document.getElementById(id);
	} else return null;
}

function $Visible(id){
	Element.show(id);
}

function $NoVisible(id){
	Element.hide(id);
}


function $deleteElement(id){
		$(id).parentNode.removeChild($(id));
}

function $isVisible(id){
	return Element.visible(id);
}

function $isExplorer(doc) {
	return (doc.all != null);
}

function $isRadioButton(obj) {
	if(!obj) return false;
	return (obj.tagName == 'INPUT' && obj.type == 'radio');
}

function $isCheckbox(obj) {
	if(!obj) return false;
	return (obj.tagName == 'INPUT' && obj.type == 'checkbox');
}

function $isDiv(obj) {
	if(!obj) return false;
	return (obj.tagName == 'DIV');
}

function $isText(keyCode) {
    return keyCode && (((keyCode >= 48) && (keyCode <= 57)) // Numeros
            || ((keyCode >= 65) && (keyCode <= 90)) // Letras
            || keyCode == Event.KEY_BACKSPACE
            || keyCode == Event.KEY_DELETE
            || keyCode == 32) // Espacio
}

function $storeObjectInDocument(id)
{
	var tempCopy = $(id).cloneNode(true);
	tempCopy.id = id;
	$deleteElement(id);
	document.documentElement.appendChild(tempCopy);
}

calendari = function(){
	
	if(arguments.length < 3)format = "%d/%m/%Y"; 
	else format = (arguments[2] == '') ? "%d/%m/%Y" : arguments[2];

	Calendar.setup(
		{
			inputField : arguments[0], // ID of the input field
			ifFormat : format, // the date format
			button : arguments[1], // ID of the button
			onUpdate : OCITValidation.validationChangeHandlerCalendar
		}
	);
}

function calendariDinamic(idField)
{
	//alert(idField+"\n"+$(idField));
	if(typeof $(idField) == 'undefined' || $(idField) == null) {
		return;
	}

	var idImgCalendari = idField+'_cal_tg_img';
	var img = new Image();
	img.id = idImgCalendari;
	img.className = 'calendarImg';
	img.src = 'images/framework/calendars/icon_calendar.gif';
	if($(idField).nextSibling)
		$(idField).parentNode.insertBefore(img, $(idField).nextSibling);
	else
		$(idField).parentNode.appendChild(img);
	calendari(idField, idImgCalendari, '');
}

/*
	FUNCIONES PARA LA VALIDACION DE FORMULARIOS
*/
function idsByName(form, name)
{
	list = form.elements;	
	var ids = new Array();
	if(name) {
		var index = 0;
		for (i=0;i<list.length;i++) {
			var element = list[i];
			if(element && element.name && element.name == name && element.id) {
				ids[index++] = element.id;
			}
		}
	}
	return ids;
}
/*
 Creacion de formulario vacio, con un action y un reqcode
 */
function submitVoidForm(action, reqCode) {
		LockService.activarEspera();
		var divForm = document.createElement("div");
		if ($('_voidactionform')){
			$('_voidactionform').action = action;
		} else {
			divForm.setAttribute("id", '_voidactionform_div');
			var theForm = '<form id="_voidactionform"  method="post" action="' + action + '" style="display:none;">';
			theForm += '<input type="hidden" id="' + '_voidactionform_reqCode" name="reqCode" value="' + reqCode + '">';
			theForm += '</form>';
			divForm.innerHTML = theForm;
			document.body.appendChild(divForm);
		}
		$('_voidactionform').submit();
	}
	
function submitVoidFormNewWindow(action) {
		var divForm = document.createElement("div");
		if ($('_voidactionnewform')){
			$('_voidactionnewform').action = action;
		} else {
			divForm.setAttribute("id", '_voidactionnewform_div');
			var theForm = '<form id="_voidactionnewform"  target="_blank" method="post" action="' + action + '" style="display:none;">';
			theForm += '</form>';		
			divForm.innerHTML = theForm;
			document.body.appendChild(divForm);
		}
		$('_voidactionnewform').submit();
	}	


var aux_idVoidForm = 0;
function submitVoidFormNewWindowParam(action, param, value) {

 var divForm = document.createElement("div");
 divForm.setAttribute("id", '_voidactionform_div_'+aux_idVoidForm);
 
 var idVoidForm = '_voidactionform_'+aux_idVoidForm;
 var theForm = '<form id="' + idVoidForm +'"  method="post" action="' + action + '" style="display:none;" target="_blank">';
 theForm += '<input type="hidden" name="ocit_form_ticket_x050107">'; 
 theForm += '<input type="hidden" id="' + param +'" name="' +  param + '" value="' + value + '">';
 theForm += '</form>';
 
 aux_idVoidForm++;
 divForm.innerHTML = theForm;
 document.body.appendChild(divForm);
 $(idVoidForm).submit();

}	


/* Formulari buit per mantenir valors en la navegacio entre pestanyes
 Creacio d'un formulari buit, amb un action, un reqcode i un id
 */
function submitVoidFormID(action, reqCode,id) {
		LockService.activarEspera();
		var divForm = document.createElement("div");
		divForm.setAttribute("id", '_voidactionform_div');
		
		var theForm = '<form id="' + '_voidactionform"  method="post" action="' + action + '" style="display:none;">';
		theForm += '<input type="hidden" id="' + '_voidactionform_reqCode" name="reqCode" value="' + reqCode + '">';
		theForm += '<input type="hidden" id="' + '_voidactionform_idAux" name="id" value="' + id + '">';
		theForm += '</form>';
		divForm.innerHTML = theForm;
		document.body.appendChild(divForm);
		$('_voidactionform').submit();
	}
	
/* Formulari buit per mantenir valors en la navegacio entre pestanyes
 Creacio d'un formulari buit, amb un action, un reqcode i tres ids:idacademia, idAdreca,idPersona
 */
function submitVoidFormAcademia(action, reqCode,id,idAdreca,idPersona,recuperadaDarp) {
		LockService.activarEspera();
		var divForm = document.createElement("div");
		divForm.setAttribute("id", '_voidactionform_div');
		
		var theForm = '<form id="' + '_voidactionform"  method="post" action="' + action + '" style="display:none;">';
		theForm += '<input type="hidden" id="' + '_voidactionform_reqCode" name="reqCode" value="' + reqCode + '">';
		theForm += '<input type="hidden" id="' + '_voidactionform_idAux" name="id" value="' + id + '">';
		theForm += '<input type="hidden" id="' + '_voidactionform_idAux2" name="idAdreca" value="' + idAdreca + '">';
		theForm += '<input type="hidden" id="' + '_voidactionform_idAux3" name="idPersona" value="' + idPersona + '">';		
		theForm += '<input type="hidden" id="' + '_voidactionform_idAux4" name="recuperadaDarp" value="' + recuperadaDarp + '">';		
		theForm += '</form>';
		divForm.innerHTML = theForm;
		document.body.appendChild(divForm);
		$('_voidactionform').submit();
	}

function certificat (nomForm, certificat){
	if (certificat == 'CRC' || certificat == ''){//Es el certificado mEdico
		$Visible('veureCRC');
		$(nomForm).certificado[0].checked = true;
		$(nomForm).certificadoAuxiliar.value="CRC";
		$NoVisible('veureISM');
		$NoVisible('veureRM');
	}
	else 
		if (certificat == 'ISM'){
			$Visible('veureISM');
			$(nomForm).certificado[1].checked = true;
			$(nomForm).certificadoAuxiliar.value="ISM";
			$NoVisible('veureCRC');
			$NoVisible('veureRM');
		} else 
			 if (certificat == 'RM') {
				 $Visible('veureRM');
				 $(nomForm).certificado[2].checked = true;
				 $(nomForm).certificadoAuxiliar.value="RM";
				 $NoVisible('veureCRC');
				 $NoVisible('veureISM');
			} 
}

function tractamentCertificat(nomForm){
	
	if($(nomForm).certificado[0].checked == true){
		$(nomForm).dataEmissioIsm.value = '';
		$(nomForm).dataEmissioRm.value = '';
	}
	if($(nomForm).certificado[1].checked == true){
		$(nomForm).dataExpCm.value = '';
		$(nomForm).dataEmissioRm.value = '';
	}
	if($(nomForm).certificado[2].checked == true){
		$(nomForm).dataExpCm.value = '';
		 $(nomForm).dataEmissioIsm.value = '';
	}
}

function $getURLPath() {
	var location = window.location.toString();
	var discrim = '/AppJava/';
	var urlUC = location;
	if(urlUC.indexOf(discrim) != -1)
		urlUC = urlUC.substring(urlUC.indexOf(discrim)+discrim.length);
	return (urlUC.indexOf('?') != -1)? urlUC.substring(0,urlUC.indexOf('?')) : urlUC;
}


// pccookielib.js


/*

DISCLAIMER: THESE JAVASCRIPT FUNCTIONS ARE SUPPLIED 'AS IS', WITH 
NO WARRANTY EXPRESSED OR IMPLIED. YOU USE THEM AT YOUR OWN RISK. 
PAUL STEPHENS DOES NOT ACCEPT ANY LIABILITY FOR 
ANY LOSS OR DAMAGE RESULTING FROM THEIR USE, HOWEVER CAUSED. 

Paul Stephens' cookie-handling object library

Version 2.1
2.0 - Introduces field names
2.1 - Fixes bug where undefined embedded fields[] elements weren't written to disk

www.paulspages.co.uk 

TO USE THIS LIBRARY, INSERT ITS CONTENTS IN THE <HEAD> SECTION 
OF YOUR WEB PAGE SOURCE, BEFORE ANY OTHER JAVASCRIPT ROUTINES.

(C) Paul Stephens, 2001-2003. Feel free to use this code, but please leave this comment block in. This code must not be sold, either alone or as part of an application, without the consent of the author.

*/

function cookieObject(name, expires, accessPath) {
var i, j
this.name = name
this.fieldSeparator = "#"
this.found = false
this.expires = expires
this.accessPath = accessPath
this.rawValue = ""
this.fields = new Array()
this.fieldnames = new Array() 
if (arguments.length > 3) { // field name(s) specified
  j = 0
  for (i = 3; i < arguments.length; i++) {
    this.fieldnames[j] = arguments[i]    
    j++
  }
  this.fields.length = this.fieldnames.length 
}
this.read = ucRead

this.write = ucWrite

this.remove = ucDelete
this.get = ucFieldGet
this.put = ucFieldPut
this.namepos = ucNamePos
this.read()
}


function ucFieldGet(fieldname) {
var i = this.namepos(fieldname)
if (i >=0) {
  return this.fields[i]
} else {
  return "BadFieldName!"
}
}

function ucFieldPut (fieldname, fieldval) {
var i = this.namepos(fieldname)
if (i >=0) {
  this.fields[i] = fieldval
  return true
} else {
  return false
}
}

function ucNamePos(fieldname) {
var i 
for (i = 0; i < this.fieldnames.length; i++) {
  if (fieldname == this.fieldnames[i]) {
    return i
  }
}
return -1
}


function ucWrite() {      
  var cookietext = this.name + "=" 

// concatenate array elements into cookie string

// Special case - single-field cookie, so write without # terminator
if (this.fields.length == 1) {
  cookietext += escape(this.fields[0])
  } else { // multi-field cookie
    for (i= 0; i < this.fields.length; i++) {
      cookietext += escape(this.fields[i]) + this.fieldSeparator }
  }


// Set expiry parameter, if specified
    if (this.expires != null) {  
      if (typeof(this.expires) == "number") { // Expiry period in days specified  
        var today=new Date()     
        var expiredate = new Date()      
        expiredate.setTime(today.getTime() + 1000*60*60*24*this.expires)
        cookietext += "; expires="; // END OF SESSION
      } else { // assume it's a date object
        cookietext +=  "; expires=" + this.expires.toGMTString()
      } // end of typeof(this.expires) if
    } // end of this.expires != null if 
   
// add path, if specified
   if (this.accessPath != null) {
   cookietext += "; PATH="+this.accessPath }

// write cookie
   // alert("writing "+cookietext)
   document.cookie = cookietext 
   return null  
}


function ucRead() {
  var search = this.name + "="                       
  var CookieString = document.cookie            
  this.rawValue = null
  this.found = false     
  if (CookieString.length > 0) {                
    offset = CookieString.indexOf(search)       
    if (offset != -1) {                         
      offset += search.length                   
      end = CookieString.indexOf(";", offset)   
      if (end == -1) {  // cookie is last item in the string, so no terminator                        
       end = CookieString.length }              
      this.rawValue = CookieString.substring(offset, end)                                   
      this.found = true 
      } 
    }
   
if (this.rawValue != null) { // unpack into fields

  var sl = this.rawValue.length
  var startidx = 0
  var endidx = 0
  var i = 0

// Special case - single-field cookies written by other functions,
// so without a '#' terminator

if (this.rawValue.substr(sl-1, 1) != this.fieldSeparator) {
  this.fields[0] = unescape(this.rawValue)
  } else { // separate fields

  do  
  {
   endidx = this.rawValue.indexOf(this.fieldSeparator, startidx)
   if (endidx !=-1) {
     this.fields[i] = unescape(this.rawValue.substring(startidx, endidx))
     i++
     startidx = endidx + 1}
  }
  while (endidx !=-1 & endidx != (this.rawValue.length -1));
}
} // end of unpack into fields if block
  return this.found
} // end of function


function ucDelete() {
  this.expires = -10
  this.write()
  return this.read()
}



/*
*********** IT'S OK TO REMOVE THE CODE BELOW HERE IF YOUR PAGE 
DOESN'T USE cookieList() OBJECTS OR THE findCookieObject() FUNCTION.
*/




function findCookieObject(cName, cObjArray) {
/* 
This function finds a named cookie among the objects
pointed to by a cookieList array (see below).

Parameters are the cookie name to search for (a string), and an array created with 
the new cookieList() constructor (see below)

NOTE - if you're only dealing with a specific, named cookie, then it's
more efficient to ceate a single cookieObject directly with that name,
and check its .found property to see if it already exists on this client.

This function is for when you've created an all-cookies array anyway,
and now want to check whether a specific cookie is present.

It returns a pointer to the cookieObject if found, or null if not found.
*/

var cpointer = null, i
for (i in cObjArray) {
  if (cName == cObjArray[i].name) {
    cpointer = cObjArray[i]
  }
}
return cpointer
}


function cookieList() {
/* 
This constructor function creates a cookieObject object (see below) 
for each cookie in document.cookie,
and returns an array of pointers to the objects.

You can use it to load all the cookies available to a page, then walk through them.

Example usage:

cookList = new cookieList()
for (i in cookList) {
 document.write(cookList[i].name + " " + cookList[i].fields[0] + "
")
}

*/

var i = 0, rawstring, offset = 0, start, newname
cpointers = new Array()
rawstring = document.cookie
if (rawstring.length > 0) {
  do {
   start = rawstring.indexOf("=", offset)
   if (start != -1) { // another cookie found in string
     // get cookie string up to end of current cookie name
     newname = rawstring.substring(0, start) 
     if (offset > 0) { 
       // if not first cookie in string, remove previous cookie data from substring
       // subsequent cookie names have a space before them (just a little browser foible!)
       newname = newname.substring(newname.lastIndexOf(";")+2, start)
     }     
     cpointers[i] = new cookieObject(newname)
     offset = start + 1
     i++
   }
  } while (start != -1)
} // end rawstring.length > 0
return cpointers
} //end function

// cookies.js

// Servicio de Cookies
var CookieService = new Object();

CookieService.EXPIRES = 1; // horas
CookieService.ATTRIBUTE_NOT_FOUND = "BadFieldName!";
CookieService.KEY_VALUE_SEPARATOR = "_:_";

CookieService.cookiesCargadas = new Object();

CookieService.getCookie = function (nomCookie, atributs) {
								var attrs = (atributs)? atributs : [];
								if(typeof CookieService.cookiesCargadas[nomCookie] == "undefined")
									CookieService.cookiesCargadas[nomCookie] = new OCITCookie( nomCookie, attrs )
								return CookieService.cookiesCargadas[nomCookie];
							};

CookieService.findAttribute = function (collection, attributeName) {
									var result = null;
									for(var iD=0; iD<collection.length; iD++) {
										var key = collection[iD].inputKey;
										if(key == attributeName) {
											result = collection[iD].inputValue;
											break;
										}
									}
									return result;
								};

// Objeto Cookie
var OCITCookie = Class.create();
OCITCookie.prototype = {
	initialize: function (nom, atributs) {
		this.cookie = new cookieObject(nom);
		for(var iAtr=0; iAtr<atributs.length; iAtr++) {
			this.cookie.fieldnames[iAtr] = atributs[iAtr];
			this.cookie.fields[iAtr] = '';
		}
		this.cookie.fieldnames.length = this.cookie.fields.length = atributs.length;
		this.cookie.read();
	},
	set: function (clau, valor) {
		if(this.cookie.namepos(clau) == -1) {
			this.cookie.fieldnames[this.cookie.fieldnames.length] = clau;
		}
		this.cookie.put(clau, valor);
		this.cookie.write();
	},
	get: function (clau) {
		this.cookie.read();
		var attr = this.cookie.get(clau);
		return (attr == CookieService.ATTRIBUTE_NOT_FOUND)? null : attr;
	},
	getValue: function () {
		this.cookie.read();
		return this.cookie.rawValue;
	},
	setValue: function (value) {
		this.cookie.fieldnames.length = 1;
		this.cookie.fields.length = 1;
		this.cookie.fields[0] = value;
		this.cookie.write();
	},
	getMap: function () {
		this.cookie.read();
		var result = new Array();
		var keyValuesArray = this.cookie.rawValue.split(this.cookie.fieldSeparator);
		for(var iAtr=0; iAtr<keyValuesArray.length; iAtr++) {
			var keyValue = unescape(keyValuesArray[iAtr]);
			var nouObj = new Object();
			var sepPos = keyValue.indexOf(CookieService.KEY_VALUE_SEPARATOR);
			nouObj['inputKey'] = keyValue.substring(0, sepPos);
			nouObj['inputValue'] = keyValue.substring(sepPos+CookieService.KEY_VALUE_SEPARATOR.length);
			result.push(nouObj);
		}
		return result;
	},
	saveMap: function (keyValuesArray) {
		for(var iPos=0; iPos<keyValuesArray.length; iPos++) {
			var keyValue = keyValuesArray[iPos];
			this.cookie.fieldnames[iPos] = keyValue.inputKey;
			this.cookie.fields[iPos] = keyValue.inputKey + CookieService.KEY_VALUE_SEPARATOR + keyValue.inputValue;
		}
		this.cookie.fieldnames.length = this.cookie.fields.length = keyValuesArray.length;
		this.cookie.write();
	}
};

//lock.js


	
	var LockService = new Object();
	
	/* Selects visibles: los que seran ocultados y mostrados en Explorer */
	var visibleSelects = new Array();
	
	LockService.LOCK      = false;
	LockService.DIV_CLASS = "divBloqueo";
	LockService.DIV_IFRAME_CLASS = "divBloqueoIframe";

	LockService.WAITING_DIV_ID = 'LockService_waiting_div';
	
	//Atributs per l'espera
	var visibleSelectsEspera = new Array();
	LockService.ESPERA_DIV_CLASS = "divEspera";
	LockService.ESPERA_DIV_PARENT_PROT = "divBloqueoWait";
	LockService.ESPERA_DIV_IFRAME_CLASS = "divEsperaIframe";
	LockService.ESPERA_DIV_ID = 'LockService_espera_div';
	LockService.ESPERA_ACTIVA = false;
	
	
	LockService.NUM_BLOQUEOS = 0;
	
  	Object.extend(LockService,{
  	initialize : function() { 
		this.myTabIndexes = new Array();
		this.myTabs = new Array("a", "button", "textarea", "input","iframe");
		
					
		/* Necesario para bloquear el TabIndex en Firefox; hay que recoger el evento onKeyPress */
		if( !$isExplorer(document) ) {
			document.onkeypress = this.lockTabFirefox;
		}
  	
		var bodyElement = document.body;
		var docuElement = document;
		var myDiv = docuElement.createElement("div");
		myDiv.id = 'divBloqueo'+LockService.NUM_BLOQUEOS;
		myDiv.className = (window.parent != window)? LockService.DIV_IFRAME_CLASS : LockService.DIV_CLASS;
					
		/* Establecemos el tamanyo del div */
		var windowHeight = 0;
		if($isExplorer(docuElement)) {
			windowHeight = screen.availHeight - window.screenTop;//screen.height - screen.availHeight - window.screenTop;
			//alert(window.clientInformation+' - '+screen.height+' - '+screen.availHeight+' - '+window.screenTop);
		}
		myDiv.style.height = Math.max(docuElement.documentElement.scrollHeight,windowHeight) + "px";
		myDiv.style.width = docuElement.documentElement.scrollWidth + "px";
		
		bodyElement.appendChild(myDiv);
	},
  	
  	activar: function(espera) {
  		this.initialize();
  		LockService.NUM_BLOQUEOS++;
		if(window.parent != window)
			window.parent.LockService.NUM_BLOQUEOS++;
		LockService.LOCK = true;

		//TODO: Desactivar la barra de scroll en IE y ir al inicio de la pagina
		if( $isExplorer(document) ) {
			this.desactivarTabIndexesIE();
			this.hideSelects();
		} else {
			//window.scrollbars.visible = false;
		}
		
		// Mostrar la imagen de espera
		if(espera && espera == true) {
			var windowObj = window.parent;
			var documentObj = windowObj.document;
			var myDiv = documentObj.createElement("div");
			
			var width = 150;
			var height = 80;
			
			myDiv.innerHTML = '<table width="100%"><tr height="'+height+'"><td align="center" valign="middle"><img src="images/wait.gif" /></td></tr></table>';
			myDiv.id = LockService.WAITING_DIV_ID;
			myDiv.className = 'overAll';
			documentObj.body.appendChild(myDiv);
			var posicion = LockService.center(width, height, windowObj);
			windowObj.Element.setStyle(myDiv, {width: width+'px', 'background-color': '#FFFFFF', position: 'absolute', top: posicion.top+'px', left: posicion.left+'px', border: '1px solid #000000'});
			//windowObj.Event.observe(documentObj.documentElement, 'scroll', LockService.centraDivEspera, true);
		}
	},
	
	desactivar: function(espera) {
		if (LockService.NUM_BLOQUEOS == 0)
			return;
		
// parche para evitar el bloqueo del div en explorer
		
		var lockDivTemp =$('divBloqueo'+(LockService.NUM_BLOQUEOS-1));
		lockDivTemp.style.display='none';
		lockDivTemp.id='dummmy';
		
		if( $isExplorer(document) ) {
			this.activarTabIndexesIE();
			this.showSelects();
		} else {
			//window.scrollbars.visible = true;
		}
		LockService.NUM_BLOQUEOS--;
		if(window.parent != window)
			window.parent.LockService.NUM_BLOQUEOS--;
		LockService.LOCK = false;

		// Ocultar la imagen de espera
		if(espera && espera == true) {
			var windowObj = window.parent;
			windowObj.$deleteElement(LockService.WAITING_DIV_ID);
			//windowObj.Event.stopObserving(windowObj.document.documentElement, 'scroll', LockService.centraDivEspera, true);
		}
	},

  	activarEspera: function() {
 		//Codi d'inicialitzaci?
  		this.myTabIndexesEspera = new Array();
		this.myTabsEspera = new Array("a", "button", "textarea", "input","iframe");
		
					
		/* Necesario para bloquear el TabIndex en Firefox; hay que recoger el evento onKeyPress */
		if( !$isExplorer(document) ) {
			document.onkeypress = this.lockTabFirefoxEspera;
		}
  	
		var bodyElement = document.body;
		var docuElement = document;
		var myDiv = docuElement.createElement("div");
		myDiv.id = 'divBloqueoWait';
		myDiv.className = LockService.ESPERA_DIV_IFRAME_CLASS;
					
		/* Establecemos el tamanyo del div */
		var windowHeight = 0;
		if($isExplorer(docuElement)) {
			windowHeight = screen.availHeight - window.screenTop;
		}
		myDiv.style.height = Math.max(docuElement.documentElement.scrollHeight,windowHeight) + "px";
		myDiv.style.width = docuElement.documentElement.scrollWidth + "px";
		
		bodyElement.appendChild(myDiv);
  		//Fi codi inicialitzaci?
  		
  		LockService.ESPERA_ACTIVA=true;

		//TODO: Desactivar la barra de scroll en IE y ir al inicio de la pagina
		if( $isExplorer(document) ) {
			this.desactivarTabIndexesIEEspera();
			this.hideSelectsEspera();
		} else {
			//window.scrollbars.visible = false;
		}
		
		// Mostrar la imagen de espera
		var windowObj = window;
		var documentObj = windowObj.document;
		var myDivContent = documentObj.createElement("div"); 
		
		var width = 190;
		var height = 75;
		
		myDivContent.innerHTML = '<table width="100%"><tr height="'+height+'"><td align="center" valign="middle"><b><i>Transferint Dades</i></b></td></tr></table>';
		myDivContent.id = LockService.ESPERA_DIV_ID;
		myDivContent.className = 'overAll';
		documentObj.body.appendChild(myDivContent);
		var posicion = LockService.center(width, height, windowObj);
		windowObj.Element.setStyle(myDivContent, {width: width+'px', 'filter' : 'filter(opacity=75)', 'background-color': '#FFFFFF', position: 'absolute', top: posicion.top+'px', left: posicion.left+'px', border: '1px solid #C0C0C0'});
		
		
	},
	
	desactivarEspera: function() {
		if(LockService.ESPERA_ACTIVA == true){
		
	// parche para evitar el bloqueo del div en explorer
			
			var lockDivTemp =$('divBloqueoWait');
			lockDivTemp.style.display='none';
			lockDivTemp.id='dummmy';
			
			if( $isExplorer(document) ) {
				this.activarTabIndexesIEEspera();
				this.showSelectsEspera();
			} else {
				//window.scrollbars.visible = true;
			}
	
			// Ocultar la imagen de espera
			var windowObj = window;
			windowObj.$deleteElement(LockService.ESPERA_DIV_ID);
			LockService.ESPERA_ACTIVA=false;
		}
	},
	/* Deshabilita el TagIndex para no poder acceder con el teclado */
	desactivarTabIndexesIEEspera: function() {
		var i = 0;
		for( var j = 0; j < this.myTabsEspera.length; j++ ) {
			var docTabs = document.getElementsByTagName(this.myTabsEspera[j]);
			for( var k = 0; k < docTabs.length; k++ ) {
				this.myTabIndexesEspera[i] = docTabs[k].tabIndex;		// Guardamos el Tag Index
				docTabs[k].tabIndex = "-1";						// Lo deshabilitamos
				i++;
			}
		}
	},
	
	/* Habilita el TagIndex despues de haberlo desactivado */
	activarTabIndexesIEEspera: function() {
		var i = 0;
		for( var j = 0; j < this.myTabsEspera.length; j++ ) {
			var docTabs = document.getElementsByTagName(this.myTabsEspera[j]);
			for( var k = 0; k < docTabs.length; k++ ) {
				docTabs[k].tabIndex = this.myTabIndexesEspera[i];		// Restauramos el Tag Index
				docTabs[k].tabEnabled = true;					// Lo habilitamos
				i++;
			}
		}
	},
	/* Esconde los selects; en IE quedan por encima */
	hideSelectsEspera: function() {
		var selects = $A( document.getElementsByTagName("select") );
		
		/* Guardamos los selects visibles */
		visibleSelectsEspera = selects.findAll(function(current) {
			return $isVisible(current.id);
		});
		
		/* Ocultamos los selects visibles */
		visibleSelectsEspera.each(function(current, i) {
			$NoVisible(current.id);
		});
	},
	
	/* Muestra los selects */
	showSelectsEspera: function() {
		/* Mostramos solo los selects que hemos ocultado desde el bloqueo */
		visibleSelectsEspera.each(function(current, i) {
			$Visible(current.id);
		});
	},
	/* Deshabilita la tecla tabulador en Firefox */
	lockTabFirefoxEspera: function(key) {
		if(key.keyCode == 9 )		// Controlamos si se pulsa el tabulador
			return false;
	},
	
	numeroBloqueos: function() {
		if(window.parent != window)
			return window.parent.LockService.NUM_BLOQUEOS;
		else
			return LockService.NUM_BLOQUEOS;
	},
	
	/* Deshabilita el TagIndex para no poder acceder con el teclado */
	desactivarTabIndexesIE: function() {
		var i = 0;
		for( var j = 0; j < this.myTabs.length; j++ ) {
			var docTabs = document.getElementsByTagName(this.myTabs[j]);
			for( var k = 0; k < docTabs.length; k++ ) {
				this.myTabIndexes[i] = docTabs[k].tabIndex;		// Guardamos el Tag Index
				docTabs[k].tabIndex = "-1";						// Lo deshabilitamos
				i++;
			}
		}
	},
	
	/* Habilita el TagIndex despues de haberlo desactivado */
	activarTabIndexesIE: function() {
		var i = 0;
		for( var j = 0; j < this.myTabs.length; j++ ) {
			var docTabs = document.getElementsByTagName(this.myTabs[j]);
			for( var k = 0; k < docTabs.length; k++ ) {
				docTabs[k].tabIndex = this.myTabIndexes[i];		// Restauramos el Tag Index
				docTabs[k].tabEnabled = true;					// Lo habilitamos
				i++;
			}
		}
	},
	
	/* Deshabilita la tecla tabulador en Firefox */
	lockTabFirefox: function(key) {
		if( LockService.LOCK && key.keyCode == 9 )		// Controlamos si se pulsa el tabulador
			return false;
	},
	
	/* Esconde los selects; en IE quedan por encima */
	hideSelects: function() {
		var selects = $A( document.getElementsByTagName("select") );
		
		/* Guardamos los selects visibles */
		visibleSelects = selects.findAll(function(current) {
			return $isVisible(current.id);
		});
		
		/* Ocultamos los selects visibles */
		visibleSelects.each(function(current, i) {
			$NoVisible(current.id);
		});
	},
	
	/* Muestra los selects */
	showSelects: function() {
		/* Mostramos solo los selects que hemos ocultado desde el bloqueo */
		visibleSelects.each(function(current, i) {
			$Visible(current.id);
		});
	},
	
	/* Auxiliar para centrar la imagen en pantalla */
	/*centraDivEspera: function () {
		var windowObj = window.parent;
		var posicion = LockService.center(150, 80, windowObj.document);
		windowObj.Element.setStyle(windowObj.$(LockService.WAITING_DIV_ID), {top: posicion.top+'px', left: posicion.left+'px'});
	},*/
	center: function(width, height, windowObj) {
		if( $isExplorer(document) ) {
			var pageWidth = windowObj.document.documentElement.clientWidth;
			var pageHeight = windowObj.document.documentElement.clientHeight;
		} else {
			var pageWidth = windowObj.innerWidth;	
			var pageHeight = windowObj.innerHeight;							
		}
		
		var winW = pageWidth - WindowGenerica.SCROLL_SIZE;
		var winH = pageHeight;
		var left = winW/2 - width/2;
		var top = winH/2 - height/2;

		return {top: top, left: left};		
	}
	
	});

//mensaje.js

 
/*
 * TODO:
 *  Para que se pueda mostrar mas de una ventana a la vez, el ID
 *  de los divs de la ventana ha de generarse dinamicamente.
 *  La funcion inicialHide podra quitarse cuando este arreglado lo
 *  de los IDs.
 *  Arreglar el appendChild para hacerlo en cada show.
 */
 
 
	/*------------------------*/
	/* CREACION DE LAS CLASES */
	/*------------------------*/
	
    //Clase Generica
    var WindowGenerica = Class.create();

	//Heredan de WindowGenerica
	var WindowMensaje = Class.create();
	var WindowContenedor = Class.create();
	
	//Heredan de WindowMensaje
	var WindowAlerta = Class.create();
	var WindowError = Class.create();
	var WindowConfirmacion = Class.create();
	var WindowInformacion = Class.create();
	var WindowEspera = Class.create();
	
	//Heredan de WindowContenedor
	var WindowErrores = Class.create(); 
	var WindowBusqSel = Class.create();

	/*------------------------*/	/* PROPIEDADES CONSTANTES */
	/*------------------------*/
	
	WindowGenerica.DIV_ID	     = 'divMensaje';
	WindowGenerica.DIV_CLASS     = 'divMensaje';
	WindowGenerica.SCROLL_SIZE   = ($isExplorer(document))? 20 : 16;
	
	WindowGenerica.IFRAME_ID 	 = 'iframeVentana';
	
	WindowInformacion.DIV_ID	     = 'divMensajeInformacion';
	WindowInformacion.DIV_CLASS     = 'divMensajeInformacion';

	WindowConfirmacion.DIV_ID	     = 'divMensajeConfirmacion';
	WindowConfirmacion.DIV_CLASS     = 'divMensajeConfirmacion';
	
	WindowEspera.DIV_ID	     = 'divMensajeEspera';
	WindowEspera.DIV_CLASS   = 'divMensajeEspera';

	WindowError.DIV_CLASS     = 'divMensajeError';

	WindowErrores.DIV_ERROR_ID = 'divMensajeError';
	WindowErrores.DIV_ERROR_CLASS = 'divMensajeError';
	WindowErrores.CLOSE_ID       = 'cierreErrores';
	WindowErrores.BUTTON_ID      = 'botonErrores';
	WindowErrores.OBSERVED_EVENT = 'click';
	WindowErrores.REDUCED_DIV_ID = 'divMensajeReducido';
	
	
	/*---------------------------*/
	/* DEFINICION DE LOS OBJETOS */
	/*---------------------------*/
	
	//WINDOW PRINCIPAL		
	WindowGenerica.prototype = {
		initialize: function() {
			this.accesoPorId = $;
			this.windowObj = window;
			this.documentObj = document;
		},
		
		show: function(top2){
			if(this.mensaje.modal) {
				LockService.activar();
			}
			
			this.center();
			if(top2)
				this.mensaje.style.top = top2 + 'px';	

			this.mensaje.style.display = "block";
			this.mensaje.style.visibility = "visible";
			
			this.accesoPorId(this.mensaje.id).hidden = false;
			$hideShowCovered(this.accesoPorId(this.mensaje.id));
			
			this.mensaje.focus();
			//IGH Si lo descomentas PETA
	//		if(this.mensaje.id == WindowGenerica.DIV_ID)
	//			new this.windowObj.Draggable(this.mensaje.id, {revert:false, handle:'tablaTitulo'});
		},
		
		hide: function(){
			if(this.mensaje && this.mensaje.modal) {
				LockService.desactivar();
			}
			this.accesoPorId(this.mensaje.id).hidden = true;
			$hideShowCovered(this.accesoPorId(this.mensaje.id));
			this.windowObj.$deleteElement(this.mensaje.id);
		},
		
		initialHide: function() {
			//this.mensaje.style.display = "none";
		},
		
		createDiv: function(width, height, modal) {

			this.height = parseInt(height)+ 20 ;			
			this.width = parseInt(width)+2;
			this.modal = modal;

			this.mensaje = this.documentObj.createElement("div");
			this.mensaje.setAttribute("id", WindowGenerica.DIV_ID);
			this.mensaje.style.width = this.width +'px';
			this.mensaje.style.height = this.height +'px';
			this.mensaje.className = WindowGenerica.DIV_CLASS;

			this.documentObj.body.appendChild(this.mensaje);
			var cabecera ="<table class='tablaTitulo'>";
			cabecera += "<tr><td style='background-color:#C0C0C0;text-align:right'>";
			cabecera += "<a href='javascript:$(WindowGenerica.DIV_ID).controller.hide();'>";
			cabecera += "	<img src='images/window/close.gif' border='0' align='top'>";
			cabecera += "</a></td></tr>";
			// generamos el iframe
			cabecera += "<tr><td><iframe id='"+WindowGenerica.IFRAME_ID+"' style='width:"+width+"px;height:"+height+"px' frameborder='0'></iframe></td></tr>";
			cabecera += "</table>";
			this.mensaje.innerHTML = cabecera;


			this.mensaje.modal = modal;
			this.mensaje.controller = this;

			


		},
		
		center: function() {
			if( $isExplorer(document) ) {
				var pageWidth = this.documentObj.documentElement.clientWidth;
				var pageHeight = this.documentObj.documentElement.clientHeight;
			} else {
				var pageWidth = this.windowObj.innerWidth;	
				var pageHeight = this.windowObj.innerHeight;							
			}
				
			var winW = pageWidth - WindowGenerica.SCROLL_SIZE;
			var winH = pageHeight;
			var left = winW/2 - this.width/2;
			var top = winH/2 - this.height/2;
			
			this.mensaje.style.top    = top  + 'px';			
			this.mensaje.style.left   = left + 'px';
			this.mensaje.style.width  = this.width  + 'px';
			//this.mensaje.style.height = this.height + 'px'; // En explorer peta
		}
	};

	//WINDOW MENSAJE
	Object.extend(Object.extend(WindowMensaje.prototype,WindowGenerica.prototype),
	{
		loadDiv: function(nameDiv,funcion){
					this.accesoPorId = $;
					this.windowObj = window;
					this.documentObj = document;
					
					this.mensaje = this.accesoPorId(nameDiv);	
					this.mensaje.modal = true;
					this.documentObj.body.appendChild(this.mensaje);				
					this.accesoPorId(nameDiv).controller = this;
					Object.extend(this,funcion);
					
					this.initialHide();
				}
	});
	
	//WINDOW ALERTA
	Object.extend(Object.extend(WindowAlerta.prototype,WindowMensaje.prototype),
	{	initialize: function(funcion,id){				
					this.accesoPorId = $t;
					this.windowObj = window;
					this.documentObj = document;
					if(id ==null){
						id ='mensajeAlerta';
					}
					this.loadDiv(id, funcion);
				}
		
		}
	);
	
	
	//WINDOW ERROR
	Object.extend(Object.extend(WindowError.prototype,WindowMensaje.prototype), {
		initialize: function(msg) {
			this.accesoPorId = $;
			this.windowObj = window;
			this.documentObj = document;
			this.createDivInfo(msg);	// Creamos el div con el mensaje
			this.initialHide();
		},

		createDivInfo: function(msg) {
			this.height = 180;
			this.width = 300;
			this.modal = true;
			
			this.mensaje = this.documentObj.createElement("div");
			this.mensaje.setAttribute("id", WindowGenerica.DIV_ID);
			
			var html ="<table class='tablaTitulo' height='6' cellpadding='2'>";
			html += "<tr><td class='columnaTituloPrimera' align='right'>";
			html += "<a href='javascript:$(WindowGenerica.DIV_ID).controller.hide();'>";
			html += "	<img src='images/window/close.gif' border='0' align='top'>";
			html += "</a></td></tr></table><table width='100%' cellpadding='30'><tr><td><table width='100%' height='"+(this.height-140)+"'><tr valign='middle'>";
			html += "<td align='center' ><img src=\"images/window/errorIcon.gif\" alt=\"Error\"></td>";
			html += "<td width='10'>&nbsp;</td><td align='left'>";
			html += msg;
			html += "</td></tr></table></td></tr></table>";
			html += "<center><input type='button' value='Aceptar' onClick=\"$(WindowGenerica.DIV_ID).controller.hide();\" style=\"width: 80px;\" class=\"boton\"/ onmouseover=\"this.className='boton_hover'\" onmouseout=\"this.className='boton'\"/></center><br><br>";
			
			this.mensaje.innerHTML = html;
			this.mensaje.className = WindowError.DIV_CLASS;
			this.mensaje.modal = true;
			
			this.documentObj.body.appendChild(this.mensaje);
			
			$(WindowGenerica.DIV_ID).controller = this;
		}
	});
	
	//WINDOW CONFIRMACION
	Object.extend(Object.extend(WindowConfirmacion.prototype,WindowMensaje.prototype),
	{	initialize: function(msg, funcion){				
						this.accesoPorId = $;
						this.windowObj = window;
						this.documentObj = document;
		
						this.createDivConfirmacion(msg,funcion);	// Creamos el div con el mensaje
						this.initialHide();
				},
		
		createDivConfirmacion: function(msg, funcion, top) {
			this.height = 200;
			this.width = 300;
			this.modal = true;
			
			this.mensaje = this.documentObj.createElement("div");
			this.mensaje.setAttribute("id", WindowConfirmacion.DIV_ID);
			
			var html ="<table class='tablaTitulo' height='6' cellpadding='2'>";
			html += "<tr><td class='columnaTituloPrimera' align='right'>";
			html += "<a href='javascript:$(WindowConfirmacion.DIV_ID).controller.hide();'>";
			html += "	<img src='images/window/close.gif' border='0' align='top'>";
			html += "</a></td></tr></table><table width='100%' cellpadding='30'><tr><td><table width='100%' height='"+(this.height-140)+"'><tr valign='middle'>";
			html += "<td align='center' ><img src=\"images/window/confirmacion.jpg\" alt=\"confirmacion\"></td>";
			html += "<td width='10'>&nbsp;</td><td align='left'>";
			html += msg;
			html += "</td></tr></table></td></tr></table>";
			html += "<table width='100%'><tr align='center'>";
			html += "<td><input type='button' value='S&iacute;' onClick=\"$(WindowConfirmacion.DIV_ID).controller.confirmar();\" style=\"width: 80px;\" class=\"boton\"/ onmouseover=\"this.className='boton_hover'\" onmouseout=\"this.className='boton'\"></td>";
			html += "<td><input type='button' value='No' onClick=\"$(WindowConfirmacion.DIV_ID).controller.cancellar();\" style=\"width: 80px;\" class=\"boton\"/ onmouseover=\"this.className='boton_hover'\" onmouseout=\"this.className='boton'\"/></td>";
			html += "</tr><tr><td colspan='2'><br><br></td>";
			html += "</tr></table>";
			
			this.mensaje.innerHTML = html;
			this.mensaje.className = WindowConfirmacion.DIV_CLASS;
			this.mensaje.modal = true;
			
			this.documentObj.body.appendChild(this.mensaje);
			
			this.accesoPorId(WindowConfirmacion.DIV_ID).controller = this;
			
			Object.extend(this,funcion);
			if(this.accesoPorId(WindowConfirmacion.DIV_ID).controller.cancellar == null){
				this.accesoPorId(WindowConfirmacion.DIV_ID).controller.cancellar = this.accesoPorId(WindowConfirmacion.DIV_ID).controller.hide;
			}


		}
	}
	);
	
	//WINDOW INFORMACION
	Object.extend(Object.extend(WindowInformacion.prototype,WindowMensaje.prototype), {
		initialize: function(msg) {
			this.accesoPorId = $;
			this.windowObj = window;
			this.documentObj = document;
			this.createDivInfo(msg);	// Creamos el div con el mensaje
			this.initialHide();
		},

		createDivInfo: function(msg) {
			this.height = 180;
			this.width = 300;
			this.modal = true;
			
			this.mensaje = this.documentObj.createElement("div");
			this.mensaje.setAttribute("id", WindowInformacion.DIV_ID);
			
			var html ="<table class='tablaTitulo' height='6' cellpadding='2'>";
			html += "<tr><td class='columnaTituloPrimera' align='right'>";
			html += "<a href='javascript:$(WindowInformacion.DIV_ID).controller.hide();'>";
			html += "	<img src='images/window/close.gif' border='0' align='top'>";
			html += "</a></td></tr></table><table width='100%' cellpadding='30'><tr><td><table width='100%' height='"+(this.height-140)+"'><tr valign='middle'>";
			html += "<td align='center' ><img src=\"images/window/icon_info_lrg.gif\" alt=\"Informacion\"></td>";
			html += "<td width='10'>&nbsp;</td><td align='left'>";
			html += msg;
			html += "</td></tr></table></td></tr></table>";
			html += "<center><input type='button' value='Aceptar' onClick=\"$(WindowInformacion.DIV_ID).controller.hide();\" style=\"width: 80px;\" class=\"boton\"/ onmouseover=\"this.className='boton_hover'\" onmouseout=\"this.className='boton'\"/></center><br><br>";
			
			this.mensaje.innerHTML = html;
			this.mensaje.className = WindowInformacion.DIV_CLASS;
			this.mensaje.modal = true;
			
			this.documentObj.body.appendChild(this.mensaje);
			
			this.accesoPorId(WindowInformacion.DIV_ID).controller = this;
		}
	});
	
	
	//WINDOW ESPERA
	Object.extend(Object.extend(WindowEspera.prototype,WindowMensaje.prototype),
	{
		initialize: function(msg, functions){				
			this.accesoPorId = $;
			this.windowObj = window;
			this.documentObj = document;

			this.createDivEspera(msg, functions);	// Creamos el div con el mensaje
			this.initialHide();
		},
		
		createDivEspera: function(msg, functions) {
			this.height = 200;
			this.width = 300;
			this.modal = true;
			
			this.mensaje = this.documentObj.createElement("div");
			this.mensaje.setAttribute("id", WindowEspera.DIV_ID);
			
			var html ="<table class='tablaTitulo' height='6' cellpadding='2'>";
			html += "<tr><td class='columnaTituloPrimera' align='right'>";
			html += "<a href='javascript:$(WindowEspera.DIV_ID).controller.onCancel();'>";
			html += "	<img src='images/window/close.gif' border='0' align='top'>";
			html += "</a></td></tr></table><table width='100%' cellpadding='30'><tr><td><table width='100%' height='"+(this.height-140)+"'><tr valign='middle'>";
			html += "<td width='10'>&nbsp;</td><td align='center'>";
			html += msg;
			html += "</td></tr></table></td></tr></table>";
			html += "<table width='100%'><tr align='center'>";
			html += "<td><input type='button' value='Finalitzar' onClick=\"$(WindowEspera.DIV_ID).controller.onComplete();\" style=\"width: 80px;\" class=\"boton\"/ onmouseover=\"this.className='boton_hover'\" onmouseout=\"this.className='boton'\"/></td>";
			html += "</tr><tr><td><br><br></td>";
			html += "</tr></table>";
			
			this.mensaje.innerHTML = html;
			this.mensaje.className = WindowEspera.DIV_CLASS;
			this.mensaje.modal = true;
			
			this.documentObj.body.appendChild(this.mensaje);
			
			this.accesoPorId(WindowEspera.DIV_ID).controller = this;
			
			Object.extend(this, functions);
			
			if(this.accesoPorId(WindowEspera.DIV_ID).controller.onCancel == null){
				this.accesoPorId(WindowEspera.DIV_ID).controller.onCancel = this.accesoPorId(WindowEspera.DIV_ID).controller.hide;
			}
			
			if(this.accesoPorId(WindowEspera.DIV_ID).controller.onComplete == null){
				this.accesoPorId(WindowEspera.DIV_ID).controller.onComplete = this.accesoPorId(WindowEspera.DIV_ID).controller.hide;
			}

		}
	}
	);
	
	/*---------------------------------------------------------------------------------*/	
	
	//WINDOW CONTENEDOR
	Object.extend(Object.extend(WindowContenedor.prototype,WindowGenerica.prototype),
		{initialize: function(id,title){}}
	);

	//WINDOW ERRORES
	Object.extend(Object.extend(WindowErrores.prototype,WindowContenedor.prototype),
		{
		initialize: function(width, height, modal, listValues) {
			this.accesoPorId = $Parent;
			this.windowObj = window.parent;
			this.documentObj = window.parent.document;
			this.createDiv(width, height, modal);
		
			var html = this.generateContent(listValues);
			this.mensaje.innerHTML = html;
			this.windowObj.Event.observe(this.accesoPorId(WindowErrores.CLOSE_ID), WindowErrores.OBSERVED_EVENT, this.hide, true);
			this.windowObj.Event.observe(this.accesoPorId(WindowErrores.BUTTON_ID), WindowErrores.OBSERVED_EVENT, this.hide, true);
		},
		
		generateContent: function(listValues) {
		
			var html = 	"<table class='tablaTitulo'>";
			html = html + "<tr>";
			html = html + "<td class='columnaTituloPrimera'><b>Aviso</b></td>";
			html = html + "<td class='columnaTituloPrimera' id='" + WindowErrores.CLOSE_ID + "'><img align='right' src='images/window/close.gif'></td>";
			html = html + "</tr>";
			hmtl = html + "</table>";
			html = html + "<table class='tablaContenido'>";
			
			//no haria falta usar $A puesto que ya le pasamos una lista, pero lo dejo, porque en caso
			//de pasarle otro tipo de dato, lo transformaria en lista y seguiria funcionando.
			var l = $A(listValues);
			var i = l.length;
			//var h = $H(l);
			//var values = h.values();				
			var j = l.length;
			
			for(i = 0; i < j; i++) {
				html = html +  "<tr><td class='validationErrorRow' width='5%'><img src='images/window/error.gif'></td><td class='validationErrorRow'>  " + (i+1) + ":  " + l[i] + "</td></tr>";
			}  
			
			html = html + "</table>";
			html = html + "<table class='tablaBoton'>";
			html = html + "<tr>";
			html = html + "<td align='center'><input id='" + WindowErrores.BUTTON_ID + "' type='button' name='botonAlerta' value='Acceptar' /></td>";
			html = html + "</tr>";
			html = html + "</table>";
			
			return html;
		}
	});
	//WINDOW BUSQUEDA Y SELECCION
	Object.extend(Object.extend(WindowBusqSel.prototype,WindowContenedor.prototype),
		{
			initialize: function(url, width, height, funcion) {
				this.accesoPorId = $;
				this.windowObj = window;
				this.documentObj = document;
				
				this.createDiv(width, height, true);	// Creamos el div modal
				this.url = url;							
				//this.left = x;
				//this.top = y;
				// Guardamos la URL que se cargara por AJAX
				
				if(funcion && funcion.hide) {
					// El metodo hide no se sobreescribe, se amplia
					for(var iFun in funcion) {
						if(iFun == 'hide') {
							Object.extend(this, { hideParent: function() {
																if(this.mensaje && this.mensaje.modal) {
																	LockService.desactivar();
																}
																$(WindowGenerica.DIV_ID).hidden = true;
																$hideShowCovered($(WindowGenerica.DIV_ID));
																$(WindowGenerica.IFRAME_ID).id = '_dummy_'+WindowGenerica.IFRAME_ID;
																$(WindowGenerica.DIV_ID).style.display = 'none';
																$(WindowGenerica.DIV_ID).id = '_dummy_'+WindowGenerica.DIV_ID;
//																$deleteElement(WindowGenerica.DIV_ID);
														},
												  hide: function() {
												  			if(LockService.numeroBloqueos() > 1)
												  				return;
												  			funcion.hide();
												  			this.hideParent();
												  		}
												});
						}
						else
							eval('Object.extend(this, { '+iFun+': funcion[iFun]})');
					}
				}
				else {
					Object.extend(this, funcion);
					Object.extend(this, { hide: function() {
										  			if(LockService.numeroBloqueos() > 1)
										  				return;
													if(this.mensaje && this.mensaje.modal) {
														LockService.desactivar();
													}
													$(WindowGenerica.DIV_ID).hidden = true;
													$hideShowCovered($(WindowGenerica.DIV_ID));
													$(WindowGenerica.IFRAME_ID).id = '_dummy_'+WindowGenerica.IFRAME_ID;
													$(WindowGenerica.DIV_ID).style.display = 'none';
													$(WindowGenerica.DIV_ID).id = '_dummy_'+WindowGenerica.DIV_ID;
//													$deleteElement(WindowGenerica.DIV_ID);
												}
					});
				}
				$(WindowGenerica.IFRAME_ID).src = url;
				//this.getHTML();
				this.initialHide();
				
			},
			
			//Esta funcion ya no hace falta, ya q se carga en el iframe i no por ajax
			getHTML: function()
			{
				var myGlobalHandlers = {
					onCreate: function(){
						document.getElementById("cargando").style.display ="block";
						document.getElementById("cargando").style.visibility = "visible";
					},					
					onComplete: function() {
						if(Ajax.activeRequestCount == 0) {
							Element.hide('cargando');
						}
					}
				};
				
				Ajax.Responders.register(myGlobalHandlers);
				var myAjax = new Ajax.Updater(WindowGenerica.DIV_ID, this.url, { method: 'post', evalScripts: 'true' });
			}
			
		}
	);
	
	
	Object.extend(Object.extend(WindowErrores.prototype),
		{
		initialize: function(width, height, modal, listValues, parentId) {
			this.createDiv(width, height, modal);
			
			this.accesoPorId = $Parent;
			this.windowObj = window.parent;
			this.documentObj = window.parent.document;
		
			// Identificador del padre, para situar el div reducido relativo a el
			this.parentId = parentId;
			var html = this.generateContent(listValues);
			this.mensaje.innerHTML = html;

			// Div que aparece cuando se ocultan los errores
			/*var reducedDiv = this.documentObj.createElement("DIV");
			reducedDiv.id = WindowErrores.REDUCED_DIV_ID;
			Element.setStyle(reducedDiv, {visibility: 'hidden', display: 'none', position: 'absolute',
							 //top: $getAbsolutePos($(this.parentId)).y+'px',
							 //left: $getAbsolutePos($(this.parentId)).x+'px',
							 top: '0px',
							 left: '0px',
							 cursor: 'pointer'});
			var reducedDivContent = "<img src='images/window/encendida.gif'>";
			reducedDiv.innerHTML = reducedDivContent;
			this.reduced = reducedDiv;
			document.body.appendChild(this.reduced);*/

			// Eventos registrados
			this.windowObj.Event.observe(this.accesoPorId(WindowErrores.CLOSE_ID), WindowErrores.OBSERVED_EVENT, this.hide, true);
			this.windowObj.Event.observe(this.accesoPorId(WindowErrores.BUTTON_ID), WindowErrores.OBSERVED_EVENT, this.hide, true);
			//Event.observe(WindowErrores.REDUCED_DIV_ID, WindowErrores.OBSERVED_EVENT, this.show, true);
		},
		show: function(){
			if($Parent(WindowErrores.DIV_ERROR_ID).modal) {
				LockService.activar();
			}

			if(this.center)
				this.center();

			/* Mostrar el mensaje o cambiar la version reducida por el popup */
			$Parent(WindowErrores.DIV_ERROR_ID).style.display = "block";
			$Parent(WindowErrores.DIV_ERROR_ID).style.visibility = "visible";
			//$(WindowErrores.REDUCED_DIV_ID).style.display = "none";
			//$(WindowErrores.REDUCED_DIV_ID).style.visibility = "hidden";
			
			$Parent(WindowErrores.DIV_ERROR_ID).hidden = false;
			$hideShowCovered($Parent(WindowErrores.DIV_ERROR_ID));
			
			$Parent(WindowErrores.DIV_ERROR_ID).focus();
			//IGH si lo descomentas peta 
			//new window.parent.Draggable(WindowErrores.DIV_ERROR_ID, {revert:false, handle:'tablaTitulo'});
		},
		hide: function(){
		
		   var accesoPorId = (window.parent != window)? $Parent : $;
		   var windowObj = (window.parent != window)? window.parent : window;
		   if($Parent(WindowErrores.DIV_ERROR_ID).controller.modal) {
		    LockService.desactivar();
		   }
		   
		   /* Cambiar el popup por una version reducida */
		   $Parent(WindowErrores.DIV_ERROR_ID).style.display = "none";
		   $Parent(WindowErrores.DIV_ERROR_ID).style.visibility = "hidden";
		   $Parent(WindowErrores.DIV_ERROR_ID).hidden = true;
		
		   $hideShowCovered($Parent(WindowErrores.DIV_ERROR_ID));
		   $Parent(WindowErrores.DIV_ERROR_ID).innerHTML = '';
			$Parent(WindowErrores.DIV_ERROR_ID).id = '__'+WindowErrores.DIV_ERROR_ID;
		   
		  }, 
		destroy: function(){
		   
		   var accesoPorId = (window.parent != window)? $Parent : $;
		   var windowObj = (window.parent != window)? window.parent : window;
		   if($Parent(WindowErrores.DIV_ERROR_ID).controller.modal) {
		    LockService.desactivar();
		   }
		   
		   $Parent(WindowErrores.DIV_ERROR_ID).hidden = true;
		   windowObj.$NoVisible(WindowErrores.DIV_ERROR_ID);
		   windowObj.$hideShowCovered($Parent(WindowErrores.DIV_ERROR_ID));
		   $Parent(WindowErrores.DIV_ERROR_ID).innerHTML = '';
			$Parent(WindowErrores.DIV_ERROR_ID).id = '__'+WindowErrores.DIV_ERROR_ID;

		  }, 
		createDiv: function(width, height, modal){
			this.height = height;
			this.width = width;
			this.modal = modal;
			var windowObjDestroy = (window.parent != window)? window.parent : window;
			//si hi ha alguna creada la borrem
			if($(WindowErrores.DIV_ERROR_ID)){
				if($Parent(WindowErrores.DIV_ERROR_ID).controller.modal) {
			    	LockService.desactivar();
			   	}
			}
			if($(WindowErrores.DIV_ERROR_ID)){
				$(WindowErrores.DIV_ERROR_ID).hidden = true;
			   windowObjDestroy.$NoVisible(WindowErrores.DIV_ERROR_ID);
			   windowObjDestroy.$hideShowCovered($(WindowErrores.DIV_ERROR_ID));
			   $(WindowErrores.DIV_ERROR_ID).innerHTML = '';
				$(WindowErrores.DIV_ERROR_ID).id = '__'+WindowErrores.DIV_ERROR_ID;
			}else if($Parent(WindowErrores.DIV_ERROR_ID)){
				$Parent(WindowErrores.DIV_ERROR_ID).hidden = true;
			   windowObjDestroy.$NoVisible(WindowErrores.DIV_ERROR_ID);
			   windowObjDestroy.$hideShowCovered($Parent(WindowErrores.DIV_ERROR_ID));
			   $Parent(WindowErrores.DIV_ERROR_ID).innerHTML = '';
				$Parent(WindowErrores.DIV_ERROR_ID).id = '__'+WindowErrores.DIV_ERROR_ID;
			}
			
			
			var parentObj = document.body;
			if(window.parent) {
				parentObj = window.parent.document.body;
			}
			var parentDoc = parentObj.ownerDocument || parentObj.document;

			this.mensaje = parentDoc.createElement("div");
			this.mensaje.setAttribute("id", WindowErrores.DIV_ERROR_ID);
			this.mensaje.className = WindowErrores.DIV_ERROR_CLASS;
			this.mensaje.modal = modal;
			this.mensaje.controller = this;
			
			parentDoc.body.appendChild(this.mensaje);
		},
		generateContent: function(listValues){
			var html = "<div id='contenidoError' align='center'>";
			html += "<table id='tablaTitulo' class='tablaTitulo'>";
			html += "<tr>";
			html += "<td class='columnaTituloPrimera'>&nbsp;<b>Error</b></td>";
			html += "<td class='columnaTituloPrimera' id='" + WindowErrores.CLOSE_ID + "'><img align='right' style='cursor:pointer;' src='images/window/close.gif'></td>";
			html += "</tr>";
			html += "</table>";
			
			//no haria falta usar $A puesto que ya le pasamos una lista, pero lo dejo, porque en caso
			//de pasarle otro tipo de dato, lo transformaria en lista y seguiria funcionando.
			var l = $A(listValues);
			var j = l.length;

			var heightDiv = Math.min(listValues.length*35, 300);
			html += "<div style='width:95%;overflow:auto;height:"+heightDiv+"px;margin-top:5px'>";
			html += "<table class='contenidoTablaErrores' width='95%'>";
			for(var i = 0; i < j; i++) {

				html +=  "<tbody class='validationErrorRow' onmouseover='this.className=\"validationErrorRow validationErrorRow_hover\"' onmouseout='this.className=\"validationErrorRow\"'><tr><td>  " + (i+1) + ":  " + l[i] + "</td></tr></tbody>";
			}  
			html += "</table>";
			html += "</div>";
			
			html += "<table class='tablaBotonErrores'>";
			html += "<tr>";
			html += "<td valign='middle' align='center'>";
			html += "<input id='" + WindowErrores.BUTTON_ID + "' type='button' class='boton' name='botonAceptar' value='Acceptar' onmouseover='this.className=\"boton_hover\"' onmouseout='this.className=\"boton\"' />&nbsp;&nbsp;";
			//html += "<input id='print" + WindowErrores.BUTTON_ID + "' type='button' class='boton' name='botonImprimir' value='Imprimir' onmouseover='this.className=\"boton_hover\"' onmouseout='this.className=\"boton\"' />";
			html += "</td>";
			html += "</tr>";
			html += "</table>";

			html += "</div>";
			return html;
		},
		center: function() {
			var accesoPorId = (window.parent)? $Parent : $;
			var windowObj = (window.parent)? window.parent : window;
			if( $isExplorer(windowObj.document) ) {
				var pageWidth = windowObj.document.documentElement.clientWidth;
				var pageHeight = windowObj.document.documentElement.clientHeight;
			} else {
				var pageWidth = windowObj.innerWidth;	
				var pageHeight = windowObj.innerHeight;							
			}
				
			var winW = pageWidth - WindowGenerica.SCROLL_SIZE;
			var winH = pageHeight;
			var left = winW/2 - this.width/2;
			var top = winH/2 - this.height/2;
			
			this.mensaje.style.top    = top  + 'px';			
			this.mensaje.style.left   = left + 'px';
			this.mensaje.style.width  = this.width  + 'px';
			//this.mensaje.style.height = this.height + 'px'; // En explorer peta
		}
	});
	
/*
	Ocultar/Mostrar selects en Explorer/Opera
*/
function $hideShowCovered(el)
{
	if (!$isExplorer(document))
		return;
	var ie_opera = ( /msie/i.test(navigator.userAgent) ||
		   !/opera/i.test(navigator.userAgent) );
	var tags = new Array("select");

	var p = $getAbsolutePos(el);
	var EX1 = p.x;
	var EX2 = el.offsetWidth + EX1;
	var EY1 = p.y;
	var EY2 = el.offsetHeight + EY1;

	for (var k = tags.length; k > 0; ) {
		var ar = document.getElementsByTagName(tags[--k]);
		var cc = null;

		for (var i = ar.length; i > 0;) {
			cc = ar[--i];

			p = $getAbsolutePos(cc);
			var CX1 = p.x;
			var CX2 = cc.offsetWidth + CX1;
			var CY1 = p.y;
			var CY2 = cc.offsetHeight + CY1;
			if (el.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = $getVisib(cc);
				}
				cc.style.visibility = cc.__msh_save_visibility;
			} else {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = $getVisib(cc);
				}
				cc.style.visibility = "hidden";
			}
		}
	}
}
function $getVisib(obj)
{
	var value = obj.style.visibility;
	if (!value) {
		if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
			if (!Calendar.is_khtml)
				value = document.defaultView.
					getComputedStyle(obj, "").getPropertyValue("visibility");
			else
				value = '';
		} else if (obj.currentStyle) { // IE
			value = obj.currentStyle.visibility;
		} else
			value = '';
	}
	return value;
}

//grid.js


var GenericGrid = Class.create();
	
GenericGrid.prototype = {

	initialize: function(gridObject, gridId, footId, numPages, objectCollection, pageSize, numRecords, footType, formMode, inspectMode, tipusSeleccio) {
		
		this.gridObject = gridObject;					// Nombre de la Instancia
		this.gridId = gridId;							// ID del Grid
		this.footId = footId;							// ID del Footer

		this.columnes = new Array();					// Array con las columnas del grid
		this.textColumnes = new Array();				// Array con los labels de las columnas del grid
		this.tipusSeleccio = tipusSeleccio;				// '' = no // 'single' // 'multiple'

		this.numPages = numPages;						// Numero total de paginas
		this.numberPage = 1;							// Pagina actual
		this.pageSize = pageSize;						// Numero de registros por pagina
		this.numRecords = numRecords;					// Numero total de registros

		this.objectCollection = objectCollection;		// Array de datos
		this.filteredCollection = objectCollection;		// Array de datos filtrados y ordenados

		this.gridFooter = new GridFooter(footType);		// Paginacion del Grid
		
		this.sortCol = '';								// Columna por la que ordenamos
		this.sortOrder = '';							// Sentido de la ordenacion
		
		this.formMode = formMode;						// Mode del formulari de la pagina
		this.INSPECT_MODE = inspectMode;				// Codi del mode inspeccio
	},


	//--------------------//
	// ACCESO A LOS DATOS //
	//--------------------//
	
	/* Devuelve un array de Prototype con todos los objetos FILTRADOS del grid */
	getAll: function() {
		return $A( this.filteredCollection );
	},
	
	/* Devuelve un array de Prototype con TODOS los objetos del grid */
	getAllObjects: function() {
		return $A( this.objectCollection );
	},
	
	/* Busca un elemento por el ID */
	getById: function(id) {
		return this.filteredCollection.find(function(current) {
			return (current.id == id);
		});
	},
	
	/* Elimina un elemento de la coleccion */
	/* NO va a servidor, por lo que es una eliminacion solo de presentacion */
	deleteElement: function(id) {
		var parts = this.filteredCollection.partition(function(current) {
			return (current.id == id);
		});
		
		this.objectCollection = parts[1];
		this.filteredCollection = parts[1];
		this.numRecords = this.numRecords - 1;
	},
	
	
	//------------------//
	// PINTADO DEL GRID //
	//------------------//
	
	/* Dibuja la pagina entera (grid y footer) */	
	drawPage: function(numPage, firstRow) {
		this.saveStatus('pagina', numPage);
		this.numberPage = numPage;
		this.fillGrid(firstRow);
		this.printFooter();	
	},
	
	/* Repinta el grid */
	redraw: function() {
		var firstRow = (this.numberPage * this.pageSize) - this.pageSize;
		this.drawPage(this.numberPage, firstRow);
	},
	
	/* Rellena el Grid a partir de la fila dada */
	fillGrid : function(rowIndex) {
		var r = this.numRecords;
		var objArr = this.filteredCollection;
		var myGrid = this.gridId;
		
		/* Mostramos y ocultamos la fila 'No hay datos' segun convenga */
		if(this.numRecords > 0)
			$NoVisible(this.gridId + '_vacio');
		else
			$Visible(this.gridId + '_vacio');

			
		for( var i = 0; i < this.pageSize; i++ ) {
			var rowId = this.gridId + '_r' + i;
			var columns = $A( $(rowId).getElementsByTagName('td') );
			
			/* Por defecto mostramos las filas (las ocultaremos si es necesario) */
			$Visible(rowId);
			
			columns.each( function(value,index) {
				var colKey = value.id.substring(value.id.lastIndexOf('_') + 1, value.id.length);

				/* Ocultamos la fila si ya no quedan datos */
				if( rowIndex >= r ) {
					$NoVisible(rowId);
				}
				else {
					/* Recalculamos el ID de los seleccionables */
					if( value.id.indexOf('select') != -1 ) {
						var inputs = $A( $(value.id).getElementsByTagName('input') );
						var input = inputs.first();
						$(input.id).value = objArr[rowIndex].getid();
						$(input.id).checked = objArr[rowIndex].checked;
					}
					/* Actualizamos la columna solo si es una columna de datos */
					else if( value.id.indexOf('actions') != -1 ) {
						eval('grid_' + myGrid + '.printAction(' + i + ', ' + rowIndex + ')');
					}
					else if( colKey != "" ) {
						if( objArr[rowIndex].isChecked(colKey) ) {
							if( eval('objArr[rowIndex].get' + colKey + '()') == "true" )
								$(value.id).innerHTML = '<input type="checkbox" class="checkbox" disabled checked>';
							else
								$(value.id).innerHTML = '<input type="checkbox" class="checkbox" disabled>';
						} else {
							$(value.id).innerHTML = eval('objArr[rowIndex].get' + colKey + '()');
						}
					}
				}
			});
				
			rowIndex++;
		}
	},
	
	printAction: function(row, objIndex) {
	
		actionHtml = '<table align="right">\n';
		actionHtml += '<tr id="' + this.gridId + '_r' + row + '_actions_row">\n';

		var obj = this.filteredCollection[objIndex];
		var actions = this.filteredCollection[objIndex].getActions();
		for( var i = 0; i < actions.length; i++ ) {
			actionHtml += "<td>\n";
			if( this.formMode != this.INSPECT_MODE || (this.formMode == this.INSPECT_MODE && actions[i].getInspectCode() != "" ) ) {
				if( actions[i].enabled == true ) {
				
					if( this.formMode == this.INSPECT_MODE && actions[i].getInspectCode() != "" ) {
						actions[i].setReqCode( actions[i].getInspectCode() );
					}
					
					if( actions[i].getType() == "custom" ) {
						actionHtml += '<a href="';
						actionHtml += actions[i].getUrl() + '">';
					}
					else if( actions[i].getType() == "javascript" ) {
						actionHtml += '<a href="javascript:';
						actionHtml +=  actions[i].getFunc() + '(\'';
												
						if( actions[i].getParamFormat() == "url" ) {
							actionHtml += actions[i].getUrl() + '?reqCode=' + actions[i].getReqCode() + '\', ';
							var paramUrl = '\'';
							var actionParams = actions[i].getParams();
							for( var j = 0; j < actionParams.length; j++ ) {
								paramUrl += '&' + actionParams[j][0] + '=' + actionParams[j][1];
							}
							actionHtml += paramUrl + '\'';
						} else {
							actionHtml += actions[i].getUrl() + '\', ';
							var paramUrl = '{reqCode: \'' + actions[i].getReqCode() + '\'';
							var actionParams = actions[i].getParams();
							for( var j = 0; j < actionParams.length; j++ ) {
								paramUrl += ',' + actionParams[j][0] + ': \'' + actionParams[j][1] + '\'';
							}
							
							actionHtml += paramUrl + '}';
						}
						actionHtml +=  ')">';
					}
					else {
						if( actions[i].isPopup() ) {
							popupUrl = actions[i].getUrl() + '?reqCode=' + actions[i].getReqCode();
							
							var actionParams = actions[i].getParams();
							for( var j = 0; j < actionParams.length; j++ ) {
								popupUrl += '&' + actionParams[j][0] + '=' + actionParams[j][1];
							}
							
							actionHtml += '<a href="javascript:new WindowBusqSel(';
							actionHtml += "'" + popupUrl + "', ";
							actionHtml += "'" + actions[i].getPopupWidth() + "', ";
							actionHtml += "'" + actions[i].getPopupHeight() + "')";
							actionHtml += '.show();" class="link">';
						}
						else {
							actionHtml += '<a href="javascript:';
							actionHtml += 'grid_' + this.gridId + '.doAction(\'';
							actionHtml += this.filteredCollection[objIndex].getid() + '\', ';
							actionHtml += "'" + actions[i].getReqCode() + "', ";
							actionHtml += "'" + actions[i].getUrl() + "', ";
							
							var paramArray = "reqCode: '" + actions[i].getReqCode() + "'";
							
							var actionParams = actions[i].getParams();
							for( var j = 0; j < actionParams.length; j++ ) {
								paramArray += "," + actionParams[j][0] + ": '" + actionParams[j][1] + "'";
							}
							
							paramArray = "{" + paramArray + "}";
							actionHtml += paramArray + ");";
							actionHtml += '" class="link">';
						}
					}
					
					actionHtml += '\n<img src="' + actions[i].getIcon() + '" border="0">';
					actionHtml += '</a>';
				} else {
					if( actions[i].getIcon() != "" ) {
						actionHtml += '<img src="' + actions[i].getIcon() + '" border="0">';
					}
				}
			}
			
			actionHtml += "\n</td>\n";
		}
		
		actionHtml += "\n</tr></table>";
		$(this.gridId + '_r' + row + '_actions').innerHTML = actionHtml;
	},
	
	
	//-------------------------//
	// ORDENACION POR COLUMNAS //
	//-------------------------//
	
	sort: function(column, order) {		
		this.saveStatus('ordenacioCol', column);
		this.saveStatus('ordenacioOrdre', order);
		this.sortCol = column;
		this.sortOrder = order;
		
		this.quickSort(this.filteredCollection, order.toLowerCase(), column);
		this.fillGrid((this.numberPage*this.pageSize)-this.pageSize);
	},
	
	quickSort: function (objArray, aod, column) {
		   if (this.esTipusData(objArray, column))//Si es una fecha
		   {
			   var arrayOrder = new Array ();
			   for (var i=0; i<objArray.length; i++) {
				    arrayOrder.push(this.dateConvert(objArray[i][column]));
	 		   }

			   if (aod == 'asc'){
				   arrayOrder.sort(this.ordenaFechaAsc);
			   } else {
				   arrayOrder.sort(this.ordenaFechaDesc);
			   }	   
			   
			   if (this.esTipusDataTimeMils(objArray, column)){
				   for (var i=0; i<objArray.length; i++) {
					   objArray[i][column] = this.formatDate(arrayOrder[i], "DD/MM/YYYY HH:MM:SS,S");
				   }   
			   } else if(this.esTipusDataTime(objArray, column)){
				   for (var i=0; i<objArray.length; i++) {
		 				objArray[i][column] = this.formatDate(arrayOrder[i], "DD/MM/YYYY HH:MM:SS");
				   }
			   }  else {
				   for (var i=0; i<objArray.length; i++) {
		 				objArray[i][column] = this.formatDate(arrayOrder[i], "DD/MM/YYYY");
				   }
			   }
		   }	
		   else {
			   if (!this.esTipusNumeric(objArray, column)) {		   		
		   			if(!this.esTipusClauConvocatoria(objArray, column)){
		   				this.procesoQS(objArray, aod, column, 0, objArray.length-1);
		   			}else{
		   				//cambio el orden de la clau convocatoria para ordenarla como string
		   		   		for (var i=0; i<objArray.length; i++) {
		   		   			objArray[i][column] = this.convToString(objArray[i][column])
		   		   		}
		   	 		    this.procesoQS(objArray, aod, column, 0, objArray.length-1); 
		   		   		for (var i=0; i<objArray.length; i++) {
		   		   			objArray[i][column] = this.stringToConv(objArray[i][column])
		   		   		}
		   			}
			   } else {
			   		//cambio la columna por el paddind a 20
			   		for (var i=0; i<objArray.length; i++) {
		   				objArray[i][column] = this.lpad(objArray[i][column], 20, '0');
		   			}
			    	this.procesoQS(objArray, aod, column, 0, objArray.length-1); 
		   			
		   			for (var i=0; i<objArray.length; i++) {
		   				objArray[i][column] = this.lunpad(objArray[i][column])
		   			}
			   }
		   }
		},

	ordenaFechaAsc: function (a, b){
		return a - b;
	},
	ordenaFechaDesc: function (a, b){
		return b - a;
	},
	lpad: function (str, len, pad) {
		if (len + 1 >= str.length) {
			str = Array(len + 1 - str.length).join(pad) + str;
		}
		return str;
	},

	lunpad: function (str) {
		var index = 0;
		for (i=0; i<str.length; i++) {
			if (str.charAt(i) == '0')
				index++;
			else {
				var ret = str.substring(index);
				if (ret.charAt(0) == '.')
					return '0' + ret;
				else 
					return ret;
			}
		}
		return str;
	},

	
	dateConvert: function(string){
		
	   if (string.length == 10) {
		    var dd   = string.substring(0,2);
			var mm   = string.substring(3,5);
			var yyyy = string.substring(6,10);
			
			var date = new Date(yyyy, mm-1, dd);
			
			return date; 
	    } else if (string.length == 19) {
	    	var dd   = string.substring(0,2);
			var mm   = string.substring(3,5);
			var yyyy = string.substring(6,10);
			var hh	 = string.substring(11,13);
			var min	 = string.substring(14,16);
			var ss	 = string.substring(17,19);
			
			var date = new Date(yyyy, mm-1, dd, hh, min, ss);

			return date; 
		} else if (string.length > 19) {
			var dd   = string.substring(0,2);
			var mm   = string.substring(3,5);
			var yyyy = string.substring(6,10);
			var hh	 = string.substring(11,13);
			var min	 = string.substring(14,16);
			var ss	 = string.substring(17,19);
			var mils = string.substring(20);
			
			var date = new Date(yyyy, mm-1, dd, hh, min, ss, mils);
	
			return date; 
	    }
	   	else  {
	    	return new Date(string);
	    }  
	},
		
	fechaToString: function (fecha) {
		if (fecha.length != 10) return fecha;
		var dd   = fecha.substring(0,2);
		var mm   = fecha.substring(3,5);
		var yyyy = fecha.substring(6,10);
		var cadena = yyyy + "/" + mm + "/" + dd;
		return cadena;
	},

	stringToFecha: function (string) {
		if (string.length != 10) return string;
		var dd   = string.substring(8,10);
		var mm   = string.substring(5,7);
		var yyyy = string.substring(0,4);
		var cadena =  dd + "/" + mm + "/" + yyyy;
		return cadena;
	},
	
	convToString: function (conv) {
		if (conv.length != 12) return conv;
		var any = conv.substring(3,5);
		any = any>=80?19+any:20+any;
		var mes = conv.substring(5,7);
		var num = conv.substring(0,3);
		var resto = conv.substring(7,12);
		var cadena = any + mes + num + resto;
		return cadena;
	},

	stringToConv: function (string) {
		if (string.length != 14) return string;
		var any = string.substring(2,4);		
		var mes = string.substring(4,6);
		var num = string.substring(6,9);
		var resto = string.substring(9,14);
		var cadena = num + any + mes + resto;
		return cadena;
	},
	
	timeToString: function (fecha) {
		if (fecha.length != 19) return fecha;
		var dd   = fecha.substring(0,2);
		var mm   = fecha.substring(3,5);
		var yyyy = fecha.substring(6,10);
		var hh	 = fecha.substring(11,13);
		var min	 = fecha.substring(14,16);
		var ss	 = fecha.substring(17,19);
		var cadena = yyyy + "/" + mm + "/" + dd + ' ' + hh + ':' + min + ':' + ss;
		return cadena;
	},

	stringToTime: function (string) {
		if (string.length != 19) return string;
		var dd   = string.substring(8,10);
		var mm   = string.substring(5,7);
		var yyyy = string.substring(0,4);
		var hh	 = string.substring(11,13);
		var min	 = string.substring(14,16);
		var ss	 = string.substring(17,19);
		var cadena =  dd + "/" + mm + "/" + yyyy + ' ' + hh + ':' + min + ':' + ss;
		return cadena;
	},
	
	timeToString2: function (fecha) {
		if (fecha.length != 16) return fecha;
		var dd   = fecha.substring(0,2);
		var mm   = fecha.substring(3,5);
		var yyyy = fecha.substring(6,10);
		var hh	 = fecha.substring(11,13);
		var min	 = fecha.substring(14,16);		
		var cadena = yyyy + "/" + mm + "/" + dd + ' ' + hh + ':' + min;
		return cadena;
	},

	stringToTime2: function (string) {
		if (string.length != 16) return string;
		var dd   = string.substring(8,10);
		var mm   = string.substring(5,7);
		var yyyy = string.substring(0,4);
		var hh	 = string.substring(11,13);
		var min	 = string.substring(14,16);		
		var cadena =  dd + "/" + mm + "/" + yyyy + ' ' + hh + ':' + min;
		return cadena;
	},
	
	formatDate: function(dateValue, format) { 

		var fmt = format.toUpperCase(); 
		
		var M = "" + (dateValue.getMonth()+1); 
		var MM = "0" + M; 
		MM = MM.substring(MM.length-2, MM.length); 
		var D = "" + (dateValue.getDate()); 
		var DD = "0" + D; 
		DD = DD.substring(DD.length-2, DD.length); 
		var YYYY = "" + (dateValue.getFullYear());
		
		result = DD + "/" + MM + "/" + YYYY + "";
	
		if (format.toUpperCase() == "DD/MM/YYYY HH:MM:SS"){
			var hh = ""+dateValue.getHours();
			if(hh.length == 1){
				hh = "0" + hh;
			}
			
			var mm = ""+dateValue.getMinutes();
			if(mm.length == 1){
				mm = "0" + mm;
			}
			
			var ss = ""+dateValue.getSeconds();
			if(ss.length == 1){
				ss = "0" + ss;
			}
			result = result + " "+ hh +":"+ mm + ":" + ss;
		}
		if (format.toUpperCase() == "DD/MM/YYYY HH:MM:SS,S"){
			var hh = ""+dateValue.getHours();
			if(hh.length == 1){
				hh = "0" + hh;
			}
			
			var mm = ""+dateValue.getMinutes();
			if(mm.length == 1){
				mm = "0" + mm;
			}
			
			var ss = ""+dateValue.getSeconds();
			if(ss.length == 1){
				ss = "0" + ss;
			}
			result = result + " "+ hh +":"+ mm + ":" + ss;
			var s = ""+dateValue.getMilliseconds();
			result = result + ","+s;
		}
		return result; 
	},
		
	esTipusData: function (objArray, column) {
	   if (objArray.length == 0) return false;
	   for (var i=0; i<objArray.length; i++) {
		   var c = objArray[i][column];
		   if ((c.substring(2,3) !='/' || c.substring(5,6) != '/') && (c != "-")) {
		   	   return false;
		   } 
	   }
	   return true;   
	},

	esTipusNumeric: function (objArray, column) {
  	   var numericoRegExp = /^[\d]*[\.]?[\d]*$/
	   if (objArray.length == 0) return false;
	   for (var i=0; i<objArray.length; i++) {
		   var c = "" + objArray[i][column];
		   if (!c.match(numericoRegExp)) {
		   	   
		   	   return false;
		   } 
	   }
   	   
	   return true;   
	},
	
	//Data i hora: dd/MM/yyyy hh:mm:ss
	esTipusDataTime: function (objArray, column) {
	   if (objArray.length == 0) return false;
	   for (var i=0; i<objArray.length; i++) {
		   var c = objArray[i][column];
		   if ((c.length != 19 || c.substring(2,3) !='/' || c.substring(5,6) != '/' ||
		   		c.substring(10,11) != ' ' || c.substring(13,14)!=':' || c.substring(16,17) != ':') 
		   		&& (c != "-")) {
		   	   return false;
		   } 
	   }
	   return true;   
	},
	
	//Data i hora sense segons: dd/MM/yyyy hh:mm
	esTipusDataTime2: function (objArray, column) {
	   if (objArray.length == 0) return false;
	   for (var i=0; i<objArray.length; i++) {
		   var c = objArray[i][column];		   
		   if ((c.length != 16 || c.substring(2,3) !='/' || c.substring(5,6) != '/' ||
		   		c.substring(10,11) != ' ' || c.substring(13,14)!=':') 
		   		&& (c != "-")) {
		   	   return false;
		   } 
	   }
	   return true;   
	},
	
	//Data i hora: dd/MM/yyyy hh:mm:ss
	esTipusDataTimeMils: function (objArray, column) {
	   if (objArray.length == 0) return false;
	   for (var i=0; i<objArray.length; i++) {
		   var c = objArray[i][column];
		   if ((c.length < 20 || c.substring(2,3) !='/' || c.substring(5,6) != '/' ||
		   		c.substring(10,11) != ' ' || c.substring(13,14)!=':' || c.substring(16,17) != ':' || c.substring(19,20) != ',') 
		   		&& (c != "-")) {
		   	   return false;
		   } 
	   }
	   return true;   
	},
	
	esTipusClauConvocatoria: function (objArray, column) {
		   var numRegExp = /^[\d]*$/;
		   var letrasRegExp = /^[A-Za-z]*$/;
		   
		   if (objArray.length == 0) return false;
		   for (var i=0; i<objArray.length; i++) {
			   var c = objArray[i][column];			   
			   if(c.length != 12){ 
				   return false;
			   }
			   else{
				   var part1 = c.substring(0,7);				  
				   var part2 = c.substring(7,11);				  
				   var part3 = c.substring(11,12);				   
				   
				   if(!part1.match(numRegExp)){					  
					   return false;
				   }
				   
				   if(!part2.match(letrasRegExp)){					   
					   return false;
				   }
				   
				   if(!part3.match(numRegExp)){					   
					   return false;
				   }
			   }
			   
		   }
		   return true;   
		},
		
	procesoQS: function (objArray, aod, column, ini, fin) {
	    var i = ini;
    	var j = fin;
	    var tmp;
	    	      		
	    var c = objArray[Math.floor( ( i + j ) / 2 )];
	    
	   if(c){	    
		    do {
		    	var cValue = c[column];
				var iObjArrayValue = objArray[i][column];
				var jObjArrayValue = objArray[j][column];
				var iTmp = i;
		    	var jTmp = j;
	
		    	c[column] = this.eliminaAcentos(c[column]);
		    	objArray[i][column] = this.eliminaAcentos(objArray[i][column]);
		    	objArray[j][column] = this.eliminaAcentos(objArray[j][column]);
		    	
		    	if ( aod == 'asc' ) {
	    	        while (( i < fin ) && ( c.compareTo(objArray[i],column) > 0 )) i++;
	    	        while (( j > ini ) && ( c.compareTo(objArray[j],column) < 0 )) j--;
		        } else {
	    	        while (( i < fin ) && ( c.compareTo(objArray[i],column) < 0 )) i++;
	    	        while (( j > ini ) && ( c.compareTo(objArray[j],column) > 0 )) j--;
		        }
		        
		        c[column] = cValue;
		    	objArray[iTmp][column] = iObjArrayValue;
		    	objArray[jTmp][column] = jObjArrayValue;
	
		    	if ( i < j ) {
		            tmp = objArray[i];
	    	        objArray[i] = objArray[j];
	        	    objArray[j] = tmp; 
		        }
	
	    	    if ( i <= j ) {
		            i++;
	    	        j--; 
		        }
		        
		    } while ( i <= j );
	
		    if ( ini < j ) this.procesoQS(objArray, aod, column, ini, j);
	    	if ( i < fin ) this.procesoQS(objArray, aod, column, i, fin); 
	   }
	},

	
	
	eliminaAcentos: function (t){
			var a = /[\xc1\xe0]/gi; //c1=? e0=?
	    	var e = /[\xc9\xe8]/gi; //c9=? e8=?
	    	var i = /[\xcd\xf2]/gi; //cd=? f2=?
	    	var o = /[\xd3\xf9]/gi; //d3=? f9=?
	    	var u = /[\xda\xfc]/gi; //da=? fc=?
	    	var coma = /[\x2c]/gi;	    	
	    	var result = t.replace(a, "a");
	    	result = result.replace(e, "e");
	    	result = result.replace(i, "i");
	    	result = result.replace(o, "o");
	    	result = result.replace(u, "u");
	    	result = result.replace(coma, "");
	    	
	    	return result.toLowerCase();
	},
	//-----------------//
	// FILTRO DE TEXTO //
	//-----------------//
	
	resetFilter: function(formText) {
		$(formText).value = "";
		
		this.saveStatus('filtre', '');

		/* Recalcular los numeros de pagina */
		this.filteredCollection = this.objectCollection;
		this.numRecords = this.objectCollection.length;
		this.numPages = Math.ceil( this.numRecords / this.pageSize );

		/* Ordenamos si es necesario */
		if( this.sortCol != '' ) {
			this.sort(this.sortCol, this.sortOrder);
		}
		
		this.drawPage(1,0);
	},
	
	filter: function(formText) {
		var text = $(formText).value;
		var pattern = text.toLowerCase();
		
		this.saveStatus('filtre', text);
			
		if( pattern.length < 1 || this.objectCollection.length < 1 )
			return;
			
		this.filteredCollection = this.filterData(pattern);
			
		/* Recalcular los numeros de pagina */
		this.numRecords = this.filteredCollection.length;
		this.numPages = Math.ceil( this.numRecords / this.pageSize );
		
		/* Ordenamos si es necesario */
		if( this.sortCol != '' ) {
			this.sort(this.sortCol, this.sortOrder);
		}
		
		this.drawPage(1,0);
	},
	
	/* Filtra los datos segun el patron dado */	
	filterData: function(pattern) {
	
		var cols = $A( $(this.gridId).getElementsByTagName('th') );
		var colKeys = cols.map(function(value, index) {
			key = value.id.substring(value.id.lastIndexOf('_') + 1, value.id.length)
			if(key.length > 1)
				return(key);
		});

		var keys = colKeys.compact();
		var list = this.objectCollection;
		var filtered = $A();
		
		list.each(function(row, i) {
			keys.each(function(key, j) {
				if( key.indexOf('select_') == -1 && key != 'id' && !list[0].isChecked(key)) {
					var str = eval('row.get' + key + '()');
					var lowStr = str.toLowerCase();
				
					if( lowStr.indexOf(pattern) != -1 && !filtered.member(row) )
						filtered[i] = row;
				}
			});
		});
			
		return(filtered.compact().flatten());
	},


	//------------------------//
	// OCULTACION DE COLUMNAS //
	//------------------------//
	
	switchVisible : function(colName) {
		if( !$isVisible(this.gridId + '_th_' + colName) ) {
			this.showColumn(colName);	
			this.saveStatus(colName, '');
		}
		else {			
			this.hideColumn(colName);
			this.saveStatus(colName, 'hidden');
		}
	},
		
	hideColumn : function(colName) {
		$NoVisible(this.gridId + '_th_' + colName);
		for( var i = 0; i < this.pageSize; i++ ) {
			$NoVisible(this.gridId + '_r' + i + '_' + colName);
		}
		$('mostrar_'+this.gridId+'_'+colName).checked = false;
	},
		
	showColumn : function(colName) {
		$Visible(this.gridId + '_th_' + colName);
		for( var i = 0; i < this.pageSize; i++ ) {
			$Visible(this.gridId + '_r' + i + '_' + colName);
		}
		$('mostrar_'+this.gridId+'_'+colName).checked = true;
	},
		
	switchHeaderVisibility: function() {
		if( !$isVisible(this.gridId + '_header_row') ) {
			$Visible(this.gridId + '_header_row');
			$NoVisible(this.gridId + '_filter_row');
		}
		else {			
			$NoVisible(this.gridId + '_header_row');
		}		
	},
	
	switchFilterVisibility: function() {
		if( !$isVisible(this.gridId + '_filter_row') ) {
			$Visible(this.gridId + '_filter_row');
			$NoVisible(this.gridId + '_header_row');
		}
		else {			
			$NoVisible(this.gridId + '_filter_row');
		}		
	},


	//------------------------------//
	// ENVIO DE DATOS SELECCIONADOS //
	//------------------------------//
	
	/* Selecciona/deselecciona una fila (seleccion multiple)*/
	check: function(row) {
		var idx = ((this.numberPage * this.pageSize) - this.pageSize) + row;
		this.filteredCollection[idx].checked = $(this.gridId + '_r' + row + '_select_check').checked;
		
		// Si hemos deseleccionado, deseleccionamos (si lo estaba) el check de seleccion global
		if( !this.filteredCollection[idx].checked ) {
			$(this.gridId + '_header_check').checked = false;
		}
		
		/* Si tiene eventos asociados a la seleccion, los lanzamos */
		if( this.filteredCollection[idx].onSelect != '' ) {
			var obj = this.filteredCollection[idx];
			eval(obj.onSelect + '(obj)');
		}
	},

	/* Selecciona/deselecciona una fila (seleccion unica)*/	
	select: function(row) {
		this.filteredCollection.each(function(value, index) {
			value.checked = false;
		});
		
		var idx = ((this.numberPage * this.pageSize) - this.pageSize) + row;
		this.filteredCollection[idx].checked = true;
//		this.saveStatus('seleccionat', this.filteredCollection[idx].getid());
		
		/* Si tiene eventos asociados a la seleccion, los lanzamos */
		if( this.filteredCollection[idx].onSelect != '' ) {
			var obj = this.filteredCollection[idx];
			eval(obj.onSelect + '(obj)');
		}
	},

	getObject: function(row) {
		
		var idx = ((this.numberPage * this.pageSize) - this.pageSize) + row;
		
		/* Si tiene eventos asociados a la seleccion, los lanzamos */
		return this.filteredCollection[idx]
	},
	
	/* Selecciona/deselecciona los registros visibles */
	checkAll: function() {
		var thisGrid = this.gridId;
		var checks = $A( $(this.gridId).getElementsByTagName('input') );

		this.filteredCollection.each(function(value, index) {
			value.checked = $(thisGrid + '_header_check').checked;
		});
		
		checks.each(function(value, index) {
			if( value.id.indexOf('_select_check') != -1 )
				$(value.id).checked = $(thisGrid + '_header_check').checked;
		});
	},
	
			
	/* Envio de datos en Grid de seleccion multiple */
	submitMultipleGrid: function(fName) {
		/* Hay que usar toda la coleccion para enviar tambien
		   los objetos seleccionados que no se ven */
		var obj = this.objectCollection.map(function(value, index) {
			if(value.checked == true)
				return value;
		});
		
		if(obj.compact() != null && fName != "") {
			eval(fName + '(obj.compact())');
		}
	},

	/* Envio de datos en Grid de seleccion simple */		
	submitSingleGrid: function(fName) {
		var obj = this.filteredCollection.find(function(value, index) {
			return (value.checked == true);
		});
		
		if(obj != null && fName != "") {
			eval(fName + '(obj)');
		}
	},
	
	
	//-------------------//
	// ACCIONES DEL GRID //
	//-------------------//
	
	doAction: function(id, reqCode, target, paramArray) {
		var divForm = document.createElement("div");
		divForm.setAttribute("id", this.gridId + '_actionform_div');
		
		var theForm = '<form id="' + this.gridId + '_actionform" name="' + this.gridId + '_actionform" method="post" action="' + target + '">';
		//theForm += '<input type="hidden" id="' + this.gridId + '_actionform_reqCode" name="reqCode" value="' + reqCode + '">';
		theForm += '<input type="hidden" id="' + this.gridId + '_actionform_hidden" name="id" value="' + id + '">';
		
		if( paramArray != '' ) {
			for( var j in paramArray ) {
				theForm += '<input type="hidden" id="' + this.gridId + '_actionform_' + j + '" name="' + j + '" value="' + paramArray[j] + '">';
			}
		}
		
		theForm += '</form>';
		
		divForm.innerHTML = theForm;
		document.body.appendChild(divForm);
		$(this.gridId + '_actionform').submit();
	},


	//---------------------//
	// PAGINACION DEL GRID //
	//---------------------//
	
	printFooter: function() {
		this.gridFooter.printFooter(this.numberPage, this.gridObject, this.pageSize, this.numPages, this.footId, this.numRecords);
	},


	//---------------------//
	// EXPORTACION A EXCEL //
	//---------------------//
	
	toExcel: function() {
		var myForm = document.createElement('FORM');
		if($isExplorer(document))
	   		myForm.target = '_blank';
	    else
			myForm.target = '_self';
		myForm.method = 'POST';
		myForm.action = 'AppJava/GridExcelServlet';
		var myInput = document.createElement('INPUT');
		myInput.type = 'hidden';
		myInput.name = 'content';
		myInput.value = this.toXML();
		myForm.appendChild(myInput);
		document.body.appendChild(myForm);
		myForm.submit();
	},
	toExcelAllData: function(idHTMLForm, exporter, configFile, newWindow) {
		var idMyForm = '_dummy_' + idHTMLForm + '_' + new Date().getTime();
		if($(idMyForm)) {
			document.body.removeChild($(idMyForm));
			try { delete $(idMyForm); } catch (e) { }
		}
		var myForm = document.createElement('FORM');
		myForm.id = idMyForm;
		myForm.name = '_dummy_' + myForm.name + '_' + new Date().getTime();
		if(newWindow || $isExplorer(document))
	   		myForm.target = '_blank';
	    else
			myForm.target = '_self';
		myForm.method = 'POST';
		myForm.action = 'AppJava/GridExcelServlet';
		myForm.style.display = 'none';
		// Exporter
		var inpEx = document.createElement('INPUT');
		inpEx.type = 'hidden';
		inpEx.name = 'exporter';
		inpEx.value = exporter;
		myForm.appendChild(inpEx);
		// Grid XML
		var inpCF = document.createElement('INPUT');
		inpCF.type = 'hidden';
		inpCF.name = 'configFile';
		inpCF.value = configFile;
		myForm.appendChild(inpCF);
		document.body.appendChild(myForm);
		
		// Campos del form
		var formOrig = $(idHTMLForm);
		var procesados = new Array();
		Form.getInputs(formOrig, 'text').each(function(elem) {
			var copia = document.createElement('INPUT');
			copia.type = 'hidden';
			copia.name = elem.name;
			copia.value = elem.value;
			myForm.appendChild(copia);
		});
		Form.getInputs(formOrig, 'hidden').each(function(elem) {
			var copia = document.createElement('INPUT');
			copia.type = 'hidden';
			copia.name = elem.name;
			copia.value = elem.value;
			myForm.appendChild(copia);
		});
		Form.getInputs(formOrig, 'radio').each(function(elem) {
			if(procesados.indexOf(elem.name) != -1) {
				return;
			}
			procesados.push(elem.name);
			var copia = document.createElement('INPUT');
			copia.type = 'hidden';
			copia.name = elem.name;
			copia.value = DWRUtil.getValue(elem);
			myForm.appendChild(copia);
		});
		Form.getInputs(formOrig, 'checkbox').each(function(elem) {
			if(procesados.indexOf(elem.name) != -1) {
				return;
			}
			procesados.push(elem.name);
			var copia = document.createElement('INPUT');
			copia.type = 'hidden';
			copia.name = elem.name;
			copia.value = DWRUtil.getValue(elem);
			myForm.appendChild(copia);
		});
		$A(formOrig.getElementsByTagName('select')).each(function(elem) {
			var copia = document.createElement('INPUT');
			copia.type = 'hidden';
			copia.name = elem.name;
			copia.value = DWRUtil.getValue(elem);
			myForm.appendChild(copia);
		});
		
		Form.getElements(myForm).each(function (elem) {
			elem.disabled = false;
		});
		
		myForm.submit();
	},
	muestraExcel: function (ticket) {
		var miForm = document.createElement('FORM');

		miForm.target = '_blank';
		miForm.method = 'get';
		miForm.action = 'AppJava/GridExcelServlet';
		var inputAction = document.createElement('INPUT');
		inputAction.type = 'hidden';
		inputAction.name = 'GRID_SERVLET_ACTION';
		inputAction.value = 'GRID_GET_ACTION';
		miForm.appendChild(inputAction);
		var inputTicket = document.createElement('INPUT');
		inputTicket.type = 'hidden';
		inputTicket.name = 'GRID_DOC_TICKET';
		inputTicket.value = ticket.responseText;
		miForm.appendChild(inputTicket);
		document.body.appendChild(miForm);

		miForm.submit();
	},
	toXML: function() {
		var separador = '#@#';
		var contenidoVacio = '-';
		var contenido = '';
		var colKeys = this.getKeys();
		var myGrid = this.gridId;
		var headerCols = this.textColumnes;
		
		if (this.filteredCollection.length < 1) {
			new WindowAlerta("No hi ha dades per exportar").show();
			return;
		}
		
		// Texto de las columnas visibles
		var textoColsVisibles = new Array();
		colKeys.each(function(key, i) {
			if( $isVisible(myGrid + '_th_' + key) ) {
				textoColsVisibles.push(headerCols[i]);
			}
		});
		
		// IDs de las columnas visibles
		var visible = colKeys.map(function(key, i) {
			if( $isVisible(myGrid + '_r0_' + key) ) {
				return key;
			}
		});
		
		var xmlRows = this.filteredCollection.map(function(row, i) {
			var xmlCols = visible.compact().map(function(key, j) {
				var value = eval('row.get' + key + '()');
				if(value == null || value == '')
					value = contenidoVacio;
				return value;
			});
			
			return xmlCols.compact().join(separador);
		});
		
		contenido += textoColsVisibles.join(separador);
		contenido += '\n';
		contenido += xmlRows.join('\n');

		return contenido;
	},
	
	/* Version enviando XML
	toXML2: function() {
		var xmlDoc = new JSXMLDocument();
		var writer = new JSXMLWriter();
		var colKeys = this.getKeys();
		var myGrid = this.gridId;
		
		if ( this.filteredCollection.length < 1 ) {
			new WindowAlerta("No hi ha dades per exportar").show();
			return;
		}
		
		var xmlHeaders = colKeys.map(function(key, i) {
			if( $isVisible(myGrid + '_th_' + key) ) {
				return writer.element('header', $(myGrid + '_th_' + key + '_label').innerHTML, {id: key});
			}
		});
		
		var visible = colKeys.map(function(key, i) {
			if( $isVisible(myGrid + '_r0_' + key) ) {
				return key;
			}
		});
		
		if ( visible.compact().length < 1 ) {
			new WindowAlerta("No hi ha dades per exportar").show();
			return;
		}
		
		var xmlRows = this.filteredCollection.map(function(row, i) {
			var xmlCols = visible.compact().map(function(key, j) {
				var value = eval('row.get' + key + '()');
				return writer.element('column', value, {id: key});
			});
			
			return writer.element('row', xmlCols.compact().join(''), {number: i + ''});
		});
		
		var xmlContent = writer.element('headers', xmlHeaders.compact().join(''));
		xmlContent += '\n\n' + xmlRows.join('\n\n');
		xmlDoc.addElement('grid', xmlContent);

		return xmlDoc.getXML();
	},*/
	
	//---------//
	// HELPERS //
	//---------//
	
	getKeys: function() {
		var cols = $A( $(this.gridId).getElementsByTagName('th') );
		var colKeys = cols.map(function(value, index) {
			key = value.id.substring(value.id.lastIndexOf('_') + 1, value.id.length)
			if(key.length > 1)
				return(key);
		});
		
		return colKeys.compact();
	},
	


	//-------------//
	// ESTAT PREVI //
	//-------------//

	loadPreviousStatus: function () {
		var prevStatus = CookieService.getCookie(this.cookieName(), this.getSavedAttributes());
		// Sin estado anterior, guardamos el actual
		if(prevStatus.getValue() == null) {
			prevStatus.set('filtre', '');
			prevStatus.set('pagina', this.numberPage);
			prevStatus.set('ordenacioCol', this.sortCol);
			prevStatus.set('ordenacioOrdre', this.sortOrder);
//			prevStatus.set('seleccionat', '');
		}
		// Cargamos el estado anterior
		else {
			// Filtro
			if(prevStatus.get('filtre') != '') {
				var filterFieldIf = this.gridId+'_filter_text';
				$(filterFieldIf).value = prevStatus.get('filtre');
				this.switchFilterVisibility();
				this.filter(filterFieldIf);
			}
			// Visibilidad de columnas
			var algunaHidden = false;
			for(var iCol=0; iCol<this.columnes.length; iCol++) {
				var nomColumna = this.columnes[iCol];
				if('hidden' == prevStatus.get(nomColumna)) {
					$('mostrar_'+this.gridId+'_'+nomColumna).checked = false;
					this.switchVisible(nomColumna);
					algunaHidden = true;
				}
			}
			if(algunaHidden)
				this.switchHeaderVisibility();
			// Ordenacion
			if(prevStatus.get('ordenacioCol') != '') {
				var columna = prevStatus.get('ordenacioCol');
				if(this.columnaExistent(columna))
					this.sort(columna, prevStatus.get('ordenacioOrdre'));
			}
			// Paginacion
			if(prevStatus.get('pagina') && parseInt(prevStatus.get('pagina')) <= this.numPages) {
				var pag = parseInt(prevStatus.get('pagina'));
				this.drawPage(pag,(pag-1)*this.pageSize);
			}
			// Elemento seleccionado
/*			if(prevStatus.get('seleccionat') && this.tipusSeleccio == 'single') {
				var posSeleccionat = -1;
				this.objectCollection.each(function(value, idx) {
					if(value.getid() == prevStatus.get('seleccionat')) {
						posSeleccionat = idx;
						value.checked = true;
						// Si tiene eventos asociados a la seleccion, los lanzamos
						//if( value.onSelect != '' ) {
							//eval(value.onSelect + '(value)');
						//}
						$(this.gridId+'_r'+value.getid()+'_select_single').checked = true;
					}
					// Desmarcamos todo (el navegador puede guardar datos al hacer F5)
					else {
						value.checked = false;
						$(this.gridId+'_r'+value.getid()+'_select_single').checked = false;
					}
				});
				// En aquest grid no es troba l'element seleccionat. Esborrem info
				if(posSeleccionat == -1) {
					this.saveStatus('seleccionat', '');
				}
			}*/
		}
	},
	saveStatus: function (param, value) {
		var prevStatus = CookieService.getCookie(this.cookieName());
		prevStatus.set(param, value);
	},
	columnaExistent: function (columna) {
		return this.columnes.indexOf(columna) != -1;
	},
	cookieName: function () {
		return 'GRID_PREV_STATUS_'+$getURLPath()+'_'+this.gridId;
	},
	getSavedAttributes: function () {
		// Atributos de configuracion del grid
		var atributs = ['filtre', 'pagina', 'ordenacioCol', 'ordenacioOrdre'];
		// Columnas para la visibilidad
		for(var iCol=0; iCol<this.columnes.length; iCol++)
			atributs[atributs.length] = this.columnes[iCol];
		return atributs;
	}
};

//gridFooter.js



var GridFooter = Class.create();
	
GridFooter.prototype = {

	initialize: function(footType) {
		this.type = footType;			// Estilo del footer
	},	

	/* Imprime la paginacion del Grid */
	printFooter: function(numberPage, gridObject, pageSize, numPages, footId, numRecords) { 
		var foot = "";
		
		if(numRecords != 0) {
			foot = "<br><table align='center'><tr>";
		
			if(numPages > 1) {
				foot += this.printPagesBack(numberPage, gridObject, pageSize, numPages);
				foot += "<td>[" + numberPage +"]</td>"
				foot += this.printPagesFront(numberPage, gridObject, pageSize, numPages);
			}
			
			foot += "</tr></table>";
			
			if(numPages > 5) {
				foot += "<table align='center'><tr>";
				foot += this.printPrevious(numberPage, gridObject, pageSize, numPages);
				foot += this.printNexts(numberPage, gridObject, pageSize, numPages);
				foot += "</tr></table>";
			}
			
			if( this.type != "simple" ) {
				foot += this.printPagination(numberPage, pageSize, numRecords);
			}
		}
		
		$(footId+'_Footer').innerHTML = foot;		
	},
	
	/* Imprime el rango de registros en que nos encontramos */
	printPagination: function(numberPage, pageSize, numRecords) {
		var firstPage = (numberPage-1)*pageSize+1;
		
		if(firstPage + pageSize > numRecords)
			return (firstPage+"-"+numRecords+"/"+numRecords);
			
		return (firstPage+"-"+numberPage*pageSize+"/"+numRecords);
	},
			
	/* Calcula cuantas paginas hay que mostrar antes que la actual */
	backLinks: function(numberPage, numPages) {
		//Importante el orden de los if, NO CAMBIAR
		if(numPages < 5)
			return numberPage - 1;	
		if(numberPage == 1)
			return 0;
		if(numberPage == 2)
			return 1;		
		if(numberPage == numPages-1)
			return 3;
		if(numberPage == numPages)
			return 4;
		return 2;
	},

	/* Calcula cuantas paginas hay que mostrar despues que la actual */	
	frontLinks: function(numberPage, numPages) {
		//Importante el orden de los if, NO CAMBIAR
		if(numPages < 5)
			return (numPages-numberPage);
		if(numberPage == numPages)
			return 0;
		if(numberPage == numPages-1)
			return 1;	
		if(numberPage == 2)
			return 3;
		if(numberPage == 1)
			return 4;
		return 2;
	},
		
	/* Imprime las paginas anteriores a la actual */
	printPagesBack: function(numberPage,gridObject, pageSize, numPages) {
		var backs = "";
					
		for(var back = this.backLinks(numberPage,numPages) ; back > 0  ; back--) {
			backs += "<td><a href='javascript:";
			backs += gridObject + ".drawPage(";
			backs += numberPage - back+",";
			backs += ((numberPage - back) * pageSize) - pageSize +")'>[";
			backs += numberPage - back +"]</a></td>";
		}
			
		return backs;	
	},

	/* Imprime las paginas posteriores a la actual */	
	printPagesFront: function(numberPage, gridObject, pageSize, numPages) {
		var fronts = "";
			
		for(var front = numberPage + 1  ; front < this.frontLinks(numberPage,numPages) + numberPage + 1 ; front++) {
			fronts += "<td><a href='javascript:";
			fronts += gridObject + ".drawPage(";
			fronts += front+",";
			fronts += (front * pageSize) - pageSize+")'>[";
			fronts += front+"]</a></td>";
		}	
			
		return fronts;
	},	
	
	/* Imprime los botones de retroceso para la navegacion */
	printPrevious: function(numberPage, gridObject, pageSize, numPages) {
		var backs = "<td>";
		
		if((numberPage > 1)&&(numPages > 5 )) {
			var previousPage = numberPage - 1;
			if(numberPage > 3) {
				backs += "<a href='javascript:"+ gridObject +".drawPage(1,";
				backs += 1 * pageSize- pageSize +")'>";
				backs += "<<</a>";
			}
			else {
				backs += "&nbsp;&nbsp;&nbsp;&nbsp;";
			}
			backs += "</td><td>";
			backs += "<a href='javascript:"+ gridObject+".drawPage("+ previousPage +",";
			backs += (previousPage * pageSize) - pageSize+")'>";
			backs += "<</a>";
		}
		else {
			backs += "&nbsp;&nbsp;&nbsp;&nbsp;</td><td>&nbsp;&nbsp;";
		}
		
		backs += "</td>";
		return backs;
	},
	
	/* Imprime los botones de avance para la navegacion */
	printNexts: function(numberPage, gridObject, pageSize, numPages) {
		var fronts = "<td>";
		
		if((numberPage != numPages)&&(numPages > 5 )) {
			var nextPage = numberPage + 1;
			fronts += "<a href='javascript:"+ gridObject +".drawPage("+ nextPage +",";
			fronts += (nextPage * pageSize) - pageSize+")'>";
			fronts += "></a>";
			fronts += "</td><td>";
			if(numPages-numberPage >= 3) {
				fronts += "<a href='javascript:"+ gridObject +".drawPage("+ numPages +",";
				fronts += numPages * pageSize -  pageSize+")'>";
				fronts += ">></a>";
			}
			else {
				fronts += "&nbsp;&nbsp;&nbsp;&nbsp;";
			}
		}
		else {
			fronts += "&nbsp;&nbsp;</td><td>&nbsp;&nbsp;&nbsp;&nbsp;"
		}
		
		fronts += "</td>";
		return fronts;
	}
};

//xmlWriter.js

var JSXMLWriter = Class.create();

JSXMLWriter.prototype = {

	initialize: function() {
		this.APOS = "'";
		this.QUOTE = '"';
		this.ESCAPED_QUOTE = {};
		this.ESCAPED_QUOTE[this.APOS] = '&apos;';
		this.ESCAPED_QUOTE[this.QUOTE] = '&quot;';
	},
	
	// Bare bones XML writer - no attributes
	element: function(name, content) {
	    var xml;
	    
	    if (!content){
	        xml = '<' + name + ' />';
	    }
	    else {
	        xml = '<' + name + '>' + content + '</' + name + '>';
	    }
	    
	    return xml;
	},
	
	// XML writer with attributes and smart attribute quote escaping 
	element: function(name, content, attributes) {
	    var xml;
	    var att_str = '';
	    
	    if (attributes) {
	        att_str = this.formatAttributes(attributes);
	    }
	    
	    if (!content) {
	        xml = '<' + name + att_str + ' />';
	    }
	    else {
	        xml = '<' + name + att_str + '>' + content + '</' + name + '>';
	    }
	    
	    return xml;
	},
	
	/*
	 * Format a dictionary of attributes into a string suitable
	 * for inserting into the start tag of an element.  Be smart
	 * about escaping embedded quotes inthe attribute values.
	 */
	formatAttributes: function(attributes) {
	    var att_value;
	    var apos_pos, quot_pos;
	    var use_quote, escape, quote_to_escape;
	    var att_str;
	    var re;
	    var result = '';
	
	    for (var att in attributes) {
	        att_value = attributes[att];
	        
	        // Find first quote marks if any
	        apos_pos = att_value.indexOf(this.APOS);
	        quot_pos = att_value.indexOf(this.QUOTE);
	       
	        // Determine which quote type to use around the attribute value
	        if (apos_pos == -1 && quot_pos == -1) {
	            att_str = ' ' + att + "='" + att_value +  "'";
	            result += att_str;
	            continue;
	        }
	        
	        // Prefer the single quote unless forced to use double
	        if (quot_pos != -1 && quot_pos < apos_pos) {
	            use_quote = this.APOS;
	        }
	        else {
	            use_quote = this.QUOTE;
	        }
	
	        // Figure out which kind of quote to escape
	        // Use nice dictionary instead of yucky if-else nests
	        escape = this.ESCAPED_QUOTE[use_quote];
	        
	        // Escape only the right kind of quote
	        re = new RegExp(use_quote, 'g');
	        att_str = ' ' + att + '=' + use_quote + 
	            att_value.replace(re, escape) + use_quote;
	        result += att_str;
	    }
	    
	    return result;
	}
};


var JSXMLDocument = Class.create();

JSXMLDocument.prototype = {

	initialize: function() {
		this.VERSION_STRING = '<?xml version="1.0"?>\n';
		
		this.XML = this.VERSION_STRING;
		this.writer = new JSXMLWriter();
	},
	
	getXML: function() {
		return this.XML;
	},
	
	addElement: function(name, content) {
		this.XML += this.writer.element(name, content);
	},
	
	addElement: function(name, content, attributes) {
		this.XML += this.writer.element(name, content, attributes);
	}
};

//bodyonload.js


	var OnLoadService = new Object();
	
	OnLoadService.FUNCTION_ARR = [];
	OnLoadService.FUNCTION_LAST_ARR = [];
	OnLoadService.LAST = 'last';
	
  	Object.extend(OnLoadService,{
  	executar : function() { 
		OnLoadService.FUNCTION_ARR.each( function(funcio){
					funcio();
				});
		OnLoadService.FUNCTION_LAST_ARR.each( function(funcio){
					funcio();
				});
		},
	registerInitMethod : function(metode, prioridad) {
			if(prioridad && prioridad == OnLoadService.LAST) {
				var i = OnLoadService.FUNCTION_LAST_ARR.length;
				OnLoadService.FUNCTION_LAST_ARR[i] = metode;
			}
			else {
				var i = OnLoadService.FUNCTION_ARR.length;
				OnLoadService.FUNCTION_ARR[i] = metode;
			}
		}
	});

	// ecnpc.js
	
	var OCITUtils = new Object();
	
Object.extend(OCITUtils, {
	getValues: function(map) {
					for (var property in map) {
						var ele = document.getElementsByName(property);
						if(ele) {
							ele = ele[0];
							map[property] = DWRUtil.getValue(property);
						}
					}
			   },
	saveTRTemplate:	function (id, index)
					{
						//alert("saveTRTemplate obj: "+$(id).innerHTML+" index: "+index);
						OCITUtils._storeObjectInDocument(id);
						OCITUtils._replacePropertyIndexInTR(id, index);
						//alert("saveTRTemplate obj: "+$(id).innerHTML);
					},
	saveTRTemplate2D:	function (id, pattern)
					{
						OCITUtils._storeObjectInDocument(id);
						OCITUtils._replacePropertyIndexInTR2D(id, pattern);
					},
					
	cloneTRTemplate2D:	function (id, indexI, indexJ)
						{
							// Creamos un TBODY y metemos una copia del TR 
							var nuevoTBody = document.createElement("TBODY");
							var copy = $(id).cloneNode(true);
							nuevoTBody.appendChild(copy);
							
							// Reemplazamos el id del TR y se lo asignamos al TBODY
							var regExp = new RegExp("\\[idx\\]","g");
							nuevoTBody.id = id.replace(regExp, "["+indexI+"]");
							if(typeof indexJ != 'undefined'){
								var regExpJ = new RegExp("\\[jdx\\]","g");
								nuevoTBody.id = nuevoTBody.id.replace(regExpJ, "["+indexJ+"]");
							} 
							copy.removeAttribute("id");

							// Reemplazamos los idx de cada TD
							var cells = copy.getElementsByTagName("TD");
							for(var i=0; i<cells.length; i++) {
								var cell = cells[i];
								var msg = cell.innerHTML+'\n\n';
								OCITUtils.replaceIdxTd(cell, indexI);
								if(typeof indexJ != 'undefined'){
									OCITUtils.replaceIdxTd(cell, indexJ, "jdx");
								}
							}
							// Ponemos visible el nuevo TR
							copy.removeAttribute("style");
							return nuevoTBody;
						},
	cloneTRTemplate:	function (id, index)
						{
							//alert("cloneTRTemplate id: "+id+" index: "+index);
							// Creamos un TBODY y metemos una copia del TR
							var nuevoTBody = document.createElement("TBODY");
							var copy = $(id).cloneNode(true);
							nuevoTBody.appendChild(copy);
							
							// Reemplazamos el id del TR y se lo asignamos al TBODY
							var regExp = new RegExp("\\[idx\\]","g");
							nuevoTBody.id = id.replace(regExp, "["+index+"]");
							copy.removeAttribute("id");

							// Reemplazamos los idx de cada TD
							var cells = copy.getElementsByTagName("TD");
							for(var i=0; i<cells.length; i++) {
								var cell = cells[i];
								var msg = cell.innerHTML+'\n\n';
								OCITUtils.replaceIdxTd(cell, index);
							}
							
							// Ponemos visible el nuevo TR
							copy.removeAttribute("style");
							return nuevoTBody;
						},
	cloneTDTemplate:	function (id, index)
						{
							 // Creamos un TBODY y metemos una copia del TR
                            var nuevoTBody = document.createElement("TBODY");
                            var copy = $(id).cloneNode(true);
                            nuevoTBody.appendChild(copy);
                            
                            // Reemplazamos el id del TR y se lo asignamos al TBODY
                            var regExp = new RegExp("\\[idx\\]","g");
                            nuevoTBody.id = id.replace(regExp, "["+index+"]");
                            copy.removeAttribute("id");

                            // Reemplazamos los idx de cada TD
                            var cells = copy.getElementsByTagName("TD");
                            for(var i=0; i<cells.length; i++) {
                                var cell = cells[i];
                                var msg = cell.innerHTML+'\n\n';
                                OCITUtils.replaceIdxTd(cell, index);
                            }
                            
                            // Ponemos visible el nuevo TR
                            copy.removeAttribute("style");
                            return nuevoTBody;

						},
	replaceText:		function (idObj, pattern, text)
						{
							var obj = $(idObj);
							pattern = pattern.replace(/\./g, '\\.').replace(/[\[]/g, '\\[').replace(/[\]]/g, '\\]').replace(/\*/g, '.*');
							var regExp = new RegExp(pattern, 'g');
							// Sus celdas
							var cells = obj.getElementsByTagName("TD");
							for(var iCell=0; iCell<cells.length; iCell++) {
								var cell = cells[iCell];
								cell.innerHTML = cell.innerHTML.replace(regExp, text);
							}
						},
	replaceTextTD:		function (idObj, pattern, text)
						{
							var obj = $(idObj);
							pattern = pattern.replace(/\./g, '\\.').replace(/[\[]/g, '\\[').replace(/[\]]/g, '\\]');
							var regExp = new RegExp(pattern, 'g');
							obj.innerHTML = obj.innerHTML.replace(regExp, text);
						},
	replaceIdxTbody:	function (obj, index, pattern)
						{
							//alert("replaceIdxTbody [Abans] obj: "+obj.innerHTML+" index: "+index+" pattern: "+pattern);
							if(typeof pattern == 'undefined') {
								pattern = "idx";
							}

							// ID del objeto
							var regExp = new RegExp("\\["+pattern+"\\]","g");
							obj.id = obj.id.replace(regExp, "["+index+"]");
							
							// Sus celdas
							var cells = obj.getElementsByTagName("TD");
							for(var iCell=0; iCell<cells.length; iCell++) {
								OCITUtils.replaceIdxTd(cells[iCell], index, pattern);
							}
							//alert("replaceIdxTbody [Despr?s] obj: "+obj.innerHTML);
						},
	_storeObjectInDocument:	function (id)
							{
								var tempCopy = $(id).cloneNode(true);
								tempCopy.id = '';
								$deleteElement(id);
								tempCopy.id = id;
								document.documentElement.appendChild(tempCopy);
							},
	// Cambiamos las propiedades, que apuntan al ultimo
	// pojo existente + 1
	_replacePropertyIndexInTR:	function (trId, index, pattern)
								{
									if(typeof pattern == "undefined")
										pattern = "idx";
									var trObj = $(trId);
									var regExp = new RegExp("\\["+index+"\\]","g");
									var cells = trObj.getElementsByTagName("TD");
									for(var i=0; i<cells.length; i++) {
										var tdObj = cells[i];
										tdObj.innerHTML = tdObj.innerHTML.replace(regExp, "["+pattern+"]");
									}
								},
	_replacePropertyIndexInTR2D:	function (trId, patternAddicional)
								{
									var pattern = "idx";
									var trObj = $(trId);
									if(typeof patternAddicional == 'undefined') {
										var regExp = new RegExp("\\[[0-9]*\\]\\.","g");
									}else{
										var regExp = new RegExp("\\[[0-9]*\\]\\.([0-9a-zA-Z_]+)\\[[0-9]*\\]\\.","g");
									}
									var cells = trObj.getElementsByTagName("TD");
									for(var i=0; i<cells.length; i++) {
										var tdObj = cells[i];
										if(typeof patternAddicional == 'undefined') {
											tdObj.innerHTML = tdObj.innerHTML.replace(regExp, "["+pattern+"].");
										} else {
											tdObj.innerHTML = tdObj.innerHTML.replace(regExp, "["+pattern+"].$1["+patternAddicional+"].");
										}
									}
								},
	replaceIdxTd:	function (obj, index, pattern)
					{
						if(typeof pattern == 'undefined') {
							pattern = "idx";
						}
						var regExp = new RegExp("\\["+pattern+"\\]","g");
						var html = obj.innerHTML;
						html = html.replace(regExp,"["+index+"]");
						obj.innerHTML = html;
					},
	_inspectBean:	function (bean, separator) {
						if(typeof separator == 'undefined')
							separator = '<br/>';
						var beanProps = '<div style="height:400px; overflow:auto">';
						for (var pr in bean) {
							beanProps += '<nobr>' + pr + ' = ' + bean[pr] + '</nobr>' + separator;
						}
						beanProps += '</div>';
						new WindowInformacion(beanProps).show();
					}
});
	
	// validation.js
	
	var OCITValidation = new Object();

OCITValidation.VALIDATION_ERROR_CLASS = 'validationError';
OCITValidation.VALIDATION_EDIT_CLASS = 'validationEdit';
OCITValidation.VALIDATION_OK_CLASS = 'validationOK';

Object.extend(OCITValidation, {
	errorInput: function (id, message)
				{
					if(typeof id == "undefined" || typeof $(id) == "undefinded")
						return;
					eval(OCITValidation.parseId(id)+'Tooltip = new Object()');
					eval(OCITValidation.parseId(id)+'Tooltip.message="'+message+'"');
					var dest = this.validationErrorStyle(id);
					this.observe(id,dest);
				},
	
	restoreClass:	function (id)
					{
						if(typeof id != "undefined" && typeof $(id) != "undefined" &&
							eval('typeof '+OCITValidation.parseId(id)+'Tooltip != "undefined"'))
						{
							var obj = eval(OCITValidation.parseId(id)+'Tooltip');
							var dest = $(id);
							if(dest) {
								if($isRadioButton(dest) || $isCheckbox(dest)) {
									if(!dest.parentNode)
										return;
									dest = dest.parentNode;
								}
								if(obj.oldClass)
									dest.className = eval(OCITValidation.parseId(id)+'Tooltip.oldClass');
								this.stopObserving(id);
							}
						}
					},
	
	validationErrorStyle:	function (id)
							{
								var dest = $(id);
								/*
									Firefox no aplica estilos a radiobuttons ni checkboxes
									Le incluimos un div que es a quien se le aplica el estilo
								*/
								if($isRadioButton($(id)) || $isCheckbox($(id))) {
									if($(id).parentNode.tagName == 'DIV') {
										dest = $(id).parentNode;
									}
									else {
										var divCont = document.createElement("DIV");
										var style = { width: '20px', height: '20px', padding: '0px',
													  margin: '0px', textAlign: 'center', verticalAlign: 'middle' };
										Element.setStyle(divCont, $H(style));
										var parent = $(id).parentNode;
										var newInput = $(id).cloneNode(true);
										newInput.id = id;
										parent.insertBefore(divCont, $(id));
										parent.removeChild($(id));
										divCont.appendChild(newInput);
										dest = divCont;
									}
									dest.className = $(id).className;
								}
								else {
									dest = $(id);
								}
								if(dest.className && eval('typeof '+OCITValidation.parseId(id)+'Tooltip != "undefined"')) {
									eval(OCITValidation.parseId(id)+'Tooltip.oldClass = "'+dest.className+'"');
								}
								dest.className = OCITValidation.VALIDATION_ERROR_CLASS;
								return dest;
							},
	
	validationErrorHandler:	function (event)
							{
							 	var header = "<span class='validationTooltipTitleClass'>Error</span>";
								var dest = null;
								if(event.srcElement) {
									dest = event.srcElement;
								}
								else {
									dest = this;
								}
								if($isDiv(dest)) {
									dest = dest.firstChild;
								}
								if(eval('typeof '+OCITValidation.parseId(dest.id)+'Tooltip != "undefined"')) {
									if(typeof domTT_tooltips.get(dest.id) != "undefined") {
										domTT_tooltips.remove(dest.id);
										domTT_tooltips.remove('[domTT]'+dest.id);
									}
									domTT_activate(dest, event, 'caption', header, 'content', eval(OCITValidation.parseId(dest.id)+'Tooltip.message'), 'type', 'greasy', 'closeLink', '', 'trail', true, 'draggable', false, 'offsetY', -2,'id','[domTT]'+dest.id);
								}
							},
	
	validationChangeHandlerCalendar:	function (cal)
										{
											// Se ejecuta siempre que se accede al calendario
											// pero solo hemos de cambiar el estilo cuando
											// el campo tenga un error de validacion
											if(cal.params && cal.params.inputField && cal.params.inputField.className == OCITValidation.VALIDATION_ERROR_CLASS) {
												cal.params.inputField.className = OCITValidation.VALIDATION_EDIT_CLASS;
											}
										},
	validationChangeHandler:	function (event)
								{
									var sourceElement = null;
									if(event.srcElement) {
										sourceElement = event.srcElement;
									}
									else {
										sourceElement = this;
									}
									if($isRadioButton(sourceElement) || $isCheckbox(sourceElement)) {
										sourceElement = sourceElement.parentNode;
									}
									if(event.type == "keydown" && !$isText(event.keyCode)) {
										return;
									}
								
									// En radiobuttons y checkboxes hay que cambiar
									// el estilo a todos los inputs de esa propiedad
									var ids = null;
									if($isDiv(sourceElement)) {
										ids = idsByName(sourceElement.firstChild.form, sourceElement.firstChild.name);
									}
									else {
										ids = idsByName(sourceElement.form, sourceElement.name);
									}
									ids.each(
										function(idObj) {
											var dest = $(idObj);
											if($isRadioButton(dest) || $isCheckbox(dest)) {
												dest = dest.parentNode;
											}
											dest.className = OCITValidation.VALIDATION_EDIT_CLASS;
											//dest.oldClass = null;
										}
									);
								},
	observe:	function(id,dest) {
					// Tooltip error
					if($isDiv(dest)) {
						Event.observe(dest.firstChild, 'mouseover', this.validationErrorHandler, false);
					}
					else {
						Event.observe(dest, 'mouseover', this.validationErrorHandler, false);
					}
					// Cambiar estilo al modificar el campo
					if($isRadioButton($(id)) || $isCheckbox($(id))) {
						Event.observe(dest.firstChild, 'click', this.validationChangeHandler, false);
					}
					else {
						Event.observe(dest, 'keydown', this.validationChangeHandler, false);
						Event.observe(dest, 'change', this.validationChangeHandler, false);
					}
					// En explorer el tooltip sigue al mouse al salir del objeto (ignora 'greasy')
					Event.observe(dest, 'mouseout', function (event) { domTT_close(dest); }, false);
				},
	stopObserving:	function (id) {
						var dest = $(id);
						// Tooltip error
						Event.stopObserving(id, 'mouseover', this.validationErrorHandler, false);
						// Cambiar estilo al modificar el campo
						if($isRadioButton($(id)) || $isCheckbox($(id))) {
							Event.stopObserving(id, 'click', this.validationChangeHandler, false);
						}
						else {
							Event.stopObserving(id, 'keydown', this.validationChangeHandler, false);
							Event.stopObserving(id, 'change', this.validationChangeHandler, false);
						}
						// En explorer el tooltip sigue al mouse al salir del objeto (ignora 'greasy')
						Event.stopObserving(id, 'mouseout', function (event) { domTT_close(dest); }, false);
					},
	parseId:	function (id) {
					return id.replace(/[\[\]]/g,"$");
				}
	}
);
	// ocitforms.js
	
	
var OCITForms = new Object();

OCITForms.formsWithErrorsPopup = new Array();
OCITForms.lockedForms = new Array();
OCITForms.initialState = new Array();
OCITForms.formNames = new Array();
OCITForms.onSubmitActions = new Array();
OCITForms.submitedForms = new Array();

Object.extend(OCITForms, {
	submit: function (id, validateForm, onSubmit) {
				if(OCITForms.arrayContains(OCITForms.submitedForms, id)) {
					//alert('form submitted, waiting response');
					return;
				}
				LockService.activarEspera();
				OCITForms.addToArray(OCITForms.submitedForms, id);
	
				var withValidation = true;
				var validationOK = true;
				if(typeof validateForm != "undefined")
					withValidation = validateForm;
				
				myform = $(id);
				
				if(onSubmit) {
					OCITForms.onSubmitActions[OCITForms.formNameIndex(id)] = onSubmit;
				}
				
				if(!withValidation) {
					myform.submit();
					// OnSubmit actions
					if(onSubmit) {
						for(var iOn=0; iOn<onSubmit.length; iOn++) {
							if(typeof onSubmit[iOn] == 'function') {
								onSubmit[iOn]();
							}
						}
					}
				}
				else {
					
		 			if(document.createEvent)
	      			{
	          			 var evt = document.createEvent('HTMLEvents');
	          			 evt.initEvent('submit', true, true);
	          			 myform.dispatchEvent(evt);
	      			}
	    		    else if(myform.fireEvent)
	      			{
	           			validationOK = myform.fireEvent('onsubmit');
	           			if(validationOK == true){
	           				myform.submit();
	           			}
	     			}
     			}
			},
	submitSenseEspera: function (id, validateForm, onSubmit) {
				if(OCITForms.arrayContains(OCITForms.submitedForms, id)) {
					//alert('form submitted, waiting response');
					return;
				}
				OCITForms.addToArray(OCITForms.submitedForms, id);
	
				var withValidation = true;
				var validationOK = true;
				if(typeof validateForm != "undefined")
					withValidation = validateForm;
				
				myform = $(id);
				
				if(onSubmit) {
					OCITForms.onSubmitActions[OCITForms.formNameIndex(id)] = onSubmit;
				}
				
				if(!withValidation) {
					myform.submit();
					// OnSubmit actions
					if(onSubmit) {
						for(var iOn=0; iOn<onSubmit.length; iOn++) {
							if(typeof onSubmit[iOn] == 'function') {
								onSubmit[iOn]();
							}
						}
					}
				}
				else {
					
		 			if(document.createEvent)
	      			{
	          			 var evt = document.createEvent('HTMLEvents');
	          			 evt.initEvent('submit', true, true);
	          			 myform.dispatchEvent(evt);
	      			}
	    		    else if(myform.fireEvent)
	      			{
	           			validationOK = myform.fireEvent('onsubmit');
	           			if(validationOK == true){
	           				myform.submit();
	           			}
	     			}
     			}
			},
	setValidated:	function (val){
						if(val==false){
							LockService.desactivarEspera();
						}				
				 	},
	formSubmitted:	function (id) {
						OCITForms.removeFromArray(OCITForms.submitedForms, id);
					},
	lock:	function (id, protectedFields) {
				if(!OCITForms.isFormLocked(id)) {
					OCITForms.storeInLocked(id);
				}
				myform = $(id);
				for(var iElem=0; iElem<myform.elements.length; iElem++) {
					var elem = myform.elements[iElem];
					if(elem.id && elem.tagName && (elem.tagName == "INPUT" || elem.tagName == "SELECT" || elem.tagName == "TEXTAREA"))
					{
						var elemId = OCITForms.parseId(elem.id);
						eval(id+elemId+" = new Object()");
						if(elem.className)
							eval(id+elemId+".clase = elem.className");
						eval(id+elemId+".estado = "+elem.disabled);

						if(!OCITForms.arrayContains($A(protectedFields), elem.id)) {
							elem.disabled = true;
							elem.className = 'disabled';
							if((elem.tagName == 'SELECT' && elem.type == 'select-multiple') || elem.tagName == 'TEXTAREA') {
								elem.disabled = false;
								elem.contentEditable = false;
							}
						}
					}
				}
				OCITForms.hideCalendars(id);
			},
	unlock:	function (id) {
				if(!OCITForms.isFormLocked(id)) {
					return;
				}
				else {
					OCITForms.removeFromLocked(id);
				}
				myform = $(id);
				for(var iElem=0; iElem<myform.elements.length; iElem++) {
					var elem = myform.elements[iElem];
					var elemId = OCITForms.parseId(elem.id);
					if(elem.tagName == "INPUT" || elem.tagName == "SELECT" || elem.tagName == "TEXTAREA") {
						if(eval("typeof "+id+elemId+" != \"undefined\""))
							elem.disabled = eval(id+elemId+".estado");
						else
							elem.disabled = false;
						if(eval("typeof "+id+elemId+" != \"undefined\"")) {
							if(eval(id+elemId+".clase"))
								elem.className = eval(id+elemId+".clase");
							else
								elem.className = '';
						}
						if((elem.tagName == 'SELECT' && elem.type == 'select-multiple') || elem.tagName == 'TEXTAREA') {
							elem.disabled = false;
							elem.contentEditable = true;
						}
					}
				}
				OCITForms.showCalendars(id);
			},
	unlockForSubmit:	function (id) {
				if(!OCITForms.isFormLocked(id)) {
					return;
				}
				else {
					OCITForms.removeFromLocked(id);
				}
				myform = $(id);
				for(var iElem=0; iElem<myform.elements.length; iElem++) {
					var elem = myform.elements[iElem];

					var elemId = OCITForms.parseId(elem.id);

					if(elem.tagName == "INPUT" || elem.tagName == "SELECT" || elem.tagName == "TEXTAREA") {

						if(eval("typeof "+id+elemId+" != \"undefined\""))
							elem.disabled = eval(id+elemId+".estado");
						else
							elem.disabled = false;

						if(eval("typeof "+id+elemId+" != \"undefined\"")) {
							if(eval(id+elemId+".clase"))
								elem.className = eval(id+elemId+".clase");
							else
								elem.className = '';
						}
						if((elem.tagName == 'SELECT' && elem.type == 'select-multiple') || elem.tagName == 'TEXTAREA') {
							elem.disabled = false;
							elem.contentEditable = true;
						}
					}
										
					eval(id+elemId+"forSubmit_ = new Object()");
					if(elem.className)
						eval(id+elemId+"forSubmit_.clase = elem.className");
					eval(id+elemId+"forSubmit_.estado = "+elem.disabled);
					
				}
					eval(id+"FORMforSubmit_ = new Object()");					
					eval(id+"FORMforSubmit_.relock = true");				

				OCITForms.showCalendars(id);
			},
	lockAfterSubmit: function (id, protectedFields) {
	
			if(!( eval("typeof "+id+"FORMforSubmit_ != \"undefined\"") && eval(id+"FORMforSubmit_.relock == true")) ){
				return;
			}
			
				if(!OCITForms.isFormLocked(id)) {
					OCITForms.storeInLocked(id);
				}
				myform = $(id);
				for(var iElem=0; iElem<myform.elements.length; iElem++) {
					var elem = myform.elements[iElem];
					if(elem.id && elem.tagName && (elem.tagName == "INPUT" || elem.tagName == "SELECT" || elem.tagName == "TEXTAREA"))
					{
						var elemId = OCITForms.parseId(elem.id);
						if(!OCITForms.arrayContains($A(protectedFields), elem.id)) {
							if(eval("typeof "+id+elemId+"forSubmit_  != \"undefined\""))
								elem.disabled = eval(id+elemId+"forSubmit_ .estado");
							else
								elem.disabled = false;
							if(eval("typeof "+id+elemId+"forSubmit_  != \"undefined\"")) {
								if(eval(id+elemId+"forSubmit_ .clase"))
									elem.className = eval(id+elemId+"forSubmit_ .clase");
								else
									elem.className = '';
							}
						
							elem.disabled = true;
							elem.className = 'disabled';
						}
						if((elem.tagName == 'SELECT' && elem.type == 'select-multiple') || elem.tagName == 'TEXTAREA') {
							elem.disabled = false;
							elem.contentEditable = false;
						}
					}
				}
				OCITForms.hideCalendars(id);
			
			},				
	saveInitialState:	function () {
							for(var indForm=0; indForm<document.forms.length; indForm++) {
								var formX = document.forms[indForm];
								var contForm = OCITForms.getFormContent(formX);

								OCITForms.formNames[indForm] = formX.name;
								OCITForms.initialState[indForm] = contForm;
							}
						},
	formChanged:	function (id) {
						var formPosition = OCITForms.formNameIndex(id);
						if(formPosition == -1) {
							// Form no cacheado
							return true;
						}
						var initState = OCITForms.initialState[formPosition];
						var actualState = OCITForms.getFormContent($(id));
						//alert($A(initState).inspect()+'\n\n'+$A(actualState).inspect());
						return $A(initState).inspect() != $A(actualState).inspect();
					},
	registerFormWithErrorsPopup:	function(id) {
										var lastIndex = OCITForms.formsWithErrorsPopup.length;
										OCITForms.formsWithErrorsPopup[lastIndex] = id;
									},
	withErrorsPopup:	function(id) {
							return OCITForms.arrayContains(OCITForms.formsWithErrorsPopup, id);
						},
	
			
			
			
	/* FUNCIONES AUXILIARES */
	isFormLocked:	function (id) {
						return OCITForms.arrayContains(OCITForms.lockedForms,id);
					},
	storeInLocked:	function (id) {
						OCITForms.addToArray(OCITForms.lockedForms, id);
					},
	removeFromLocked:	function (id) {
							OCITForms.removeFromArray(OCITForms.lockedForms, id);
						},
	parseId:	function (id) {
					return id.replace(/[\[\]]/g,"$").replace(/\./g,"_");
				},
	getFormContent:	function (formulari) {
		  		  		var beanResult = new Array();
		  		  		var listElems = formulari.elements;
						for (iElement=0; iElement<listElems.length; iElement++){	  		  	
							var elem = listElems[iElement];
							if((elem.tagName == "INPUT" || elem.tagName == "SELECT" || elem.tagName == "TEXTAREA")
								&& elem.name && elem.name != "")
								beanResult.push(eval("{"+OCITForms.parseId(elem.name)+": DWRUtil.getValue(elem.name)}"));
						}
						return beanResult;
					},
	hideCalendars:	function (id) {
						var imagesForm = $(id).getElementsByTagName("IMG");
						for(var iImage=0; iImage<imagesForm.length; iImage++) {
							var imgActual = imagesForm[iImage];
							var regExp = /_cal_tg_img$/;
							if(imgActual.id.match(regExp)) {
								$NoVisible(imgActual.id);
							}
						}
					},
	showCalendars:	function (id) {
						var imagesForm = $(id).getElementsByTagName("IMG");
						for(var iImage=0; iImage<imagesForm.length; iImage++) {
							var imgActual = imagesForm[iImage];
							var regExp = /_cal_tg_img$/;
							if(imgActual.id.match(regExp)) {
								$Visible(imgActual.id);
							}
						}
					},
	formNameIndex:	function (id) {
						return OCITForms.positionInArray(OCITForms.formNames, id);
					},
	onSubmitEvents:	function (id) {
						return OCITForms.onSubmitActions[OCITForms.formNameIndex(id)];
					},
	/* Funciones auxiliares de listas */
	arrayContains:	function(array, obj) {
						return OCITForms.positionInArray(array, obj) != -1;
					},
	addToArray:		function (array, id) {
						for(var ind=0; ind<array.length; ind++) {
							if(array[ind] == null)
								array[ind] = id;
						}
						if(array.length == 0)
							array[0] = id;
						
					},
	removeFromArray:	function (array, id) {
							for(var ind=0; ind<array.length; ind++) {
								if(array[ind] == id)
									array[ind] = null;
							}
						},
	positionInArray:	function (array, id) {
							for(var iObj=0; iObj<array.length; iObj++) {
								if(array[iObj] == id)
									return iObj;
							}
							return -1;
						}
});


// Registramos la copia de los formularios
OnLoadService.registerInitMethod(OCITForms.saveInitialState, OnLoadService.LAST);

// calendar.js

/*  Copyright Mihai Bazon, 2002-2005  |  www.bazon.net/mishoo
 * -----------------------------------------------------------
 *
 * The DHTML Calendar, version 1.0 "It is happening again"
 *
 * Details and latest version at:
 * www.dynarch.com/projects/calendar
 *
 * This script is developed by Dynarch.com.  Visit us at www.dynarch.com.
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 */

// $Id$

/** The Calendar object constructor. */
Calendar = function (firstDayOfWeek, dateStr, onSelected, onClose) {
	// member variables
	this.activeDiv = null;
	this.currentDateEl = null;
	this.getDateStatus = null;
	this.getDateToolTip = null;
	this.getDateText = null;
	this.timeout = null;
	this.onSelected = onSelected || null;
	this.onClose = onClose || null;
	this.dragging = false;
	this.hidden = false;
	this.minYear = 1970;
	this.maxYear = 2050;
	this.dateFormat = Calendar._TT["DEF_DATE_FORMAT"];
	this.ttDateFormat = Calendar._TT["TT_DATE_FORMAT"];
	this.isPopup = true;
	this.weekNumbers = true;
	this.firstDayOfWeek = typeof firstDayOfWeek == "number" ? firstDayOfWeek : Calendar._FD; // 0 for Sunday, 1 for Monday, etc.
	this.showsOtherMonths = false;
	this.dateStr = dateStr;
	this.ar_days = null;
	this.showsTime = false;
	this.time24 = true;
	this.yearStep = 2;
	this.hiliteToday = true;
	this.multiple = null;
	// HTML elements
	this.table = null;
	this.element = null;
	this.tbody = null;
	this.firstdayname = null;
	// Combo boxes
	this.monthsCombo = null;
	this.yearsCombo = null;
	this.hilitedMonth = null;
	this.activeMonth = null;
	this.hilitedYear = null;
	this.activeYear = null;
	// Information
	this.dateClicked = false;

	// one-time initializations
	if (typeof Calendar._SDN == "undefined") {
		// table of short day names
		if (typeof Calendar._SDN_len == "undefined")
			Calendar._SDN_len = 3;
		var ar = new Array();
		for (var i = 8; i > 0;) {
			ar[--i] = Calendar._DN[i].substr(0, Calendar._SDN_len);
		}
		Calendar._SDN = ar;
		// table of short month names
		if (typeof Calendar._SMN_len == "undefined")
			Calendar._SMN_len = 3;
		ar = new Array();
		for (var i = 12; i > 0;) {
			ar[--i] = Calendar._MN[i].substr(0, Calendar._SMN_len);
		}
		Calendar._SMN = ar;
	}
};

// ** constants

/// "static", needed for event handlers.
Calendar._C = null;

/// detect a special case of "web browser"
Calendar.is_ie = ( /msie/i.test(navigator.userAgent) &&
		   !/opera/i.test(navigator.userAgent) );

Calendar.is_ie5 = ( Calendar.is_ie && /msie 5\.0/i.test(navigator.userAgent) );

/// detect Opera browser
Calendar.is_opera = /opera/i.test(navigator.userAgent);

/// detect KHTML-based browsers
Calendar.is_khtml = /Konqueror|Safari|KHTML/i.test(navigator.userAgent);

// BEGIN: UTILITY FUNCTIONS; beware that these might be moved into a separate
//        library, at some point.

Calendar.getAbsolutePos = function(el) {
	var SL = 0, ST = 0;
	var is_div = /^div$/i.test(el.tagName);
	if (is_div && el.scrollLeft)
		SL = el.scrollLeft;
	if (is_div && el.scrollTop)
		ST = el.scrollTop;
	var r = { x: el.offsetLeft - SL, y: el.offsetTop - ST };
	if (el.offsetParent) {
		var tmp = this.getAbsolutePos(el.offsetParent);
		r.x += tmp.x;
		r.y += tmp.y;
	}
	return r;
};

Calendar.isRelated = function (el, evt) {
	var related = evt.relatedTarget;
	if (!related) {
		var type = evt.type;
		if (type == "mouseover") {
			related = evt.fromElement;
		} else if (type == "mouseout") {
			related = evt.toElement;
		}
	}
	while (related) {
		if (related == el) {
			return true;
		}
		related = related.parentNode;
	}
	return false;
};

Calendar.removeClass = function(el, className) {
	if (!(el && el.className)) {
		return;
	}
	var cls = el.className.split(" ");
	var ar = new Array();
	for (var i = cls.length; i > 0;) {
		if (cls[--i] != className) {
			ar[ar.length] = cls[i];
		}
	}
	el.className = ar.join(" ");
};

Calendar.addClass = function(el, className) {
	Calendar.removeClass(el, className);
	el.className += " " + className;
};

// FIXME: the following 2 functions totally suck, are useless and should be replaced immediately.
Calendar.getElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.currentTarget;
	while (f.nodeType != 1 || /^div$/i.test(f.tagName))
		f = f.parentNode;
	return f;
};

Calendar.getTargetElement = function(ev) {
	var f = Calendar.is_ie ? window.event.srcElement : ev.target;
	while (f.nodeType != 1)
		f = f.parentNode;
	return f;
};

Calendar.stopEvent = function(ev) {
	ev || (ev = window.event);
	if (Calendar.is_ie) {
		ev.cancelBubble = true;
		ev.returnValue = false;
	} else {
		ev.preventDefault();
		ev.stopPropagation();
	}
	return false;
};

Calendar.addEvent = function(el, evname, func) {
	if (el.attachEvent) { // IE
		el.attachEvent("on" + evname, func);
	} else if (el.addEventListener) { // Gecko / W3C
		el.addEventListener(evname, func, true);
	} else {
		el["on" + evname] = func;
	}
};

Calendar.removeEvent = function(el, evname, func) {
	if (el.detachEvent) { // IE
		el.detachEvent("on" + evname, func);
	} else if (el.removeEventListener) { // Gecko / W3C
		el.removeEventListener(evname, func, true);
	} else {
		el["on" + evname] = null;
	}
};

Calendar.createElement = function(type, parent) {
	var el = null;
	if (document.createElementNS) {
		// use the XHTML namespace; IE won't normally get here unless
		// _they_ "fix" the DOM2 implementation.
		el = document.createElementNS("http://www.w3.org/1999/xhtml", type);
	} else {
		el = document.createElement(type);
	}
	if (typeof parent != "undefined") {
		parent.appendChild(el);
	}
	return el;
};

// END: UTILITY FUNCTIONS

// BEGIN: CALENDAR STATIC FUNCTIONS

/** Internal -- adds a set of events to make some element behave like a button. */
Calendar._add_evs = function(el) {
	with (Calendar) {
		addEvent(el, "mouseover", dayMouseOver);
		addEvent(el, "mousedown", dayMouseDown);
		addEvent(el, "mouseout", dayMouseOut);
		if (is_ie) {
			addEvent(el, "dblclick", dayMouseDblClick);
			el.setAttribute("unselectable", true);
		}
	}
};

Calendar.findMonth = function(el) {
	if (typeof el.month != "undefined") {
		return el;
	} else if (typeof el.parentNode.month != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.findYear = function(el) {
	if (typeof el.year != "undefined") {
		return el;
	} else if (typeof el.parentNode.year != "undefined") {
		return el.parentNode;
	}
	return null;
};

Calendar.showMonthsCombo = function () {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var mc = cal.monthsCombo;
	if (cal.hilitedMonth) {
		Calendar.removeClass(cal.hilitedMonth, "hilite");
	}
	if (cal.activeMonth) {
		Calendar.removeClass(cal.activeMonth, "active");
	}
	var mon = cal.monthsCombo.getElementsByTagName("div")[cal.date.getMonth()];
	Calendar.addClass(mon, "active");
	cal.activeMonth = mon;
	var s = mc.style;
	s.display = "block";
	if (cd.navtype < 0)
		s.left = cd.offsetLeft + "px";
	else {
		var mcw = mc.offsetWidth;
		if (typeof mcw == "undefined")
			// Konqueror brain-dead techniques
			mcw = 50;
		s.left = (cd.offsetLeft + cd.offsetWidth - mcw) + "px";
	}
	s.top = (cd.offsetTop + cd.offsetHeight) + "px";
};

Calendar.showYearsCombo = function (fwd) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	var cal = cal;
	var cd = cal.activeDiv;
	var yc = cal.yearsCombo;
	if (cal.hilitedYear) {
		Calendar.removeClass(cal.hilitedYear, "hilite");
	}
	if (cal.activeYear) {
		Calendar.removeClass(cal.activeYear, "active");
	}
	cal.activeYear = null;
	var Y = cal.date.getFullYear() + (fwd ? 1 : -1);
	var yr = yc.firstChild;
	var show = false;
	for (var i = 12; i > 0; --i) {
		if (Y >= cal.minYear && Y <= cal.maxYear) {
			yr.innerHTML = Y;
			yr.year = Y;
			yr.style.display = "block";
			show = true;
		} else {
			yr.style.display = "none";
		}
		yr = yr.nextSibling;
		Y += fwd ? cal.yearStep : -cal.yearStep;
	}
	if (show) {
		var s = yc.style;
		s.display = "block";
		if (cd.navtype < 0)
			s.left = cd.offsetLeft + "px";
		else {
			var ycw = yc.offsetWidth;
			if (typeof ycw == "undefined")
				// Konqueror brain-dead techniques
				ycw = 50;
			s.left = (cd.offsetLeft + cd.offsetWidth - ycw) + "px";
		}
		s.top = (cd.offsetTop + cd.offsetHeight) + "px";
	}
};

// event handlers

Calendar.tableMouseUp = function(ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	if (cal.timeout) {
		clearTimeout(cal.timeout);
	}
	var el = cal.activeDiv;
	if (!el) {
		return false;
	}
	var target = Calendar.getTargetElement(ev);
	ev || (ev = window.event);
	Calendar.removeClass(el, "active");
	if (target == el || target.parentNode == el) {
		Calendar.cellClick(el, ev);
	}
	var mon = Calendar.findMonth(target);
	var date = null;
	if (mon) {
		date = new Date(cal.date);
		if (mon.month != date.getMonth()) {
			date.setMonth(mon.month);
			cal.setDate(date);
			cal.dateClicked = false;
			cal.callHandler();
		}
	} else {
		var year = Calendar.findYear(target);
		if (year) {
			date = new Date(cal.date);
			if (year.year != date.getFullYear()) {
				date.setFullYear(year.year);
				cal.setDate(date);
				cal.dateClicked = false;
				cal.callHandler();
			}
		}
	}
	with (Calendar) {
		removeEvent(document, "mouseup", tableMouseUp);
		removeEvent(document, "mouseover", tableMouseOver);
		removeEvent(document, "mousemove", tableMouseOver);
		cal._hideCombos();
		_C = null;
		return stopEvent(ev);
	}
};

Calendar.tableMouseOver = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return;
	}
	var el = cal.activeDiv;
	var target = Calendar.getTargetElement(ev);
	if (target == el || target.parentNode == el) {
		Calendar.addClass(el, "hilite active");
		Calendar.addClass(el.parentNode, "rowhilite");
	} else {
		if (typeof el.navtype == "undefined" || (el.navtype != 50 && (el.navtype == 0 || Math.abs(el.navtype) > 2)))
			Calendar.removeClass(el, "active");
		Calendar.removeClass(el, "hilite");
		Calendar.removeClass(el.parentNode, "rowhilite");
	}
	ev || (ev = window.event);
	if (el.navtype == 50 && target != el) {
		var pos = Calendar.getAbsolutePos(el);
		var w = el.offsetWidth;
		var x = ev.clientX;
		var dx;
		var decrease = true;
		if (x > pos.x + w) {
			dx = x - pos.x - w;
			decrease = false;
		} else
			dx = pos.x - x;

		if (dx < 0) dx = 0;
		var range = el._range;
		var current = el._current;
		var count = Math.floor(dx / 10) % range.length;
		for (var i = range.length; --i >= 0;)
			if (range[i] == current)
				break;
		while (count-- > 0)
			if (decrease) {
				if (--i < 0)
					i = range.length - 1;
			} else if ( ++i >= range.length )
				i = 0;
		var newval = range[i];
		el.innerHTML = newval;

		cal.onUpdateTime();
	}
	var mon = Calendar.findMonth(target);
	if (mon) {
		if (mon.month != cal.date.getMonth()) {
			if (cal.hilitedMonth) {
				Calendar.removeClass(cal.hilitedMonth, "hilite");
			}
			Calendar.addClass(mon, "hilite");
			cal.hilitedMonth = mon;
		} else if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
	} else {
		if (cal.hilitedMonth) {
			Calendar.removeClass(cal.hilitedMonth, "hilite");
		}
		var year = Calendar.findYear(target);
		if (year) {
			if (year.year != cal.date.getFullYear()) {
				if (cal.hilitedYear) {
					Calendar.removeClass(cal.hilitedYear, "hilite");
				}
				Calendar.addClass(year, "hilite");
				cal.hilitedYear = year;
			} else if (cal.hilitedYear) {
				Calendar.removeClass(cal.hilitedYear, "hilite");
			}
		} else if (cal.hilitedYear) {
			Calendar.removeClass(cal.hilitedYear, "hilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.tableMouseDown = function (ev) {
	if (Calendar.getTargetElement(ev) == Calendar.getElement(ev)) {
		return Calendar.stopEvent(ev);
	}
};

Calendar.calDragIt = function (ev) {
	var cal = Calendar._C;
	if (!(cal && cal.dragging)) {
		return false;
	}
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posX = ev.pageX;
		posY = ev.pageY;
	}
	cal.hideShowCovered();
	var st = cal.element.style;
	st.left = (posX - cal.xOffs) + "px";
	st.top = (posY - cal.yOffs) + "px";
	return Calendar.stopEvent(ev);
};

Calendar.calDragEnd = function (ev) {
	var cal = Calendar._C;
	if (!cal) {
		return false;
	}
	cal.dragging = false;
	with (Calendar) {
		removeEvent(document, "mousemove", calDragIt);
		removeEvent(document, "mouseup", calDragEnd);
		tableMouseUp(ev);
	}
	cal.hideShowCovered();
};

Calendar.dayMouseDown = function(ev) {
	var el = Calendar.getElement(ev);
	if (el.disabled) {
		return false;
	}
	var cal = el.calendar;
	cal.activeDiv = el;
	Calendar._C = cal;
	if (el.navtype != 300) with (Calendar) {
		if (el.navtype == 50) {
			el._current = el.innerHTML;
			addEvent(document, "mousemove", tableMouseOver);
		} else
			addEvent(document, Calendar.is_ie5 ? "mousemove" : "mouseover", tableMouseOver);
		addClass(el, "hilite active");
		addEvent(document, "mouseup", tableMouseUp);
	} else if (cal.isPopup) {
		cal._dragStart(ev);
	}
	if (el.navtype == -1 || el.navtype == 1) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout("Calendar.showMonthsCombo()", 250);
	} else if (el.navtype == -2 || el.navtype == 2) {
		if (cal.timeout) clearTimeout(cal.timeout);
		cal.timeout = setTimeout((el.navtype > 0) ? "Calendar.showYearsCombo(true)" : "Calendar.showYearsCombo(false)", 250);
	} else {
		cal.timeout = null;
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseDblClick = function(ev) {
	Calendar.cellClick(Calendar.getElement(ev), ev || window.event);
	if (Calendar.is_ie) {
		document.selection.empty();
	}
};

Calendar.dayMouseOver = function(ev) {
	var el = Calendar.getElement(ev);
	if (Calendar.isRelated(el, ev) || Calendar._C || el.disabled) {
		return false;
	}
	if (el.ttip) {
		if (el.ttip.substr(0, 1) == "_") {
			el.ttip = el.caldate.print(el.calendar.ttDateFormat) + el.ttip.substr(1);
		}
		el.calendar.tooltips.innerHTML = el.ttip;
	}
	if (el.navtype != 300) {
		Calendar.addClass(el, "hilite");
		if (el.caldate) {
			Calendar.addClass(el.parentNode, "rowhilite");
		}
	}
	return Calendar.stopEvent(ev);
};

Calendar.dayMouseOut = function(ev) {
	with (Calendar) {
		var el = getElement(ev);
		if (isRelated(el, ev) || _C || el.disabled)
			return false;
		removeClass(el, "hilite");
		if (el.caldate)
			removeClass(el.parentNode, "rowhilite");
		if (el.calendar)
			el.calendar.tooltips.innerHTML = _TT["SEL_DATE"];
		return stopEvent(ev);
	}
};

/**
 *  A generic "click" handler :) handles all types of buttons defined in this
 *  calendar.
 */
Calendar.cellClick = function(el, ev) {
	var cal = el.calendar;
	var closing = false;
	var newdate = false;
	var date = null;
	if (typeof el.navtype == "undefined") {
		if (cal.currentDateEl) {
			Calendar.removeClass(cal.currentDateEl, "selected");
			Calendar.addClass(el, "selected");
			closing = (cal.currentDateEl == el);
			if (!closing) {
				cal.currentDateEl = el;
			}
		}
		cal.date.setDateOnly(el.caldate);
		date = cal.date;
		var other_month = !(cal.dateClicked = !el.otherMonth);
		if (!other_month && !cal.currentDateEl)
			cal._toggleMultipleDate(new Date(date));
		else
			newdate = !el.disabled;
		// a date was clicked
		if (other_month)
			cal._init(cal.firstDayOfWeek, date);
	} else {
		if (el.navtype == 200) {
			Calendar.removeClass(el, "hilite");
			cal.callCloseHandler();
			return;
		}
		date = new Date(cal.date);
		if (el.navtype == 0)
			date.setDateOnly(new Date()); // TODAY
		// unless "today" was clicked, we assume no date was clicked so
		// the selected handler will know not to close the calenar when
		// in single-click mode.
		// cal.dateClicked = (el.navtype == 0);
		cal.dateClicked = false;
		var year = date.getFullYear();
		var mon = date.getMonth();
		function setMonth(m) {
			var day = date.getDate();
			var max = date.getMonthDays(m);
			if (day > max) {
				date.setDate(max);
			}
			date.setMonth(m);
		};
		switch (el.navtype) {
		    case 400:
			Calendar.removeClass(el, "hilite");
			var text = Calendar._TT["ABOUT"];
			if (typeof text != "undefined") {
				text += cal.showsTime ? Calendar._TT["ABOUT_TIME"] : "";
			} else {
				// FIXME: this should be removed as soon as lang files get updated!
				text = "Help and about box text is not translated into this language.\n" +
					"If you know this language and you feel generous please update\n" +
					"the corresponding file in \"lang\" subdir to match calendar-en.js\n" +
					"and send it back to <mihai_bazon@yahoo.com> to get it into the distribution  ;-)\n\n" +
					"Thank you!\n" +
					"http://dynarch.com/mishoo/calendar.epl\n";
			}
			alert(text);
			return;
		    case -2:
			if (year > cal.minYear) {
				date.setFullYear(year - 1);
			}
			break;
		    case -1:
			if (mon > 0) {
				setMonth(mon - 1);
			} else if (year-- > cal.minYear) {
				date.setFullYear(year);
				setMonth(11);
			}
			break;
		    case 1:
			if (mon < 11) {
				setMonth(mon + 1);
			} else if (year < cal.maxYear) {
				date.setFullYear(year + 1);
				setMonth(0);
			}
			break;
		    case 2:
			if (year < cal.maxYear) {
				date.setFullYear(year + 1);
			}
			break;
		    case 100:
			cal.setFirstDayOfWeek(el.fdow);
			return;
		    case 50:
			var range = el._range;
			var current = el.innerHTML;
			for (var i = range.length; --i >= 0;)
				if (range[i] == current)
					break;
			if (ev && ev.shiftKey) {
				if (--i < 0)
					i = range.length - 1;
			} else if ( ++i >= range.length )
				i = 0;
			var newval = range[i];
			el.innerHTML = newval;
			cal.onUpdateTime();
			return;
		    case 0:
			// TODAY will bring us here
			if ((typeof cal.getDateStatus == "function") &&
			    cal.getDateStatus(date, date.getFullYear(), date.getMonth(), date.getDate())) {
				return false;
			}
			break;
		}
		if (!date.equalsTo(cal.date)) {
			cal.setDate(date);
			newdate = true;
		} else if (el.navtype == 0)
			newdate = closing = true;
	}
	if (newdate) {
		ev && cal.callHandler();
	}
	if (closing) {
		Calendar.removeClass(el, "hilite");
		ev && cal.callCloseHandler();
	}
};

// END: CALENDAR STATIC FUNCTIONS

// BEGIN: CALENDAR OBJECT FUNCTIONS

/**
 *  This function creates the calendar inside the given parent.  If _par is
 *  null than it creates a popup calendar inside the BODY element.  If _par is
 *  an element, be it BODY, then it creates a non-popup calendar (still
 *  hidden).  Some properties need to be set before calling this function.
 */
Calendar.prototype.create = function (_par) {
	var parent = null;
	if (! _par) {
		// default parent is the document body, in which case we create
		// a popup calendar.
		parent = document.getElementsByTagName("body")[0];
		this.isPopup = true;
	} else {
		parent = _par;
		this.isPopup = false;
	}
	this.date = this.dateStr ? new Date(this.dateStr) : new Date();

	var table = Calendar.createElement("table");
	this.table = table;
	table.cellSpacing = 0;
	table.cellPadding = 0;
	table.calendar = this;
	Calendar.addEvent(table, "mousedown", Calendar.tableMouseDown);

	var div = Calendar.createElement("div");
	this.element = div;
	div.className = "calendar";
	if (this.isPopup) {
		div.style.position = "absolute";
		div.style.display = "none";
	}
	div.appendChild(table);

	var thead = Calendar.createElement("thead", table);
	var cell = null;
	var row = null;

	var cal = this;
	var hh = function (text, cs, navtype) {
		cell = Calendar.createElement("td", row);
		cell.colSpan = cs;
		cell.className = "button";
		if (navtype != 0 && Math.abs(navtype) <= 2)
			cell.className += " nav";
		Calendar._add_evs(cell);
		cell.calendar = cal;
		cell.navtype = navtype;
		cell.innerHTML = "<div unselectable='on'>" + text + "</div>";
		return cell;
	};

	row = Calendar.createElement("tr", thead);
	var title_length = 6;
	(this.isPopup) && --title_length;
	(this.weekNumbers) && ++title_length;

	hh("?", 1, 400).ttip = Calendar._TT["INFO"];
	this.title = hh("", title_length, 300);
	this.title.className = "title";
	if (this.isPopup) {
		this.title.ttip = Calendar._TT["DRAG_TO_MOVE"];
		this.title.style.cursor = "move";
		hh("&#x00d7;", 1, 200).ttip = Calendar._TT["CLOSE"];
	}

	row = Calendar.createElement("tr", thead);
	row.className = "headrow";

	this._nav_py = hh("&#x00ab;", 1, -2);
	this._nav_py.ttip = Calendar._TT["PREV_YEAR"];

	this._nav_pm = hh("&#x2039;", 1, -1);
	this._nav_pm.ttip = Calendar._TT["PREV_MONTH"];

	this._nav_now = hh(Calendar._TT["TODAY"], this.weekNumbers ? 4 : 3, 0);
	this._nav_now.ttip = Calendar._TT["GO_TODAY"];

	this._nav_nm = hh("&#x203a;", 1, 1);
	this._nav_nm.ttip = Calendar._TT["NEXT_MONTH"];

	this._nav_ny = hh("&#x00bb;", 1, 2);
	this._nav_ny.ttip = Calendar._TT["NEXT_YEAR"];

	// day names
	row = Calendar.createElement("tr", thead);
	row.className = "daynames";
	if (this.weekNumbers) {
		cell = Calendar.createElement("td", row);
		cell.className = "name wn";
		cell.innerHTML = Calendar._TT["WK"];
	}
	for (var i = 7; i > 0; --i) {
		cell = Calendar.createElement("td", row);
		if (!i) {
			cell.navtype = 100;
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}
	this.firstdayname = (this.weekNumbers) ? row.firstChild.nextSibling : row.firstChild;
	this._displayWeekdays();

	var tbody = Calendar.createElement("tbody", table);
	this.tbody = tbody;

	for (i = 6; i > 0; --i) {
		row = Calendar.createElement("tr", tbody);
		if (this.weekNumbers) {
			cell = Calendar.createElement("td", row);
		}
		for (var j = 7; j > 0; --j) {
			cell = Calendar.createElement("td", row);
			cell.calendar = this;
			Calendar._add_evs(cell);
		}
	}

	if (this.showsTime) {
		row = Calendar.createElement("tr", tbody);
		row.className = "time";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = 2;
		cell.innerHTML = Calendar._TT["TIME"] || "&nbsp;";

		cell = Calendar.createElement("td", row);
		cell.className = "time";
		cell.colSpan = this.weekNumbers ? 4 : 3;

		(function(){
			function makeTimePart(className, init, range_start, range_end) {
				var part = Calendar.createElement("span", cell);
				part.className = className;
				part.innerHTML = init;
				part.calendar = cal;
				part.ttip = Calendar._TT["TIME_PART"];
				part.navtype = 50;
				part._range = [];
				if (typeof range_start != "number")
					part._range = range_start;
				else {
					for (var i = range_start; i <= range_end; ++i) {
						var txt;
						if (i < 10 && range_end >= 10) txt = '0' + i;
						else txt = '' + i;
						part._range[part._range.length] = txt;
					}
				}
				Calendar._add_evs(part);
				return part;
			};
			var hrs = cal.date.getHours();
			var mins = cal.date.getMinutes();
			var t12 = !cal.time24;
			var pm = (hrs > 12);
			if (t12 && pm) hrs -= 12;
			var H = makeTimePart("hour", hrs, t12 ? 1 : 0, t12 ? 12 : 23);
			var span = Calendar.createElement("span", cell);
			span.innerHTML = ":";
			span.className = "colon";
			var M = makeTimePart("minute", mins, 0, 59);
			var AP = null;
			cell = Calendar.createElement("td", row);
			cell.className = "time";
			cell.colSpan = 2;
			if (t12)
				AP = makeTimePart("ampm", pm ? "pm" : "am", ["am", "pm"]);
			else
				cell.innerHTML = "&nbsp;";

			cal.onSetTime = function() {
				var pm, hrs = this.date.getHours(),
					mins = this.date.getMinutes();
				if (t12) {
					pm = (hrs >= 12);
					if (pm) hrs -= 12;
					if (hrs == 0) hrs = 12;
					AP.innerHTML = pm ? "pm" : "am";
				}
				H.innerHTML = (hrs < 10) ? ("0" + hrs) : hrs;
				M.innerHTML = (mins < 10) ? ("0" + mins) : mins;
			};

			cal.onUpdateTime = function() {
				var date = this.date;
				var h = parseInt(H.innerHTML, 10);
				if (t12) {
					if (/pm/i.test(AP.innerHTML) && h < 12)
						h += 12;
					else if (/am/i.test(AP.innerHTML) && h == 12)
						h = 0;
				}
				var d = date.getDate();
				var m = date.getMonth();
				var y = date.getFullYear();
				date.setHours(h);
				date.setMinutes(parseInt(M.innerHTML, 10));
				date.setFullYear(y);
				date.setMonth(m);
				date.setDate(d);
				this.dateClicked = false;
				this.callHandler();
			};
		})();
	} else {
		this.onSetTime = this.onUpdateTime = function() {};
	}

	var tfoot = Calendar.createElement("tfoot", table);

	row = Calendar.createElement("tr", tfoot);
	row.className = "footrow";

	cell = hh(Calendar._TT["SEL_DATE"], this.weekNumbers ? 8 : 7, 300);
	cell.className = "ttip";
	if (this.isPopup) {
		cell.ttip = Calendar._TT["DRAG_TO_MOVE"];
		cell.style.cursor = "move";
	}
	this.tooltips = cell;

	div = Calendar.createElement("div", this.element);
	this.monthsCombo = div;
	div.className = "combo";
	for (i = 0; i < Calendar._MN.length; ++i) {
		var mn = Calendar.createElement("div");
		mn.className = Calendar.is_ie ? "label-IEfix" : "label";
		mn.month = i;
		mn.innerHTML = Calendar._SMN[i];
		div.appendChild(mn);
	}

	div = Calendar.createElement("div", this.element);
	this.yearsCombo = div;
	div.className = "combo";
	for (i = 12; i > 0; --i) {
		var yr = Calendar.createElement("div");
		yr.className = Calendar.is_ie ? "label-IEfix" : "label";
		div.appendChild(yr);
	}

	this._init(this.firstDayOfWeek, this.date);
	parent.appendChild(this.element);
};

/** keyboard navigation, only for popup calendars */
Calendar._keyEvent = function(ev) {
	var cal = window._dynarch_popupCalendar;
	if (!cal || cal.multiple)
		return false;
	(Calendar.is_ie) && (ev = window.event);
	var act = (Calendar.is_ie || ev.type == "keypress"),
		K = ev.keyCode;
	if (ev.ctrlKey) {
		switch (K) {
		    case 37: // KEY left
			act && Calendar.cellClick(cal._nav_pm);
			break;
		    case 38: // KEY up
			act && Calendar.cellClick(cal._nav_py);
			break;
		    case 39: // KEY right
			act && Calendar.cellClick(cal._nav_nm);
			break;
		    case 40: // KEY down
			act && Calendar.cellClick(cal._nav_ny);
			break;
		    default:
			return false;
		}
	} else switch (K) {
	    case 32: // KEY space (now)
		Calendar.cellClick(cal._nav_now);
		break;
	    case 27: // KEY esc
		act && cal.callCloseHandler();
		break;
	    case 37: // KEY left
	    case 38: // KEY up
	    case 39: // KEY right
	    case 40: // KEY down
		if (act) {
			var prev, x, y, ne, el, step;
			prev = K == 37 || K == 38;
			step = (K == 37 || K == 39) ? 1 : 7;
			function setVars() {
				el = cal.currentDateEl;
				var p = el.pos;
				x = p & 15;
				y = p >> 4;
				ne = cal.ar_days[y][x];
			};setVars();
			function prevMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() - step);
				cal.setDate(date);
			};
			function nextMonth() {
				var date = new Date(cal.date);
				date.setDate(date.getDate() + step);
				cal.setDate(date);
			};
			while (1) {
				switch (K) {
				    case 37: // KEY left
					if (--x >= 0)
						ne = cal.ar_days[y][x];
					else {
						x = 6;
						K = 38;
						continue;
					}
					break;
				    case 38: // KEY up
					if (--y >= 0)
						ne = cal.ar_days[y][x];
					else {
						prevMonth();
						setVars();
					}
					break;
				    case 39: // KEY right
					if (++x < 7)
						ne = cal.ar_days[y][x];
					else {
						x = 0;
						K = 40;
						continue;
					}
					break;
				    case 40: // KEY down
					if (++y < cal.ar_days.length)
						ne = cal.ar_days[y][x];
					else {
						nextMonth();
						setVars();
					}
					break;
				}
				break;
			}
			if (ne) {
				if (!ne.disabled)
					Calendar.cellClick(ne);
				else if (prev)
					prevMonth();
				else
					nextMonth();
			}
		}
		break;
	    case 13: // KEY enter
		if (act)
			Calendar.cellClick(cal.currentDateEl, ev);
		break;
	    default:
		return false;
	}
	return Calendar.stopEvent(ev);
};

/**
 *  (RE)Initializes the calendar to the given date and firstDayOfWeek
 */
Calendar.prototype._init = function (firstDayOfWeek, date) {
	var today = new Date(),
		TY = today.getFullYear(),
		TM = today.getMonth(),
		TD = today.getDate();
	this.table.style.visibility = "hidden";
	var year = date.getFullYear();
	if (year < this.minYear) {
		year = this.minYear;
		date.setFullYear(year);
	} else if (year > this.maxYear) {
		year = this.maxYear;
		date.setFullYear(year);
	}
	this.firstDayOfWeek = firstDayOfWeek;
	this.date = new Date(date);
	var month = date.getMonth();
	var mday = date.getDate();
	var no_days = date.getMonthDays();

	// calendar voodoo for computing the first day that would actually be
	// displayed in the calendar, even if it's from the previous month.
	// WARNING: this is magic. ;-)
	date.setDate(1);
	var day1 = (date.getDay() - this.firstDayOfWeek) % 7;
	if (day1 < 0)
		day1 += 7;
	date.setDate(-day1);
	date.setDate(date.getDate() + 1);

	var row = this.tbody.firstChild;
	var MN = Calendar._SMN[month];
	var ar_days = this.ar_days = new Array();
	var weekend = Calendar._TT["WEEKEND"];
	var dates = this.multiple ? (this.datesCells = {}) : null;
	for (var i = 0; i < 6; ++i, row = row.nextSibling) {
		var cell = row.firstChild;
		if (this.weekNumbers) {
			cell.className = "day wn";
			cell.innerHTML = date.getWeekNumber();
			cell = cell.nextSibling;
		}
		row.className = "daysrow";
		var hasdays = false, iday, dpos = ar_days[i] = [];
		for (var j = 0; j < 7; ++j, cell = cell.nextSibling, date.setDate(iday + 1)) {
			iday = date.getDate();
			var wday = date.getDay();
			cell.className = "day";
			cell.pos = i << 4 | j;
			dpos[j] = cell;
			var current_month = (date.getMonth() == month);
			if (!current_month) {
				if (this.showsOtherMonths) {
					cell.className += " othermonth";
					cell.otherMonth = true;
				} else {
					cell.className = "emptycell";
					cell.innerHTML = "&nbsp;";
					cell.disabled = true;
					continue;
				}
			} else {
				cell.otherMonth = false;
				hasdays = true;
			}
			cell.disabled = false;
			cell.innerHTML = this.getDateText ? this.getDateText(date, iday) : iday;
			if (dates)
				dates[date.print("%Y%m%d")] = cell;
			if (this.getDateStatus) {
				var status = this.getDateStatus(date, year, month, iday);
				if (this.getDateToolTip) {
					var toolTip = this.getDateToolTip(date, year, month, iday);
					if (toolTip)
						cell.title = toolTip;
				}
				if (status === true) {
					cell.className += " disabled";
					cell.disabled = true;
				} else {
					if (/disabled/i.test(status))
						cell.disabled = true;
					cell.className += " " + status;
				}
			}
			if (!cell.disabled) {
				cell.caldate = new Date(date);
				cell.ttip = "_";
				if (!this.multiple && current_month
				    && iday == mday && this.hiliteToday) {
					cell.className += " selected";
					this.currentDateEl = cell;
				}
				if (date.getFullYear() == TY &&
				    date.getMonth() == TM &&
				    iday == TD) {
					cell.className += " today";
					cell.ttip += Calendar._TT["PART_TODAY"];
				}
				if (weekend.indexOf(wday.toString()) != -1)
					cell.className += cell.otherMonth ? " oweekend" : " weekend";
			}
		}
		if (!(hasdays || this.showsOtherMonths))
			row.className = "emptyrow";
	}
	this.title.innerHTML = Calendar._MN[month] + ", " + year;
	this.onSetTime();
	this.table.style.visibility = "visible";
	this._initMultipleDates();
	// PROFILE
	// this.tooltips.innerHTML = "Generated in " + ((new Date()) - today) + " ms";
};

Calendar.prototype._initMultipleDates = function() {
	if (this.multiple) {
		for (var i in this.multiple) {
			var cell = this.datesCells[i];
			var d = this.multiple[i];
			if (!d)
				continue;
			if (cell)
				cell.className += " selected";
		}
	}
};

Calendar.prototype._toggleMultipleDate = function(date) {
	if (this.multiple) {
		var ds = date.print("%Y%m%d");
		var cell = this.datesCells[ds];
		if (cell) {
			var d = this.multiple[ds];
			if (!d) {
				Calendar.addClass(cell, "selected");
				this.multiple[ds] = date;
			} else {
				Calendar.removeClass(cell, "selected");
				delete this.multiple[ds];
			}
		}
	}
};

Calendar.prototype.setDateToolTipHandler = function (unaryFunction) {
	this.getDateToolTip = unaryFunction;
};

/**
 *  Calls _init function above for going to a certain date (but only if the
 *  date is different than the currently selected one).
 */
Calendar.prototype.setDate = function (date) {
	if (!date.equalsTo(this.date)) {
		this._init(this.firstDayOfWeek, date);
	}
};

/**
 *  Refreshes the calendar.  Useful if the "disabledHandler" function is
 *  dynamic, meaning that the list of disabled date can change at runtime.
 *  Just * call this function if you think that the list of disabled dates
 *  should * change.
 */
Calendar.prototype.refresh = function () {
	this._init(this.firstDayOfWeek, this.date);
};

/** Modifies the "firstDayOfWeek" parameter (pass 0 for Synday, 1 for Monday, etc.). */
Calendar.prototype.setFirstDayOfWeek = function (firstDayOfWeek) {
	this._init(firstDayOfWeek, this.date);
	this._displayWeekdays();
};

/**
 *  Allows customization of what dates are enabled.  The "unaryFunction"
 *  parameter must be a function object that receives the date (as a JS Date
 *  object) and returns a boolean value.  If the returned value is true then
 *  the passed date will be marked as disabled.
 */
Calendar.prototype.setDateStatusHandler = Calendar.prototype.setDisabledHandler = function (unaryFunction) {
	this.getDateStatus = unaryFunction;
};

/** Customization of allowed year range for the calendar. */
Calendar.prototype.setRange = function (a, z) {
	this.minYear = a;
	this.maxYear = z;
};

/** Calls the first user handler (selectedHandler). */
Calendar.prototype.callHandler = function () {
	if (this.onSelected) {
		this.onSelected(this, this.date.print(this.dateFormat));
	}
};

/** Calls the second user handler (closeHandler). */
Calendar.prototype.callCloseHandler = function () {
	if (this.onClose) {
		this.onClose(this);
	}
	this.hideShowCovered();
};

/** Removes the calendar object from the DOM tree and destroys it. */
Calendar.prototype.destroy = function () {
	var el = this.element.parentNode;
	el.removeChild(this.element);
	Calendar._C = null;
	window._dynarch_popupCalendar = null;
};

/**
 *  Moves the calendar element to a different section in the DOM tree (changes
 *  its parent).
 */
Calendar.prototype.reparent = function (new_parent) {
	var el = this.element;
	el.parentNode.removeChild(el);
	new_parent.appendChild(el);
};

// This gets called when the user presses a mouse button anywhere in the
// document, if the calendar is shown.  If the click was outside the open
// calendar this function closes it.
Calendar._checkCalendar = function(ev) {
	var calendar = window._dynarch_popupCalendar;
	if (!calendar) {
		return false;
	}
	var el = Calendar.is_ie ? Calendar.getElement(ev) : Calendar.getTargetElement(ev);
	for (; el != null && el != calendar.element; el = el.parentNode);
	if (el == null) {
		// calls closeHandler which should hide the calendar.
		window._dynarch_popupCalendar.callCloseHandler();
		return Calendar.stopEvent(ev);
	}
};

/** Shows the calendar. */
Calendar.prototype.show = function () {
	var rows = this.table.getElementsByTagName("tr");
	for (var i = rows.length; i > 0;) {
		var row = rows[--i];
		Calendar.removeClass(row, "rowhilite");
		var cells = row.getElementsByTagName("td");
		for (var j = cells.length; j > 0;) {
			var cell = cells[--j];
			Calendar.removeClass(cell, "hilite");
			Calendar.removeClass(cell, "active");
		}
	}
	this.element.style.display = "block";
	this.hidden = false;
	if (this.isPopup) {
		window._dynarch_popupCalendar = this;
		Calendar.addEvent(document, "keydown", Calendar._keyEvent);
		Calendar.addEvent(document, "keypress", Calendar._keyEvent);
		Calendar.addEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.hideShowCovered();
};

/**
 *  Hides the calendar.  Also removes any "hilite" from the class of any TD
 *  element.
 */
Calendar.prototype.hide = function () {
	if (this.isPopup) {
		Calendar.removeEvent(document, "keydown", Calendar._keyEvent);
		Calendar.removeEvent(document, "keypress", Calendar._keyEvent);
		Calendar.removeEvent(document, "mousedown", Calendar._checkCalendar);
	}
	this.element.style.display = "none";
	this.hidden = true;
	this.hideShowCovered();
};

/**
 *  Shows the calendar at a given absolute position (beware that, depending on
 *  the calendar element style -- position property -- this might be relative
 *  to the parent's containing rectangle).
 */
Calendar.prototype.showAt = function (x, y) {
	var s = this.element.style;
	s.left = x + "px";
	s.top = y + "px";
	this.show();
};

/** Shows the calendar near a given element. */
Calendar.prototype.showAtElement = function (el, opts) {
	var self = this;
	var p = Calendar.getAbsolutePos(el);
	if (!opts || typeof opts != "string") {
		this.showAt(p.x, p.y + el.offsetHeight);
		return true;
	}
	function fixPosition(box) {
		if (box.x < 0)
			box.x = 0;
		if (box.y < 0)
			box.y = 0;
		var cp = document.createElement("div");
		var s = cp.style;
		s.position = "absolute";
		s.right = s.bottom = s.width = s.height = "0px";
		document.body.appendChild(cp);
		var br = Calendar.getAbsolutePos(cp);
		document.body.removeChild(cp);
		if (Calendar.is_ie) {
			br.y += document.body.scrollTop;
			br.x += document.body.scrollLeft;
		} else {
			br.y += window.scrollY;
			br.x += window.scrollX;
		}
		var tmp = box.x + box.width - br.x;
		if (tmp > 0) box.x -= tmp;
		tmp = box.y + box.height - br.y;
		if (tmp > 0) box.y -= tmp;
	};
	this.element.style.display = "block";
	Calendar.continuation_for_the_fucking_khtml_browser = function() {
		var w = self.element.offsetWidth;
		var h = self.element.offsetHeight;
		self.element.style.display = "none";
		var valign = opts.substr(0, 1);
		var halign = "l";
		if (opts.length > 1) {
			halign = opts.substr(1, 1);
		}
		// vertical alignment
		switch (valign) {
		    case "T": p.y -= h; break;
		    case "B": p.y += el.offsetHeight; break;
		    case "C": p.y += (el.offsetHeight - h) / 2; break;
		    case "t": p.y += el.offsetHeight - h; break;
		    case "b": break; // already there
		}
		// horizontal alignment
		switch (halign) {
		    case "L": p.x -= w; break;
		    case "R": p.x += el.offsetWidth; break;
		    case "C": p.x += (el.offsetWidth - w) / 2; break;
		    case "l": p.x += el.offsetWidth - w; break;
		    case "r": break; // already there
		}
		p.width = w;
		p.height = h + 40;
		self.monthsCombo.style.display = "none";
		fixPosition(p);
		self.showAt(p.x, p.y);
	};
	if (Calendar.is_khtml)
		setTimeout("Calendar.continuation_for_the_fucking_khtml_browser()", 10);
	else
		Calendar.continuation_for_the_fucking_khtml_browser();
};

/** Customizes the date format. */
Calendar.prototype.setDateFormat = function (str) {
	this.dateFormat = str;
};

/** Customizes the tooltip date format. */
Calendar.prototype.setTtDateFormat = function (str) {
	this.ttDateFormat = str;
};

/**
 *  Tries to identify the date represented in a string.  If successful it also
 *  calls this.setDate which moves the calendar to the given date.
 */
Calendar.prototype.parseDate = function(str, fmt) {
	if (!fmt)
		fmt = this.dateFormat;
	this.setDate(Date.parseDate(str, fmt));
};

Calendar.prototype.hideShowCovered = function () {
	if (!Calendar.is_ie && !Calendar.is_opera)
		return;
	function getVisib(obj){
		var value = obj.style.visibility;
		if (!value) {
			if (document.defaultView && typeof (document.defaultView.getComputedStyle) == "function") { // Gecko, W3C
				if (!Calendar.is_khtml)
					value = document.defaultView.
						getComputedStyle(obj, "").getPropertyValue("visibility");
				else
					value = '';
			} else if (obj.currentStyle) { // IE
				value = obj.currentStyle.visibility;
			} else
				value = '';
		}
		return value;
	};

	var tags = new Array("applet", "iframe", "select");
	var el = this.element;

	var p = Calendar.getAbsolutePos(el);
	var EX1 = p.x;
	var EX2 = el.offsetWidth + EX1;
	var EY1 = p.y;
	var EY2 = el.offsetHeight + EY1;

	for (var k = tags.length; k > 0; ) {
		var ar = document.getElementsByTagName(tags[--k]);
		var cc = null;

		for (var i = ar.length; i > 0;) {
			cc = ar[--i];

			p = Calendar.getAbsolutePos(cc);
			var CX1 = p.x;
			var CX2 = cc.offsetWidth + CX1;
			var CY1 = p.y;
			var CY2 = cc.offsetHeight + CY1;

			if (this.hidden || (CX1 > EX2) || (CX2 < EX1) || (CY1 > EY2) || (CY2 < EY1)) {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = cc.__msh_save_visibility;
			} else {
				if (!cc.__msh_save_visibility) {
					cc.__msh_save_visibility = getVisib(cc);
				}
				cc.style.visibility = "hidden";
			}
		}
	}
};

/** Internal function; it displays the bar with the names of the weekday. */
Calendar.prototype._displayWeekdays = function () {
	var fdow = this.firstDayOfWeek;
	var cell = this.firstdayname;
	var weekend = Calendar._TT["WEEKEND"];
	for (var i = 0; i < 7; ++i) {
		cell.className = "day name";
		var realday = (i + fdow) % 7;
		if (i) {
			cell.ttip = Calendar._TT["DAY_FIRST"].replace("%s", Calendar._DN[realday]);
			cell.navtype = 100;
			cell.calendar = this;
			cell.fdow = realday;
			Calendar._add_evs(cell);
		}
		if (weekend.indexOf(realday.toString()) != -1) {
			Calendar.addClass(cell, "weekend");
		}
		cell.innerHTML = Calendar._SDN[(i + fdow) % 7];
		cell = cell.nextSibling;
	}
};

/** Internal function.  Hides all combo boxes that might be displayed. */
Calendar.prototype._hideCombos = function () {
	this.monthsCombo.style.display = "none";
	this.yearsCombo.style.display = "none";
};

/** Internal function.  Starts dragging the element. */
Calendar.prototype._dragStart = function (ev) {
	if (this.dragging) {
		return;
	}
	this.dragging = true;
	var posX;
	var posY;
	if (Calendar.is_ie) {
		posY = window.event.clientY + document.body.scrollTop;
		posX = window.event.clientX + document.body.scrollLeft;
	} else {
		posY = ev.clientY + window.scrollY;
		posX = ev.clientX + window.scrollX;
	}
	var st = this.element.style;
	this.xOffs = posX - parseInt(st.left);
	this.yOffs = posY - parseInt(st.top);
	with (Calendar) {
		addEvent(document, "mousemove", calDragIt);
		addEvent(document, "mouseup", calDragEnd);
	}
};

// BEGIN: DATE OBJECT PATCHES

/** Adds the number of days array to the Date object. */
Date._MD = new Array(31,28,31,30,31,30,31,31,30,31,30,31);

/** Constants used for time computations */
Date.SECOND = 1000 /* milliseconds */;
Date.MINUTE = 60 * Date.SECOND;
Date.HOUR   = 60 * Date.MINUTE;
Date.DAY    = 24 * Date.HOUR;
Date.WEEK   =  7 * Date.DAY;

Date.parseDate = function(str, fmt) {
	var today = new Date();
	var y = 0;
	var m = -1;
	var d = 0;
	var a = str.split(/\W+/);
	var b = fmt.match(/%./g);
	var i = 0, j = 0;
	var hr = 0;
	var min = 0;
	for (i = 0; i < a.length; ++i) {
		if (!a[i])
			continue;
		switch (b[i]) {
		    case "%d":
		    case "%e":
			d = parseInt(a[i], 10);
			break;

		    case "%m":
			m = parseInt(a[i], 10) - 1;
			break;

		    case "%Y":
		    case "%y":
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
			break;

		    case "%b":
		    case "%B":
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { m = j; break; }
			}
			break;

		    case "%H":
		    case "%I":
		    case "%k":
		    case "%l":
			hr = parseInt(a[i], 10);
			break;

		    case "%P":
		    case "%p":
			if (/pm/i.test(a[i]) && hr < 12)
				hr += 12;
			else if (/am/i.test(a[i]) && hr >= 12)
				hr -= 12;
			break;

		    case "%M":
			min = parseInt(a[i], 10);
			break;
		}
	}
	if (isNaN(y)) y = today.getFullYear();
	if (isNaN(m)) m = today.getMonth();
	if (isNaN(d)) d = today.getDate();
	if (isNaN(hr)) hr = today.getHours();
	if (isNaN(min)) min = today.getMinutes();
	if (y != 0 && m != -1 && d != 0)
		return new Date(y, m, d, hr, min, 0);
	y = 0; m = -1; d = 0;
	for (i = 0; i < a.length; ++i) {
		if (a[i].search(/[a-zA-Z]+/) != -1) {
			var t = -1;
			for (j = 0; j < 12; ++j) {
				if (Calendar._MN[j].substr(0, a[i].length).toLowerCase() == a[i].toLowerCase()) { t = j; break; }
			}
			if (t != -1) {
				if (m != -1) {
					d = m+1;
				}
				m = t;
			}
		} else if (parseInt(a[i], 10) <= 12 && m == -1) {
			m = a[i]-1;
		} else if (parseInt(a[i], 10) > 31 && y == 0) {
			y = parseInt(a[i], 10);
			(y < 100) && (y += (y > 29) ? 1900 : 2000);
		} else if (d == 0) {
			d = a[i];
		}
	}
	if (y == 0)
		y = today.getFullYear();
	if (m != -1 && d != 0)
		return new Date(y, m, d, hr, min, 0);
	return today;
};

/** Returns the number of days in the current month */
Date.prototype.getMonthDays = function(month) {
	var year = this.getFullYear();
	if (typeof month == "undefined") {
		month = this.getMonth();
	}
	if (((0 == (year%4)) && ( (0 != (year%100)) || (0 == (year%400)))) && month == 1) {
		return 29;
	} else {
		return Date._MD[month];
	}
};

/** Returns the number of day in the year. */
Date.prototype.getDayOfYear = function() {
	var now = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var then = new Date(this.getFullYear(), 0, 0, 0, 0, 0);
	var time = now - then;
	return Math.floor(time / Date.DAY);
};

/** Returns the number of the week in year, as defined in ISO 8601. */
Date.prototype.getWeekNumber = function() {
	var d = new Date(this.getFullYear(), this.getMonth(), this.getDate(), 0, 0, 0);
	var DoW = d.getDay();
	d.setDate(d.getDate() - (DoW + 6) % 7 + 3); // Nearest Thu
	var ms = d.valueOf(); // GMT
	d.setMonth(0);
	d.setDate(4); // Thu in Week 1
	return Math.round((ms - d.valueOf()) / (7 * 864e5)) + 1;
};

/** Checks date and time equality */
Date.prototype.equalsTo = function(date) {
	return ((this.getFullYear() == date.getFullYear()) &&
		(this.getMonth() == date.getMonth()) &&
		(this.getDate() == date.getDate()) &&
		(this.getHours() == date.getHours()) &&
		(this.getMinutes() == date.getMinutes()));
};

/** Set only the year, month, date parts (keep existing time) */
Date.prototype.setDateOnly = function(date) {
	var tmp = new Date(date);
	this.setDate(1);
	this.setFullYear(tmp.getFullYear());
	this.setMonth(tmp.getMonth());
	this.setDate(tmp.getDate());
};

/** Prints the date in a string according to the given format. */
Date.prototype.print = function (str) {
	var m = this.getMonth();
	var d = this.getDate();
	var y = this.getFullYear();
	var wn = this.getWeekNumber();
	var w = this.getDay();
	var s = {};
	var hr = this.getHours();
	var pm = (hr >= 12);
	var ir = (pm) ? (hr - 12) : hr;
	var dy = this.getDayOfYear();
	if (ir == 0)
		ir = 12;
	var min = this.getMinutes();
	var sec = this.getSeconds();
	s["%a"] = Calendar._SDN[w]; // abbreviated weekday name [FIXME: I18N]
	s["%A"] = Calendar._DN[w]; // full weekday name
	s["%b"] = Calendar._SMN[m]; // abbreviated month name [FIXME: I18N]
	s["%B"] = Calendar._MN[m]; // full month name
	// FIXME: %c : preferred date and time representation for the current locale
	s["%C"] = 1 + Math.floor(y / 100); // the century number
	s["%d"] = (d < 10) ? ("0" + d) : d; // the day of the month (range 01 to 31)
	s["%e"] = d; // the day of the month (range 1 to 31)
	// FIXME: %D : american date style: %m/%d/%y
	// FIXME: %E, %F, %G, %g, %h (man strftime)
	s["%H"] = (hr < 10) ? ("0" + hr) : hr; // hour, range 00 to 23 (24h format)
	s["%I"] = (ir < 10) ? ("0" + ir) : ir; // hour, range 01 to 12 (12h format)
	s["%j"] = (dy < 100) ? ((dy < 10) ? ("00" + dy) : ("0" + dy)) : dy; // day of the year (range 001 to 366)
	s["%k"] = hr;		// hour, range 0 to 23 (24h format)
	s["%l"] = ir;		// hour, range 1 to 12 (12h format)
	s["%m"] = (m < 9) ? ("0" + (1+m)) : (1+m); // month, range 01 to 12
	s["%M"] = (min < 10) ? ("0" + min) : min; // minute, range 00 to 59
	s["%n"] = "\n";		// a newline character
	s["%p"] = pm ? "PM" : "AM";
	s["%P"] = pm ? "pm" : "am";
	// FIXME: %r : the time in am/pm notation %I:%M:%S %p
	// FIXME: %R : the time in 24-hour notation %H:%M
	s["%s"] = Math.floor(this.getTime() / 1000);
	s["%S"] = (sec < 10) ? ("0" + sec) : sec; // seconds, range 00 to 59
	s["%t"] = "\t";		// a tab character
	// FIXME: %T : the time in 24-hour notation (%H:%M:%S)
	s["%U"] = s["%W"] = s["%V"] = (wn < 10) ? ("0" + wn) : wn;
	s["%u"] = w + 1;	// the day of the week (range 1 to 7, 1 = MON)
	s["%w"] = w;		// the day of the week (range 0 to 6, 0 = SUN)
	// FIXME: %x : preferred date representation for the current locale without the time
	// FIXME: %X : preferred time representation for the current locale without the date
	s["%y"] = ('' + y).substr(2, 2); // year without the century (range 00 to 99)
	s["%Y"] = y;		// year with the century
	s["%%"] = "%";		// a literal '%' character

	var re = /%./g;
	if (!Calendar.is_ie5 && !Calendar.is_khtml)
		return str.replace(re, function (par) { return s[par] || par; });

	var a = str.match(re);
	for (var i = 0; i < a.length; i++) {
		var tmp = s[a[i]];
		if (tmp) {
			re = new RegExp(a[i], 'g');
			str = str.replace(re, tmp);
		}
	}

	return str;
};

Date.prototype.__msh_oldSetFullYear = Date.prototype.setFullYear;
Date.prototype.setFullYear = function(y) {
	var d = new Date(this);
	d.__msh_oldSetFullYear(y);
	if (d.getMonth() != this.getMonth())
		this.setDate(28);
	this.__msh_oldSetFullYear(y);
};

// END: DATE OBJECT PATCHES


// global object that remembers the calendar
window._dynarch_popupCalendar = null;

//calendar-ca.js

// ** I18N

// Calendar CA 
// Modified by openFrame

Calendar._DN = new Array
("Domingo",
 "Dilluns",
 "Dimarts",
 "Dimecres",
 "Dijous",
 "Divendres",
 "Dissabte",
 "Diumenge");

// Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary.  We give it here
// for exemplification on how one can customize the short day names, but if
// they are simply the first N letters of the full name you can simply say:
//
//   Calendar._SDN_len = N; // short day name length
//   Calendar._SMN_len = N; // short month name length
//
// If N = 3 then this is not needed either since we assume a value of 3 if not
// present, to be compatible with translation files that were written before
// this feature.

// short day names
Calendar._SDN = new Array
("Dg",
 "Dl",
 "Dm",
 "Dx",
 "Dj",
 "Dv",
 "Di",
 "Dg");

// First day of the week. "0" means display Sunday first, "1" means display
// Monday first, etc.
Calendar._FD = 1;

// full month names
Calendar._MN = new Array
("Gener",
 "Febrer",
 "Mar&ccedil;",
 "Abril",
 "Maig",
 "Juny",
 "Juliol",
 "Agost",
 "Setembre",
 "Octubre",
 "Novembre",
 "Desembre");

// short month names
Calendar._SMN = new Array
("Gen",
 "Feb",
 "Mar",
 "Abr",
 "Mai",
 "Jun",
 "Jul",
 "Ago",
 "Set",
 "Oct",
 "Nov",
 "Des");

// tooltips
Calendar._TT = {};
Calendar._TT["INFO"] = "Calendari";

Calendar._TT["ABOUT"] = "Calendari";

Calendar._TT["PREV_YEAR"] = "Any anterior";
Calendar._TT["PREV_MONTH"] = "Mes anterior";
Calendar._TT["GO_TODAY"] = "Anar a avui";
Calendar._TT["NEXT_MONTH"] = "Mes seg&uuml;ent";
Calendar._TT["NEXT_YEAR"] = "Any seg&uuml;ent";
Calendar._TT["SEL_DATE"] = "Seleccionar data";
Calendar._TT["DRAG_TO_MOVE"] = "Arrossegar per moure";
Calendar._TT["PART_TODAY"] = " (avui)";

// the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Fer %s el primer dia de la setmana";

// This may be locale-dependent.  It specifies the week-end days, as an array
// of comma-separated numbers.  The numbers are from 0 to 6: 0 means Sunday, 1
// means Monday, etc.
Calendar._TT["WEEKEND"] = "6,0";

Calendar._TT["CLOSE"] = "Tancar";
Calendar._TT["TODAY"] = "Avui";
Calendar._TT["TIME_PART"] = "(Maj&uacute;scula-)Click o arrossegar per canviar el valor";

// date formats
Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y";
Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y";

Calendar._TT["WK"] = "setm";
Calendar._TT["TIME"] = "Hora:";


// calendar-setup.js

/*  Copyright Mihai Bazon, 2002, 2003  |  http://dynarch.com/mishoo/
 * ---------------------------------------------------------------------------
 *
 * The DHTML Calendar
 *
 * Details and latest version at:
 * http://dynarch.com/mishoo/calendar.epl
 *
 * This script is distributed under the GNU Lesser General Public License.
 * Read the entire license text here: http://www.gnu.org/licenses/lgpl.html
 *
 * This file defines helper functions for setting up the calendar.  They are
 * intended to help non-programmers get a working calendar on their site
 * quickly.  This script should not be seen as part of the calendar.  It just
 * shows you what one can do with the calendar, while in the same time
 * providing a quick and simple method for setting it up.  If you need
 * exhaustive customization of the calendar creation process feel free to
 * modify this code to suit your needs (this is recommended and much better
 * than modifying calendar.js itself).
 */

// $Id$

/**
 *  This function "patches" an input field (or other element) to use a calendar
 *  widget for date selection.
 *
 *  The "params" is a single object that can have the following properties:
 *
 *    prop. name   | description
 *  -------------------------------------------------------------------------------------------------
 *   inputField    | the ID of an input field to store the date
 *   displayArea   | the ID of a DIV or other element to show the date
 *   button        | ID of a button or other element that will trigger the calendar
 *   eventName     | event that will trigger the calendar, without the "on" prefix (default: "click")
 *   ifFormat      | date format that will be stored in the input field
 *   daFormat      | the date format that will be used to display the date in displayArea
 *   singleClick   | (true/false) wether the calendar is in single click mode or not (default: true)
 *   firstDay      | numeric: 0 to 6.  "0" means display Sunday first, "1" means display Monday first, etc.
 *   align         | alignment (default: "Br"); if you don't know what's this see the calendar documentation
 *   range         | array with 2 elements.  Default: [1900, 2999] -- the range of years available
 *   weekNumbers   | (true/false) if it's true (default) the calendar will display week numbers
 *   flat          | null or element ID; if not null the calendar will be a flat calendar having the parent with the given ID
 *   flatCallback  | function that receives a JS Date object and returns an URL to point the browser to (for flat calendar)
 *   disableFunc   | function that receives a JS Date object and should return true if that date has to be disabled in the calendar
 *   onSelect      | function that gets called when a date is selected.  You don't _have_ to supply this (the default is generally okay)
 *   onClose       | function that gets called when the calendar is closed.  [default]
 *   onUpdate      | function that gets called after the date is updated in the input field.  Receives a reference to the calendar.
 *   date          | the date that the calendar will be initially displayed to
 *   showsTime     | default: false; if true the calendar will include a time selector
 *   timeFormat    | the time format; can be "12" or "24", default is "12"
 *   electric      | if true (default) then given fields/date areas are updated for each move; otherwise they're updated only on close
 *   step          | configures the step of the years in drop-down boxes; default: 2
 *   position      | configures the calendar absolute position; default: null
 *   cache         | if "true" (but default: "false") it will reuse the same calendar object, where possible
 *   showOthers    | if "true" (but default: "false") it will show days from other months too
 *
 *  None of them is required, they all have default values.  However, if you
 *  pass none of "inputField", "displayArea" or "button" you'll get a warning
 *  saying "nothing to setup".
 */
Calendar.setup = function (params) {
	function param_default(pname, def) { if (typeof params[pname] == "undefined") { params[pname] = def; } };

	param_default("inputField",     null);
	param_default("displayArea",    null);
	param_default("button",         null);
	param_default("eventName",      "click");
	param_default("ifFormat",       "%Y/%m/%d");
	param_default("daFormat",       "%Y/%m/%d");
	param_default("singleClick",    true);
	param_default("disableFunc",    null);
	param_default("dateStatusFunc", params["disableFunc"]);	// takes precedence if both are defined
	param_default("dateText",       null);
	param_default("firstDay",       null);
	param_default("align",          "Br");
	param_default("range",          [1900, 2999]);
	param_default("weekNumbers",    true);
	param_default("flat",           null);
	param_default("flatCallback",   null);
	param_default("onSelect",       null);
	param_default("onClose",        null);
	param_default("onUpdate",       null);
	param_default("date",           null);
	param_default("showsTime",      false);
	param_default("timeFormat",     "24");
	param_default("electric",       true);
	param_default("step",           2);
	param_default("position",       null);
	param_default("cache",          false);
	param_default("showOthers",     false);
	param_default("multiple",       null);

	var tmp = ["inputField", "displayArea", "button"];
	for (var i in tmp) {
		if (typeof params[tmp[i]] == "string") {
			params[tmp[i]] = document.getElementById(params[tmp[i]]);
		}
	}
	if (!(params.flat || params.multiple || params.inputField || params.displayArea || params.button)) {
		alert("Calendar.setup:\n  Nothing to setup (no fields found).  Please check your code");
		return false;
	}

	function onSelect(cal) {
		var p = cal.params;
		var update = (cal.dateClicked || p.electric);
		if (update && p.inputField) {
			p.inputField.value = cal.date.print(p.ifFormat);
			if (typeof p.inputField.onchange == "function")
				p.inputField.onchange();
		}
		if (update && p.displayArea)
			p.displayArea.innerHTML = cal.date.print(p.daFormat);
		if (update && typeof p.onUpdate == "function")
			p.onUpdate(cal);
		if (update && p.flat) {
			if (typeof p.flatCallback == "function")
				p.flatCallback(cal);
		}
		if (update && p.singleClick && cal.dateClicked)
			cal.callCloseHandler();
	};

	if (params.flat != null) {
		if (typeof params.flat == "string")
			params.flat = document.getElementById(params.flat);
		if (!params.flat) {
			alert("Calendar.setup:\n  Flat specified but can't find parent.");
			return false;
		}
		var cal = new Calendar(params.firstDay, params.date, params.onSelect || onSelect);
		cal.showsOtherMonths = params.showOthers;
		cal.showsTime = params.showsTime;
		cal.time24 = (params.timeFormat == "24");
		cal.params = params;
		cal.weekNumbers = params.weekNumbers;
		cal.setRange(params.range[0], params.range[1]);
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		if (params.ifFormat) {
			cal.setDateFormat(params.ifFormat);
		}
		if (params.inputField && typeof params.inputField.value == "string") {
			cal.parseDate(params.inputField.value);
		}
		cal.create(params.flat);
		cal.show();
		return false;
	}

	var triggerEl = params.button || params.displayArea || params.inputField;
	triggerEl["on" + params.eventName] = function() {
		var dateEl = params.inputField || params.displayArea;
		var dateFmt = params.inputField ? params.ifFormat : params.daFormat;
		var mustCreate = false;
		var cal = window.calendar;
		if (dateEl)
			params.date = Date.parseDate(dateEl.value || dateEl.innerHTML, dateFmt);
		if (!(cal && params.cache)) {
			window.calendar = cal = new Calendar(params.firstDay,
							     params.date,
							     params.onSelect || onSelect,
							     params.onClose || function(cal) { cal.hide(); });
			cal.showsTime = params.showsTime;
			cal.time24 = (params.timeFormat == "24");
			cal.weekNumbers = params.weekNumbers;
			mustCreate = true;
		} else {
			if (params.date)
				cal.setDate(params.date);
			cal.hide();
		}
		if (params.multiple) {
			cal.multiple = {};
			for (var i = params.multiple.length; --i >= 0;) {
				var d = params.multiple[i];
				var ds = d.print("%Y%m%d");
				cal.multiple[ds] = d;
			}
		}
		cal.showsOtherMonths = params.showOthers;
		cal.yearStep = params.step;
		cal.setRange(params.range[0], params.range[1]);
		cal.params = params;
		cal.setDateStatusHandler(params.dateStatusFunc);
		cal.getDateText = params.dateText;
		cal.setDateFormat(dateFmt);
		if (mustCreate)
			cal.create();
		cal.refresh();
		if (!params.position)
			cal.showAtElement(params.button || params.displayArea || params.inputField, params.align);
		else
			cal.showAt(params.position[0], params.position[1]);
		return false;
	};

	return cal;
};

// Behaviour.js

/*
   Behaviour v1.0 by Ben Nolan, June 2005. Based largely on the work
   of Simon Willison (see comments by Simon below).

   Description:
   	
   	Uses css selectors to apply javascript behaviours to enable
   	unobtrusive javascript in html documents.
   	
   Usage:   
   
	var myrules = {
		'b.someclass' : function(element){
			element.onclick = function(){
				alert(this.innerHTML);
			}
		},
		'#someid u' : function(element){
			element.onmouseover = function(){
				this.innerHTML = "BLAH!";
			}
		}
	};
	
	Behaviour.register(myrules);
	
	// Call Behaviour.apply() to re-apply the rules (if you
	// update the dom, etc).

   License:
   
   	My stuff is BSD licensed. Not sure about Simon's.
   	
   More information:
   	
   	http://ripcord.co.nz/behaviour/
   
*/   

var Behaviour = {
	list : new Array,
	
	register : function(sheet){
		Behaviour.list.push(sheet);
	},
	
	start : function(){
		Behaviour.addLoadEvent(function(){
			Behaviour.apply();
		});
	},
	
	apply : function(){
		for (h=0;sheet=Behaviour.list[h];h++){
			for (selector in sheet){
				//alert(selector);
				list = document.getElementsBySelector(selector);
				
				if (!list){
					continue;
				}

				for (i=0;element=list[i];i++){
					try{
					sheet[selector](element);
					}
					catch(e){
						alert(e.message);
					}
				}
			}
		}
	},
	
	addLoadEvent : function(func){
		var oldonload = window.onload;
		if(!window.onload){
			window.onload = func;
			return;
		}
		if (typeof window.onload != 'function') {
			window.onload = func;
		} else {
			window.onload = function() {
				if(oldonload){
					oldonload();
				}
				func();
			}
		}
	}
}

//Behaviour.start();

/*
   The following code is Copyright (C) Simon Willison 2004.

   document.getElementsBySelector(selector)
   - returns an array of element objects from the current document
     matching the CSS selector. Selectors can contain element names, 
     class names and ids and can be nested. For example:
     
       elements = document.getElementsBySelect('div#main p a.external')
     
     Will return an array of all 'a' elements with 'external' in their 
     class attribute that are contained inside 'p' elements that are 
     contained inside the 'div' element which has id="main"

   New in version 0.4: Support for CSS2 and CSS3 attribute selectors:
   See http://www.w3.org/TR/css3-selectors/#attribute-selectors

   Version 0.4 - Simon Willison, March 25th 2003
   -- Works in Phoenix 0.5, Mozilla 1.3, Opera 7, Internet Explorer 6, Internet Explorer 5 on Windows
   -- Opera 7 fails 
*/

function getAllChildren(e) {
  // Returns all children of element. Workaround required for IE5/Windows. Ugh.
  return e.all ? e.all : e.getElementsByTagName('*');
}

document.getElementsBySelector = function(selector, context) {
  // Attempt to fail gracefully in lesser browsers
  if (!document.getElementsByTagName) {
    return new Array();
  }
  // Split selector in to tokens
  var tokens = selector.split(' ');
  
  var currentContext;
  if(context){
  	currentContext=context;
  }
  else{
	currentContext= new Array(document);
  }
  for (var i = 0; i < tokens.length; i++) {
    token = tokens[i].replace(/^\s+/,'').replace(/\s+$/,'');;
    if (token.indexOf('#') > -1) {
      // Token is an ID selector
      var bits = token.split('#');
      var tagName = bits[0];
      var id = bits[1];
      var element = document.getElementById(id);
      if (tagName && element.nodeName.toLowerCase() != tagName) {
        // tag with that ID not found, return false
        return new Array();
      }
      // Set currentContext to contain just this element
      currentContext = new Array(element);
      continue; // Skip to next token
    }
    if (token.indexOf('.') > -1) {
      // Token contains a class selector
      var bits = token.split('.');
      var tagName = bits[0];
      var className = bits[1];
      if (!tagName) {
        tagName = '*';
      }
      // Get elements matching tag, filter them for class selector
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (found[k].className && found[k].className.match(new RegExp('\\b'+className+'\\b'))) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      continue; // Skip to next token
    }
    // Code to deal with attribute selectors
    if (token.match(/^(\w*)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/)) {
      var tagName = RegExp.$1;
      var attrName = RegExp.$2;
      var attrOperator = RegExp.$3;
      var attrValue = RegExp.$4;
      if (!tagName) {
        tagName = '*';
      }
      // Grab all of the tagName elements within current context
      var found = new Array;
      var foundCount = 0;
      for (var h = 0; h < currentContext.length; h++) {
        var elements;
        if (tagName == '*') {
            elements = getAllChildren(currentContext[h]);
        } else {
            elements = currentContext[h].getElementsByTagName(tagName);
        }
        for (var j = 0; j < elements.length; j++) {
          found[foundCount++] = elements[j];
        }
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      var checkFunction; // This function will be used to filter the elements
      switch (attrOperator) {
        case '=': // Equality
          checkFunction = function(e) { return (e.getAttribute(attrName) == attrValue); };
          break;
        case '~': // Match one of space seperated words 
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('\\b'+attrValue+'\\b'))); };
          break;
        case '|': // Match start with value followed by optional hyphen
          checkFunction = function(e) { return (e.getAttribute(attrName).match(new RegExp('^'+attrValue+'-?'))); };
          break;
        case '^': // Match starts with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) == 0); };
          break;
        case '$': // Match ends with value - fails with "Warning" in Opera 7
          checkFunction = function(e) { return (e.getAttribute(attrName).lastIndexOf(attrValue) == e.getAttribute(attrName).length - attrValue.length); };
          break;
        case '*': // Match ends with value
          checkFunction = function(e) { return (e.getAttribute(attrName).indexOf(attrValue) > -1); };
          break;
        default :
          // Just test for existence of attribute
          checkFunction = function(e) { return e.getAttribute(attrName); };
      }
      currentContext = new Array;
      var currentContextIndex = 0;
      for (var k = 0; k < found.length; k++) {
        if (checkFunction(found[k])) {
          currentContext[currentContextIndex++] = found[k];
        }
      }
      // alert('Attribute Selector: '+tagName+' '+attrName+' '+attrOperator+' '+attrValue);
      continue; // Skip to next token
    }
    
    if (!currentContext[0]){
    	return;
    }
    
    // If we get here, token is JUST an element (not a class or ID selector)
    tagName = token;
    var found = new Array;
    var foundCount = 0;
    for (var h = 0; h < currentContext.length; h++) {
      var elements = currentContext[h].getElementsByTagName(tagName);
      for (var j = 0; j < elements.length; j++) {
        found[foundCount++] = elements[j];
      }
    }
    currentContext = found;
  }
  return currentContext;
}

/* That revolting regular expression explained 
/^(\w+)\[(\w+)([=~\|\^\$\*]?)=?"?([^\]"]*)"?\]$/
  \---/  \---/\-------------/    \-------/
    |      |         |               |
    |      |         |           The value
    |      |    ~,|,^,$,* or =
    |   Attribute 
   Tag
*/

// ajaxtags-1.1.js

/**
 * Copyright 2005 Darren L. Spurgeon
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var AjaxJspTag = {
  Version: '@AJAXTAGS_VERSION@'
}

var isSafari = false;
var isMoz = false;
var isIE = false;

if (navigator.userAgent.indexOf("Safari") > 0) {
  isSafari = true;
  isMoz = false;
  isIE = false;
}
else if (navigator.product == "Gecko") {
  isSafari = false;
  isMoz = true;
  isIE = false;
} else {
  isSafari = false;
  isMoz = false;
  isIE = true;
}

AJAX_METHOD_UPDATER = "updater";
AJAX_METHOD_REQUEST = "request";

AJAX_DEFAULT_PARAMETER = "ajaxParameter";

AJAX_PORTLET_MAX = 1;
AJAX_PORTLET_MIN = 2;
AJAX_PORTLET_CLOSE = 3;


/* ---------------------------------------------------------------------- */
/* Example File From "_JavaScript and DHTML Cookbook"
   Published by O'Reilly & Associates
   Copyright 2003 Danny Goodman
*/

// utility function to retrieve a future expiration date in proper format;
// pass three integer parameters for the number of days, hours,
// and minutes from now you want the cookie to expire; all three
// parameters required, so use zeros where appropriate
function getExpDate(days, hours, minutes) {
  var expDate = new Date();
  if (typeof days == "number" && typeof hours == "number" && typeof hours == "number") {
    expDate.setDate(expDate.getDate() + parseInt(days));
    expDate.setHours(expDate.getHours() + parseInt(hours));
    expDate.setMinutes(expDate.getMinutes() + parseInt(minutes));
    return expDate.toGMTString();
  }
}

// utility function called by getCookie()
function getCookieVal(offset) {
  var endstr = document.cookie.indexOf (";", offset);
  if (endstr == -1) {
    endstr = document.cookie.length;
  }
  return unescape(document.cookie.substring(offset, endstr));
}

// primary function to retrieve cookie by name
function getCookie(name) {
  var arg = name + "=";
  var alen = arg.length;
  var clen = document.cookie.length;
  var i = 0;
  while (i < clen) {
    var j = i + alen;
    if (document.cookie.substring(i, j) == arg) {
      return getCookieVal(j);
    }
    i = document.cookie.indexOf(" ", i) + 1;
    if (i == 0) break;
  }
  return null;
}

// store cookie value with optional details as needed
function setCookie(name, value, expires, path, domain, secure) {
  document.cookie = name + "=" + escape (value) +
    ((expires) ? "; expires=" + expires : "") +
    ((path) ? "; path=" + path : "") +
    ((domain) ? "; domain=" + domain : "") +
    ((secure) ? "; secure" : "");
}

// remove the cookie by setting ancient expiration date
function deleteCookie(name,path,domain) {
  if (getCookie(name)) {
    document.cookie = name + "=" +
      ((path) ? "; path=" + path : "") +
      ((domain) ? "; domain=" + domain : "") +
      "; expires=Thu, 01-Jan-70 00:00:01 GMT";
  }
}
/* ---------------------------------------------------------------------- */
/* End Copyright 2003 Danny Goodman */


/* ---------------------------------------------------------------------- */
/* UTILITY FUNCTIONS
 */

/**
 * Type Detection
 */
function isAlien(a) {
  return isObject(a) && typeof a.constructor != 'function';
}

function isArray(a) {
  return isObject(a) && a.constructor == Array;
}

function isBoolean(a) {
  return typeof a == 'boolean';
}

function isEmpty(o) {
  var i, v;
  if (isObject(o)) {
    for (i in o) {
      v = o[i];
      if (isUndefined(v) && isFunction(v)) {
        return false;
      }
    }
  }
  return true;
}

function isFunction(a) {
  return typeof a == 'function';
}

function isNull(a) {
  return typeof a == 'object' && !a;
}

function isNumber(a) {
  return typeof a == 'number' && isFinite(a);
}

function isObject(a) {
  return (a && typeof a == 'object') || isFunction(a);
}

function isString(a) {
  return typeof a == 'string';
}

function isUndefined(a) {
  return typeof a == 'undefined';
}

function getPropertyByName(node, nodeName) {
  var arr = new Array();
  var items = node.getElementsByTagName("name");
  for (var i=0; i<items.length; i++) {
    if (nodeName == items[i].firstChild.nodeValue) {
      arr[0] = items[i].firstChild.nodeValue;
      arr[1] = items[i].parentNode.getElementsByTagName("value")[0].firstChild.nodeValue;
      return arr;
    }
  }
  return null;
}

function getValueForNode(node, nodeName) {
  var arr = getPropertyByName(node, nodeName);
  return arr != null ? arr[1] : null;
}

function evalBoolean(value, defaultValue) {
  if (!isNull(value) && isString(value)) {
    return ("true" == value.toLowerCase() || "yes" == value.toLowerCase()) ? "true" : "false";
  } else {
    return defaultValue == true ? "true" : "false";
  }
}

/*
 * Extract querystring from a URL
 */
function extractQueryString(url) {
  var ret = (url.indexOf('?') >= 0 && url.indexOf('?') < (url.length-1))
    ? url.substr(url.indexOf('?')+1)
    : '';
  return ret;
}

/*
 * Trim the querystring from a URL
 */
function trimQueryString(url) {
  var ret = url.indexOf('?') >= 0
    ? url.substring(0, url.indexOf('?'))
    : url;
  return ret;
}

/*
 *
 */
function delimitQueryString(qs) {
  var ret = '';
  if (qs.length > 0) {
    var params = qs.split('&');
    for (var i=0; i<params.length; i++) {
      if (i > 0) ret += ',';
      ret += params[i];
    }
  }
  return ret;
}

function getElementsByClassName(node, className) {
  var children = node.getElementsByTagName('*');
  var elements = new Array();

  for (var i = 0; i < children.length; i++) {
    var child = children[i];
    var classNames = child.className.split(' ');
    for (var j = 0; j < classNames.length; j++) {
      if (classNames[j] == className) {
        elements.push(child);
        break;
      }
    }
  }
  return elements;
}

/*
 * Add multiple onLoad Events
 */
function addOnLoadEvent(func) {
  if (typeof func == 'function') {
	  var oldonload = window.onload;
	  if (typeof window.onload != 'function') {
	    window.onload = func;
	  } else {
	    window.onload = function() {
	      oldonload();
	      func();
	    }
	  }
  }
}

function getElementY(element){
  var targetTop = 0;
  if (element.offsetParent) {
    while (element.offsetParent) {
      targetTop += element.offsetTop;
      element = element.offsetParent;
    }
  } else if (element.y) {
    targetTop += element.y;
  }
  return targetTop;
}

function getElementX(element){
  var targetLeft = 0;
  if (element.offsetParent) {
    while (element.offsetParent) {
      targetLeft += element.offsetLeft;
      element = element.offsetParent;
    }
  } else if (element.x) {
    targetLeft += element.yx;
  }
  return targetLeft;
}

function findNextElementByTagName(element, tagName) {
  var children = element.getElementsByTagName('*');
  for (var i = 0; i < children.length; i++) {
    var child = children[i];
    if (child.tagName.toLowerCase() == tagName.toLowerCase())
      return child;
  }
  return null;
}


/**
 * Returns true if an element has a specified class name
 */
function hasClass(node, className) {
  if (node.className == className) {
    return true;
  }
  var reg = new RegExp('(^| )'+ className +'($| )')
  if (reg.test(node.className)) {
    return true;
  }
  return false;
}

/**
 * Emulate PHP's ereg_replace function in javascript
 */
function eregReplace(search, replace, subject) {
  return subject.replace(new RegExp(search,'g'), replace);
}

function arrayToParameterString(array) {
  var str = '';
  for (var i=0; i<array.length; i++) {
    str += (i >= 0 ? '&' : '') + array[i];
  }
  return str;
}

function replaceWithValue(sourceString, regExp, element) {
  var retString = "";
  switch (element.type) {
    case 'checkbox':
    case 'radio':
    case 'text':
    case 'textarea':
    case 'password':
    case 'hidden':
    case 'select-one':
    case 'select-multiple':
      retString = sourceString.replace(regExp, $F(element));
      break;
    default:
      retString = sourceString.replace(regExp, element.innerHTML);
      break;
  }
  return retString;
}

function decodeHtml(sourceString) {
  var retString = sourceString.replace(/&amp;/, "&");
  retString = retString.replace(/&lt;/, "<");
  retString = retString.replace(/&gt;/, ">");
  return retString;
}


/* ---------------------------------------------------------------------- */
/* AJAXJSPTAG.BASE
 */

AjaxJspTag.Base = function() {};
AjaxJspTag.Base.prototype = {

  resolveParameters: function() {
    // Strip URL of querystring and append it to parameters
    var qs = delimitQueryString(extractQueryString(this.baseUrl));
    if (this.options.parameters) {
      this.options.parameters += ',' + qs;
    } else {
      this.options.parameters = qs;
    }
    this.baseUrl = trimQueryString(this.baseUrl);
  },

  setAjaxOptions: function(ajaxOptions) {
    this.ajaxOptions = {
      asynchronous: true,
      method: 'get',
      evalScripts: true,
      onComplete: this.onRequestComplete.bind(this)
    }.extend(ajaxOptions || {});
  },

  sendRequest: function() {
    new Ajax.Request(this.baseUrl, this.ajaxOptions);
  },

  sendUpdateRequest: function(target) {
    this.ajaxUpdater = new Ajax.Updater(target, this.baseUrl, this.ajaxOptions);
  },

  sendPeriodicalUpdateRequest: function(target) {
    this.ajaxPeriodicalUpdater =
      new Ajax.PeriodicalUpdater(target, this.baseUrl, this.ajaxOptions);
  },

  onRequestComplete: function(request) {
    if (request != null && request.status == 200) {
      var xmlDoc = request.responseXML;
      if (this.options.ajaxMethod != AJAX_METHOD_UPDATER
          && this.isEmptyResponse(request.responseXML)) {
        if (this.options.emptyFunction) {
          this.options.emptyFunction(request);
        }
      } else if (this.options.ajaxMethod != AJAX_METHOD_UPDATER
                 && this.isErrorResponse(request.responseXML)) {
        this.options.errorFunction(request.responseXML);
      } else {
        this.handlerFunction(request.responseXML);
      }
    } else {
      if (this.options.errorFunction) {
        this.options.errorFunction(request);
      }
    }
  },

  isEmptyResponse: function(xml) {
    var root = xml.documentElement;
    if (root.getElementsByTagName("response").length == 0
        || root.getElementsByTagName("response")[0].getElementsByTagName("item").length == 0) {
      return true;
    }
    return false;
  },

  isErrorResponse: function(xml) {
    var root = xml.documentElement;
    if (root.nodeName == "parsererror"
        || root.getElementsByTagName("error").length == 1
        || root.getElementsByTagName("response").length == 0) {
      return true;
    }
    return false;
  },

  buildParameterString: function(parameterList) {
    var ajaxParameters = parameterList || '';
    var re = new RegExp("(\\{[^,]*\\})", 'g'); // should retrieve each {} group
    var results = ajaxParameters.match(re);
    if (results != null) {
      for (var r=0; r<results.length; r++) {
        var nre = new RegExp(results[r], 'g');
        var field = $(results[r].substring(1, results[r].length-1));
        ajaxParameters = replaceWithValue(ajaxParameters, nre, field);
      }
    }
    return ajaxParameters;
  },

  attachBehaviors: function(element, event, listener, obj) {
    if (isArray(element)) {
      for (var i=0; i<element.length; i++) {
    	if(element.attachEvent){
    		element[i].attachEvent('on'+event,listener.bindAsEventListener(obj));
    	}
    	else {
	    	element[i].addEventListener(event,listener.bindAsEventListener(obj),'true');
    	}
      }
    } else {
    	if(element.attachEvent){
    		element.attachEvent('on'+event,listener.bindAsEventListener(obj));
    	}
    	else {
	    	element.addEventListener(event,listener.bindAsEventListener(obj),'true');
    	}
    }
  }

}


/* ---------------------------------------------------------------------- */
/* SELECT TAG
 */

AjaxJspTag.Select = Class.create();
AjaxJspTag.Select.prototype =Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    this.attachBehaviors(this.options.sourceElem, this.options.eventType, this.sourceElemChanged, this);
  },

  setOptions: function(options) {
    this.options = {
      sourceElem: $(options.source),
      targetElem: $(options.target),
      eventType: options.eventType ? options.eventType : "change"
    }.extend(options || {});
  },

  populateSelect: function(xml) {
    var root = xml.documentElement;

    // reset field
    this.options.targetElem.options.length = 0;
    this.options.targetElem.disabled = false;

    // grab list of options
    var respNode = root.getElementsByTagName("response")[0];
    var items = respNode.getElementsByTagName("item");
    for (var i=0; i<items.length; i++) {
      var name = items[i].getElementsByTagName("name")[0].firstChild.nodeValue;
      var value = items[i].getElementsByTagName("value")[0].firstChild.nodeValue;
      this.options.targetElem.options[i] = new Option(name, value);
    }
  },

  sourceElemChanged: function(e) {
    this.resolveParameters();
    this.setAjaxOptions({
      parameters: arrayToParameterString(this.buildParameterString(this.options.parameters).split(','))
    });
    this.sendRequest();
  },

  handlerFunction: function(xml) {
    this.populateSelect(xml);
    if (this.options.postFunction) {
      this.options.postFunction(xml);
    }
  }

});


/* ---------------------------------------------------------------------- */
/* TOGGLE TAG
 */

AjaxJspTag.Toggle = Class.create();
AjaxJspTag.Toggle.prototype = Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    this.attachBehaviors(this.options.imageElem, this.options.eventType, this.imageElemClicked, this);
  },

  setOptions: function(options) {
    this.options = {
      imageElem: $(options.image),
      stateElem: $(options.state),
      stateXmlName: options.stateXmlName ? options.stateXmlName : "toggleState",
      eventType: options.eventType ? options.eventType : "click"
    }.extend(options || {});
  },

  toggleImage: function(xml) {
    var root = xml.documentElement;

    // set state
    var respNode = root.getElementsByTagName("response")[0];
    var toggleState = getValueForNode(respNode, this.options.stateXmlName);
    if (this.options.stateElem) {
      this.options.stateElem.value = toggleState;
    }

    // set image
    var patternRegExp = /\{0\}/;
    this.options.imageElem.src = this.options.imagePattern.replace(patternRegExp, toggleState);
  },

  imageElemClicked: function(e) {
    this.resolveParameters();
    this.setAjaxOptions({
      parameters: this.options.parameters ?
        arrayToParameterString(this.buildParameterString(this.options.parameters).split(','))
        : ''
    });
    this.sendRequest();
  },

  handlerFunction: function(xml) {
    this.toggleImage(xml);
    if (this.options.postFunction) {
      this.options.postFunction(xml);
    }
  }

});


/* ---------------------------------------------------------------------- */
/* UPDATE FIELD TAG
 */

AjaxJspTag.UpdateField = Class.create();
AjaxJspTag.UpdateField.prototype = Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    this.attachBehaviors(this.options.actionElem, this.options.eventType, this.actionElemClicked, this);
  },

  setOptions: function(options) {
    this.options = {
      sourceElem: $(options.source),
      actionElem: $(options.action),
      eventType: options.eventType ? options.eventType : "click"
    }.extend(options || {});
  },

  updateField: function(xml) {
    var root = xml.documentElement;
    var respNode = root.getElementsByTagName("response")[0];

    var items = respNode.getElementsByTagName("item");
    var targetArray = this.options.target.split(",");
    if (items.length > 0) {
      for (var i=0; i<targetArray.length; i++) {
        var value = getValueForNode(respNode, targetArray[i]);
        var field = $(targetArray[i]);
        if (value != null && field != null
            && (field.type == "text"
                || field.type == "textarea"
                || field.type == "hidden")) {
          field.value = value;
        }
      }
    }
  },

  actionElemClicked: function(e) {
    this.resolveParameters();
    this.setAjaxOptions({
      parameters: arrayToParameterString(this.buildParameterString(this.options.parameters).split(','))
    });
    this.sendRequest();
  },

  handlerFunction: function(xml) {
    this.updateField(xml);
    if (this.options.postFunction) {
      this.options.postFunction(xml);
    }
  }

});


/* ---------------------------------------------------------------------- */
/* AUTOCOMPLETE TAG
 */

AjaxJspTag.Autocomplete = Class.create();
AjaxJspTag.Autocomplete.prototype = Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    this.suggestList = new Array();
    this.currentIndex = 0;
    this.createPopup();
    this.createIframe();
    this.options.sourceElem.setAttribute("autocomplete", "off");
    this.attachBehaviors(this.options.sourceElem, this.options.eventType, this.sourceElemChanged, this);
  },

  setOptions: function(options) {
    this.options = {
      sourceElem: $(options.source),
      targetElem: $(options.target),
      eventType: options.eventType ? options.eventType : "keyup",
      appendValue: evalBoolean(options.appendValue),
      appendSeparator: options.appendSeparator || " ",
      forceSelection: evalBoolean(options.forceSelection)
    }.extend(options || {});

    // Autocomplete is unique in that we may have a progress icon
    // So, we need to hook in the resetProgressStyle function on an empty result
    var self = this;
    this.options.emptyFunction = function() {
      self.handleEmptyResult();
      if (options.emptyFunction) options.emptyFunction();
    }

    this.popupElem = "ajaxAutocompletePopup";
  },

  autocomplete: function() {
    var root = this.xml.documentElement;

    // clear contents of container (i.e., DIV tag)
    $(this.popupElem).innerHTML = "";

    var ul = document.createElement("ul");
    items = root.getElementsByTagName("item");
    for (var i=0; i<items.length; i++) {
      var name = items[i].getElementsByTagName("name")[0].firstChild.nodeValue;
      var value = items[i].getElementsByTagName("value")[0].firstChild.nodeValue;
      var li = document.createElement("li");
      var liIdAttr = document.createAttribute("id");
      li.setAttribute("id", value);
      var liText = document.createTextNode(name);
      li.appendChild(liText);
      ul.appendChild(li);
    }
    $(this.popupElem).appendChild(ul);
    $(this.popupElem).style.visibility = 'visible';

    this.setSelected();
  },

  sourceElemChanged: function(e) {
    var key = 0;
    if (e.keyCode) { key = e.keyCode; }
    else if (typeof(e.which)!= 'undefined') { key = e.which; }
    var fieldLength = $F(this.options.sourceElem).length;

    //up arrow
    if (key == 38) {
      if (this.currentIndex > 0) {
        this.suggestList[this.currentIndex].className = '';
        this.currentIndex--;
        this.suggestList[this.currentIndex].className = 'selected';
        this.suggestList[this.currentIndex].scrollIntoView(false);
      }

    //down arrow
    } else if (key == 40) {
      if(this.currentIndex < this.suggestList.length - 1) {
        this.suggestList[this.currentIndex].className = '';
        this.currentIndex++;
        this.suggestList[this.currentIndex].className = 'selected';
        this.suggestList[this.currentIndex].scrollIntoView(false);
      }

    //enter
    } else if (key == 13 && $(this.popupElem).style.visibility == 'visible') {
      this.fillField(this.suggestList[this.currentIndex]);
      Event.stop(e);
      this.executePostFunction();

    //escape
    } else if (key == 27) {
      this.hidePopup();
      Event.stop(e);

    } else {
      if (fieldLength < this.options.minimumCharacters) {
        this.hidePopup();
      } else if (key != 37 && key != 39 && key != 17 && key != 18) {
        this.resolveParameters();
        this.setAjaxOptions({
          parameters: arrayToParameterString(this.buildParameterString(this.options.parameters).split(','))
        });
        this.setProgressStyle();
        this.sendRequest();
      }
    }
  },

  fillField: function(selection) {
    this.options.sourceElem.value = decodeHtml(selection.innerHTML);
    if (this.options.appendValue == "false") {
      this.options.targetElem.value = selection.getAttribute("id");
    } else {
      if (this.options.targetElem.value.length > 0)
        this.options.targetElem.value += this.options.appendSeparator;
      this.options.targetElem.value += selection.getAttribute("id");
    }
    $(this.popupElem).style.visibility = 'hidden';
    this.hidePopup();
  },

  handleEmptyResult: function(e) {
    this.resetProgressStyle();
    if (this.options.forceSelection == "true") {
      // remove last character typed
      this.options.sourceElem.value = this.options.sourceElem.value.substr(0, this.options.sourceElem.value.length-1);
    } else {
      // simply hide the popup
      this.hidePopup();
    }
  },

  handlerFunction: function(xml) {
    this.xml = xml;
    this.resetProgressStyle();
    this.autocomplete();
  },

  executePostFunction: function() {
    if (this.options.postFunction) {
      this.options.postFunction(this.xml);
    }
  },

  createPopup: function() {
    new Insertion.Top(
      document.getElementsByTagName("body")[0],
        "<div id=\""+this.popupElem+"\" class=\""+this.options.className+"\"></div>");
  },

  hidePopup: function() {
    $(this.popupElem).style.visibility = 'hidden';
    $('layerCover').style.display = "none";
  },

  setProgressStyle: function() {
    if (this.options.progressStyle != null) {
      Element.addClassName(this.options.sourceElem, this.options.progressStyle);
    }
  },

  resetProgressStyle: function() {
    if (this.options.progressStyle != null) {
      Element.removeClassName(this.options.sourceElem, this.options.progressStyle);
    }
  },

  setSelected: function() {
    this.currentIndex = 0;
    this.suggestList = $(this.popupElem).getElementsByTagName("li");
    if ((this.suggestList.length > 1)
       || (this.suggestList.length == 1
           && this.suggestList[0].innerHTML != $F(this.options.sourceElem))) {
      this.setPopupStyles();
      for (var i = 0; i < this.suggestList.length; i++) {
        this.suggestList[i].index = i;
        this.addOptionHandlers(this.suggestList[i]);
      }
      this.suggestList[0].className = 'selected';
    } else {
      $(this.popupElem).style.visibility = 'hidden';
    }
    return null;
  },

  setPopupStyles: function() {
    var maxHeight;
    if (isIE) {
      maxHeight = 200;
    } else {
      maxHeight = window.outerHeight/3;
    }

    if ($(this.popupElem).offsetHeight < maxHeight) {
      $(this.popupElem).style.overflow = 'hidden';
    } else if (isMoz) {
      $(this.popupElem).style.maxHeight = maxHeight + 'px';
      $(this.popupElem).style.overflow = '-moz-scrollbars-vertical';
    } else {
      $(this.popupElem).style.height = maxHeight + 'px';
      $(this.popupElem).style.overflowY = 'auto';
    }
    $(this.popupElem).scrollTop = 0;
    $(this.popupElem).style.visibility = 'visible';

    $(this.popupElem).style.top = (getElementY(this.options.sourceElem)+this.options.sourceElem.offsetHeight+2) + "px";
    $(this.popupElem).style.left = getElementX(this.options.sourceElem) + "px";
    if (isIE) {
      $(this.popupElem).style.width = this.options.sourceElem.offsetWidth + "px";
    } else {
      $(this.popupElem).style.minWidth = this.options.sourceElem.offsetWidth + "px";
    }
    $(this.popupElem).style.overflow = "visible";

    // do iframe
    $('layerCover').style.top = (getElementY(this.options.sourceElem)+this.options.sourceElem.offsetHeight+2) + "px";
    $('layerCover').style.left = getElementX(this.options.sourceElem) + "px";
    $('layerCover').style.width = $(this.popupElem).offsetWidth;
    $('layerCover').style.height = $(this.popupElem).offsetHeight;
    $('layerCover').style.display = "block";
    $('layerCover').style.zIndex = 10;
    $(this.popupElem).style.zIndex = 20;
  },

  createIframe: function() {
    new Insertion.Before($(this.popupElem), "<iframe id='layerCover' style='display: none; position: absolute; top: 0; left: 0;' src='about:blank' frameborder='0' scrolling='no'></iframe>");
  },

  handleClick: function(e) {
    this.fillField(Event.element(e));
    this.executePostFunction();
  },

  handleOver: function(e) {
    this.suggestList[this.currentIndex].className = '';
    this.currentIndex = Event.element(e).index;
    this.suggestList[this.currentIndex].className = 'selected';
  },

  addOptionHandlers: function(option) {
    option.onclick = this.handleClick.bindAsEventListener(this);
    option.onmouseover = this.handleOver.bindAsEventListener(this);
  }

});


/* ---------------------------------------------------------------------- */
/* CALLOUT TAG
 */

AjaxJspTag.Callout = Class.create();
AjaxJspTag.Callout.prototype = Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    this.attachBehaviors(this.options.sourceElementList,
                         this.options.eventType,
                         this.sourceElemClicked,
                         this);
    this.createContainer();
    this.targetElem = this.constructBox();
    this.activeElem = null;
  },

  setOptions: function(options) {
    var list;
    if (options.sourceClass) {
      list = document.getElementsByClassName(options.sourceClass);
    } else {
      list = new Array();
      list.push($(options.source));
    }
    this.options = {
      sourceElementList: list,
      classNamePrefix: options.classNamePrefix ? options.classNamePrefix : "callout",
      eventType: options.eventType ? options.eventType : "click"
    }.extend(options || {});

    if (options.timeout) {
      if (Number(options.timeout) > 250)
        this.options.timeout = Number(options.timeout)
      else
        this.options.timeout = 250;
    }

    if (options.title) {
      this.options.useTitleBar = "true";
    } else if (options.useTitleBar) {
      this.options.useTitleBar = evalBoolean(options.useTitleBar);
    } else {
      this.options.useTitleBar = "false";
    }

    if (!options.boxPosition) this.options.boxPosition = "top right";
    this.calloutContainer = "calloutContainer";
    this.calloutParameter = AJAX_DEFAULT_PARAMETER;
  },

  callout: function(xml) {
    var root = xml.documentElement;

    var items = root.getElementsByTagName("item");
    if (items.length > 0) {
      var name = items[0].getElementsByTagName("name")[0].firstChild.nodeValue;
      var value = items[0].getElementsByTagName("value")[0].firstChild.nodeValue;
      // fill text (if present)
      if (this.options.useTitleBar == "true") {
        if (!this.options.title) {
          this.targetElem.childNodes[1].innerHTML = name;
        } else {
          this.targetElem.childNodes[1].innerHTML = this.options.title;
        }
        this.targetElem.childNodes[2].innerHTML = value;
      } else {
        this.targetElem.childNodes[1].innerHTML = value;
      }

      // size box
      if (isIE) {
        this.targetElem.style.width = "250px";
      } else {
        this.targetElem.style.minWidth = "250px";
      }
      this.targetElem.style.overflow = "visible";

      // bring box to front
      this.targetElem.style.display = "block";
      this.targetElem.style.visibility = "visible";

      // move box to new location
      this.moveBox(this.activeElem, this.targetElem);

      // hook events
      this.targetElem.childNodes[0].onclick = this.handleCloseClick.bindAsEventListener(this);
      window.onclick = this.checkBoxPosition.bindAsEventListener(this); // when clicked outside callout
      if (this.options.timeout) {
        if (this.timer)
          clearTimeout(this.timer);
        this.timer = setTimeout(this.handleHover.bind(this), this.options.timeout);
      }
    }
  },

  sourceElemClicked: function(e) {
    // replace unique parameter 'ajaxCallout' with inner content of containing element
    // ONLY IF we are using the class as the identifier; otherwise, treat it like a field
    this.activeElem = Event.element(e);
    this.resolveParameters();
    var ajaxParameters = this.options.parameters || '';
    var re = new RegExp("(\\{"+this.calloutParameter+"\\})", 'g');
    ajaxParameters = replaceWithValue(ajaxParameters, re, this.activeElem);
    // set the rest of the parameters generically
    this.setAjaxOptions({
      parameters: arrayToParameterString(this.buildParameterString(ajaxParameters).split(','))
    });
    this.sendRequest();
  },

  handlerFunction: function(xml) {
    this.callout(xml);
    if (this.options.postFunction) {
      this.options.postFunction(this.activeElem);
    }
  },

  createContainer: function() {
    new Insertion.Top(
      document.getElementsByTagName("body")[0],
        "<div id=\""+this.calloutContainer+"\" style=\"position: absolute; top: 0; left: 0\"></div>");
  },

  constructBox: function() {
    // create base
    var eBox = document.createElement("div");
    eBox.className = this.options.classNamePrefix+"Box";
    eBox.setAttribute("style", "position: absolute; top: 0; left: 0");
    document.documentElement.appendChild(eBox);

    // add elements
    var eClose = document.createElement("div");
    eClose.className = this.options.classNamePrefix+"Close";
    eClose.appendChild(document.createTextNode("X"));
    eBox.appendChild(eClose);

    if (this.options.useTitleBar == "true") {
      var eTitle = document.createElement("div");
      eTitle.className = this.options.classNamePrefix+"Title";
      eBox.appendChild(eTitle);
    }

    var eContent = document.createElement("div");
    eContent.className = this.options.classNamePrefix+"Content";
    eBox.appendChild(eContent);

    eBox.style.display = "none";
    $(this.calloutContainer).appendChild(eBox);
    return eBox;
  },

  moveBox: function(anchor, box) {
    box.style.position = "absolute";
    var posXY = Position.cumulativeOffset(anchor);

    if (this.options.boxPosition.indexOf("top") >= 0) {
      box.style.top = (posXY[1] - (box.offsetHeight) - 10) + "px";
    } else {
      box.style.top = (posXY[1] + (anchor.offsetHeight) + 10) + "px";
    }
    if (this.options.boxPosition.indexOf("right") >= 0) {
      box.style.left = (posXY[0] + 10) + "px";
    } else {
      box.style.left = (posXY[0] - (box.offsetWidth) - 10) + "px";
    }

    // Check for off-screen position
    if (box.offsetLeft < 0) {
      box.style.left = 0;
    }
    if (box.offsetTop < 0) {
      box.style.top = 0;
    }
  },

  handleCloseClick: function(e) {
    clearTimeout(this.timer);
    if (window.captureEvents) {
      window.releaseEvents(Event.MOUSEMOVE);
    }
    window.onmousemove = null;
    this.targetElem.style.display = "none";
  },

  checkBoxPosition: function(e) {
    var outsideContainer = false;
    var outsideSource = false;

    // evaluate if cursor is over box
    var clickX = e.clientX; // cursor X position
    var clickY = e.clientY; // cursor Y position
    var boundX1 = this.targetElem.offsetLeft;
    var boundX2 = boundX1 + this.targetElem.offsetWidth;
    var boundY1 = this.targetElem.offsetTop;
    var boundY2 = boundY1 + this.targetElem.offsetHeight;
    if (clickX < boundX1 || clickX > boundX2 || clickY < boundY1 || clickY > boundY2) {
      outsideContainer = true;
    }

    // evaluate if cursor is over source
    boundX1 = this.activeElem.offsetLeft;
    boundX2 = boundX1 + this.activeElem.offsetWidth;
    boundY1 = this.activeElem.offsetTop;
    boundY2 = boundY1 + this.activeElem.offsetHeight;

    if (clickX < boundX1 || clickX > boundX2 || clickY < boundY1 || clickY > boundY2) {
      outsideSource = true;
    }
    if (outsideContainer && outsideSource) {
      this.handleCloseClick();
    }
  },

  handleHover: function(e) {
    if (window.captureEvents) {
      window.captureEvents(Event.MOUSEMOVE);
    }
    window.onmousemove = this.checkBoxPosition.bindAsEventListener(this);
  }

});


/* ---------------------------------------------------------------------- */
/* HTML CONTENT TAG
 */

AjaxJspTag.HtmlContent = Class.create();
AjaxJspTag.HtmlContent.prototype = Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    this.attachBehaviors(this.options.sourceElementList,
                         this.options.eventType,
                         this.sourceElemClicked,
                         this);
  },

  setOptions: function(options) {
    var list;
    if (options.sourceClass) {
      list = document.getElementsByClassName(options.sourceClass);
    } else {
      list = new Array();
      list.push($(options.source));
    }
    this.options = {
      sourceElementList: list,
      targetElem: $(options.target),
      eventType: options.eventType ? options.eventType : "click",
      ajaxMethod: AJAX_METHOD_UPDATER
    }.extend(options || {});

    this.contentParameter = AJAX_DEFAULT_PARAMETER;
  },

  sourceElemClicked: function(e) {
    this.resolveParameters();

    var ajaxParameters = this.options.parameters || '';
    if (this.options.sourceClass) {
      this.activeElem = Event.element(e);
      var re = new RegExp("(\\{"+this.contentParameter+"\\})", 'g');
      ajaxParameters = replaceWithValue(ajaxParameters, re, this.activeElem);
    }
    this.setAjaxOptions({
      parameters: arrayToParameterString(this.buildParameterString(ajaxParameters).split(','))
    });

    this.sendUpdateRequest(this.options.target);
  },

  handlerFunction: function(xml) {
    if (this.options.postFunction) {
      this.options.postFunction(xml);
    }
  }

});


/* ---------------------------------------------------------------------- */
/* TAB PANEL TAG
 */

AjaxJspTag.TabPanel = Class.create();
AjaxJspTag.TabPanel.prototype = Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    this.execute();
  },

  setOptions: function(options) {
    this.options = {
      ajaxMethod: AJAX_METHOD_UPDATER
    }.extend(options || {});
  },

  execute: function() {
    this.resolveParameters();

    this.setAjaxOptions({
      parameters: arrayToParameterString(this.buildParameterString(this.options.parameters).split(','))
    });

    this.sendUpdateRequest(this.options.target);

    var ele = $(this.options.currentStyleId);
    if(ele.tagName.toLowerCase()=='a'){
    	ele = ele.parentNode;
    }
    
    //alert('ele.childNodes[0].tagName='+ele.childNodes[0].tagName+'\nele.tagName='+ele.tagName+'\nthis.options.currentStyleId='+this.options.currentStyleId+'\n$(this.options.currentStyleId).tagName='+$(this.options.currentStyleId).tagName+'\nthis.options.source.parentNode.tagName='+this.options.source.parentNode.tagName+'\nthis.options.source.tagName='+this.options.source.tagName);
    ele.removeAttribute('id');
    ele.childNodes[0].removeAttribute('id');
    if(this.options.source.tagName.toLowerCase()=='a'){
    	this.options.source.parentNode.id = this.options.currentStyleId;
    }
    this.options.source.id = this.options.currentStyleId;
  },

  handlerFunction: function(xml) {
    if (this.options.postFunction) {
      this.options.postFunction(xml);
    }
  }

});


/* ---------------------------------------------------------------------- */
/* PORTLET TAG
 */

AjaxJspTag.Portlet = Class.create();
AjaxJspTag.Portlet.prototype = Object.extend(new AjaxJspTag.Base(),{

  initialize: function(url, options) {
    this.baseUrl = url;
    this.setOptions(options);
    if (this.options.executeOnLoad == "true") {
      this.execute();
    }
    if (this.preserveState) this.checkCookie();

    // Attach events to icons if defined
    if (this.options.imageClose) {
      this.attachBehaviors(this.options.closeElement, "click", this.closePortlet, this);
    }
    if (this.options.imageRefresh) {
      this.attachBehaviors(this.options.refreshElement, "click", this.refreshPortlet, this);
    }
    if (this.options.imageMaximize && this.options.imageMinimize) {
      this.attachBehaviors(this.options.toggleElement, "click", this.togglePortlet, this);
    }
  },

  checkCookie: function() {
    // Check cookie for save state
    var cVal = getCookie("AjaxJspTag.Portlet."+this.options.source);
    if (cVal != null) {
      if (cVal == AJAX_PORTLET_MIN) {
        this.togglePortlet();
      } else if (cVal == AJAX_PORTLET_CLOSE) {
        this.closePortlet();
      }
    }
  },

  setOptions: function(options) {
    this.options = {
      ajaxMethod: AJAX_METHOD_UPDATER,
      targetElement: options.classNamePrefix+"Content",
      closeElement: getElementsByClassName($(options.source), (options.classNamePrefix+"Close"))[0],
      refreshElement: getElementsByClassName($(options.source), (options.classNamePrefix+"Refresh"))[0],
      toggleElement: getElementsByClassName($(options.source), (options.classNamePrefix+"Size"))[0],
      executeOnLoad: evalBoolean(options.executeOnLoad, true),
      preserveState: evalBoolean(options.preserveState),
      expireDays: options.expireDays || "0",
      expireHours: options.expireHours || "0",
      expireMinutes: options.expireMinutes || "0",
      isMaximized: true
    }.extend(options || {});

    if (parseInt(this.options.expireDays) > 0
        || parseInt(this.options.expireHours) > 0
        || parseInt(this.options.expireMinutes) > 0) {
      this.preserveState = true;
      this.options.expireDate = getExpDate(
        parseInt(this.options.expireDays),
        parseInt(this.options.expireHours),
        parseInt(this.options.expireMinutes));
    }

    this.autoRefreshSet = false;
  },

  execute: function() {
    this.resolveParameters();

    this.setAjaxOptions({
      frequency: this.options.refreshPeriod ? (this.options.refreshPeriod) : null,
      parameters: arrayToParameterString(this.buildParameterString(this.options.parameters).split(','))
    });

    if (this.options.refreshPeriod && this.autoRefreshSet == false) {
      this.sendPeriodicalUpdateRequest(
          getElementsByClassName($(this.options.source), this.options.targetElement)[0]);
      this.autoRefreshSet = true;
    } else {
      this.sendUpdateRequest(
          getElementsByClassName($(this.options.source), this.options.targetElement)[0]);
    }
  },

  stopAutoRefresh: function() {
    // stop auto-update if present
    if (this.ajaxPeriodicalUpdater != null
        && this.options.refreshPeriod
        && this.autoRefreshSet == true) {
      this.ajaxPeriodicalUpdater.stop();
    }
  },

  startAutoRefresh: function() {
    // stop auto-update if present
    if (this.ajaxPeriodicalUpdater != null && this.options.refreshPeriod) {
      this.ajaxPeriodicalUpdater.start();
    }
  },

  refreshPortlet: function(e) {
    // clear existing updater
    this.stopAutoRefresh();
    if (this.ajaxPeriodicalUpdater != null) {
      this.startAutoRefresh();
    } else {
      this.execute();
    }
  },

  closePortlet: function(e) {
    this.stopAutoRefresh();
    Element.remove(this.options.source);
    // Save state in cookie
    if (this.preserveState) {
      setCookie("AjaxJspTag.Portlet."+this.options.source,
        AJAX_PORTLET_CLOSE,
        this.options.expireDate);
    }
  },

  togglePortlet: function(e) {
    Element.toggle(getElementsByClassName($(this.options.source), this.options.targetElement)[0]);
    var image = this.options.toggleElement;
    if (this.options.isMaximized) {
      image.src = this.options.imageMaximize;
      this.stopAutoRefresh();
    } else {
      image.src = this.options.imageMinimize;
      this.startAutoRefresh();
    }
    this.options.isMaximized = !this.options.isMaximized;
    // Save state in cookie
    if (this.preserveState) {
      setCookie("AjaxJspTag.Portlet."+this.options.source,
        (this.options.isMaximized == true ? AJAX_PORTLET_MAX : AJAX_PORTLET_MIN),
        this.options.expireDate);
    }
  },

  handlerFunction: function(xml) {
    if (this.options.postFunction) {
      this.options.postFunction(xml);
    }
  }

});

//openFrame-ajaxtags-validation.js

var bean;
var validated = false;
var windowError = false;

var OpenFrameFormTag = {
  Version: '1.0'
}

/**
 * Prototype of String to add upper case of first letter of each word
 */
String.prototype.toProperCase = function(){
  return this.replace(/\w+/g,function(s){
    return s.charAt(0).toUpperCase() + s.substr(1);
  })
}

/**
 * Extension of Ajax tag Base
 */
 
OpenFrameFormTag.Base = function() {};
OpenFrameFormTag.Base.prototype = Object.extend(new AjaxJspTag.Base(),{
});



/******************************************************************************
 * openFrame Validation behaviour
 ******************************************************************************/
function setFocus(objectid) {
	if(document.getElementById(objectid)) {
		document.getElementById(objectid).focus();
	}
}

 
 
function errorHandling(error){
	window.alert("Error sending request to server" + error);
}

var camposConError = new Array();

function callbackValidateForm(dataFromServer,dataFromBrowser,doSubmit) {
	
    // Obtain sourceForm of previous call to callback
    var sourceForm = $(dataFromBrowser['sourceForm']);

	// Notificamos que el formulario ha terminado el submit de validacion
	OCITForms.formSubmitted(sourceForm.name);
	// KOKO esta mal con el name pq se apila el id !!!
	OCITForms.formSubmitted(sourceForm.getAttributeNode("id").value);
	resetErrors();
	var errors = dataFromServer;
	if (errors && eval(errors.errorCount)>0) {
		validated = false;
		OCITForms.setValidated(false);
		OCITForms.lockAfterSubmit(sourceForm.getAttributeNode("id").value);
		pintarErrores(sourceForm,errors.allErrors);
/*		else if(OCITForms.withErrorsPopup(dataFromBrowser['sourceForm'].name)) {
			new WindowErrores('400','', false, listaErrores, sourceForm).show();
			windowError = true;
		}*/
	} else {
		// Do a submit 
		if (sourceForm && doSubmit) {
			// Set validated to true in order to bypass validation and do submit without checkings
			validated = true;
			OCITForms.setValidated(true);
			sourceForm.submit();
		}
		// OnSubmit actions
		var onSubmit = OCITForms.onSubmitEvents(sourceForm.name);
		if(onSubmit) {
			for(var iOn=0; iOn<onSubmit.length; iOn++) {
				if(typeof onSubmit[iOn] == 'function') {
					onSubmit[iOn]();
				}
			}
		}
	}
}
 function pintarErrores(sourceForm,errors) {
		i=0;
		var businessValidation = false;
		var numErrors = errors.length;
		var listaErrores = new Array();
		var indexCampo = 0;
		for(numError=0; numError<numErrors; numError++) {
			var error = errors[numError];
			if(error.code && error.code == 'BUSSINESS_VALIDATOR_ERROR')
				businessValidation = true;
				
			if(!businessValidation) {
				// Message to show to each error
				var fieldName = error.field;
				var fieldNameError = fieldName + "Error";
			
				// Sobre cada id (puede haber varios en caso de radioButtons o checkbox
				// aplicamos la funcion que resalta los campos con errores
				// Ids de los campos con name="fieldName"
				var fieldIds = idsByName(sourceForm, fieldName);
				for(numField=0; numField<fieldIds.length; numField++) {
					OCITValidation.errorInput(fieldIds[numField], error.defaultMessage);
					camposConError[indexCampo++] = $(fieldIds[numField]);
				}
			}
	
			listaErrores[numError] = error.defaultMessage;
		
			// Process how to show field names
			//processReply(false, fieldName, fieldNameError, defaultMessage);	
			
			// Show errors in errorList div
			
			//errorRow = "<a href='javascript:void(0)' onclick=\" setFocus('" + fieldName + "')\" >" + defaultMessage + "</a>";
			//DWRUtil.addOptions('errorList',[errorRow]);	
		}
		// Abrimos la ventana de errores, si se requiere
			
		new WindowErrores(400, 300, true, listaErrores, null).show();
		windowError = true;
 }
 
 function resetErrors (){
	//DWRUtil.removeAllOptions('errorList');
	// Restauramos el estilo de todos los campos
	for(var iCampo=0;iCampo<camposConError.length;iCampo++) {
		var formElem = camposConError[iCampo];
		if(formElem && formElem.id && formElem.id != "") {
			OCITValidation.restoreClass(formElem.id);
		}
	}
	camposConError = new Array();
 }




 function mostrarErroresNegocio(listaErrores) {
		for(numError=0; numError<listaErrores.length; numError++) {
			errorRow = "<a href='javascript:void(0)'>" + listaErrores[numError] + "</a>";
			DWRUtil.addOptions('errorList',[errorRow]);	
		}
		$Visible('errorsZone');
}

function processReply(valid, id, errid, error) {
    if (valid) {
    	if ($(errid)) {
	        DWRUtil.setValue(errid, "");
	    }
        /*$(id).style.color = "black";*/
    }
    else
    {
	    if ($(errid)) {
	        DWRUtil.setValue(errid, error);
	    }
        /*$(id).style.color = "red";*/
    }
}


function validateFormDynamic(form) {
	
}
 
/******************************************************************************
 * Code to validate on client
 ******************************************************************************/
OpenFrameFormTag.ClientValidation = Class.create();
OpenFrameFormTag.ClientValidation.prototype=Object.extend(new AjaxJspTag.Base(),{

  initialize: function(options) {    
    this.setOptions(options);
    this.attachBehaviors(this.options.sourceElem, this.options.eventType, this.actionElem, this);
  },

  actionElem: function(e) {  
 	// Generate return validateValidatorName()
  	// Example: return validateAccount(this)
  	var javascriptFunction;
  	var functionName = "validate" + this.options.validatorName.toProperCase();
  	//var form = $(this.options.sourceElem);
  	//var formName = form.name;
	//javascriptFunction = functionName + "($('" + formName + "'));";  	
	javascriptFunction = functionName + "($('" + this.options.sourceName + "'));";
  	var submitValidated = eval(javascriptFunction);
  	if (!submitValidated)
  		Event.stop(e);
  },
  	
   setOptions: function(options) {
    this.options = Object.extend({
      sourceElem: $(options.source),
      sourceName: options.source,
      validatorName: $(options.validatorName),
      eventType: options.eventType ? options.eventType : "submit"      
    },options || {});
  }
});





OpenFrameFormTag.ServerValidation = Class.create();

OpenFrameFormTag.ServerValidation.prototype=Object.extend(new AjaxJspTag.Base(),{

  initialize: function(options) { 
    this.setOptions(options);
    this.attachBehaviors(this.options.sourceElem, this.options.eventType, this.actionElemClicked, this);
  },



  // Create bean with values to send to validation service
  validateFormSubmit: function(sourceForm,validatorName,doSubmit,clbkFunct) {  	
  		// Ocultamos la ventana de errores, si habia alguna
//     	if(windowError) {
     		/*if($(WindowErrores.DIV_ERROR_ID))
	     		$deleteElement(WindowErrores.DIV_ERROR_ID);
     		if($(WindowErrores.REDUCED_DIV_ID))
	     		$deleteElement(WindowErrores.REDUCED_DIV_ID);
     		if($Parent(WindowErrores.DIV_ERROR_ID)){     		
	     		window.parent.$deleteElement(WindowErrores.DIV_ERROR_ID);
	     	}
     		if($Parent(WindowErrores.REDUCED_DIV_ID))     	
	     		window.parent.$deleteElement(WindowErrores.REDUCED_DIV_ID);     				
     		windowError = false;*/
  //   	}
   //if(windowError) {
  //alert("1 "+ $(WindowErrores.DIV_ERROR_ID))
  //alert("2" + $Parent(WindowErrores.DIV_ERROR_ID))
  	if($(WindowErrores.DIV_ERROR_ID)){
  	//alert('a')
        $(WindowErrores.DIV_ERROR_ID).controller.destroy();
       }if($Parent(WindowErrores.DIV_ERROR_ID)){
        //alert('b')
        $Parent(WindowErrores.DIV_ERROR_ID).controller.destroy();}
       windowError = false;
     // }
	  //  DWREngine.setErrorHandler(errorHandling);
	    
	  	// Obtain all components in form
	  	if (sourceForm) {
	  		// form expected
	  		list = sourceForm.elements;				
	  		if (list){
  		  		bean = new Object();
				for (i=0;i<list.length;i++){	  		  	
					var element = list[i];
					if (element && element.name) {
						bean[element.name] = '';
					} 				  		
				}
			}
	  	}
	  		  		  		  	
		OCITUtils.getValues(bean);
	  		    
	    if (validatorName) {		
	        var dataFromBrowser = new Object();
		 	dataFromBrowser['sourceForm'] = sourceForm;
		 	//validationService.getValidationResults(validatorName,bean,
	        webValidationService.getWebValidationResultsReq(validatorName,bean,
		 	{
		 		callback:function(dataFromServer) {
		 			callbackValidateForm(dataFromServer,dataFromBrowser,doSubmit);
					if (!(dataFromServer && eval(dataFromServer.errorCount)>0)) {		 			
			 			if(clbkFunct){	
			
				 			clbkFunct();
				 		}
			 		}
		 		},
	 		timeout:5000
	 	}
	 );
	        
	    } 
	    
	    return false;           
  },

  validateForm: function(sourceForm,validatorName) {
	return this.validateFormSubmit(sourceForm,validatorName,true);
  },
  
  actionElemClicked: function(e) {  
	    // DWR calling
	   if (!validated) {
		   this.validateForm(this.options.sourceElem,this.options.validatorName);   
		   Event.stop(e);
   	   }
  },
  	
   setOptions: function(options) {
    this.options = Object.extend({
      sourceElem: $(options.source),
      validatorName: $(options.validatorName),
      eventType: options.eventType ? options.eventType : "submit"      
    },options || {});
  }
});

// openFrame-ajaxtags-fields.js

var OpenFrameFieldTag = {
  Version: '1.0'
}

var OpenFrameTextFieldTag = {
  Version: '1.0'
}



/**
 * Function to obtain the index of a fieldName in a form
 */
function getFormIndex (form, fieldName) {
  var found = false;
  for (var i = 0; i < form.elements.length; i++)
    if ((found = form.elements[i].name == fieldName))
      break;
  return found ? i : -1;
}


/**
 * Extension of Ajax tag Base
 */
 
OpenFrameFieldTag.Base = function() {};
OpenFrameFieldTag.Base.prototype = Object.extend(new AjaxJspTag.Base(),{
});


OpenFrameTextFieldTag.Base = function() {};
OpenFrameTextFieldTag.Base.prototype =Object.extend(new OpenFrameFieldTag.Base(),{
});


/******************************************************************************
 * openFrame Tooltips behaviour
 * Example of use  :
 * <script type="text/javascript">
 *   new OpenFrameTextFieldTag.Tooltip(
 *     {
 *           source: "subject",
 * 			 tooltipMessage: "message",
 *           tooltipTitleMessage: "title",
 * 			 tooltipOptions: "options"
 *     });
 * </script>
 ******************************************************************************/
OpenFrameFieldTag.Tooltip = Class.create();
OpenFrameFieldTag.Tooltip.prototype=Object.extend(new OpenFrameFieldTag.Base(),{
 initialize: function(options) {
    this.setOptions(options);

    if (this.options.sourceElem) {
    	var element = this.options.sourceElem;

        // Obtain associated label with 'for' attribute equals to id of this element
		var labels = document.getElementsByTagName("label");			

			
		for (var i = labels.length; --i >= 0;) {
			var l = labels[i];
			
			var forName = this.getForAttributeOfLabel(l);
			if (forName) {
				

				if (forName==element.id) {
					this.options.sourceElem = l;
					// Put cursor as help
					l.style.cursor = "help";
					// Put an href containing label
					
					var element = this.options.sourceElem;
				  	var tooltipMessage = this.options.tooltipMessage;
				  	var tooltipTitleMessage = this.options.tooltipTitleMessage;
				 	var tooltipOptions = this.options.tooltipOptions;
					
					var callTooltip = "domTT_activate(this, event";
					if (tooltipTitleMessage && tooltipTitleMessage!="") {
						callTooltip = callTooltip + ",'caption','" + tooltipTitleMessage + "'";
					}
					
					if (tooltipMessage && tooltipMessage!="") {
						callTooltip = callTooltip + ",'content','" + tooltipMessage + "'";
					} 
				
					
				
					if (tooltipOptions && tooltipOptions!="") {
						callTooltip = callTooltip + "," + tooltipOptions;
					} else {
						callTooltip = callTooltip + ",'trail','x'";		
					}
				
					callTooltip = callTooltip + ");";	
					
					var callFunction = "on" + this.options.eventType + "=\"";
					callFunction = callFunction + callTooltip
					callFunction = callFunction + "\"";
					
					l.innerHTML = "<a class='tooltip' href=\"javascript:void(0)\"" + callFunction + ">" + l.innerHTML.toString() + "</a>";														
					//alert(l.innerHTML)
				}
			}
				
		}
    }    
    	
    
  },

  /* Depending on browser the DOM of attribute 'for' of label has been defined in different attribute? */
  getForAttributeOfLabel:function(label) {
  	var forLabel = label.getAttribute("htmlFor");
	if (!forLabel) {
  		forLabel = label.getAttribute("for");  		    	
  	}
 	return forLabel;
  },


  setOptions: function(options) {
    this.options = Object.extend({
      sourceElem: $(options.source),
      eventType: options.eventType ? options.eventType : "mouseover"
    },options || {});
  }
});



/******************************************************************************
 * openFrame Calendar behaviour
 * An image with icon will be generated
 * Example of use  :
 * <script type="text/javascript">
 *   new OpenFrameTextFieldTag.Calendar(
 *     {
 *           source: "source",
 * 			 datePattern: "dd/MM/yyyy"
 *     });
 * </script>
 ******************************************************************************/
OpenFrameTextFieldTag.Calendar = Class.create();
OpenFrameTextFieldTag.Calendar.prototype=Object.extend(new OpenFrameTextFieldTag.Base(),{
 initialize: function(options) {
    this.setOptions(options);
    if (this.options.sourceElem) {
    
    	// First generate <img> tag with image
    	var sourceElemId = this.options.sourceElem.id;
    	var calendarId = sourceElemId + "-calendar";
    	var content = "<img src=\""+contextPath+"/images/framework/calendars/icon_calendar.gif\" id=\"" +  calendarId + "\"";
    	content = content + " style=\"cursor:pointer;border:0px solid;\"";
    	content = content + "/>";
    	new Insertion.After(this.options.sourceElem,content);
    	
    	var dynarchDateFormat = this.getDynarchDateFormat(this.options.datePattern);
    	
    	var calendarCall = "Calendar.setup({";
    	calendarCall+= "inputField:\"" + this.options.sourceElem.id + "\",";
    	calendarCall+= "ifFormat:\"" + dynarchDateFormat + "\",";
    	calendarCall+= "button:\"" + calendarId + "\"";
    	calendarCall+= "});";
    	eval(calendarCall);    	
    }
  },


  // Function to return format expected by Dynarch versus SimpleDateFormat
  getDynarchDateFormat: function(datePattern) {
  	if (datePattern=='dd/MM/yyyy')
  		return '%d/%m/%Y';
  }, 

  setOptions: function(options) {
    this.options = Object.extend({
      sourceElem: $(options.source),
      datePattern: options.datePattern ? options.dattePattern : "dd/MM/yyyy"      
    },options || {});
  }
});

// openFrame-ajaxtags-select.js


var OpenFrameSelectFieldTag = {
  Version: '1.0'
}

function populateSelect(dataFromServer,dataFromBrowser)
{
    // Obtain target from dataFromBrowser of previous call to callback
    var targetElem = $(dataFromBrowser['target']);
    var defaultSelected = dataFromBrowser['defaultSelected'];
	var initIndex = 0;
		
    if (targetElem) {	
    	if (targetElem.options) {
    		if (targetElem.options[0] && targetElem.options[0].value==''){
				targetElem.options.length=1;
				initIndex = 1;
			} else {
				targetElem.options.length=0;
			}
	    }
	    
	    if (dataFromServer) {
		   
    		// grab list of options from list
    		var items = dataFromServer;
		    for (var i=0; i<items.length; i++) {    		      
		      var label = items[i]['label'];
		      var value = items[i]['value'];
	  	      targetElem.options[i+initIndex] = new Option(label, value);
	  	      if(value == defaultSelected){
	  	      	targetElem.options[i+initIndex].selected = true;
	  	      }
    		} 
    		
 			if(document.createEvent)
  			{
      			 var evt = document.createEvent('HTMLEvents');
      			 evt.initEvent('change', true, true);
      			 targetElem.dispatchEvent(evt);
  			}
		    else if(targetElem.fireEvent)
  			{
       			targetElem.fireEvent('onchange');
 			}
	    }
	    
    }    
}

/* populate select sense Tri? una opci? */
function populateSelectSense(dataFromServer,dataFromBrowser,init, message)
{ 
    // Obtain target from dataFromBrowser of previous call to callback
    var targetElem = $(dataFromBrowser['target']);
    var defaultSelected = dataFromBrowser['defaultSelected'];
	var initIndex = 0;
	var valueDisabled;
	if (targetElem) {	
		
 	  	valueDisabled = targetElem.disabled;
 	  	targetElem.options.length=0;
	    targetElem.disabled = false; 
	    
	    if (dataFromServer) {
		   
    		// grab list of options from list
    		var items = dataFromServer;
    		if(init == 1){
			      targetElem.options[initIndex] = new Option(message, '');
			      targetElem.options.length=1;
			      initIndex = 1;
		    }
		    for (var i=0; i<items.length; i++) {    		      
		      var label = items[i]['label'];
		      var value = items[i]['value'];
    
		      
			  targetElem.options[i+initIndex] = new Option(label, value);  	      
	  	      if(value == defaultSelected){
	  	      	targetElem.options[i+initIndex].selected = true;
	  	      }
	    	} 
    		
 			if(document.createEvent)
  			{
      			 var evt = document.createEvent('HTMLEvents');
      			 evt.initEvent('change', true, true);
      			 targetElem.dispatchEvent(evt);
  			}
		    else if(targetElem.fireEvent)
  			{
       			targetElem.fireEvent('onchange');
 			}
	    }
    }    
  targetElem.disabled = valueDisabled;
}


/**
 * Extension of OpenFrameFieldTag
 */ 
OpenFrameSelectFieldTag.Base = function() {};
OpenFrameSelectFieldTag.Base.prototype = Object.extend(new AjaxJspTag.Base(),{
});


/******************************************************************************
 * openFrame Select Dependency behaviour
 * Example of use  :
 * <script type="text/javascript">
 *   new OpenFrameSelectFieldTag.SelectTarget(
 *     {
 *           defaultSelected: "...", // defaultSelected
 *           source: "...", // id of source select
 * 			 target: "...", // id of target select
 *           paramName: "title" // name of parameter to be created in order to populate target
 *			 optionsSourceListName: "" // name of configured list name of target options
 *     });
 * </script>
 ******************************************************************************/
 

OpenFrameSelectFieldTag.SelectTarget = Class.create();
OpenFrameSelectFieldTag.SelectTarget.prototype=Object.extend(new OpenFrameSelectFieldTag.Base(),{

  initialize: function(options) {
    this.setOptions(options);
    
    if (this.options.sourceElem) {    	
    	this.attachBehaviors(this.options.sourceElem, this.options.eventType, this.actionElemChanged, this);
    	this.actionElemChanged(new Object());
	}
  },


  setOptions: function(options) {
   this.options = Object.extend({
      defaultSelected: $(options.defaultSelected),
      sourceElem: $(options.source),
      targetElem: $(options.target),
      paramName: options.paramName,
      optionsTargetListName: options.targetListName,
      eventType: options.eventType ? options.eventType : "change"
   },options || {});
  },  

  
  actionElemChanged: function(e) {        
     var value = $F(this.options.sourceElem);
     
     // Create parameters to call 'getOptions'
	 var parametersCall = new Object();
  	 parametersCall[this.options.paramName] = value;   	
	 parametersCall['sourceElem'] = this.options.sourceElem.id;   	
	 
	 Event.stop(e);
  	 
  	 
	 var optionsListName = this.options.optionsTargetListName;
	 var dataFromBrowser = new Object();
  	 dataFromBrowser['target'] = this.options.targetElem.id;
  	 dataFromBrowser['defaultSelected'] = $F(this.options.targetElem);
  	 
  	 if  (dataFromBrowser['defaultSelected']=='')
  	 {
	  	 dataFromBrowser['defaultSelected'] = this.options.defaultSelected;
  	 }

	 webOptionsListService.getOptionsFromMap(optionsListName,parametersCall,
	 	{
	 		callback:function(dataFromServer) {
	 			populateSelect(dataFromServer,dataFromBrowser);
	 		},
	 		timeout:5000
	 	}
	 );
  	} 
}); 

/*******Webvalidationservice.js*/
function webValidationService() { }
webValidationService._path = '/darp_ecnp/AppJava/dwr';

webValidationService.getWebValidationResultsReq = function(p0, p1, callback) {
    DWREngine._execute(webValidationService._path, 'webValidationService', 'getWebValidationResultsReq', p0, p1, false, callback);
}

/************  weboptionlist.js*/

function webOptionsListService() { }
webOptionsListService._path = '/darp_ecnp/AppJava/dwr';

webOptionsListService.getOptionsFromMap = function(p0, p1, callback) {
    DWREngine._execute(webOptionsListService._path, 'webOptionsListService', 'getOptionsFromMap', p0, p1, callback);
}


/***********engine.js*/



















function DWREngine() { }





DWREngine.setErrorHandler = function(handler) {
DWREngine._errorHandler = handler;
};





DWREngine.setWarningHandler = function(handler) {
DWREngine._warningHandler = handler;
};





DWREngine.setTimeout = function(timeout) {
DWREngine._timeout = timeout;
};





DWREngine.setPreHook = function(handler) {
DWREngine._preHook = handler;
};





DWREngine.setPostHook = function(handler) {
DWREngine._postHook = handler;
};


DWREngine.XMLHttpRequest = 1;


DWREngine.IFrame = 2;






DWREngine.setMethod = function(newmethod) {
if (newmethod != DWREngine.XMLHttpRequest && newmethod != DWREngine.IFrame) {
DWREngine._handleError("Remoting method must be one of DWREngine.XMLHttpRequest or DWREngine.IFrame");
return;
}
DWREngine._method = newmethod;
};





DWREngine.setVerb = function(verb) {
if (verb != "GET" && verb != "POST") {
DWREngine._handleError("Remoting verb must be one of GET or POST");
return;
}
DWREngine._verb = verb;
};





DWREngine.setOrdered = function(ordered) {
DWREngine._ordered = ordered;
};





DWREngine.setAsync = function(async) {
DWREngine._async = async;
};





DWREngine.defaultMessageHandler = function(message) {
if (typeof message == "object" && message.name == "Error" && message.description) {
alert("Error: " + message.description);
}
else {
alert(message);
}
};





DWREngine.beginBatch = function() {
if (DWREngine._batch) {
DWREngine._handleError("Batch already started.");
return;
}

DWREngine._batch = {};
DWREngine._batch.map = {};
DWREngine._batch.paramCount = 0;
DWREngine._batch.map.callCount = 0;
DWREngine._batch.ids = [];
DWREngine._batch.preHooks = [];
DWREngine._batch.postHooks = [];
};





DWREngine.endBatch = function(options) {
var batch = DWREngine._batch;
if (batch == null) {
DWREngine._handleError("No batch in progress.");
return;
}

if (options && options.preHook) batch.preHooks.unshift(options.preHook);
if (options && options.postHook) batch.postHooks.push(options.postHook);
if (DWREngine._preHook) batch.preHooks.unshift(DWREngine._preHook);
if (DWREngine._postHook) batch.postHooks.push(DWREngine._postHook);

if (batch.method == null) batch.method = DWREngine._method;
if (batch.verb == null) batch.verb = DWREngine._verb;
if (batch.async == null) batch.async = DWREngine._async;
if (batch.timeout == null) batch.timeout = DWREngine._timeout;

batch.completed = false;


DWREngine._batch = null;



if (!DWREngine._ordered) {
DWREngine._sendData(batch);
DWREngine._batches[DWREngine._batches.length] = batch;
}
else {
if (DWREngine._batches.length == 0) {

DWREngine._sendData(batch);
DWREngine._batches[DWREngine._batches.length] = batch;
}
else {

DWREngine._batchQueue[DWREngine._batchQueue.length] = batch;
}
}
};






DWREngine._errorHandler = DWREngine.defaultMessageHandler;


DWREngine._warningHandler = DWREngine.defaultMessageHandler;


DWREngine._preHook = null;


DWREngine._postHook = null;


DWREngine._batches = [];


DWREngine._batchQueue = [];


DWREngine._handlersMap = {};


DWREngine._method = DWREngine.XMLHttpRequest;


DWREngine._verb = "POST";


DWREngine._ordered = false;


DWREngine._async = true;


DWREngine._batch = null;


DWREngine._timeout = 0;


DWREngine._DOMDocument = ["Msxml2.DOMDocument.6.0", "Msxml2.DOMDocument.5.0", "Msxml2.DOMDocument.4.0", "Msxml2.DOMDocument.3.0", "MSXML2.DOMDocument", "MSXML.DOMDocument", "Microsoft.XMLDOM"];


DWREngine._XMLHTTP = ["Msxml2.XMLHTTP.6.0", "Msxml2.XMLHTTP.5.0", "Msxml2.XMLHTTP.4.0", "MSXML2.XMLHTTP.3.0", "MSXML2.XMLHTTP", "Microsoft.XMLHTTP"];










DWREngine._execute = function(path, scriptName, methodName, vararg_params) {
var singleShot = false;
if (DWREngine._batch == null) {
DWREngine.beginBatch();
singleShot = true;
}

var args = [];
for (var i = 0; i < arguments.length - 3; i++) {
args[i] = arguments[i + 3];
}

if (DWREngine._batch.path == null) {
DWREngine._batch.path = path;
}
else {
if (DWREngine._batch.path != path) {
DWREngine._handleError("Can't batch requests to multiple DWR Servlets.");
return;
}
}


var params;
var callData;
var firstArg = args[0];
var lastArg = args[args.length - 1];

if (typeof firstArg == "function") {
callData = { callback:args.shift() };
params = args;
}
else if (typeof lastArg == "function") {
callData = { callback:args.pop() };
params = args;
}
else if (typeof lastArg == "object" && lastArg.callback != null && typeof lastArg.callback == "function") {
callData = args.pop();
params = args;
}
else if (firstArg == null) {



if (lastArg == null && args.length > 2) {
if (DWREngine._warningHandler) {
DWREngine._warningHandler("Ambiguous nulls at start and end of parameter list. Which is the callback function?");
}
}
callData = { callback:args.shift() };
params = args;
}
else if (lastArg == null) {
callData = { callback:args.pop() };
params = args;
}
else {
if (DWREngine._warningHandler) {
DWREngine._warningHandler("Missing callback function or metadata object.");
}
return;
}


var random = Math.floor(Math.random() * 10001);
var id = (random + "_" + new Date().getTime()).toString();
var prefix = "c" + DWREngine._batch.map.callCount + "-";
DWREngine._batch.ids.push(id);


if (callData.method != null) {
DWREngine._batch.method = callData.method;
delete callData.method;
}
if (callData.verb != null) {
DWREngine._batch.verb = callData.verb;
delete callData.verb;
}
if (callData.async != null) {
DWREngine._batch.async = callData.async;
delete callData.async;
}
if (callData.timeout != null) {
DWREngine._batch.timeout = callData.timeout;
delete callData.timeout;
}


if (callData.preHook != null) {
DWREngine._batch.preHooks.unshift(callData.preHook);
delete callData.preHook;
}
if (callData.postHook != null) {
DWREngine._batch.postHooks.push(callData.postHook);
delete callData.postHook;
}


if (callData.errorHandler == null) callData.errorHandler = DWREngine._errorHandler;
if (callData.warningHandler == null) callData.warningHandler = DWREngine._warningHandler;


DWREngine._handlersMap[id] = callData;

DWREngine._batch.map[prefix + "scriptName"] = scriptName;
DWREngine._batch.map[prefix + "methodName"] = methodName;
DWREngine._batch.map[prefix + "id"] = id;


DWREngine._addSerializeFunctions();
for (i = 0; i < params.length; i++) {
DWREngine._serializeAll(DWREngine._batch, [], params[i], prefix + "param" + i);
}
DWREngine._removeSerializeFunctions();


DWREngine._batch.map.callCount++;
if (singleShot) {
DWREngine.endBatch();
}
};




DWREngine._sendData = function(batch) {

if (batch.map.callCount == 0) return;

for (var i = 0; i < batch.preHooks.length; i++) {
batch.preHooks[i]();
}
batch.preHooks = null;

if (batch.timeout && batch.timeout != 0) {
batch.interval = setInterval(function() {
clearInterval(batch.interval);
DWREngine._abortRequest(batch);
}, batch.timeout);
}

var statsInfo;
if (batch.map.callCount == 1) {
statsInfo = batch.map["c0-scriptName"] + "." + batch.map["c0-methodName"] + ".dwr";
}
else {
statsInfo = "Multiple." + batch.map.callCount + ".dwr";
}


if (batch.method == DWREngine.XMLHttpRequest) {
if (window.XMLHttpRequest) {
batch.req = new XMLHttpRequest();
}

else if (window.ActiveXObject && !(navigator.userAgent.indexOf('Mac') >= 0 && navigator.userAgent.indexOf("MSIE") >= 0)) {
batch.req = DWREngine._newActiveXObject(DWREngine._XMLHTTP);
}
}

var query = "";
var prop;
if (batch.req) {
batch.map.xml = "true";

if (batch.async) {
batch.req.onreadystatechange = function() {
DWREngine._stateChange(batch);
};
}

var indexSafari = navigator.userAgent.indexOf('Safari/');
if (indexSafari >= 0) {

var version = navigator.userAgent.substring(indexSafari + 7);
var verNum = parseInt(version, 10);
if (verNum < 400) {
batch.verb == "GET";
}



}
if (batch.verb == "GET") {



batch.map.callCount = "" + batch.map.callCount;

for (prop in batch.map) {
var qkey = encodeURIComponent(prop);
var qval = encodeURIComponent(batch.map[prop]);
if (qval == "") {
if (DWREngine._warningHandler) {
DWREngine._warningHandler("Found empty qval for qkey=" + qkey);
}
}
query += qkey + "=" + qval + "&";
}
query = query.substring(0, query.length - 1);

try {
batch.req.open("GET", batch.path + "/exec/" + statsInfo + "?" + query, batch.async);
batch.req.send(null);
if (!batch.async) {
DWREngine._stateChange(batch);
}
}
catch (ex) {
DWREngine._handleMetaDataError(null, ex);
}
}
else {
for (prop in batch.map) {
if (typeof batch.map[prop] != "function") {
query += prop + "=" + batch.map[prop] + "\n";
}
}

try {




batch.req.open("POST", batch.path + "/exec/" + statsInfo, batch.async);
batch.req.setRequestHeader('Content-Type', 'text/plain');
batch.req.send(query);
if (!batch.async) {
DWREngine._stateChange(batch);
}
}
catch (ex) {
DWREngine._handleMetaDataError(null, ex);
}
}
}
else {
batch.map.xml = "false";
var idname = "dwr-if-" + batch.map["c0-id"];

batch.div = document.createElement('div');
batch.div.innerHTML = "<iframe src='javascript:void(0)' frameborder='0' width='0' height='0' id='" + idname + "' name='" + idname + "'></iframe>";
document.body.appendChild(batch.div);
batch.iframe = document.getElementById(idname);
batch.iframe.setAttribute('style', 'width:0px; height:0px; border:0px;');

if (batch.verb == "GET") {
for (prop in batch.map) {
if (typeof batch.map[prop] != "function") {
query += encodeURIComponent(prop) + "=" + encodeURIComponent(batch.map[prop]) + "&";
}
}
query = query.substring(0, query.length - 1);

batch.iframe.setAttribute('src', batch.path + "/exec/" + statsInfo + "?" + query);
document.body.appendChild(batch.iframe);
}
else {
batch.form = document.createElement('form');
batch.form.setAttribute('id', 'dwr-form');
batch.form.setAttribute('action', batch.path + "/exec" + statsInfo);
batch.form.setAttribute('target', idname);
batch.form.target = idname;
batch.form.setAttribute('method', 'post');
for (prop in batch.map) {
var formInput = document.createElement('input');
formInput.setAttribute('type', 'hidden');
formInput.setAttribute('name', prop);
formInput.setAttribute('value', batch.map[prop]);
batch.form.appendChild(formInput);
}

document.body.appendChild(batch.form);
batch.form.submit();
}
}
};




DWREngine._stateChange = function(batch) {
if (!batch.completed && batch.req.readyState == 4) {
try {
var reply = batch.req.responseText;
var status = batch.req.status;

if (reply == null || reply == "") {
DWREngine._handleMetaDataError(null, "No data received from server");
return;
}


if (reply.search("DWREngine._handle") == -1) {
DWREngine._handleMetaDataError(null, "Invalid reply from server");
return;
}

if (status != 200) {
if (reply == null) reply = "Unknown error occured";
DWREngine._handleMetaDataError(null, reply);
return;
}

eval(reply);


DWREngine._clearUp(batch);
}
catch (ex) {
if (ex == null) ex = "Unknown error occured";
DWREngine._handleMetaDataError(null, ex);
}
finally {



if (DWREngine._batchQueue.length != 0) {
var sendbatch = DWREngine._batchQueue.shift();
DWREngine._sendData(sendbatch);
DWREngine._batches[DWREngine._batches.length] = sendbatch;
}
}
}
};






DWREngine._handleResponse = function(id, reply) {

var handlers = DWREngine._handlersMap[id];
DWREngine._handlersMap[id] = null;

if (handlers) {


try {
if (handlers.callback) handlers.callback(reply);
}
catch (ex) {
DWREngine._handleMetaDataError(handlers, ex);
}
}


if (DWREngine._method == DWREngine.IFrame) {
var responseBatch = DWREngine._batches[DWREngine._batches.length-1];

if (responseBatch.map["c"+(responseBatch.map.callCount-1)+"-id"] == id) {
DWREngine._clearUp(responseBatch);
}
}
};




DWREngine._handleServerError = function(id, error) {

var handlers = DWREngine._handlersMap[id];
DWREngine._handlersMap[id] = null;
if (error.message) {
DWREngine._handleMetaDataError(handlers, error.message, error);
}
else {
DWREngine._handleMetaDataError(handlers, error);
}
};




DWREngine._abortRequest = function(batch) {
if (batch && batch.metadata != null && !batch.completed) {
DWREngine._clearUp(batch);
if (batch.req) batch.req.abort();

var handlers;
var id;
for (var i = 0; i < batch.ids.length; i++) {
id = batch.ids[i];
handlers = DWREngine._handlersMap[id];
DWREngine._handleMetaDataError(handlers, "Timeout");
}
}
};




DWREngine._clearUp = function(batch) {
if (batch.completed) {
alert("double complete");
return;
}


if (batch.div) batch.div.parentNode.removeChild(batch.div);
if (batch.iframe) batch.iframe.parentNode.removeChild(batch.iframe);
if (batch.form) batch.form.parentNode.removeChild(batch.form);


if (batch.req) delete batch.req;

for (var i = 0; i < batch.postHooks.length; i++) {
batch.postHooks[i]();
}
batch.postHooks = null;


for (var i = 0; i < DWREngine._batches.length; i++) {
if (DWREngine._batches[i] == batch) {
DWREngine._batches.splice(i, 1);
break;
}
}

batch.completed = true;
};




DWREngine._handleError = function(reason, ex) {
if (DWREngine._errorHandler) {
DWREngine._errorHandler(reason, ex);
}
};




DWREngine._handleMetaDataError = function(handlers, reason, ex) {
if (handlers && typeof handlers.errorHandler == "function") {
handlers.errorHandler(reason, ex);
}
else {
DWREngine._handleError(reason, ex);
}
};




DWREngine._addSerializeFunctions = function() {
Object.prototype.dwrSerialize = DWREngine._serializeObject;
Array.prototype.dwrSerialize = DWREngine._serializeArray;
Boolean.prototype.dwrSerialize = DWREngine._serializeBoolean;
Number.prototype.dwrSerialize = DWREngine._serializeNumber;
String.prototype.dwrSerialize = DWREngine._serializeString;
Date.prototype.dwrSerialize = DWREngine._serializeDate;
};




DWREngine._removeSerializeFunctions = function() {
delete Object.prototype.dwrSerialize;
delete Array.prototype.dwrSerialize;
delete Boolean.prototype.dwrSerialize;
delete Number.prototype.dwrSerialize;
delete String.prototype.dwrSerialize;
delete Date.prototype.dwrSerialize;
};








DWREngine._serializeAll = function(batch, referto, data, name) {
if (data == null) {
batch.map[name] = "null:null";
return;
}

switch (typeof data) {
case "boolean":
batch.map[name] = "boolean:" + data;
break;

case "number":
batch.map[name] = "number:" + data;
break;

case "string":
batch.map[name] = "string:" + encodeURIComponent(data);
break;

case "object":
if (data.dwrSerialize) {
batch.map[name] = data.dwrSerialize(batch, referto, data, name);
}
else if (data.nodeName) {
batch.map[name] = DWREngine._serializeXml(batch, referto, data, name);
}
else {
if (DWREngine._warningHandler) {
DWREngine._warningHandler("Object without dwrSerialize: " + typeof data + ", attempting default converter.");
}
batch.map[name] = "default:" + data;
}
break;

case "function":

break;

default:
if (DWREngine._warningHandler) {
DWREngine._warningHandler("Unexpected type: " + typeof data + ", attempting default converter.");
}
batch.map[name] = "default:" + data;
break;
}
};


DWREngine._lookup = function(referto, data, name) {
var lookup;

for (var i = 0; i < referto.length; i++) {
if (referto[i].data == data) {
lookup = referto[i];
break;
}
}
if (lookup) {
return "reference:" + lookup.name;
}
referto.push({ data:data, name:name });
return null;
};


DWREngine._serializeObject = function(batch, referto, data, name) {
var ref = DWREngine._lookup(referto, this, name);
if (ref) return ref;

if (data.nodeName) {
return DWREngine._serializeXml(batch, referto, data, name);
}


var reply = "Object:{";
var element;
for (element in this)  {
if (element != "dwrSerialize") {
batch.paramCount++;
var childName = "c" + DWREngine._batch.map.callCount + "-e" + batch.paramCount;
DWREngine._serializeAll(batch, referto, this[element], childName);

reply += encodeURIComponent(element);
reply += ":reference:";
reply += childName;
reply += ", ";
}
}

if (reply.substring(reply.length - 2) == ", ") {
reply = reply.substring(0, reply.length - 2);
}
reply += "}";

return reply;
};


DWREngine._serializeXml = function(batch, referto, data, name) {
var ref = DWREngine._lookup(referto, this, name);
if (ref) {
return ref;
}
var output;
if (window.XMLSerializer) {
var serializer = new XMLSerializer();
output = serializer.serializeToString(data);
}
else {
output = data.toXml;
}
return "XML:" + encodeURIComponent(output);
};


DWREngine._serializeArray = function(batch, referto, data, name) {
var ref = DWREngine._lookup(referto, this, name);
if (ref) return ref;

var reply = "Array:[";
for (var i = 0; i < this.length; i++) {
if (i != 0) {
reply += ",";
}

batch.paramCount++;
var childName = "c" + DWREngine._batch.map.callCount + "-e" + batch.paramCount;
DWREngine._serializeAll(batch, referto, this[i], childName);
reply += "reference:";
reply += childName;
}
reply += "]";

return reply;
};


DWREngine._serializeBoolean = function(batch, referto, data, name) {
return "Boolean:" + this;
};


DWREngine._serializeNumber = function(batch, referto, data, name) {
return "Number:" + this;
};


DWREngine._serializeString = function(batch, referto, data, name) {
return "String:" + encodeURIComponent(this);
};


DWREngine._serializeDate = function(batch, referto, data, name) {
return "Date:" + this.getTime();
};


DWREngine._unserializeDocument = function(xml) {
var dom;
if (window.DOMParser) {
var parser = new DOMParser();
dom = parser.parseFromString(xml, "text/xml");
if (!dom.documentElement || dom.documentElement.tagName == "parsererror") {
var message = dom.documentElement.firstChild.data;
message += "\n" + dom.documentElement.firstChild.nextSibling.firstChild.data;
throw message;
}
return dom;
}
else if (window.ActiveXObject) {
dom = DWREngine._newActiveXObject(DWREngine._DOMDocument);
dom.loadXML(xml);

return dom;
}








else {
var div = document.createElement('div');
div.innerHTML = xml;
return div;
}
};





DWREngine._newActiveXObject = function(axarray) {
var returnValue;
for (var i = 0; i < axarray.length; i++) {
try {
returnValue = new ActiveXObject(axarray[i]);
break;
}
catch (ex) {
}
}
return returnValue;
};


if (typeof window.encodeURIComponent === 'undefined') {
DWREngine._utf8 = function(wide) {
wide = "" + wide;
var c;
var s;
var enc = "";
var i = 0;
while (i < wide.length) {
c = wide.charCodeAt(i++);

if (c >= 0xDC00 && c < 0xE000) continue;
if (c >= 0xD800 && c < 0xDC00) {
if (i >= wide.length) continue;
s = wide.charCodeAt(i++);
if (s < 0xDC00 || c >= 0xDE00) continue;
c = ((c - 0xD800) << 10) + (s - 0xDC00) + 0x10000;
}

if (c < 0x80) {
enc += String.fromCharCode(c);
}
else if (c < 0x800) {
enc += String.fromCharCode(0xC0 + (c >> 6), 0x80 + (c & 0x3F));
}
else if (c < 0x10000) {
enc += String.fromCharCode(0xE0 + (c >> 12), 0x80 + (c >> 6 & 0x3F), 0x80 + (c & 0x3F));
}
else {
enc += String.fromCharCode(0xF0 + (c >> 18), 0x80 + (c >> 12 & 0x3F), 0x80 + (c >> 6 & 0x3F), 0x80 + (c & 0x3F));
}
}
return enc;
}

DWREngine._hexchars = "0123456789ABCDEF";

DWREngine._toHex = function(n) {
return DWREngine._hexchars.charAt(n >> 4) + DWREngine._hexchars.charAt(n & 0xF);
}

DWREngine._okURIchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";

window.encodeURIComponent = function(s)  {
s = DWREngine._utf8(s);
var c;
var enc = "";
for (var i= 0; i<s.length; i++) {
if (DWREngine._okURIchars.indexOf(s.charAt(i)) == -1) {
enc += "%" + DWREngine._toHex(s.charCodeAt(i));
}
else {
enc += s.charAt(i);
}
}
return enc;
}
}


if (typeof Array.prototype.splice === 'undefined') {
Array.prototype.splice = function(ind, cnt)
{
if (arguments.length == 0) {
return ind;
}
if (typeof ind != "number") {
ind = 0;
}
if (ind < 0) {
ind = Math.max(0,this.length + ind);
}
if (ind > this.length) {
if (arguments.length > 2) {
ind = this.length;
}
else {
return [];
}
}
if (arguments.length < 2) {
cnt = this.length-ind;
}

cnt = (typeof cnt == "number") ? Math.max(0, cnt) : 0;
removeArray = this.slice(ind, ind + cnt);
endArray = this.slice(ind + cnt);
this.length = ind;

for (var i = 2; i < arguments.length; i++) {
this[this.length] = arguments[i];
}
for (i = 0; i < endArray.length; i++) {
this[this.length] = endArray[i];
}

return removeArray;
}
}


if (typeof Array.prototype.shift === 'undefined') {
Array.prototype.shift = function(str) {
var val = this[0];
for (var i = 1; i < this.length; ++i) {
this[i - 1] = this[i];
}
this.length--;
return val;
}
}


if (typeof Array.prototype.unshift === 'undefined') {
Array.prototype.unshift = function() {
var i = unshift.arguments.length;
for (var j = this.length - 1; j >= 0; --j) {
this[j + i] = this[j];
}
for (j = 0; j < i; ++j) {
this[j] = unshift.arguments[j];
}
}
}


if (typeof Array.prototype.push === 'undefined') {
Array.prototype.push = function() {
var sub = this.length;
for (var i = 0; i < push.arguments.length; ++i) {
this[sub] = push.arguments[i];
sub++;
}
}
}


if (typeof Array.prototype.pop === 'undefined') {
Array.prototype.pop = function() {
var lastElement = this[this.length - 1];
this.length--;
return lastElement;
}
}

/**************** Scriptaculous*/
// Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

var Scriptaculous = {
  Version: '1.5.3',
  require: function(libraryName) {
    // inserting via DOM fails in Safari 2.0, so brute force approach
    document.write('<script type="text/javascript" src="'+libraryName+'"></script>');
  },
  load: function() {
    if((typeof Prototype=='undefined') ||
      parseFloat(Prototype.Version.split(".")[0] + "." +
                 Prototype.Version.split(".")[1]) < 1.4)
      throw("script.aculo.us requires the Prototype JavaScript framework >= 1.4.0");
    
    $A(document.getElementsByTagName("script")).findAll( function(s) {
      return (s.src && s.src.match(/scriptaculous\.js(\?.*)?$/))
    }).each( function(s) {
      var path = s.src.replace(/scriptaculous\.js(\?.*)?$/,'');
      var includes = s.src.match(/\?.*load=([a-z,]*)/);
      (includes ? includes[1] : 'effects,dragdrop').split(',').each(
       function(include) { Scriptaculous.require(path+include+'.js') });
    });
  }
}

Scriptaculous.load();

  	  
  	   

  	   /***********browser.js*/
  	   
  	   /*
Inspired by script
ua.js revision 0.200 2001-12-03
Contributor(s): Bob Clary, Netscape Communications, Copyright 2001
	***
	Netscape grants you a royalty free license to use, modify and 
	distribute this software provided that this copyright notice 
	appears on all copies.  This software is provided "AS IS," 
	without a warranty of any kind
	***

Modified by AT Mulyana (atmulyana@yahoo.com) in October 26, 2005 (lists only intended browsers)
Distributed as part of 'AT JsMenu' under LGPL (http://gnu.org/licenses/lgpl.html)
*/
(function() {
	var navFamily = navigator.userAgent.toLowerCase();
	if (navFamily.indexOf('opera')!=-1) { 
		navigator.version = parseFloat( navFamily.substring(navFamily.indexOf('opera')+6,
			navFamily.length) );
		if (navigator.version >= 7.0) navFamily = 'Opera7';
		else navFamily = '';
	} else if (navFamily.indexOf('msie')!=-1) {
		navigator.version = parseFloat( navFamily.substring(navFamily.indexOf('msie')+5,
			navFamily.length) );
		if (navigator.version >= 6.0) navFamily = 'IE6';
		else navFamily = '';
	} else if (navFamily.indexOf('gecko')!=-1) {
		navigator.version = parseFloat( navFamily.substring(navFamily.indexOf('gecko')+6,
			navFamily.length) );
		if (navigator.version >= 20020823) navFamily = 'Gecko'; //Good Gecko; Netscape 7+ / Mozilla 1.0.1+
		else navFamily = '';
	} else {
		navFamily = '';
		navigator.version = 0;
	}
	
	navigator.family = navFamily;
})();

