/*
 * Copyright (c) 1998-2009 TeamDev Ltd. All Rights Reserved.
 * Use is subject to license terms.
 */

var QuipuKit = Q$ = function(id) {
  return document.getElementById(id);
}

Q$.extend = function(obj, withObj) {
  for (propertyName in withObj) {
    if (propertyName != "prototype")
    obj[propertyName] = withObj[propertyName];
  }
}

Q$.createClass = function(classMembers, instanceMembers) {
  var constructor = instanceMembers.constructor;
  instanceMembers.constructor = undefined;
  var classFunction = function() {
    if (constructor)
      constructor.apply(this, arguments);
  }
  if (classMembers)
    Q$.extend(classFunction, classMembers);
  Q$.extend(classFunction.prototype, instanceMembers);
  return classFunction;
}

Q$.extend(Q$, {
  DEBUG: true
});


Q$.initComponent = function(clientId, styles, events) {
  var component = Q$(clientId);
  if (styles) {
    if (styles.rollover)
      q__setupHoverStateFunction(component, function(mouseInside) {
        q__setElementStyleMappings(component, {_rolloverStyle: mouseInside ? styles.rollover : null});
      });
  }
  if (events) {
    component._events = {};
    for (var eventName in events) {
      var handlerScript = events[eventName];
      if (!handlerScript)
      continue;
      var handlerFunction;
      if (typeof handlerScript == "string")
        eval("handlerFunction = function(event) {" + handlerScript + "}");
      else if (typeof handlerScript == "function")
        handlerFunction = handlerScript;
      else
        throw "Type of a handler script should either be a string or a function, but it was a " +
              (typeof handlerScript) + "; " + handlerScript;
      component._events[eventName] = handlerFunction;
    }
  }

}

Q$.extend(Q$, { /* Rectangle class */
  Rectangle: Q$.createClass(null, {
    constructor: function (x, y, width, height) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
    },
    clone: function() {
      return new Q$.Rectangle(this.x, this.y, this.width, this.height);
    },
    getMinX: function() {
      return this.x;
    },
    getMinY: function() {
      return this.y;
    },
    getMaxX: function() {
      var result = this.x + this.width;
      return result;
    },
    getMaxY: function() {
      var result = this.y + this.height;
      return result;
    },

    addRectangle: function(rect) {
      q__assert(rect, "rect parameter should be passed");
      var x1 = this.getMinX();
      if (rect.getMinX() < x1)
        x1 = rect.getMinX();
      var y1 = this.getMinY();
      if (rect.getMinY() < y1)
        y1 = rect.getMinY();
      var x2 = this.getMaxX();
      if (rect.getMaxX() > x2)
        x2 = rect.getMaxX();
      var y2 = this.getMaxY();
      if (rect.getMaxY() > y2)
        y2 = rect.getMaxY();
      this.x = x1;
      this.y = y1
      this.width = x2 - x1;
      this.height = y2 - y1;
    },

    intersectWith: function(rect) {
      q__assert(rect, "rect parameter should be passed");

      var x1 = q__maxDefined(this.getMinX(), rect.getMinX());
      var x2 = q__minDefined(this.getMaxX(), rect.getMaxX());
      var y1 = q__maxDefined(this.getMinY(), rect.getMinY());
      var y2 = q__minDefined(this.getMaxY(), rect.getMaxY());
      if (x2 < x1)
        x2 = x1;
      if (y2 < y1)
        y2 = y1;

      this.x = x1;
      this.y = y1

      this.width = x1 !== undefined && x2 !== undefined ? x2 - x1 : undefined;
      this.height = y1 !== undefined && y2 !== undefined ? y2 - y1 : undefined;
    },

    intersects: function(rect) {
      var x1 = this.getMinX();
      var x2 = this.getMaxX();
      var rectX1 = rect.getMinX();
      var rectX2 = rect.getMaxX();
      var y1 = this.getMinY();
      var y2 = this.getMaxY();
      var rectY1 = rect.getMinY();
      var rectY2 = rect.getMaxY();

      return (rectX2 > x1 && rectY2 > y1 && rectX1 < x2 && rectY1 < y2);
    },

    containsRectangle: function(rect) {
      var x1 = this.getMinX();
      var x2 = this.getMaxX();
      var rectX1 = rect.getMinX();
      var rectX2 = rect.getMaxX();
      var y1 = this.getMinY();
      var y2 = this.getMaxY();
      var rectY1 = rect.getMinY();
      var rectY2 = rect.getMaxY();

      return (x1 <= rectX1 && x2 >= rectX2 && y1 <= rectY1 && y2 >= rectY2);
    },

    containsPoint: function(x, y) {
      return x >= this.getMinX() && x <= this.getMaxX() &&
             y >= this.getMinY() && y <= this.getMaxY();
    }

  })
});

/* GraphicLine class -- displays a horizontal or vertical line on the specified element. */
Q$.GraphicLine = Q$.createClass({
  ALIGN_BY_TOP_OR_LEFT: "alignByTopOrLeft",
  ALIGN_BY_CENTER: "alignByCenter",
  ALIGN_BY_BOTTOM_OR_RIGHT: "alignByBottomOrRight"
}, {
  constructor: function (lineStyle, alignment, x1, y1, x2, y2) {
    this._element = document.createElement("div");
    this._element.style.visibility = "hidden";
    this._element.style.position = "absolute";

    if (x1)
      this.setLine(x1, y1, x2, y2, true);
    if (!lineStyle)
      lineStyle = "1px solid black";
    this.setLineStyle(lineStyle, true);
    if (!alignment)
      alignment = Q$.GraphicLine.ALIGN_BY_CENTER;
    this.setAlignment(alignment, false);
  },

  setLine: function(x1, y1, x2, y2, dontUpdateNow) {
    this.x1 = x1;
    this.y1 = y1;
    this.x2 = x2;
    this.y2 = y2;
    var horizontal = y1 == y2;
    if (!horizontal && x1 != x2)
      throw "GraphicLine.setLine: Only horizontal and vertical lines are supported.";
    if (!dontUpdateNow)
      this.updatePresentation();
  },

  setLineStyle: function(lineStyle, dontUpdateNow) {
    this.lineStyle = lineStyle;
    if (!dontUpdateNow)
      this.updatePresentation();
  },

  setAlignment: function(alignment, dontUpdateNow) {
    this.alignment = alignment;
    if (!dontUpdateNow)
      this.updatePresentation();
  },

  updatePresentation: function() {
    if (this.x1 === undefined || this.y1 === undefined || this.x2 === undefined || this.y2 === undefined) {
      this._element.style.visibility = "hidden"
      return;
    }
    var horizontal = this.y1 == this.y2;
    if (!horizontal && this.x1 != this.x2)
      throw "GraphicLine.updatePresentation: Only horizontal and vertical lines are supported.";
    var width;
    if (horizontal) {
      this._element.style.borderTop = this.lineStyle;
      this._element.style.borderLeft = "none";
      width = q__getNumericStyleProperty(this._element, "border-top-width");
    } else {
      this._element.style.borderLeft = this.lineStyle;
      this._element.style.borderTop = "none";
      width = q__getNumericStyleProperty(this._element, "border-left-width");
    }
    var alignment = this.alignment;
    var alignmentCorrection =
            alignment == Q$.GraphicLine.ALIGN_BY_TOP_OR_LEFT ? 0 :
            alignment == Q$.GraphicLine.ALIGN_BY_CENTER || !alignment ? -width / 2 :
            alignment == Q$.GraphicLine.ALIGN_BY_BOTTOM_OR_RIGHT ? -width :
            (function() {
              throw "Invalid alignment: " + alignment
            })();
    q__setElementBorderRectangle(this._element,
            horizontal ? new Q$.Rectangle(this.x1, this.y1 + alignmentCorrection, this.x2 - this.x1, width)
                    : new Q$.Rectangle(this.x1 + alignmentCorrection, this.y1, width, this.y2 - this.y1));
  },

  show: function (parentElement) {
    if (!parentElement)
      parentElement = q__getDefaultAbsolutePositionParent();
    this._element.style.visibility = "visible";
    if (this._element.parentNode != parentElement)
      parentElement.appendChild(this._element);
    // updatePresentation here is needed for recalculating border width after an element is already in DOM
    this.updatePresentation();
  },

  hide: function () {
    this._element.style.visibility = "hidden";
  },

  remove: function () {
    this._element.parentNode.remove(this._element);
  }
});

/* GraphicRectangle class -- displays a rectangle on the specified element. */
Q$.GraphicRectangle = Q$.createClass({
  /* the following constants deptermine the way that outline line is aligned with respect to the rectangle's edge
   * (this is especially important for thick lines) */
  ALIGN_INSIDE: "alignInside", // the entire outline line is aligned to be inside of the rectangle
  ALIGN_CENTER_LINE: "alignCenterLine", // center of the outline line is aligned with the rectangle edge
  ALIGN_OUTSIDE: "alignOutside" // the entire contents of outline line is aligned to be outside of the rectangle
}, {
  constructor: function (lineStyle, lineAlignment, rectangle) {
    this._leftLine = new Q$.GraphicLine();
    this._rightLine = new Q$.GraphicLine();
    this._topLine = new Q$.GraphicLine();
    this._bottomLine = new Q$.GraphicLine();
    if (rectangle)
      this.setRectangle(rectangle, true);
    this.setLineStyle(lineStyle, true);
    if (!lineAlignment)
      lineAlignment = Q$.GraphicRectangle.ALIGN_INSIDE;
    this.setLineAlignment(lineAlignment, false);
  },

  setRectangle: function(rectangle, dontUpdateNow) {
    this.rectangle = rectangle;
    if (!dontUpdateNow)
      this._updateRect();
  },

  setLineStyle: function(lineStyle, dontUpdateNow) {
    this.lineStyle = lineStyle;
    this._leftLine.setLineStyle(lineStyle, dontUpdateNow);
    this._rightLine.setLineStyle(lineStyle, dontUpdateNow);
    this._topLine.setLineStyle(lineStyle, dontUpdateNow);
    this._bottomLine.setLineStyle(lineStyle, dontUpdateNow);
    if (!dontUpdateNow)
      this._updateRect();
  },

  setLineAlignment: function(lineAlignment, dontUpdateNow) {
    var topAndLeftLinesAlignment =
            lineAlignment == Q$.GraphicRectangle.ALIGN_INSIDE ? Q$.GraphicLine.ALIGN_BY_TOP_OR_LEFT :
            lineAlignment == Q$.GraphicRectangle.ALIGN_OUTSIDE ? Q$.GraphicLine.ALIGN_BY_BOTTOM_OR_RIGHT :
            Q$.GraphicLine.ALIGN_BY_CENTER;
    var bottomAndRightLinesAlignment =
            lineAlignment == Q$.GraphicRectangle.ALIGN_INSIDE ? Q$.GraphicLine.ALIGN_BY_BOTTOM_OR_RIGHT :
            lineAlignment == Q$.GraphicRectangle.ALIGN_OUTSIDE ? Q$.GraphicLine.ALIGN_BY_TOP_OR_LEFT :
            Q$.GraphicLine.ALIGN_BY_CENTER;
    this._leftLine.setAlignment(topAndLeftLinesAlignment, dontUpdateNow);
    this._topLine.setAlignment(topAndLeftLinesAlignment, dontUpdateNow);
    this._rightLine.setAlignment(bottomAndRightLinesAlignment, dontUpdateNow);
    this._bottomLine.setAlignment(bottomAndRightLinesAlignment, dontUpdateNow);
    if (!dontUpdateNow)
      this._updateRect();
  },

  _updateRect: function() {
    var rect = this.rectangle;
    if (!rect)
      return;
    var x1 = rect.getMinX();
    var x2 = rect.getMaxX();
    var y1 = rect.getMinY();
    var y2 = rect.getMaxY();
    var lineWidth = q__calculateLineWidth(this.lineStyle);
    var alignment = this.alignment;
    var cornerSpacing =
            alignment == Q$.GraphicRectangle.ALIGN_INSIDE ? 0 :
            alignment == Q$.GraphicRectangle.ALIGN_OUTSIDE ? lineWidth :
            alignment == Q$.GraphicRectangle.ALIGN_CENTER_LINE || !alignment ? lineWidth / 2 :
            (function() {
              throw "Unknown alignment: " + alignment
            })();

    this._leftLine.setLine(x1, y1 - cornerSpacing, x1, y2 + cornerSpacing);
    this._rightLine.setLine(x2, y1 - cornerSpacing, x2, y2 + cornerSpacing);
    this._topLine.setLine(x1 - cornerSpacing, y1, x2 + cornerSpacing, y1);
    this._bottomLine.setLine(x1 - cornerSpacing, y2, x2 + cornerSpacing, y2);
  },

  show: function (parentElement) {
    this._leftLine.show(parentElement);
    this._rightLine.show(parentElement);
    this._topLine.show(parentElement);
    this._bottomLine.show(parentElement);
  },

  hide: function () {
    this._leftLine.hide();
    this._rightLine.hide();
    this._topLine.hide();
    this._bottomLine.hide();
  },

  remove: function() {
    this._leftLine.remove();
    this._rightLine.remove();
    this._topLine.remove();
    this._bottomLine.remove();
  }
});


// ----------------- DEBUG ---------------------------------------------------

function q__logError(message) {
  if (Q$.DEBUG)
    alert("ERROR: " + message);
}

function q__logWarning(message) {
  //  if (Q__DEBUG)
  //    alert("WARNING: " + message);
}


function q__assert(value, message) {
  if (value !== null && value !== undefined && value !== false)
    return;
  q__logError(message);
}

function q__assertEquals(expectedValue, actualValue, message) {
  if (expectedValue == actualValue)
    return;
  q__logError((message ? message + " ; " : "") + "expected: " + expectedValue + ", but was: " + actualValue);
}


setTimeout(function() {
  window._logEnabled = true
}, 0);
function q__log(text) {
  if (!window._logEnabled)
    return;
  if (!window._logger)
    window._logger = new q__Logger();
  window._logger.log(text);
}

function q__Logger() {
  var div = document.createElement("div");
  div.style.position = "absolute";
  div.style.left = "200px";
  div.style.top = "400px";
  div.style.width = "700px";
  div.style.height = "200px";
  div.style.overflow = "auto";
  div.style.background = "white";
  div.style.border = "2px solid black";
  div.style.zIndex = 10000;
  document.body.appendChild(div);

  if (!document._q_loggersCreated)
    document._q_loggersCreated = 1;
  else
    document._q_loggersCreated++;
  div.id = "_q_logger_" + document._q_loggersCreated;
  //  q__initPopupLayer(div.id, 100, 100, 700, 200, null, null, true);

  this._div = div;
  //  this._win = window.open("about:blank", "q__logger");
  this.log = function (text) {
    var date = new Date();
    //    this._win.document.write(date + " : " + text + "<br>");
    this._div.innerHTML = date + " : " + text + "<br/>" + this._div.innerHTML;
  }
}

function q__Profiler() {
  this._timeStamps = new Array();
  this._timeAccumulators = new Array();

  this.logTimeStamp = function(name) {
    this._timeStamps.push({time: new Date(), name: name});
  }

  this.startMeasuring = function(name) {
    var timeAccumulator = this._timeAccumulators[name];
    if (timeAccumulator == null) {
      timeAccumulator = {name: name, secondsElapsed: 0.0, lastPeriodStartDate: null};
      this._timeAccumulators[name] = timeAccumulator;
      this._timeAccumulators.push(timeAccumulator);
    }
    q__assert(!timeAccumulator.lastPeriodStartDate, "q__Profiler.startMeasuring cannot be called twice for the same name without endMeasuring being called: " + name);
    timeAccumulator.lastPeriodStartDate = new Date();
  }

  this.endMeasuring = function(name) {
    var dateAfter = new Date();
    var timeAccumulator = this._timeAccumulators[name];
    q__assert(timeAccumulator, "q__Profiler.endMeasuring: startMeasuring wasn't called for name: " + name);
    q__assert(timeAccumulator.lastPeriodStartDate, "q__Profiler.endMeasuring: startMeasuring wasn't called for name: " + name);
    var dateBefore = timeAccumulator.lastPeriodStartDate;
    timeAccumulator.lastPeriodStartDate = null;
    var secondsElapsed = (dateAfter.getTime() - dateBefore.getTime()) / 1000;
    timeAccumulator.secondsElapsed += secondsElapsed;
  }

  this.showTimeStamps = function() {
    var result = "";
    for (var i = 0, count = this._timeStamps.length - 1; i < count; i++) {
      var stampBefore = this._timeStamps[i];
      var stampAfter = this._timeStamps[i + 1];
      var elapsed = (stampAfter.time.getTime() - stampBefore.time.getTime()) / 1000;
      result += stampBefore.name + " - " + stampAfter.name + " : " + elapsed + "\n";
    }
    alert(result);
  }

  this.showTimeMeasurements = function() {
    var result = "";
    for (var i = 0, count = this._timeAccumulators.length; i < count; i++) {
      var accumulator = this._timeAccumulators[i];
      var name = accumulator.name;
      var elapsed = accumulator.secondsElapsed;
      result += name + " : " + elapsed + "\n";
    }
    alert(result);
  }

  this.showAllTimings = function() {
    var result = "--- Time-stamps: --- \n\n";
    var i, count, elapsed;
    for (i = 0,count = this._timeStamps.length - 1; i < count; i++) {
      var stampBefore = this._timeStamps[i];
      var stampAfter = this._timeStamps[i + 1];
      elapsed = (stampAfter.time.getTime() - stampBefore.time.getTime()) / 1000;
      result += stampBefore.name + " - " + stampAfter.name + " : " + elapsed + "\n";
    }
    result += "\n--- Time measurements: --- \n\n";
    for (i = 0,count = this._timeAccumulators.length; i < count; i++) {
      var accumulator = this._timeAccumulators[i];
      var name = accumulator.name;
      elapsed = accumulator.secondsElapsed;
      result += name + " : " + elapsed + "\n";
    }
    alert(result);
  }

}

// ----------------- STRING, ARRAYS, OTHER LANGUAGE UTILITIES ---------------------------------------------------

function q__stringsEqualIgnoreCase(str1, str2) {
  if (str1)
    str1 = str1.toLowerCase();
  if (str2)
    str2 = str2.toLowerCase();
  return str1 == str2;
}

function q__StringBuffer() {
  this._strings = [];
  this.append = function(value) {
    this._strings.push(value);
    return this;
  }
  this.toString = function() {
    return this._strings.join("");
  }
  this.getNextIndex = function() {
    return this._strings.length;
  }
  this.setValueAtIndex = function(index, value) {
    this._strings[index] = value;
  }
}

function q__ltrim(value) {
  var re = /\s*((\S+\s*)*)/;
  return value.replace(re, "$1");
}

function q__rtrim(value) {
  var re = /((\s*\S+)*)\s*/;
  return value.replace(re, "$1");
}

function q__trim(value) {
  return q__ltrim(q__rtrim(value));
}

function q__stringEndsWith(str, ending) {
  if (!str || !ending)
    return false;
  var endingLength = ending.length;
  var length = str.length;
  if (length < endingLength)
    return false;
  var actualEnding = str.substring(length - endingLength, length);
  return actualEnding == ending;
}

function q__stringStartsWith(str, text) {
  if (!str || !text)
    return false;
  var textLength = text.length;
  var length = str.length;
  if (length < textLength)
    return false;
  var actualStartText = str.substring(0, textLength);
  return actualStartText == text;
}

function q__findValueInArray(value, arr) {
  for (var i = 0, count = arr.length; i < count; i++) {
    var obj = arr[i];
    if (obj == value)
      return i;
  }
  return -1;
}

function q__getArrayFromString(str, delimiter) {
  var idx = str.indexOf(delimiter);
  var arr = new Array();
  var arrIdx = 0;
  while (idx != -1) {
    arr[arrIdx++] = str.substring(0, idx);
    str = str.substring(idx + 1);
    idx = str.indexOf(delimiter);
  }
  arr[arrIdx] = str;
  return arr;
}

function q__arrayContainsValue(array, value) {
  var idx = q__findValueInArray(value, array);
  return idx != -1;
}

function q__unescapeHtml(val) {
  var re = /\&\#(\d+)\;/
  while (re.test(val)) {
    val = val.replace(re, String.fromCharCode(RegExp.$1));
  }
  return val;
}

if (!Array.prototype.every) {
  Array.prototype.every = function(fun /*, thisp*/) {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();
    var thisp = arguments[1];
    for (var i = 0; i < len; i++) {
      if (i in this &&
          fun.call(thisp, this[i], i, this) == false)
        return false;
    }
    return true;
  };
}

function q__dateByTimeMillis(time) {
  var date = new Date();
  date.setTime(time);
  return date;
}

function q__cloneDate(date) {
  return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}

function q__cloneDateTime(date) {
  var clonedDate = new Date();
  clonedDate.setTime(date.getTime());
  return clonedDate;
}

function q__incDay(date, increment) {
  if (increment == undefined)
    increment = 1;
  var newDate = new Date(date.getTime() + increment * 86400000);
  return newDate;
}

function q__minDefined(value1, value2) {
  if (value1 != undefined && value2 != undefined && !isNaN(value1) && !isNaN(value2))
    return Math.min(value1, value2);
  return value1 !== undefined && !isNaN(value1) ? value1 : value2;
}

function q__maxDefined(value1, value2) {
  if (value1 != undefined && value2 != undefined && !isNaN(value1) && !isNaN(value2))
    return Math.max(value1, value2);
  return value1 !== undefined && !isNaN(value1) ? value1 : value2;
}

// ----------------- BROWSER DETECTION ---------------------------------------------------

function q__userAgentContains(browserName) {
  return navigator.userAgent.toLowerCase().indexOf(browserName.toLowerCase()) > -1;
}

function q__isStrictMode() {
  return document.compatMode == "CSS1Compat";
}
function q__isQuirksMode() {
  return document.compatMode != "CSS1Compat";
}

function q__isMozillaFF() {
  if (window._q_mozilla == undefined)
    window._q_mozilla = q__userAgentContains("mozilla") &&
                        !q__userAgentContains("msie") &&
                        !q__userAgentContains("safari");
  return window._q_mozilla;
}

function q__isMozillaFF2() {
  return q__isMozillaFF() && !q__userAgentContains("Firefox/3.0");
}

function q__isMozillaFF3() {
  return q__isMozillaFF() && q__userAgentContains("Firefox/3.0");
}

function q__isExplorer() {
  if (window._q_explorer == undefined)
    window._q_explorer = q__userAgentContains("msie") && !q__userAgentContains("opera");
  return window._q_explorer;
}

function q__isExplorer7() {
  if (window._q_explorer7 == undefined)
    window._q_explorer7 = q__isExplorer() && q__userAgentContains("MSIE 7");
  return window._q_explorer7;
}

function q__isOpera9AndLate() {
  if (window._q_opera9 == undefined) {
    if (q__isOpera()) {
      window._q_opera9 = /\bOpera(\s|\/)(\d{2,}|([9]){1})/i.test(navigator.userAgent);
    }
  }
  return window._q_opera9;
}

function q__isSafari3AndLate() {
  if (window._q_safari3 == undefined)
    if (q__isSafari()) {
      window._q_safari3 = /\bversion(\s|\/)(\d{2,}|[3-9]{1})/i.test(navigator.userAgent);
    }
  return window._q_safari3;
}

function q__isSafariOnMac() {
  if (window._q_safariOnMac == undefined) {
    window._q_safariOnMac = q__isSafari() && q__userAgentContains("Macintosh");
  }
  return window._q_safariOnMac;
}

function q__isSafariOnWindows() {
  if (window._q_safariOnWindows == undefined) {
    window._q_safariOnWindows = q__isSafari() && q__userAgentContains("Windows");
  }
  return window._q_safariOnWindows;
}

function q__isSafari2() {
  if (window._q_safari2 == undefined) {
    window._q_safari2 = q__isSafari() && !q__isSafari3AndLate() && !q__isChrome();
  }
  return window._q_safari2;
}

function q__isChrome() {
  if (window._q_chrome == undefined)
    window._q_chrome = q__userAgentContains("Chrome");
  return window._q_chrome;
}

function q__isOpera() {
  if (window._q_opera == undefined)
    window._q_opera = q__userAgentContains("opera");
  return window._q_opera;
}

function q__isSafari() {
  if (window._q_safari == undefined)
    window._q_safari = q__userAgentContains("safari");
  return window._q_safari;
}

// ----------------- DOM FUNCTIONS ---------------------------------------------------

function q__getControl(id) {
  return document.getElementById(id);
}

function q__findParentNode(element, tagName) {
  tagName = tagName.toUpperCase();
  while (element) {
    var elementNodeName = element.nodeName;
    if (elementNodeName)
      elementNodeName = elementNodeName.toUpperCase();
    if (elementNodeName == tagName)
      break;
    element = element.parentNode;
  }
  if (element != null)
    return element;
  else
    return null;
}

function q__findAnyParentNode(element, tagNames) {
  for (var i = 0, count = tagNames.length; i < count; i++)
    tagNames[i] = tagNames[i].toUpperCase();
  while (element && q__findValueInArray(element.nodeName.toUpperCase(), tagNames) == -1)
    element = element.parentNode;
  if (element != null)
    return element;
  else
    return null;
}

function q__getElement(identifier) {
  var element = document.getElementById(identifier);
  if (element)
    return element;

  var elementCollection = document.getElementsByName(identifier);
  if (elementCollection)
    return elementCollection[0];

  return null;
}

function q__isChild(parent, child) {
  if (parent.id && child.id && parent.id == child.id) return true;
  if (child.parentNode && child.parentNode.nodeName && child.parentNode.nodeName.toUpperCase() != "BODY") {
    return q__isChild(parent, child.parentNode);
  }
  return false;
}

function q__findChildNodesByClass(node, className, searchTopLevelOnly) {
  var result = new Array();
  var children = node.childNodes;
  for (var i = 0, count = children.length; i < count; i++) {
    var child = children[i];
    if (child.className == className)
      result.push(child);
    //    var childClass = child.className;
    //    var childClassNames = childClass ? childClass.split(" ") : new Array();
    //    if (childClassNames.q__indexOf(className))
    var subResult = !searchTopLevelOnly && q__findChildNodesByClass(child, className);
    for (var childIndex = 0, subResultCount = subResult.length; childIndex < subResultCount; childIndex++) {
      var innerResult = subResult[childIndex];
      result.push(innerResult);
    }
  }
  return result;
}

function q__getChildNodesWithNames(node, nodeNames) {
  var selectedChildren = new Array();
  var children = node.childNodes;
  for (var i = 0, count = children.length; i < count; i++) {
    var child = children[i];
    var childNodeName = child.nodeName;
    if (childNodeName)
      childNodeName = childNodeName.toLowerCase();
    for (var j = 0, jcount = nodeNames.length; j < jcount; j++) {
      var nodeName = nodeNames[j];
      nodeName = nodeName.toLowerCase();
      if (childNodeName == nodeName)
        selectedChildren.push(child);
    }
  }
  return selectedChildren;
}

function q__findElementByPath(node, childPath, ignoreNonExistingElements) {
  var separatorIndex = childPath.indexOf("/");
  var locator = separatorIndex == -1 ? childPath : childPath.substring(0, separatorIndex);
  var remainingPath = separatorIndex != -1 ? childPath.substring(separatorIndex + 1) : null;

  var bracketIndex = locator.indexOf("[");
  var childElementName = bracketIndex == -1 ? locator : locator.substring(0, bracketIndex);
  var childElementIndex;
  if (bracketIndex == -1) {
    childElementIndex = 0;
  } else {
    q__assert(q__stringEndsWith(locator, "]"), "q__findElementByPath: unparsable element locator - non-matching brackets: " + childPath);
    var indexStr = locator.substring(bracketIndex + 1, locator.length - 1);
    try {
      childElementIndex = parseInt(indexStr);
    } catch (e) {
      if (ignoreNonExistingElements)
        return null;
      throw "q__findElementByPath: Couldn't parse child index (" + indexStr + "); childPath = " + childPath;
    }
  }
  var childrenByName = q__getChildNodesWithNames(node, [childElementName]);
  if (childrenByName.length == 0) {
    if (ignoreNonExistingElements)
      return null;
    throw "q__findElementByPath: Couldn't find child nodes by element name: " + childElementName + " ; childPath = " + childPath;
  }
  var child = childrenByName[childElementIndex];
  if (!child) {
    if (ignoreNonExistingElements)
      return null;
    throw "q__findElementByPath: Child not found by index: " + childElementIndex + " ; childPath = " + childPath;
  }
  if (remainingPath == null)
    return child;
  else
    return q__findElementByPath(child, remainingPath);
}

function q__isElementPresentInDocument(element) {
  var result = false;
  if (element == document) {
    return true;
  }
  if (element.parentNode != null) {
    result = q__isElementPresentInDocument(element.parentNode);
  }
  return result;
}

function q__removeAllChildNodes(element) {
  while (element.childNodes.length > 0)
    element.removeChild(element.childNodes[0]);
}

function q__setInnerText(element, text, escapeHtml) {
  if (escapeHtml === false) {
    element.innerHTML = text;
    return;
  }
  q__removeAllChildNodes(element);
  element.appendChild(document.createTextNode(text));
}

function q__createStyledText(text, styleClass) {
  var container = document.createElement("span")
  container.appendChild(document.createTextNode(text));
  container.className = styleClass;
  return container;
}

// ----------------- FORM, FORM ELEMENTS MANIPULATION ---------------------------------------------------

function q__submitEnclosingForm(element) {
  q__assert(element, "element should be passed to q__submitEnclosingForm");
  var frm = q__findParentNode(element, "FORM");
  q__assert(frm, "q__submitEnclosingForm: Enclosing form not found for element with id: " + element.id + "; element tag name: " + element.tagName);
  if (frm.onsubmit)
    if (!frm.onsubmit())
      return;

  frm.submit();
}

function q__submitEnclosingElementsForm(elements) {
  q__assert(elements[0], "elements should be passed to q__submitEnclosingElementsForm");
  var frm = q__findParentNode(elements[0], "FORM");
  if (!elements.every(function(element) {
    return (frm == q__findParentNode(element, "FORM"));
  })) {
    q__logError("q__submitEnclosingElementsForm: Enclosing forms differ for components");
  }
  q__assert(frm, "q__submitEnclosingElementsForm: Enclosing form not found for elements");
  if (frm.onsubmit)
    if (!frm.onsubmit())
      return;

  frm.submit();
}
function q__submitFormWithAdditionalParams(element, params) {
  q__assert(element, "element should be passed to q__submitFormWithAdditionalParams");
  q__assert(params, "params should be passed to q__submitFormWithAdditionalParams");
  for (var i = 0, count = params.length; i < count; i++) {
    var param = params[i];
    q__addHiddenField(element, param[0], param[1]);
  }

  var frm = q__findParentNode(element, "FORM");
  frm.submit();
}

function q__submitFormWithAdditionalParam(element, paramName, paramValue) {
  q__submitFormWithAdditionalParams(element, [[paramName, paramValue]]);
}

function q__addHiddenField(element, fieldName, fieldValue) {
  var frm;
  if (!element) {
    frm = document.forms[0];
    q__assert(frm, "q__addHiddenField: There must be a form in the document");
  } else {
    frm = element._form ? element._form : q__findParentNode(element, "FORM");
    q__assert(frm, "q__addHiddenField: Enclosing form not found for element with id: " + element.id + "; element tag name: " + element.tagName);
  }
  var existingField = document.getElementById(fieldName);
  var newParamField = existingField ? existingField : document.createElement("input");
  if (!existingField) {
    newParamField.type = "hidden";
    newParamField.id = fieldName;
    newParamField.name = fieldName;
    frm.appendChild(newParamField);
  }
  if (!fieldValue)
    fieldValue = "";
  newParamField.value = fieldValue;
  return newParamField;
}

function q__submitById(elementId) {
  var element = document.getElementById(elementId);
  q__assert(element, "correct element id should be passed to q__submitById");
  q__submitEnclosingForm(element);
}

function q__submitByIds(elementIds) {
  var elements = new Array();
  for (var i = 0, count = elementIds.length; i < count; i++) {
    elements[elements.length] = document.getElementById(elementIds[i]);
    q__assert(elements[elements.length - 1], "correct element id should be passed to q__submitByIds");
  }
  q__submitEnclosingElementsForm(elements);
}

function q__setValue(elementId, value) {
  var field = document.getElementById(elementId);
  q__assert(field, "Correct element id should be passed to q__setValue; elementId = " + elementId);
  if (field) {
    field.value = value;
  }
}

q__addLoadEvent(function() {
  for (var i = 0, count = document.forms.length; i < count; i++) {
    var frm = document.forms[i];
    q__addEventHandler(frm, "submit", function() {
      if (!this.target || this.target != "_blank") {
        document._q_formSubmissionJustStarted = true;
        // _q_formSubmissionJustStarted should be reset so as not to block further ajax actions if this is not actually
        // a normal form submission, but file download (JSFC-2940)
        setTimeout(function() {
          document._q_formSubmissionJustStarted = false;
        }, 100);
      }
    });
    if (frm._q_prevSubmit) continue;
    frm._q_prevSubmit = frm.submit;
    frm.submit = function() {
      if (!this.target || this.target != "_blank") {
        document._q_formSubmissionJustStarted = true;
        setTimeout(function() {
          document._q_formSubmissionJustStarted = false;
        }, 100);
      }
      this._q_prevSubmit();
    }
  }

});

//{
//  var submitElement = null;
//  submitElement = document.getElementById("submit");
//  if (submitElement == null) {
//    for (var i = 0, count = document.forms.length; i < count; i++) {
//      submitElement = document.forms.getElementsByName("submit");
//      if (submitElement)
//        break;
//    }
//  }
//  if (submitElement) {
//    q__logError("The document contains an element with id or name equal to \"submit\". Please use different id/name in order to avoid collision with form.submit() method");
//  }
//}
//
function q__isFormSubmissionJustStated() {
  return document._q_formSubmissionJustStarted;
}

// ----------------- EVENT UTILITIES ---------------------------------------------------

function q__getEventHandlerFunction(handlerName, handlerArgs, mainObj) {
  var handlerFunction;

  if (!q__getEventHandlerFunction.apply) {
    eval("handlerFunction = function() { return arguments.callee.prototype._ownObj." + handlerName + "(" + (handlerArgs ? handlerArgs : "") + "); }");
  } else {
    var argString = handlerArgs ? ("[" + handlerArgs + "]") : "arguments";
    eval("handlerFunction = function() { return arguments.callee.prototype._ownObj." + handlerName + ".apply(arguments.callee.prototype._ownObj," + argString + "); }");
  }
  handlerFunction.prototype._ownObj = mainObj;
  return handlerFunction;
}

function q__addEvent(componentCilentId, eventName, functionScript) {
  if (!document.__attachedEvents) {
    document.__attachedEvents = new Array();
  }

  var element = q__getElement(componentCilentId);
  if (element) {
    q__addEventHandler(element, eventName, functionScript);
  }

  var eventToDetach = new Object();
  eventToDetach.componentClientId = componentCilentId;
  eventToDetach.eventName = eventName;
  eventToDetach.functionScript = functionScript;

  if (!document.__attachedEvents[componentCilentId]) {
    document.__attachedEvents[componentCilentId] = new Array();
  }

  var componentAttachedEvents = document.__attachedEvents[componentCilentId];
  componentAttachedEvents.push(eventToDetach);
  document.__attachedEvents[componentCilentId] = componentAttachedEvents;
}

function q__addEventHandler(elt, evtName, evtScript, useCapture) {
  if (elt.addEventListener) {
    elt.addEventListener(evtName, evtScript, !!useCapture);
  } else if (elt.attachEvent) {
    elt.attachEvent("on" + evtName, evtScript);
  }
}

function q__removeEventHandler(elt, evtName, evtScript, useCapture) {
  if (elt.addEventListener) {
    elt.removeEventListener(evtName, evtScript, !!useCapture);
  } else if (elt.attachEvent) {
    elt.detachEvent("on" + evtName, evtScript);
  }
}

/* Use this function instead of direct field assignment to work around Mozilla problems firing old events when
 new page is loading (JSFC-2276) */
function q__assignEventHandlerField(element, fieldName, handler) {
  element[fieldName] = handler;
  if (q__isMozillaFF()) {
    q__addUnloadEvent(function() {
      element[fieldName] = null;
    })
  }
}

function q__assignEvents(element, eventsContainer, useEventFields, additionalEventProperties) {
  if (!eventsContainer || eventsContainer.length == 0)
    return;
  var eventPrefix = "on";
  for (var propertyName in eventsContainer) {
    if (!q__stringStartsWith(propertyName, eventPrefix))
      continue;
    var eventScript = eventsContainer[propertyName];
    if (!eventScript)
      continue;

    var handlerFunction;
    if (typeof eventScript == "string")
      eval("handlerFunction = function(event) {return eval(arguments.callee.prototype._handlerScript); }");
    else
      handlerFunction = eventScript;
    handlerFunction.prototype._handlerScript = eventScript;
    if (additionalEventProperties) {
      function wrapHandlerFunction(originalHandlerFunction) {
        return function(event) {
          for (var propertyName in additionalEventProperties) {
            var propertyValue = additionalEventProperties[propertyName];
            if (typeof propertyValue != "function")
              event[propertyName] = propertyValue;
          }
          originalHandlerFunction(event);
        }
      }
      handlerFunction = wrapHandlerFunction(handlerFunction);
    }
    var eventName = propertyName.substring(eventPrefix.length);
    if (useEventFields)
      element[propertyName] = handlerFunction;
    else
      q__addEventHandler(element, eventName, handlerFunction);
  }
}

function q__repeatClickOnDblclick(e) {
  if (q__isExplorer() && this.onclick) this.onclick(e);
  if (q__isExplorer() && this.onmousedown) this.onmousedown(e);
}

q__invokeOnce(q__initDocumentMouseClickListeners, "q__initDocumentMouseClickListeners");

function q__initDocumentMouseClickListeners() {
  if (document._q__initDocumentMouseClickListeners_called) {
    return;
  }

  if (!document._mouseClickListeners) {
    document._mouseClickListeners = new Array();
  }
  document._addClickListener = function (listener) {
    if (listener) {
      this._mouseClickListeners.push(listener);
    }
  };
  document._fireDocumentClicked = function (event) {
    for (var i = 0; i < document._mouseClickListeners.length; i++) {
      document._mouseClickListeners[i](event);
    }
  };
  q__addEventHandler(document, "mousedown", document._fireDocumentClicked);

  document._q__initDocumentMouseClickListeners_called = true;
}

/*
 * The last "receiverThisRef" parameter can be omitted if it's acceptable that "this" variable in the
 * event handler refer to eventSource.
 */
function q__addEventHandlerSimple(eventSource, eventName, handlerFunctionName, receiverThisRef) {
  var handler = q__getEventHandlerFunction(handlerFunctionName, null, receiverThisRef ? receiverThisRef : eventSource);
  q__addEventHandler(eventSource, eventName, handler);
}

/*
 * eventName should be without the "on" prefix, for example: "change", "click", etc.
 */
function q__createEvent(eventName) {
  var e;
  try {
    e = document.createEvent ? document.createEvent("Events") : document.createEventObject();
  } catch (exception) {
    e = [];
  }

  var eventInitialized = false;
  try {
    if (document.createEvent)
      e.initEvent(eventName, true, true);
  } catch (exception) {
    // e.g. takes place in Safari
  }
  if (!eventInitialized)
    e.name = "on" + eventName;

  return e;
}

/*
 * eventName should be without the "on" prefix, for example: "change", "click", etc.
 */
function q__sendEvent(object, eventName) {
  var safari = q__isSafari();
  var e = safari ? {} :
          document.createEvent ? document.createEvent("Event") :
          document.createEventObject();
  if (document.createEvent && !safari) {
    e.initEvent(eventName, true, true);
    e._qk_event = true;
    e.returnValue = true;
    object.dispatchEvent(e);
    return e.returnValue;
  } else {
    e.name = "on" + eventName;
    e._qk_event = true;
    var handler = object[e.name];
    if (!handler)
      return true;
    return object[e.name](e);
    //    object.fireEvent(e.name, e); // - didn't work for firing "onchange" for <table>
  }

}


function q__cancelBubble(evt) {
  var e = evt ? evt : window.event;
  e.cancelBubble = true;
}

function q__isAltPressed(event) {
  if (event == null || event.altKey == null)
    return false;
  return event.altKey;
}
//

function q__isCtrlPressed(event) {
  if (event == null || event.ctrlKey == null)
    return false;
  return event.ctrlKey;
}
//

function q__isShiftPressed(event) {
  if (event == null || event.shiftKey == null)
    return false;
  return event.shiftKey;
}

function q__getEvent(e) {
  return e ? e : event;
}

function q__breakEvent(e) {
  q__stopEvent(e);
  q__preventDefaultEvent(e);
}

function q__preventDefaultEvent(e) {
  var evt = q__getEvent(e);

  if (evt.preventDefault) {
    evt.preventDefault();
  }
  evt.returnValue = false;
}

function q__stopEvent(e) {
  var evt = q__getEvent(e);

  if (evt.stopPropagation)
    evt.stopPropagation();
  evt.cancelBubble = true;
}

function q__getEventPointOnDocument(e) {
  var evt = q__getEvent(e);
  var pageScrollPos = q__getPageScrollPos();
  return {x: evt.clientX + pageScrollPos.x, y: evt.clientY + pageScrollPos.y};
}

function q__addLoadEvent(func, _isAjaxRequest) {
  if (document._q_onLoadEventsProcessed || _isAjaxRequest) {
    func();
  }
  else {
    q__addEventHandler(window, "load", func);
  }
}

function q__addUnloadEvent(func) {
  var invokeOnUnloadHandlersFunction = function() {
    for (var i = 0, count = window._q_onUnloadEvents.length; i < count; i++) {
      var onUnloadHandler = window._q_onUnloadEvents[i];
      onUnloadHandler();
    }
  }

  if (!window._q_onUnloadEvents) {
    window._q_onUnloadEvents = new Array();

    var oldonunload = window.onunload;
    if (typeof window.onunload != "function") {
      window.onunload = function() {
        invokeOnUnloadHandlersFunction();
      }
    } else {
      window.onunload = function() {
        oldonunload();
        invokeOnUnloadHandlersFunction();
      }
    }
  }

  _q_onUnloadEvents.push(func);
}


// This function call is required to make components know certainly that onLoad event had been already proccesed.
q__addLoadEvent(function() {
  document._q_onLoadEventsProcessed = true;
});

function q__isLoadedFullPage() {
  return document._q_onLoadEventsProcessed;
}

function q__createHiddenFocusElement() {
  var createTextArea = true;
  var focusControl = document.createElement(createTextArea ? "textarea" : "input");
  if (!createTextArea)
    focusControl.type = "button";
  focusControl.className = "q_hiddenFocus";
  if (q__isSafari()) {
    focusControl.style.border = "1px solid transparent !important"
  }
  return focusControl;
}

function q__initDefaultScrollPosition(trackerFieldId, scrollPos) {
  q__addHiddenField(null, trackerFieldId, scrollPos);
  q__initScrollPosition_(trackerFieldId, true, 1, null);
}

function q__initScrollPosition(scrollPosFieldId, autoSaveScrollPos) {
  q__initScrollPosition_(scrollPosFieldId, autoSaveScrollPos, 2, null);
}
function q__initScrollPosition(scrollPosFieldId, autoSaveScrollPos, scrollableComponentId) {
  q__initScrollPosition_(scrollPosFieldId, autoSaveScrollPos, 2, scrollableComponentId);
}

function q__initScrollPosition_(scrollPosFieldId, autoSaveScrollPos, priority, scrollableComponentId) {
  if (scrollableComponentId) {
    var scrollableComponent = document.getElementById(scrollableComponentId);
    if (scrollableComponent && scrollableComponent.q__scrollPosTrackingParams)
      if (scrollableComponent.q__scrollPosTrackingParams.priority > priority)
        return;
  } else {
    if (window.q__scrollPosTrackingParams)
      if (window.q__scrollPosTrackingParams.priority > priority)
        return;
  }

  var targetComponent = (scrollableComponent) ? scrollableComponent : window;

  targetComponent.q__scrollPosTrackingParams = {fieldId: scrollPosFieldId, autoSave: autoSaveScrollPos,
    priority: priority, scrollableId:scrollableComponentId};

  q__addLoadEvent(function() {
    if (!targetComponent.q__scrollPosTrackingParams)
      return;
    var scrollPosFieldId = targetComponent.q__scrollPosTrackingParams.fieldId;
    var autoSaveScrollPos = targetComponent.q__scrollPosTrackingParams.autoSave;
    targetComponent.q__scrollPosTrackingParams = null;
    var fld = document.getElementById(scrollPosFieldId)
    if (targetComponent == window) {
      document.q__scrollPositionField = fld;
    } else {
      targetComponent.q__scrollPositionField = fld;
    }

    var scrollPos = fld.value;

    q__scrollToPosition(targetComponent, scrollPos);

    q__addEventHandler(targetComponent, "scroll", function() {
      var scrollPos = (targetComponent == window)
              ? q__getPageScrollPos() : q__getScrollPos(scrollableComponent);

      if (targetComponent == window) {
        document.q__scrollPositionField.value = "[" + scrollPos.x + "," + scrollPos.y + "]";
      } else {
        targetComponent.q__scrollPositionField.value = "[" + scrollPos.x + "," + scrollPos.y + "]";
      }
    });
  });
}

function q__saveScrollPositionIfNeeded() {
  // needed for saving scroll position between ajax request under Mozilla Firefox
  var isMozilla = q__isMozillaFF() || q__isSafari3AndLate() /*todo:check whether q__isSafari3AndLate check is really needed (it was added by mistake)*/;
  var isScrollPositionTrackingEnabled = (document.q__scrollPositionField);

  // remember scrollPosition before replacing oldElement by new one
  if (isMozilla && isScrollPositionTrackingEnabled) {
    var scrollPosFieldId = document.q__scrollPositionField.id;
    var fld = document.getElementById(scrollPosFieldId)
    var scrollPos = fld.value;
    document.q__scrollPositionBeforeAjaxRequest = scrollPos;
  }
}

function q__retoreScrollPositionIfNeeded() {
  var isMozilla = q__isMozillaFF() || q__isSafari3AndLate() /*todo:check whether q__isSafari3AndLate check is really needed (it was added by mistake)*/;
  var isScrollPositionTrackingEnabled = (document.q__scrollPositionField);

  // scroll to previous scrollPosition
  if (isMozilla && isScrollPositionTrackingEnabled) {
    var scrollPos = document.q__scrollPositionBeforeAjaxRequest;
    q__scrollToPosition(window, scrollPos);
  }
}

function q__scrollToPosition(scrollableComponent, scrollPos) {
  var x, y, separatorIndex, currentScrollPos;
  if (scrollableComponent.scrollTo && scrollPos && scrollPos != "") {
    scrollPos = scrollPos.substring(1, scrollPos.length - 1);
    separatorIndex = scrollPos.indexOf(",");
    x = scrollPos.substring(0, separatorIndex);
    y = scrollPos.substring(separatorIndex + 1, scrollPos.length);
    currentScrollPos = (scrollableComponent == window)
            ? q__getScrollPos(scrollableComponent)
            : q__getPageScrollPos();

    if (x == currentScrollPos.x && y == currentScrollPos.y) {
      return;
    }
    scrollableComponent.scrollTo(x, y);
    if (q__isExplorer()) {
      setTimeout(function() {
        scrollableComponent.scrollTo(x, y)
      }, 10);
    }
  } else if (scrollPos && scrollPos != "") {
    scrollPos = scrollPos.substring(1, scrollPos.length - 1);
    separatorIndex = scrollPos.indexOf(",");
    x = scrollPos.substring(0, separatorIndex);
    y = scrollPos.substring(separatorIndex + 1, scrollPos.length);
    currentScrollPos = (scrollableComponent == window)
            ? q__getScrollPos(scrollableComponent)
            : q__getPageScrollPos();

    if (x == currentScrollPos.x && y == currentScrollPos.y) {
      return;
    }

    scrollableComponent.scrollLeft = x;
    scrollableComponent.scrollTop = y;

    if (q__isExplorer()) {
      setTimeout(function() {
        scrollableComponent.scrollLeft = x;
        scrollableComponent.scrollTop = y;
      }, 10);
    }
  }
}
function q__initDefaultFocus(trackerFieldId, focusedComponentId) {
  q__addHiddenField(null, trackerFieldId, focusedComponentId);
  q__initFocus_(trackerFieldId, true, 1);
}

function q__initFocus(trackerFieldId, autoSaveFocus) {
  q__initFocus_(trackerFieldId, autoSaveFocus, 2);
}

function q__initFocus_(trackerFieldId, autoSaveFocus, priority) {
  q__addLoadEvent(function() {
    if (!document.q__focusPriority || priority > document.q__focusPriority) {
      document.q__focusPriority = priority;
      var trackerField = document.getElementById(trackerFieldId);
      document.q__focusField = trackerField;
      var componentId = trackerField.value;
      var focused = false;
      if (componentId) {
        var c = document.getElementById(componentId);
        if (c && c.focus) {
          try {
            c.focus();
            var rect = q__getElementBorderRectangle(c);
            q__scrollRectIntoView(rect);
          } catch(ex) {
          }
          document.q__activeElement = c;
          focused = true;
        }
      }
      if (!focused && document.q__activeElement && document.q__activeElement.blur) {
        document.q__activeElement.blur();
        //        q__setPageScrollPos({x: 0, y: 0});
      }
    }

    if (!autoSaveFocus)
      return;

    if (document.q__autoSavingFocusInitialized)
      return;
    document.q__autoSavingFocusInitialized = true;

    var bodyElement = document.getElementsByTagName("body")[0];
    if (bodyElement == null)
      return;
    q__setupFocusOnTags(bodyElement, "input");
    q__setupFocusOnTags(bodyElement, "a");
    q__setupFocusOnTags(bodyElement, "button");
    q__setupFocusOnTags(bodyElement, "textarea");
    q__setupFocusOnTags(bodyElement, "select");
  });
}

function q__setupFocusOnTags(parent, tagName) {
  var elements = parent.getElementsByTagName(tagName);
  for (var i = 0; i < elements.length; i++) {
    var element = elements[i];
    element.q__prevOnFocusHandler = element.onfocus;
    element.onfocus = function (e) {
      document.q__activeElement = this;
      document.q__focusField.value = this.id;
      if (this.q__prevOnFocusHandler)
        this.q__prevOnFocusHandler(e);
    }
    element.q__prevOnBlurHandler = element.onblur;
    element.onblur = function (e) {
      if (document.q__activeElement == this) {
        document.q__activeElement = null;
        document.q__focusField.value = "";
      }
      if (this.q__prevOnBlurHandler)
        this.q__prevOnBlurHandler(e);
    }
  }

}

function q__initMouseListenerUtils() {
  if (document._mouseListenerUtilsInitialized)
    return;
  document._mouseListenerUtilsInitialized = true;
  document._q_elementUnderMouse = null;
  document._q_prevMouseMove = document.onmousemove;
  document.onmousemove = function(e) {
    var result = undefined;
    if (document._q_prevMouseMove) {
      result = document._q_prevMouseMove(e);
    }

    var evt = q__getEvent(e);
    var elementList = new Array();
    if (document._q_elementUnderMouse) {
      for (var element = document._q_elementUnderMouse; element; element = element.parentNode) {
        element._q_mouseInside = false;
        element._q_fireMouseOut = true;
        elementList.push(element);
      }
    }
    document._q_elementUnderMouse = evt.target ? evt.target : evt.srcElement;
    if (document._q_elementUnderMouse) {
      for (var element = document._q_elementUnderMouse; element; element = element.parentNode) {
        element._q_mouseInside = true;
        element._q_fireMouseOver = true;
        elementList.push(element);
      }
    }

    for (var i = 0, count = elementList.length; i < count; i++) {
      var el = elementList[i];
      if (!el._q_fireMouseOut && !el._q_fireMouseOver)
        continue;
      if (el._q_fireMouseOut && el._q_fireMouseOver) {
        el._q_fireMouseOut = undefined;
        el._q_fireMouseOver = undefined;
        continue;
      }
      if (el._q_fireMouseOut) {
        if (el._q_mouseOutListeners)
          for (var listenerIndex = 0, listenerCount = el._q_mouseOutListeners.length; listenerIndex < listenerCount; listenerIndex++) {
            var listener = el._q_mouseOutListeners[listenerIndex];
            listener(e);
          }
        el._q_fireMouseOut = undefined;
      }
      if (el._q_fireMouseOver) {
        if (el._q_mouseOverListeners)
          for (var listenerIndex = 0, listenerCount = el._q_mouseOverListeners.length; listenerIndex < listenerCount; listenerIndex++) {
            var listener = el._q_mouseOverListeners[listenerIndex];
            listener(e);
          }
        el._q_fireMouseOver = undefined;
      }
    }

    return result;
  }
}

function q__invokeFunctionAfterDelay(func, delay, actionId) {
  // Invokes the specified function after the specified delay in milliseconds. If another invocation request comes for
  // the same function during the delay, then the invocation is postponed until that new invocation delay expires, etc.
  // thus making only one call in case of multiple frequent invocations.
  // actionId parameter can obtionally be specified as a string that allows several "postponable" actions for the same
  // function, or several functions for the same action, that is actionId instead of function serves as a criteria for
  // canceling the previous action and scheduling the new one.
  var actionReference = func;
  if (typeof actionId == "string") {
    if (!QuipuKit._actionReferendes)
      QuipuKit._actionReferendes = {};
    actionReference = QuipuKit._actionReferendes[actionId];
    if (!actionReference) {
      actionReference = {};
      QuipuKit._actionReferendes[actionId] = actionReference;
    }
  }
  if (!actionReference._delayedInvocationCount)
    actionReference._delayedInvocationCount = 0;
  actionReference._delayedInvocationCount++;
  setTimeout(function() {
    actionReference._delayedInvocationCount--;
    if (actionReference._delayedInvocationCount == 0)
      func();
  }, delay);
}

function q__setupHoverAndPressStateFunction(element, fn) {
  var state = {
    mouseInside: false,
    pressed: false,
    reset: function() {
      this.mouseInside = false;
      this.pressed = false;
      this._update();
    },
    _update: function() {
      fn(this.mouseInside, this.pressed);
    }
  };
  q__setupHoverStateFunction(element, function(mouseInside) {
    state.mouseInside = mouseInside;
    if (!mouseInside)
      state.pressed = false;
    state._update();

  });
  q__setupMousePressedStateFunction(element, function(pressed) {
    state.pressed = pressed;
    state._update();
  });
  return state;
}

function q__setupHoverStateFunction(element, fn) {
  q__addMouseOverListener(element, function() {
    fn(true, element);
  });
  q__addMouseOutListener(element, function() {
    fn(false, element);
  });
}

function q__setupMousePressedStateFunction(element, fn) {
  q__addEventHandler(element, "mousedown", function() {
    fn(true, element);
  });
  q__addEventHandler(element, "mouseup", function() {
    fn(false, element);
  });
}

function q__addMouseOverListener(element, listener) {
  if (q__isExplorer()) {
    element.onmouseenter = listener;
    return;
  }
  q__initMouseListenerUtils();
  if (!element._q_mouseOverListeners)
    element._q_mouseOverListeners = new Array();
  element._q_mouseOverListeners.push(listener);
}

function q__addMouseOutListener(element, listener) {
  if (q__isExplorer()) {
    element.onmouseleave = listener;
    return;
  }
  q__initMouseListenerUtils();
  if (!element._q_mouseOutListeners)
    element._q_mouseOutListeners = new Array();
  element._q_mouseOutListeners.push(listener);
}

function q__isEventFromInsideOfElement(e, element) {
  var evt = q__getEvent(e);
  var eventTarget = evt.target ? evt.target : evt.srcElement;
  for (var currElement = eventTarget; currElement; currElement = currElement.parentNode) {
    if (currElement == element)
      return true;
  }
  return false;
}

function q__disabledContextMenuFor(element) {
  if (element) {
    element._oldoncontextmenu = element.oncontextmenu;
    element.oncontextmenu = function() {
      if (element._oldoncontextmenu) element._oldoncontextmenu();
      return false;
    };
    element._isDisabledContextMenu = true;
  }
}

function q__enabledContextMenuFor(element) {
  if (element) {
    if (element._oldoncontextmenu)
      element.oncontextmenu = element._oldoncontextmenu;
    else element.oncontextmenu = function() {
      return true;
    };
    element._isDisabledContextMenu = false;
  }
}


function q__getTargetComponentHasOwnMouseBehavior(evt) {
  var element = evt.target ? evt.target : evt.srcElement;
  var tagName = element ? element.tagName : null;
  if (tagName)
    tagName = tagName.toLowerCase();
  var elementHasItsOwnMouseBehavior =
          tagName == "input" ||
          tagName == "textarea" ||
          tagName == "select" ||
          tagName == "option" ||
          tagName == "button" ||
          tagName == "a";
  return elementHasItsOwnMouseBehavior;
}

function q__startDragAndDrop(e, draggable) {
  var evt = q__getEvent(e);
  if (q__getTargetComponentHasOwnMouseBehavior(evt))
    return; // don't drag native components to avoid unwanted effects (see JSFC-2347 and all related requests)

  q__addEventHandler(document, "mousemove", q__handleDragMove, true);
  q__addEventHandler(document, "mouseup", q__handleDragEnd, true);
  draggable._draggingInProgress = true;
  draggable._draggingWasStarted = false;

  var pageScrollPos = q__getPageScrollPos();
  draggable._lastDragX = evt.clientX + pageScrollPos.x;
  draggable._lastDragY = evt.clientY + pageScrollPos.y;
  if (!draggable._getPositionLeft)
    draggable._getPositionLeft = function() {
      return this.offsetLeft;
    }
  if (!draggable._getPositionTop)
    draggable._getPositionTop = function() {
      return this.offsetTop;
    }
  draggable._lastDragOffsetLeft = draggable._getPositionLeft();
  draggable._lastDragOffsetTop = draggable._getPositionTop();

  document._q_draggedElement = draggable;
  q__breakEvent(evt);
  if (document._fireDocumentClicked)
    document._fireDocumentClicked(evt);
}


function q__handleDragMove(e) {
  var evt = q__getEvent(e);
  var draggable = document._q_draggedElement;

  draggable._draggingInProgress = true;
  if (!draggable._draggingWasStarted) {
    draggable._draggingWasStarted = true;
    if (draggable.ondragstart)
      draggable.ondragstart(evt);
  }

  var pageScrollPos = q__getPageScrollPos();
  var dragX = evt.clientX + pageScrollPos.x;
  var dragY = evt.clientY + pageScrollPos.y;
  var left = draggable._getPositionLeft();
  var top = draggable._getPositionTop();
  var xChangeSinceLastDrag = left - draggable._lastDragOffsetLeft;
  var yChangeSinceLastDrag = top - draggable._lastDragOffsetTop;
  var dx = dragX - draggable._lastDragX - xChangeSinceLastDrag;
  var dy = dragY - draggable._lastDragY - yChangeSinceLastDrag;
  var newLeft = left + dx;
  var newTop = top + dy;
  if (draggable.setPosition) {
    draggable.setPosition(newLeft, newTop, dx, dy);
  } else {
    draggable.setLeft(newLeft, dx);
    draggable.setTop(newTop, dy);
  }
  var offsetLeftAfterDragging = draggable._getPositionLeft();
  var offsetTopAfterDragging = draggable._getPositionTop();
  dragX -= newLeft - offsetLeftAfterDragging;
  dragY -= newTop - offsetTopAfterDragging;

  draggable._lastDragX = dragX;
  draggable._lastDragY = dragY;
  draggable._lastDragOffsetLeft = offsetLeftAfterDragging;
  draggable._lastDragOffsetTop = offsetTopAfterDragging;

  q__breakEvent(evt);
}

function q__handleDragEnd(e) {
  var evt = q__getEvent(e);

  var draggable = document._q_draggedElement;
  if (draggable._draggingWasStarted) {
    draggable._draggingWasStarted = undefined;
    if (draggable.ondragend)
      draggable.ondragend(evt);
  }

  q__removeEventHandler(document, "mousemove", q__handleDragMove, true);
  q__removeEventHandler(document, "mouseup", q__handleDragEnd, true);
  if (!draggable._onmouseup) {
    q__breakEvent(evt);
  }
  draggable._draggingInProgress = false;
}

/**
 * Avoids IE issue where mouse events on an absolute element without backgroud and content "leak" to the underlying layer
 * instead of being processed by the element itself.
 */
function fixIEEventsForTransparentLayer(layerElement) {
  if (q__isExplorer()) {
    // specify background for an element to avoid passing events to the underlying layer
    layerElement.style.background = "white";
    q__setOpacityLevel(layerElement, 0);
  }
}


function q__showFocusOutline(component, outlineStyleClass) {
  if (!outlineStyleClass)
    return;

  if (!component._focusOutline) {
    var outline = new Q$.GraphicRectangle("2px solid blue", Q$.GraphicRectangle.ALIGN_OUTSIDE);
    outline._control = component;
    outline._updatePosition = function() {
      var outlineToControlSpacingPx = 2;
      var rect = q__getElementBorderRectangle(component);
      var x = rect.x;
      var y = rect.y;
      var width = rect.width;
      var height = rect.height;
      this.setRectangle(new Q$.Rectangle(
              x - outlineToControlSpacingPx,
              y - outlineToControlSpacingPx,
              width + outlineToControlSpacingPx * 2,
              height + outlineToControlSpacingPx * 2
              ));
    }
    component._focusOutline = outline;
  }
  component._focusOutline._updatePosition();
  component._focusOutline.show();
}

function q__hideFocusOutline(component) {
  if (!component._focusOutline)
    return;
  component._focusOutline.hide();
}

var q__tableBlurCounter = 0;

function q__setupArtificialFocus(component, focusedClassName) {
  component._focused = false;
  component._updateOutline = function() {
    if (this._outlineUpdateBlocked)
      return;
    q__setElementStyleMappings(this, {
      focused: this._focused ? focusedClassName : null
    });

    if (this._focused)
      q__showFocusOutline(this, null);
    else
      q__hideFocusOutline(this);
  }

  component._blockOutlineUpdate = function() {
    this._outlineUpdateBlocked = true;
    this._focusedBeforeBlocking = this._focused;
  }

  component._unblockOutlineUpdate = function () {
    if (!q__tableBlurCounter)
      q__tableBlurCounter = 0;
    if (!q__isMozillaFF()) {
      setTimeout(function() {
        component._doUnblockOutlineUpdate();
      }, 1);
    } else {
      component._doUnblockOutlineUpdate();
    }
  }
  component._doUnblockOutlineUpdate = function() {
    this._outlineUpdateBlocked = false;
    if (this._focusedBeforeBlocking != null && this._focusedBeforeBlocking != this._focused) {
      this._focusedBeforeBlocking = null;
      if (this._focused) {
        if (this._prevOnfocusHandler_af)
          this._prevOnfocusHandler_af(null);
      } else {
        if (this._prevOnblurHandler_af)
          this._prevOnblurHandler_af(null);
      }
    }
    this._updateOutline();
  }

  component._prevOnfocusHandler_af = component.onfocus;
  component._prevOnblurHandler_af = component.onblur;

  component.onfocus = function(evt) {
    if (this._submitting)
      return;
    this._focused = true;
    if (this._prevOnfocusHandler_af && !this._outlineUpdateBlocked)
      this._prevOnfocusHandler_af(evt);

    component._updateOutline();
  }
  component.onblur = function(evt) {
    if (this._submitting)
      return;
    this._focused = false;
    if (this._prevOnblurHandler_af && !this._outlineUpdateBlocked)
      this._prevOnblurHandler_af(evt);
    if (!q__isMozillaFF()) {
      setTimeout(function() {
        component._updateOutline();
      }, 1);
    } else {
      component._updateOutline();
    }
  }

  var focusControl = q__createHiddenFocusElement();

  function fireEvent(object, eventName, param) {
    var handler = object[eventName];
    if (!handler)
      return undefined;
    if (q__isExplorer())
      return object[eventName]();
    else
      return object[eventName](param);
  }

  focusControl._destComponent = component;
  focusControl.onfocus = function(evt) {
    this._prevStatusText = window.status;
    window.status = "";
    return fireEvent(this._destComponent, "onfocus", evt);
  }
  focusControl.onblur = function(evt) {
    window.status = this._prevStatusText;
    return fireEvent(this._destComponent, "onblur", evt);
  }
  focusControl.onkeydown = function(evt) {
    return fireEvent(this._destComponent, "onkeydown", evt);
  }
  focusControl.onkeyup = function(evt) {
    return fireEvent(this._destComponent, "onkeyup", evt);
  }
  focusControl.onkeypress = function(evt) {
    return fireEvent(this._destComponent, "onkeypress", evt);
  }

  function isControlFocusable(control) {
    if (!control)
      return false;

    if (control._focusable)
      return true;
    var tagName = control.tagName;
    if (!tagName)
      return false;
    tagName = tagName.toLowerCase();
    if (tagName == "input" ||
        tagName == "select" ||
        tagName == "textarea" ||
        tagName == "button" ||
        tagName == "a")
      return true;
    else
      return false;
  }

  component._focusControl = focusControl;

  component._focusOnClick = function(evt) {
    if (window.getSelection) {
      if (window.getSelection() != "")
        return; // don't switch focus to make text selection possible under FF (JSFC-1134)
    }
    var e = evt ? evt : event;
    if (this._focused)
      return;

    var target = (e != null)
            ? (e.target ? e.target : e.srcElement)
            : null;
    if (target.id && target.id == this.id)
      return;
    if (isControlFocusable(target))
      return;
    this._preventPageScrolling = true;
    this.focus();
    this._preventPageScrolling = false;
  }

  component._focusable = true;
  component.focus = function() {
    if (this._preventPageScrolling) {
      var pageScrollPos = q__getPageScrollPos();
      this._focusControl.style.left = pageScrollPos.x + "px";
      this._focusControl.style.top = pageScrollPos.y + "px";
    } else {
      this._focusControl.style.left = "";
      this._focusControl.style.top = "";
    }
    this._focusControl.focus();
  }

  component.blur = function() {
    this._focusControl.blur();
  }

  q__addEventHandlerSimple(component, "click", "_focusOnClick");
  q__addEventHandlerSimple(component, "mousedown", "_blockOutlineUpdate");
  q__addEventHandlerSimple(component, "mouseup", "_unblockOutlineUpdate");
  q__addEventHandlerSimple(component, "mouseout", "_unblockOutlineUpdate");

  component.parentNode.insertBefore(focusControl, component);

  var oldUnloadHandler = component.onComponentUnload;
  component.onComponentUnload = function() {
    oldUnloadHandler();
    if (component._focusOutline)
      component._focusOutline.remove();
  }
}

// ----------------- STYLE UTILITIES ---------------------------------------------------

function q__addCssRules(ruleArray) {
  for (var i = 0, count = ruleArray.length; i < count; i++) {
    var rule = ruleArray[i];
    q__addCssRule(rule);
  }
}

function q__getLocalStyleSheet() {
  var styleSheets = document.styleSheets;
  if (!styleSheets)
    return null;

  if (document._q_localStyleSheet)
    return document._q_localStyleSheet;

  function locateLocalStyleSheet() {
    var documentLocation = document.location;
    for (var i = styleSheets.length - 1; i >= 0; i--) {
      var styleSheet = styleSheets[i];
      if (styleSheet.href == documentLocation || /* Mozilla Firefox */
          !styleSheet.href /* other browsers */) {
        document._q_localStyleSheet = styleSheet;
        break;
      }
    }
  }

  //  locateLocalStyleSheet();
  //  if (document._q_localStyleSheet)
  //    return document._q_localStyleSheet;

  if (document.createStyleSheet) {
    document._q_localStyleSheet = document.createStyleSheet();
    if (document._q_localStyleSheet)
      return document._q_localStyleSheet;
  } else {
    var styleElement = document.createElement("style");
    var headTags = document.getElementsByTagName("head");
    var styleParent = headTags.length > 0 ? headTags[0] : document.getElementsByTagName("body")[0];
    styleParent.appendChild(styleElement);
  }
  locateLocalStyleSheet();
  if (!document._q_localStyleSheet) {
    if (styleSheets.length > 0) {
      q__logWarning(document._q_localStyleSheet, "q__getLocalStyleSheet: couldn't find or create local style-sheet in this document, using the first available one.");
      document._q_localStyleSheet = styleSheets[0];
      // relative url paths in background won't work in Mozilla in this case
    } else {
      q__logWarning(document._q_localStyleSheet, "q__getLocalStyleSheet: no style-sheets could be found or created in this document");
    }
  }
  return document._q_localStyleSheet;
}

function q__addCssRule(strRule) {
  var styleSheet = q__getLocalStyleSheet();
  if (!styleSheet)
    return;

  try {
    if (styleSheet.addRule) { // IE only
      var idx1 = strRule.indexOf("{");
      var idx2 = strRule.indexOf("}");
      q__assert(idx1 != -1 && idx2 != -1 && idx2 > idx1, "q__addCssRule: Couldn't parse CSS rule \"{...}\"  boundaries: " + strRule);
      var selector = strRule.substring(0, idx1);
      var declaration = strRule.substring(idx1 + 1, idx2);

      styleSheet.addRule(selector, declaration);
    } else { // all others
      styleSheet.insertRule(strRule, styleSheet.cssRules.length);
    }
  } catch (e) {
    q__logError("q__addCssRule throw an exception " + (e ? e.message : e) +
                "; tried to add the following rule: " + strRule);
    throw e;
  }

}

document._q_dynamicRulesCreated = 0;
function q__createCssClass(declaration, disableCaching) {
  if (!disableCaching) {
    if (!document._cachedDynamicCssRules)
      document._cachedDynamicCssRules = {};
    var cachedClassName = document._cachedDynamicCssRules[declaration];
    if (cachedClassName)
      return;
  }
  var className = "q__dynamicRule" + document._q_dynamicRulesCreated++;
  var ruleText = "." + className + " {" + declaration + "}";
  q__addCssRule(ruleText);
  if (!disableCaching) {
    document._cachedDynamicCssRules[declaration] = className;
  }
  return className;
}

function q__findCssRule(selector) {
  var rules = q__findCssRules([selector]);
  if (rules === undefined)
    return undefined;
  if (rules.length == 0)
    return null;
  return rules[0];
}

/**
 * Searches for CSS rules with the specified selectors, and returns an array of CSSStyleRule (or CSSRule) objects
 * in order of their occurence in DOM
 */
function q__findCssRules(selectors) {
  var styleSheets = document.styleSheets;
  if (!styleSheets)
    return undefined;

  var selectorCount = selectors.length
  if (selectorCount == 0)
    return [];

  for (var i = 0; i < selectorCount; i++)
    selectors[i] = selectors[i].toLowerCase();

  var rulesFound = new Array();
  for (var sheetIndex = 0; sheetIndex < styleSheets.length; sheetIndex++) {
    var ss = styleSheets[sheetIndex];
    var rules = ss.cssRules ? ss.cssRules : ss.rules;
    if (!rules) continue;
    for (var ruleIndex = 0, ruleCount = rules.length; ruleIndex < ruleCount; ruleIndex++) {
      var rule = rules[ruleIndex];
      var selectorName = rule.selectorText;
      if (!selectorName)
        continue;
      selectorName = selectorName.toLowerCase();
      if (q__findValueInArray(selectorName, selectors) != -1)
        rulesFound.push(rule);
    }
  }
  return rulesFound;
}

function q__getStyleClassProperty(styleClass, propertyName) {
  var propertyValues = q__getStyleClassProperties(styleClass, [propertyName]);
  return propertyValues[propertyName];
}

function q__getStyleClassProperties(styleClass, propertyNames) {
  if (!styleClass || propertyNames.length == 0)
    return {};
  var classNames = styleClass.split(" ");
  var classSelectors = new Array();
  for (var i = 0, count = classNames.length; i < count; i++) {
    var className = classNames[i];
    if (className)
      classSelectors.push("." + className);
  }
  var cssRules = q__findCssRules(classSelectors);
  if (!cssRules)
    return {};

  var propertyCount = propertyNames.length;
  var propertyValues = new Object();
  var propertyImportantFlags = new Array();
  for (var i = 0, count = cssRules.length; i < count; i++) {
    var cssRule = cssRules[i];
    var ruleStyle = cssRule.style;
    for (var propertyIndex = 0; propertyIndex < propertyCount; propertyIndex++) {
      var propertyName = propertyNames[propertyIndex];
      var capitalizedPropertyName = q__capitalizeCssPropertyName(propertyName);
      var thisPropertyValue = ruleStyle[capitalizedPropertyName];
      if (!thisPropertyValue)
        continue;
      var thisPropertyImportant = ruleStyle.getPropertyPriority && (ruleStyle.getPropertyPriority(capitalizedPropertyName) == "important");
      if (!propertyImportantFlags[propertyIndex]) {
        propertyValues[propertyName] = thisPropertyValue;
        propertyValues[capitalizedPropertyName] = thisPropertyValue;
        if (thisPropertyImportant)
          propertyImportantFlags[propertyIndex] = true;
      } else {
        if (thisPropertyImportant) {
          propertyValues[propertyName] = thisPropertyValue;
          propertyValues[capitalizedPropertyName] = thisPropertyValue;
        }
      }
    }
  }

  return propertyValues;
}

//

function q__combineClassNames(classNames) {
  var nonNullClassNames = new Array();
  for (var i = 0, count = classNames.length; i < count; i++) {
    var className = classNames[i];
    if (className)
      nonNullClassNames.push(className);
  }
  var result = nonNullClassNames.join(" ");
  return result;
}

function q__appendClassNames(element, classesToAppend) {
  var oldClassName = element.className;
  var newClassName = q__combineClassNames(classesToAppend);
  if (oldClassName)
    newClassName = newClassName ? oldClassName + " " + newClassName : oldClassName;
  if (newClassName != oldClassName)
    element.className = newClassName;
  return oldClassName;
}

function q__excludeClassNames(element, classesToExclude) {
  var newClassesToExclude = new Array();
  for (var i = 0, count = classesToExclude.length; i < count; i++) {
    var clsToExclude = classesToExclude[i];
    if (!clsToExclude)
      continue;
    var subClassesToExclude = clsToExclude.split(" ");
    for (var j = 0, jcount = subClassesToExclude.length; j < jcount; j++) {
      var subClassToExclude = subClassesToExclude[j];
      newClassesToExclude.push(subClassToExclude);
    }
  }

  var someClassesExcluded = false;
  var clsName = element.className;
  var clsNames = clsName ? clsName.split(" ") : new Array();
  var newNames = new Array();
  for (var nameIndex = 0, nameCount = clsNames.length; nameIndex < nameCount; nameIndex++) {
    var currName = clsNames[nameIndex];
    if (currName) {
      if (q__findValueInArray(currName, newClassesToExclude) == -1)
        newNames.push(currName);
      else
        someClassesExcluded = true;
    }
  }
  var newClsName = newNames.join(" ");
  if (element.className != newClsName)
    element.className = newClsName;
  return someClassesExcluded;
}

function q__getElementOwnStyle(element) {
  var styleMappings = element._styleMappings;
  if (!styleMappings)
    return element.className;
  else
    return styleMappings.__initialStyle;
}

function q__setElementOwnStyle(element, value) {
  var styleMappings = element._styleMappings;
  if (!styleMappings)
    return element.className = value;
  else
    return styleMappings.__initialStyle = value;
}

function q__setElementStyleMappings(element, styleMappings) {
  if (!element._styleMappings)
    element._styleMappings = {__initialStyle: element.className};
  var elementStyleMappings = element._styleMappings;
  var styleName, styleValue;
  for (styleName in styleMappings) {
    if (!styleName)
      continue;
    styleValue = styleMappings[styleName];
    if (styleValue && typeof styleValue != "string")
      continue;
    elementStyleMappings[styleName] = styleValue;
  }
  var compoundClassName = "";
  for (styleName in elementStyleMappings) {
    if (!styleName)
      continue;
    styleValue = elementStyleMappings[styleName];
    if (styleValue && typeof styleValue != "string")
      continue;
    if (styleValue) {
      if (compoundClassName.length > 0)
        compoundClassName += " ";
      compoundClassName += styleValue;
    }
  }
  if (element.className != compoundClassName) {
    element.className = compoundClassName;
    if (element._classNameChangeHandler)
      element._classNameChangeHandler();
  }
}

function q__getElementStyleProperty(element, propertyName, enableValueCaching) {
  var propertyValues = q__getElementStyleProperties(element, [propertyName], enableValueCaching);
  return propertyValues[propertyName];
}

function q__getElementStyleProperties(element, propertyNames, enableValueCaching) {
  if (enableValueCaching) {
    if (!element._cachedStyleValues)
      element._cachedStyleValues = {};
  }
  var propertyValues = {};
  var currentStyle = element.currentStyle;
  var computedStyle = !currentStyle && document.defaultView ? document.defaultView.getComputedStyle(element, "") : null;
  for (var i = 0, count = propertyNames.length; i < count; i++) {
    var propertyName = propertyNames[i];
    var capitalizedPropertyName = q__capitalizeCssPropertyName(propertyName);

    var propertyValue = undefined;
    if (enableValueCaching)
      propertyValue = element._cachedStyleValues[propertyName];
    if (propertyValue != undefined) {
      propertyValues[propertyName] = propertyValue;
      propertyValues[capitalizedPropertyName] = propertyValue;
      continue;
    }

    if (currentStyle) {
      propertyValue = currentStyle[capitalizedPropertyName];
    } else if (computedStyle) {
      propertyValue = computedStyle.getPropertyValue(propertyName);
    }
    if (!propertyValue)
      propertyValue = "";
    if (enableValueCaching) {
      element._cachedStyleValues[propertyName] = propertyValue;
    }
    propertyValues[propertyName] = propertyValue;
    propertyValues[capitalizedPropertyName] = propertyValue;
  }

  return propertyValues;
}


function q__capitalizeCssPropertyName(propertyName) {
  while (true) {
    var idx = propertyName.indexOf("-");
    if (idx == -1)
      return propertyName;
    var firstPart = propertyName.substring(0, idx);
    var secondPart = propertyName.substring(idx + 1);
    if (secondPart.length > 0) {
      var firstChar = secondPart.substring(0, 1);
      firstChar = firstChar.toUpperCase();
      var otherChars = secondPart.substring(1);
      secondPart = firstChar + otherChars;
    }
    propertyName = firstPart + secondPart;
  }
}

function q__repaintAreaForOpera(element, deferredRepainting) {
  if (!q__isOpera())
    return;
  if (!element)
    return;
  if (deferredRepainting) {
    setTimeout(function() {
      q__repaintAreaForOpera(element, false);
    }, 1);
    return;
  }
  // using backgroundColor instead of just background is important here for cases when image is set as background
  // NOTE: setting the calculated border is an erroneous pattern because any further background changes through
  // element's className will be overriden by this in-place style declaration. However it must be uesd for document.body
  // because this element behaves differently when assigned old background - assigning a non-specified old background
  // makes the background white disregarding the appropriate stylesheets (JSFC-2346, JSFC-2275)
  var oldBackgroundColor = element != document.body
          ? element.style.backgroundColor
          : q__getElementStyleProperty(element, "background-color");
  element.style.backgroundColor = "white";
  element.style.backgroundColor = "#fefefe";
  element.style.backgroundColor = oldBackgroundColor;
}

// JSFC-3270
function q__repaintWindowForSafari(deferredRepainting) {
  if (!q__isSafari())
    return;
  if (deferredRepainting) {
    setTimeout(function() {               // for fast machine
      q__repaintWindowForSafari(false);
    }, 50);
    setTimeout(function() {               // for slow machine
      q__repaintWindowForSafari(false);
    }, 300);
    return;
  }
  var tempDiv = document.createElement("div");
  tempDiv.innerHTML = "<div> <style type='text/css'> .d_u_m_p_c_l_a_s_s_ { background: black; filter: alpha( opacity = 50 ); opacity: .50; } </style> </div>"
}

function q__preloadImage(imageUrl) {
  if (!imageUrl)
    return;
  var image = new Image();
  image.src = imageUrl;
}

function q__preloadImages(imageUrls) {
  for (var i = 0, count = imageUrls.length; i < count; i++) {
    var imageUrl = imageUrls[i];
    q__preloadImage(imageUrl);
  }
}

function q__blendColors(colorString1, colorString2, color2Proportion) {
  if (color2Proportion < 0)
    color2Proportion = 0;
  else if (color2Proportion > 1)
    color2Proportion = 1;
  return new q__Color(colorString1).blendWith(new q__Color(colorString2), color2Proportion).toHtmlColorString();
}

function q__Color(htmlColorString) {
  if (!q__stringStartsWith(htmlColorString, "#"))
    throw "Color string should start with '#', but was: " + htmlColorString;
  this.r = parseInt(htmlColorString.substring(1, 3), 16);
  this.g = parseInt(htmlColorString.substring(3, 5), 16);
  this.b = parseInt(htmlColorString.substring(5, 7), 16);

  this.toHtmlColorString = function() {
    function intTo2DigitHex(intValue) {
      var str = intValue.toString(16);
      if (str.length < 2)
        str = "0" + str;
      return str;
    }
    return "#" + intTo2DigitHex(this.r) + intTo2DigitHex(this.g) + intTo2DigitHex(this.b);
  }

  this.blendWith = function(anotherColor, anotherColorPortion) {
    function blendValues(val1, val2, val2Portion) {
      return Math.round(val1 + (val2 - val1) * val2Portion);
    }
    this.r = blendValues(this.r, anotherColor.r, anotherColorPortion);
    this.g = blendValues(this.g, anotherColor.g, anotherColorPortion);
    this.b = blendValues(this.b, anotherColor.b, anotherColorPortion);
    return this;
  }

}

function q__getOpacityLevel(element) {
  return element._q_opacity !== undefined ? element._q_opacity : 1;
}

function q__setOpacityLevel(element, opacity) {
  if (opacity < 0)
    opacity = 0;
  else if (opacity > 1)
    opacity = 1;
  if (opacity != 1) {
    element.style.opacity = opacity;
    element.style.MozOpacity = opacity;
    element.style.filter = "alpha(opacity=" + (opacity * 100) + ");";
    element.style.KhtmlOpacity = opacity;
  } else {
    element.style.opacity = "";
    element.style.MozOpacity = "";
    element.style.filter = "";
    element.style.KhtmlOpacity = "";
  }
  element._q_opacity = opacity;
}

/*
 Ensures that z-index of the specified element is greater than that of the specified reference element.
 */
function q__correctElementZIndex(element, referenceElement, zIndexIncrement) {
  if (zIndexIncrement === undefined)
    zIndexIncrement = 1;
  var zIndex = q__getElementZIndex(element);
  var refZIndex = referenceElement._maxZIndex ? referenceElement._maxZIndex : q__getElementZIndex(referenceElement);
  if (zIndex <= refZIndex)
    element.style.zIndex = refZIndex + zIndexIncrement;
}

/*
 Calculates z-index for the specified element, or if it is not a positioned element itself,
 returns z-index of the nearest parent containing block if it exists, otherwise returns the default z-index of 0.
 */
function q__getElementZIndex(element) {
  var container = q__getContainingBlock(element);
  if (!container)
    return 0;
  var zIndex = q__getNumericStyleProperty(container, "z-index");
  return zIndex;
}

function q__getContainingBlock(element, ignoreThisElement) {
  for (var el = !ignoreThisElement ? element : element.parentNode; el; el = el.parentNode) {
    if (q__isContainingBlock(el))
      return el;
  }
  return null;
}

// ----------------- DATE/TIME UTILITIES ---------------------------------------------------

function q__initDateTimeFormatObject(months, shortMonths, days, shortDays, localeStr) {
  if (!this._dateTimeFormatMap) this._dateTimeFormatMap = [];
  if (!this._dateTimeFormatLocales) this._dateTimeFormatLocales = [];

  if (!this._dateTimeFormatMap[localeStr]) {
    this._dateTimeFormatMap[localeStr] = new DateTimeFormat(months, shortMonths, days, shortDays);
    this._dateTimeFormatLocales.push(localeStr);
  }

  //  this._dateTimeFormat = new DateTimeFormat(months, shortMonths, days, shortDays);
}

function q__getDateTimeFormatObject(locale) {
  if (this._dateTimeFormatMap)
    return this._dateTimeFormatMap[locale];
  return null;
}

function q__parseDateTime(str) {
  var fields = str.split(" ");
  var dateStr = fields[0];
  var timeStr = fields[1];

  var dtf = q__getDateTimeFormatObject(this._dateTimeFormatLocales[0])
  var date = dtf.parse(dateStr, "dd/MM/yyyy");

  q__parseTime(timeStr, date);
  return date;
}

function q__parseTime(timeStr, destDate) {
  if (!destDate)
    destDate = new Date();
  var timeFields = timeStr.split(":");
  var hours = timeFields[0];
  var minutes = timeFields[1];
  destDate.setHours(hours, minutes, 0, 0);
  return destDate;

}

function q__formatDateTime(date) {
  if (!date)
    return "";
  var dtf = q__getDateTimeFormatObject(this._dateTimeFormatLocales[0]);
  var str = dtf.format(date, "dd/MM/yyyy");
  str += " " + q__formatTime(date);
  return str;
}

function q__formatTime(date) {
  if (!date)
    return "";
  var hours = date.getHours();
  var minutes = date.getMinutes();
  if (minutes < 10)
    minutes = "0" + minutes;
  return hours + ":" + minutes;
}

// ----------------- ABSOLUTE POSITIONING / METRICS UTILITIES ---------------------------------------------------

function q__getDefaultAbsolutePositionParent() {
  var prnt = document.forms[0];
  if (prnt)
    prnt = prnt.parent;
  if (!prnt) {
    prnt = document.body;
    if (!prnt) // document.body can be undefined in Mozilla with application/xhtml+xml mime type
      prnt = document.documentElement;
  }
  return prnt;
}

function q__createAbsolutePositionedElement(parent) {
  var elt = document.createElement("div");
  elt.style.position = "absolute";
  if (!parent)
    parent = q__getDefaultAbsolutePositionParent();
  parent.appendChild(elt);
  return elt;
}

/*
 q__calculateNumericStyleProperty doesn't work when calculating margin on a table under Mozilla 2 for some reason,
 so here's an alternative implementation that works for this case.
 */
function q__calculateMozillaMargins(element) {
  var styleClassProperties = {};
  styleClassProperties = q__getStyleClassProperties(
          element.className, ["marginLeft", "marginRight", "marginTop", "marginBottom"]);
  var marginLeft = q__calculateNumericCSSValue(styleClassProperties.marginLeft);
  var marginRight = q__calculateNumericCSSValue(styleClassProperties.marginRight);
  var marginTop = q__calculateNumericCSSValue(styleClassProperties.marginTop);
  var marginBottom = q__calculateNumericCSSValue(styleClassProperties.marginBottom);
  marginLeft = Math.max(marginLeft, q__calculateNumericCSSValue(element.style.marginLeft));
  marginRight = Math.max(marginRight, q__calculateNumericCSSValue(element.style.marginRight));
  marginTop = Math.max(marginTop, q__calculateNumericCSSValue(element.style.marginTop));
  marginBottom = Math.max(marginBottom, q__calculateNumericCSSValue(element.style.marginBottom));
  return {marginLeft: marginLeft, marginRight: marginRight, marginTop: marginTop, marginBottom: marginBottom};
}

/*
 Returns an object {left, top} that points to the top-left corner of the specified element. This method takes into account
 element's border if it exists, that is it determines the position of the element's border box.

 If relativeToNearestContainingBlock parameter is not specified or specified as false, this method
 calculates the elements' "absolute" position relative to the top-left corner of the entire document.

 If relativeToNearestContainingBlock is specified as true, it returns an offset relative to the nearest containing block
 (see http://www.w3.org/TR/REC-CSS2/visuren.html#containing-block for definition of a containing block). More exactly
 it calculates offset relative to the containing block's client area. In other words if there is another absolutely
 positioned element in the same containing block, placing it at the position returned by this function will place that
 element at the same position as the element being measured with this function.

 Note that this function can't calculate position of an element that is hidden using "display: none" CSS declaration.
 Though you may work around such problems by using "visibility: hidden" instead of "display: none".

 See also: q__setElementPos, q__getElementBorderRectangle, q__setElementBorderRectangle.
 */
function q__getElementPos(element, relativeToNearestContainingBlock) {
  var left, top;

  if (element.getBoundingClientRect) {
    var rect = element.getBoundingClientRect();
    left = rect.left;
    top = rect.top;
    var containingBlock;
    if (relativeToNearestContainingBlock) {
      containingBlock = q__getContainingBlock(element, true);
      if (containingBlock) {
        var containingRect = containingBlock.getBoundingClientRect();
        left += containingBlock.scrollLeft - containingRect.left - containingBlock.clientLeft;
        top += containingBlock.scrollTop - containingRect.top - containingBlock.clientTop;
      }
    }
    if (!containingBlock) {
      var pageScrollPos = q__getPageScrollPos();
      left += pageScrollPos.x;
      top += pageScrollPos.y;
      if (q__isExplorer()) {
        if (q__isQuirksMode()) {
          left -= 2;
          top -= 2;
        } else {
          left -= document.documentElement.clientLeft;
          top -= document.documentElement.clientTop;
        }
      }
    }
    return {left: left, top: top};
  }

  left = top = 0;
  // Mozilla 2.0.x strict reports margins on tables to be part of table when measuring it with offsetXXX attributes
  if (q__isMozillaFF2() && q__isStrictMode() && element.tagName && element.tagName.toLowerCase() == "table") {
    var margins = q__calculateMozillaMargins(element);
    left += margins.marginLeft;
    top += margins.marginTop;
  }

  while (element) {
    left += element.offsetLeft;
    top += element.offsetTop;
    var thisIsContainingBlock = q__isContainingBlock(element);

    var offsetParent = element.offsetParent;
    if (!offsetParent)
      break;

    if (q__isMozillaFF2() && q__getElementStyleProperty(offsetParent, "overflow") != "visible") {
      left += q__getNumericStyleProperty(offsetParent, "border-left-width");
      top += q__getNumericStyleProperty(offsetParent, "border-top-width");
    }

    var parentIsContainingBlock = q__isContainingBlock(offsetParent);
    if (relativeToNearestContainingBlock && parentIsContainingBlock) {
      if (offsetParent.tagName.toLowerCase() == "div" && (q__isOpera9AndLate() || q__isSafari2())) {
        if (q__getElementStyleProperty(offsetParent, "border-style") != "none") {
          var borderLeftWidth = q__getNumericStyleProperty(offsetParent, "border-left-width");
          var borderTopWidth = q__getNumericStyleProperty(offsetParent, "border-top-width");
          left -= borderLeftWidth;
          top -= borderTopWidth;
        }
      }
      break;
    }

    for (var parent = element.parentNode; parent; parent = parent.parentNode) {
      var parentNodeName = parent.nodeName ? parent.nodeName.toLowerCase() : null;
      var parentIsAPage = parentNodeName == "html" || parentNodeName == "body";
      if (!parentIsAPage) {
        var pscrollLeft = parent.scrollLeft;
        if (pscrollLeft)
          left -= pscrollLeft;
        var pscrollTop = parent.scrollTop;
        if (pscrollTop)
          top -= pscrollTop;
      }

      //      if (q__calculateElementStyleProperty(parent, "overflow") != "visible") {
      //        left += q__calculateNumericStyleProperty(parent, "padding-left");
      //        top += q__calculateNumericStyleProperty(parent, "padding-top");
      //      }

      if (!thisIsContainingBlock) {
        // containing blocks already have the following corrections as part of offsetLeft/offsetTop
        if (q__isMozillaFF2()) {
          if (parentNodeName == "td") {
            left -= q__getNumericStyleProperty(parent, "border-left-width");
            top -= q__getNumericStyleProperty(parent, "border-top-width");
          }
          if (parentNodeName == "table" && q__isStrictMode()) {
            var parentMargins = q__calculateMozillaMargins(parent);
            left += parentMargins.marginLeft;
            top += parentMargins.marginTop;
          }
        }
        if (q__isSafari()) {
          if (parentNodeName == "table") {
            left += q__getNumericStyleProperty(parent, "border-left-width");
            top += q__getNumericStyleProperty(parent, "border-top-width");
          }
        }
      }

      if (parent == offsetParent)
        break;
    }

    // account for offsetParent's border
    if (!q__isSafari2()) {
      var lowerCaseTagName = offsetParent.tagName.toLowerCase();
      if (lowerCaseTagName == "table" && q__isSafari3AndLate()) {
        var border = q__calculateNumericCSSValue(offsetParent.border);
        if (border > 0) {
          left += border;
          top += border;
        }
      } else {
        if (lowerCaseTagName == "div" || lowerCaseTagName == "td") {
          if (!q__isOpera9AndLate()) { // border in Opera 9 included in offsetLeft and offsetTop
            left += (offsetParent.clientLeft == undefined ? q__getNumericStyleProperty(offsetParent, "border-left-width") : offsetParent.clientLeft);
            top += (offsetParent.clientTop == undefined ? q__getNumericStyleProperty(offsetParent, "border-top-width") : offsetParent.clientTop);
          }
        }
      }
    }

    element = offsetParent;
  }
  return {left: left, top: top};
}

function q__getCuttingContainingRectangle(element, cachedDataContainer) {
  var left, right, top, bottom;

  while (true) {
    var container = q__getContainingBlock(element, true);
    if (!container)
      break;
    var overflowX = q__getElementStyleProperty(container, "overflow-x");
    var overflowY = q__getElementStyleProperty(container, "overflow-y");
    var containerRect = (overflowX != "visible" || overflowY != "visible") ?
                        q__getElementPaddingRectangle(container, false, cachedDataContainer) : null;
    if (overflowX != "visible") {
      left = q__maxDefined(left, containerRect.getMinX());
      right = q__minDefined(right, containerRect.getMaxX());
    }
    if (overflowY != "visible") {
      top = q__maxDefined(top, containerRect.getMinY());
      bottom = q__minDefined(bottom, containerRect.getMaxY());
    }
    element = container;
  }
  var result = new Q$.Rectangle(left, top, right ? right - left : undefined, bottom ? bottom - top : undefined);
  var visibleAreaRect = q__getVisibleAreaRectangle();
  result.intersectWith(visibleAreaRect);
  return result;
}

function q__getVisibleElementBorderRectangle(element, relativeToNearestContainingBlock, cachedDataContainer) {
  var rect = q__getElementBorderRectangle(element, relativeToNearestContainingBlock, cachedDataContainer);
  var cuttingRect = q__getCuttingContainingRectangle(element, cachedDataContainer);
  if (relativeToNearestContainingBlock) {
    var elementContainer = q__getContainingBlock(element, true);
    var containerPos = elementContainer ? q__getElementPos(elementContainer) : null;
    if (cuttingRect.left && containerPos)
      cuttingRect.left -= containerPos.left;
    if (cuttingRect.top && containerPos)
      cuttingRect.top -= containerPos.top;
  }
  rect.intersectWith(cuttingRect);
  return rect;
}

/*
 Returns the Q$.Rectangle object that corresponds to the bounding rectangle of the passed element. This method takes
 into account element's border. That is it returns element's border box rectangle.

 relativeToNearestContainingBlock is an optional parameter that specifies whether the position is calculated relative
 to the document (if not specified or specified as false), or the nearest containing block's client area.

 cachedDataContainer is an optional parameter that if specifies introduces caching of the calculated value for improved
 performance. It should be specified as a reference to any object where the data should be cached. If this parameter is
 specified and rectangle of this element was already calculated with the same cachedDataContainer object before, then
 the previously calculated value is returned. Otherwise it calculates the current rectangle and saves it into the
 specified object.

 Note that this function can't calculate a rectangle of an element that is hidden using "display: none" CSS declaration.
 Though you may work around such problems by using "visibility: hidden" instead of "display: none".

 See also: q__setElementBorderRectangle, q__getElementPos, q__setElementPos.
 */
function q__getElementBorderRectangle(element, relativeToNearestContainingBlock, cachedDataContainer) {
  if (cachedDataContainer) {
    if (!element._q__getElementRectangle)
      element._q__getElementRectangle = {}
    if (element._q__getElementRectangle._currentCache == cachedDataContainer)
      return element._q__getElementRectangle._cachedValue;
  }
  var pos = q__getElementPos(element, relativeToNearestContainingBlock);
  var size = q__getElementSize(element);
  var rect = new Q$.Rectangle(pos.left, pos.top, size.width, size.height);
  if (cachedDataContainer) {
    element._q__getElementRectangle._currentCache = cachedDataContainer;
    element._q__getElementRectangle._cachedValue = rect;
  }
  return rect;
}

function q__getElementSize(element) {
  var width = element.offsetWidth;
  var height = element.offsetHeight;
  // Mozilla 2.0.x strict reports margins on tables to be part of table when measuring it with offsetXXX attributes
  if (q__isMozillaFF2() && q__isStrictMode() && element.tagName && element.tagName.toLowerCase() == "table") {
    var margins = q__calculateMozillaMargins(element);
    width -= margins.marginLeft + margins.marginRight;
    height -= margins.marginTop + margins.marginBottom;
  }
  return {width: width, height: height};
}

function q__getElementPaddingRectangle(element, relativeToNearestContainngBlock, cachedDataContainer) {
  var rect = q__getElementBorderRectangle(element, relativeToNearestContainngBlock, cachedDataContainer);
  var borderLeftWidth = q__getNumericStyleProperty(element, "border-left-width");
  var borderRightWidth = q__getNumericStyleProperty(element, "border-right-width");
  var borderTopWidth = q__getNumericStyleProperty(element, "border-top-width");
  var borderBottomWidth = q__getNumericStyleProperty(element, "border-bottom-width");
  rect.x += borderLeftWidth;
  rect.y += borderTopWidth;
  rect.width -= borderLeftWidth + borderRightWidth;
  rect.height -= borderTopWidth + borderBottomWidth;
  return rect;
}

/*
 Moves the specified element to the specified position (specified as {left, top} object). More exactly the top-left
 corner of element's border box will be at the specified position after this method is invoked.

 See also: q__getElementPos, q__getElementBorderRectangle, q__setElementBorderRectangle.
 */
function q__setElementPos(element, pos) {
  element.style.left = pos.left + "px";
  element.style.top = pos.top + "px";
}

function q__setElementSize(element, size, _paddingsHaveBeenReset) {
  var width = size.width;
  var height = size.height;

  if (!_paddingsHaveBeenReset)
    q__excludeClassNames(element, ["q_zeroPaddings"]);
  if (!q__isExplorer() || q__isStrictMode()) {
    width -= q__getNumericStyleProperty(element, "padding-left") + q__getNumericStyleProperty(element, "padding-right");
    height -= q__getNumericStyleProperty(element, "padding-top") + q__getNumericStyleProperty(element, "padding-bottom");
    width -= q__getNumericStyleProperty(element, "border-left-width") + q__getNumericStyleProperty(element, "border-right-width");
    height -= q__getNumericStyleProperty(element, "border-top-width") + q__getNumericStyleProperty(element, "border-bottom-width");
  }
  if (!_paddingsHaveBeenReset && (width < 0 || height < 0)) {
    // make it possible to specify element rectangle less than the size of element's paddings
    q__appendClassNames(element, ["q_zeroPaddings"]);
    q__setElementSize(element, size, true);
    return;
  }
  if (width < 0)
    width = 0;
  if (height < 0)
    height = 0;
  element.style.width = width + "px";
  element.style.height = height + "px";
}

/*
 Changes size and position of the specified element according to the specified rectangle. The rectangle speicifies
 the element's border box.

 See also: q__getElementBorderRectangle, q__getElementPos, q__setElementPos.
 */
function q__setElementBorderRectangle(element, rect, _paddingsHaveBeenReset) {
  q__setElementSize(element, {width: rect.width, height: rect.height});
  q__setElementPos(element, {left: rect.x, top: rect.y});
}

/**
 * Introduced according to CSS spec http://www.w3.org/TR/REC-CSS2/visudet.html#containing-block-details
 * See JSFC-2045 Popups displayed incorrectly under JBoss Portal
 */
function q__isContainingBlock(elt) {
  q__assert(elt, "elt is null");
  if (elt == document) {
    // q__calculateElementStyleProperty fails to determine position on the document element, and
    // document element can't have a non-static position
    return false;
  }
  var position = q__getElementStyleProperty(elt, "position");
  if (!position) return false;
  return position != "static";
}


function q__getVisibleAreaSize() {
  var width = 0, height = 0;
  if (q__isMozillaFF()) {
    if (q__isQuirksMode()) {
      width = document.body.clientWidth;
      height = document.body.clientHeight;
    } else {
      width = document.documentElement.clientWidth;
      height = document.documentElement.clientHeight;
    }
  } else if (q__isSafari()) {
    width = document.documentElement.clientWidth;
    height = document.documentElement.clientHeight;
  } else if (typeof window.innerWidth == "number") {
    width = window.innerWidth;
    height = window.innerHeight;
  } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
    width = document.documentElement.clientWidth;
    height = document.documentElement.clientHeight;
  } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
    width = document.body.clientWidth;
    height = document.body.clientHeight;
  }
  return {width : width, height : height};
}

function q__getVisibleAreaRectangle() {
  var pageScrollPos = q__getPageScrollPos();
  var x = pageScrollPos.x;
  var y = pageScrollPos.y;
  var visibleAreaSize = q__getVisibleAreaSize();
  var width = visibleAreaSize.width;
  var height = visibleAreaSize.height;
  return new Q$.Rectangle(x, y, width, height);
}

function q__scrollElementIntoView(element, cachedDataContainer) {
  var scrollingOccured = false;
  var rect = q__getElementBorderRectangle(element);
  for (var parent = element.parentNode; parent; parent = parent.parentNode) {
    var parentScrollable;
    if (parent != document) {
      var overflowY = q__getElementStyleProperty(parent, "overflow-y");
      parentScrollable = overflowY != "visible";
    } else {
      parentScrollable = true;
    }
    if (!parentScrollable)
      continue;
    var parentRect = parent != document
            ? q__getElementPaddingRectangle(parent, false, cachedDataContainer)
            : q__getVisibleAreaRectangle();

    var scrollTopAdjustment = 0;
    if (parentRect.getMinY() > rect.getMinY())
      scrollTopAdjustment = rect.getMinY() - parentRect.getMinY();
    else if (parentRect.getMaxY() < rect.getMaxY())
      scrollTopAdjustment = rect.getMaxY() - parentRect.getMaxY();
    if (scrollTopAdjustment) {
      if (parent != document)
        parent.scrollTop += scrollTopAdjustment;
      else
        window.scrollBy(0, scrollTopAdjustment);
      rect.y -= scrollTopAdjustment;
      scrollingOccured = true;
    }
  }
  return scrollingOccured;
}

function q__scrollRectIntoView(rect) {
  var visibleRect = q__getVisibleAreaRectangle();
  var dx = 0;
  if (rect.getMinX() < visibleRect.getMinX())
    dx = rect.getMinX() - visibleRect.getMinX();
  if (rect.getMaxX() > visibleRect.getMaxX())
    dx = rect.getMaxX() - visibleRect.getMaxX();
  var dy = 0;
  if (rect.getMinY() < visibleRect.getMinY())
    dy = rect.getMinY() - visibleRect.getMinY();
  if (rect.getMaxY() > visibleRect.getMaxY())
    dy = rect.getMaxY() - visibleRect.getMaxY();

  // account for rect being bigger than visibleRect - align by top, right edges should have a priority in this case
  var newMinX = visibleRect.getMinX() + dx;
  if (rect.getMinX() < newMinX)
    dx = rect.getMinX() - newMinX;
  var newMinY = visibleRect.getMinY() + dy;
  if (rect.getMinY() < newMinY)
    dy = rect.getMinY() - newMinY;

  window.scrollBy(dx, dy);
}

function q__getScrollPos(scrollableComponent) {
  var x = 0;
  var y = 0;

  if (typeof( scrollableComponent.pageYOffset ) == "number") {
    // Netscape compliant
    y = scrollableComponent.pageYOffset;
    x = scrollableComponent.pageXOffset;
  } else if (scrollableComponent.scrollLeft || scrollableComponent.scrollTop) {
    // DOM compliant
    y = scrollableComponent.scrollTop;
    x = scrollableComponent.scrollLeft;
  }

  return {x: x, y: y};
}

function q__getPageScrollPos() {
  var x = 0;
  var y = 0;
  if (typeof( window.pageYOffset ) == "number") {
    // Netscape compliant
    y = window.pageYOffset;
    x = window.pageXOffset;
  } else if (document.body && ( document.body.scrollLeft || document.body.scrollTop )) {
    // DOM compliant
    y = document.body.scrollTop;
    x = document.body.scrollLeft;
  } else if (document.documentElement && ( document.documentElement.scrollLeft || document.documentElement.scrollTop )) {
    // IE6 standards compliant mode
    y = document.documentElement.scrollTop;
    x = document.documentElement.scrollLeft;
  }
  return {x: x, y: y};
}

function q__setPageScrollPos(scrollPos) {
  window.scrollTo(scrollPos.x, scrollPos.y);
}

function q__getNumericStyleProperty(element, propertyName, enableValueCaching) {
  if (q__isExplorer() || q__isOpera()) {
    // border "medium none black" under IE is actually displayed with zero width because of "none" style, so we should
    // skip calculating "medium" width and just return 0 in such cases.
    var capitalizedPropertyName = q__capitalizeCssPropertyName(propertyName);
    if (q__stringStartsWith(capitalizedPropertyName, "border") && q__stringEndsWith(capitalizedPropertyName, "Width")) {
      var borderStylePropertyName = capitalizedPropertyName.substring(0, capitalizedPropertyName.length - "Width".length) + "Style";
      if (q__getElementStyleProperty(element, borderStylePropertyName) == "none")
        return 0;
    }
  }
  var str = q__getElementStyleProperty(element, propertyName, enableValueCaching);
  var result = q__calculateNumericCSSValue(str);
  return result;
}

function q__calculateNumericCSSValue(value) {
  if (!value)
    return 0;
  if (!isNaN(1 * value))
    return 1 * value;
  if (q__stringEndsWith(value, "px"))
    return 1 * value.substring(0, value.length - 2);
  if (value == "auto")
    return 0; // todo: can't calculate "auto" (e.g. from margin property) on a simulated border -- consider simulating such "non-border" values on other properties

  if (!window._q_nonPixelValueMeasurements)
    window._q_nonPixelValueMeasurements = [];
  var pixelValue = window._q_nonPixelValueMeasurements[value];
  if (pixelValue != undefined)
    return pixelValue;

  pixelValue = q__calculateLineWidth(value + " solid white");
  window._q_nonPixelValueMeasurements[value] = pixelValue;
  return pixelValue;
}

function q__calculateLineWidth(lineStyleStr) {
  if (!lineStyleStr)
    return 0;
  if (!window._q_lineWidthMeasurements)
    window._q_lineWidthValueMeasurements = [];
  var width = window._q_lineWidthValueMeasurements[lineStyleStr];
  if (width != undefined)
    return width;

  var outerDiv = window._q_nonPixelMeasurements_outerDiv;
  var innerDiv = window._q_nonPixelMeasurements_innerDiv;
  if (!outerDiv) {
    outerDiv = document.createElement("div");
    outerDiv.style.visibility = "hidden";
    outerDiv.style.padding = "0px";
    outerDiv.style.margin = "0px";
    innerDiv = document.createElement("div");
    innerDiv.style.padding = "0px";
    innerDiv.style.margin = "0px";
    outerDiv.appendChild(innerDiv);
    window._q_nonPixelMeasurements_outerDiv = outerDiv;
    window._q_nonPixelMeasurements_innerDiv = innerDiv;
  }
  outerDiv.style.border = lineStyleStr;
  document.body.appendChild(outerDiv);
  width = innerDiv.offsetTop - outerDiv.offsetTop;
  document.body.removeChild(outerDiv);
  window._q_lineWidthValueMeasurements[lineStyleStr] = width;
  return width;
}

var Q_CENTER = "center";
var Q_LEFT = "left";
var Q_LEFT_EDGE = "leftEdge";
var Q_RIGHT_EDGE = "rightEdge";
var Q_RIGHT = "right";
var Q_ABOVE = "above";
var Q_TOP_EDGE = "topEdge";
var Q_BOTTOM_EDGE = "bottomEdge";
var Q_BELOW = "below"

function q__alignPopupByElement(popup, element, horizAlignment, vertAlignment, horizDistance, vertDistance, ignoreVisibleArea, disableRepositioning, repositioningAttempt) {
  if (!horizAlignment) horizAlignment = Q_LEFT_EDGE;
  if (!vertAlignment) vertAlignment = Q_BELOW;
  if (!horizDistance) horizDistance = 0;
  if (!vertDistance) vertDistance = 0;
  horizDistance = q__calculateNumericCSSValue(horizDistance);
  vertDistance = q__calculateNumericCSSValue(vertDistance);

  var elementRect = ignoreVisibleArea
          ? q__getElementBorderRectangle(element)
          : q__getVisibleElementBorderRectangle(element);
  var popupSize = q__getElementSize(popup);
  var popupWidth = popupSize.width;
  var popupHeight = popupSize.height;

  var x;
  switch (horizAlignment) {
    case Q_LEFT:
      x = elementRect.getMinX() - popupWidth - horizDistance;
      break;
    case Q_LEFT_EDGE:
      x = elementRect.getMinX() + horizDistance;
      break;
    case Q_CENTER:
      x = elementRect.getMinX() + (elementRect.width - popupWidth) / 2;
      break;
    case Q_RIGHT_EDGE:
      x = elementRect.getMaxX() - popupWidth - horizDistance;
      break;
    case Q_RIGHT:
      x = elementRect.getMaxX() + horizDistance;
      break;
    default:
      q__logError("q__alignPopupByElement: unrecognized horizAlignment: " + horizAlignment);
  }
  var y;
  switch (vertAlignment) {
    case Q_ABOVE:
      y = elementRect.getMinY() - popupHeight - vertDistance;
      break;
    case Q_TOP_EDGE:
      y = elementRect.getMinY() + vertDistance;
      break;
    case Q_CENTER:
      y = elementRect.getMinY() + (elementRect.height - popupHeight) / 2;
      break;
    case Q_BOTTOM_EDGE:
      y = elementRect.getMaxY() - popupHeight - vertDistance;
      break;
    case Q_BELOW:
      y = elementRect.getMaxY() + vertDistance;
      break;
    default:
      q__logError("q__alignPopupByElement: unrecognized vertAlignment: " + vertAlignment);
  }

  if (!disableRepositioning) {
    var allowedRectangle = q__getCuttingContainingRectangle(popup);
    var shouldBeRepositioned = !allowedRectangle.containsRectangle(new Q$.Rectangle(x, y, popupWidth, popupHeight)) &&
                               allowedRectangle.width >= popupWidth && allowedRectangle.height >= popupHeight;
    if (shouldBeRepositioned) {
      if (repositioningAttempt)
        return false;
      var alternativeVertAlignment = vertAlignment == Q_BELOW || vertAlignment == Q_ABOVE
              ? vertAlignment == Q_BELOW ? Q_ABOVE : Q_BELOW
              : null;
      if (alternativeVertAlignment) {
        if (q__alignPopupByElement(popup, element, horizAlignment, alternativeVertAlignment, horizDistance, vertDistance, ignoreVisibleArea, false, true))
          return;
      }
      var alternativeHorizAlignment = horizAlignment == Q_LEFT || horizAlignment == Q_RIGHT
              ? horizAlignment == Q_RIGHT ? Q_LEFT : Q_RIGHT
              : null;
      if (alternativeHorizAlignment) {
        if (q__alignPopupByElement(popup, element, alternativeHorizAlignment, vertAlignment, horizDistance, vertDistance, ignoreVisibleArea, false, true))
          return;
      }
      if (alternativeHorizAlignment && alternativeVertAlignment) {
        if (q__alignPopupByElement(popup, element, alternativeHorizAlignment, alternativeVertAlignment, horizDistance, vertDistance, ignoreVisibleArea, false, true))
          return;
      }
      var xOffset = x < allowedRectangle.getMinX()
              ? allowedRectangle.getMinX() - x
              : x + popupWidth > allowedRectangle.getMaxX() ? allowedRectangle.getMaxX() - (x + popupWidth) : 0;
      var yOffset = y < allowedRectangle.getMinY()
              ? allowedRectangle.getMinY() - y
              : y + popupHeight > allowedRectangle.getMaxY() ? allowedRectangle.getMaxY() - (y + popupHeight) : 0;
      x += xOffset;
      y += yOffset;
    }
  }

  var popupContainer = q__getContainingBlock(popup, true);
  if (popupContainer) {
    var containerRect = q__getElementPaddingRectangle(popupContainer);
    x -= containerRect.x;
    y -= containerRect.y;


  }
  if (popup.setLeft) {
    popup.setLeft(x);
    popup.setTop(y);
  } else {
    q__setElementPos(popup, {left: x, top: y});
  }
  if (repositioningAttempt)
    return true;
}

function q__isAlignmentInsideOfElement(horizAlignment, vertAlignment) {
  var insideHorizontaly = horizAlignment == Q_LEFT_EDGE || horizAlignment == Q_CENTER || horizAlignment == Q_RIGHT_EDGE;
  var insideVertically = vertAlignment == Q_TOP_EDGE || vertAlignment == Q_CENTER || vertAlignment == Q_BOTTOM_EDGE;
  return insideHorizontaly && insideVertically;
}

// ----------------- HIDE <SELECT> CONTROLS UNDER POPUP IN IE ---------------------------------------------------

var q__controlsToHide = q__isExplorer() ? new Array("select-one", "select-multiple") : null;
var q__controlsHiddenControlsMap = new Object();

function q__walkControlsToHide(popup, runFunction) {
  if (popup._coveredControls) {
    for (var i = 0; i < popup._coveredControls.length; i++) {
      var control = popup._coveredControls[i];
      runFunction.call(this, control);
    }
  }
}

function q__hideControlsUnderPopup(popup) {
  if (q__isExplorer() && q__controlsToHide && q__controlsToHide.length > 0) {
    var runFunction = function(control) {
      var controlData = new Object();
      controlData.id = popup.id;
      controlData.visibility = control.style.visibility;
      q__controlsHiddenControlsMap[control.id] = controlData;
      control.style.visibility = "hidden";
    }

    var rectangle = new Q$.Rectangle(popup.offsetLeft, popup.offsetTop, popup.offsetWidth, popup.offsetHeight);
    popup._coveredControls = new Array();
    var frm = q__findParentNode(popup, "FORM");
    var controls = frm.elements;
    var index = 0;
    for (var i = 0; i < controls.length; i++) {
      var control = controls[i];
      if (control.type && q__arrayContainsValue(q__controlsToHide, control.type)) {
        if (! q__isChild(popup, control)) {
          var examRectangle = q__getElementBorderRectangle(control);
          if (rectangle.intersects(examRectangle)) {
            popup._coveredControls[index++] = control;
          }
        }
      }
    }


    q__walkControlsToHide(popup, runFunction);
  }
}

function q__unhideControlsUnderPopup(popup) {
  if (q__isExplorer() && q__controlsToHide && q__controlsToHide.length > 0) {
    var runFunction = function(control) {
      var controlData = q__controlsHiddenControlsMap[control.id];
      if (controlData && (controlData.id == popup.id)) {
        control.style.visibility = controlData.visibility;
      }
    }
    q__walkControlsToHide(popup, runFunction);
    popup._coveredControls = null;
  }
}

function q__initIETransparencyWorkaround(popup) {
  if (!q__isExplorer() || q__isExplorer7())
    return;
  popup._requireTransparencyWorkaround = true;
  if (popup._preCreatedIETransparencyControl)
    return;

  var iframe = document.createElement("iframe");
  iframe.src = "javascript:'';";
  // to overcome the "nonsecure items" message on HTTPS pages
  iframe.id = popup.id + "::ieTransparencyControl";
  iframe.scrolling = "No";
  iframe.frameBorder = "0";
  iframe.style.position = "absolute";
  iframe.style.filter = "progid:DXImageTransform.Microsoft.Alpha(style=0,opacity=0)";
  // to support transparency of the popup itself

  iframe._updatePositionAndSize = function() {
    iframe.style.width = popup.offsetWidth + "px";
    iframe.style.height = popup.offsetHeight + "px";
    iframe.style.left = popup.offsetLeft + "px";
    iframe.style.top = popup.offsetTop + "px";
  }

  var popupZIndex = q__getElementStyleProperty(popup, "z-index");
  if (!popupZIndex) {
    popupZIndex = 10;
    popup.style.zIndex = popupZIndex;
  }
  iframe.zIndex = popup.zIndex - 1;

  iframe.style.display = "none";
  popup.parentNode.insertBefore(iframe, popup);
  popup._preCreatedIETransparencyControl = iframe;
}

function q__addIETransparencyControl(popup) {
  if (!popup._requireTransparencyWorkaround)
    return;
  if (popup._ieTransparencyControl) {
    popup._ieTransparencyControl._updatePositionAndSize();
    return;
  }

  if (!popup._preCreatedIETransparencyControl)
    q__initIETransparencyWorkaround(popup);
  var iframe = popup._preCreatedIETransparencyControl;
  iframe.style.display = "";
  iframe._updatePositionAndSize();
  popup._ieTransparencyControl = iframe;
}

function q__removeIETransparencyControl(popup) {
  if (!popup._requireTransparencyWorkaround || !popup._ieTransparencyControl)
    return;

  popup._ieTransparencyControl.style.display = "none";
  popup._ieTransparencyControl = undefined;
}

function q__invokeOnce(func, funcId) {
  if (!q__isInvoked(funcId)) {
    func();
    q__getInvokedFunctions().push(funcId);
  }
}

function q__isInvoked(funcId) {
  var invokedFunctions = q__getInvokedFunctions();
  return q__contains(invokedFunctions, funcId);
}

function q__getInvokedFunctions() {
  var invokedFunctions = document.q__invokedFunctions;
  if (!invokedFunctions) {
    invokedFunctions = new Array();
    document.q__invokedFunctions = invokedFunctions;
  }
  return invokedFunctions;
}

function q__contains(array, object) {
  for (var i = 0, count = array.length; i < count; i++) {
    if (object == array[i])
      return true;
  }
  return false;
}

function q__isInvisible(element) {
  if (!element.style) {
    return false;
  }
  return element.style.display == "none" || element.style.visibility == "hidden";
}

function q__isVisibleRecursive(element) {
  if (q__isInvisible(element))
    return false;

  var parentNode = element.parentNode;
  if (!parentNode)
    return true;

  return q__isVisibleRecursive(parentNode);
}


// ----------------- EFFECTS ---------------------------------------------------

function q__getInterpolatedValue(value1, value2, value2Proportion) {
  // handle numbers
  if (!isNaN(1 * value1) && !isNaN(1 * value2))
    return value1 + (value2 - value1) * value2Proportion;

  // handle colors
  if (typeof value1 === "string" && q__stringStartsWith(value1, "#"))
    return q__blendColors(value1, value2, value2Proportion);

  // handle points
  if (typeof value1 === "object" && value1 != null && value1.left !== undefined)
    return {left: q__getInterpolatedValue(value1.left, value2.left, value2Proportion),
      top: q__getInterpolatedValue(value1.top, value2.top, value2Proportion)};

  // handle rectangles
  if (typeof value1 === "object" && value1 != null && value1.width !== undefined)
    return new Q$.Rectangle(
            q__getInterpolatedValue(value1.x, value2.x, value2Proportion),
            q__getInterpolatedValue(value1.y, value2.y, value2Proportion),
            q__getInterpolatedValue(value1.width, value2.width, value2Proportion),
            q__getInterpolatedValue(value1.height, value2.height, value2Proportion)
            );

  // the rest is treated as CSS units such as px, cm, etc.
  value1 = q__calculateNumericCSSValue(value1);
  value2 = q__calculateNumericCSSValue(value2);
  return value1 + (value2 - value1) * value2Proportion + "px";
}

/*
 Similar to q__calculateElementStyleProperty, but it supports some "pseudo" properties for the sake of simplicity and
 portability, such as element's opacity, position, rectangle, etc.
 */
function q__getElementEffectProperty(element, property) {
  if (property == "opacity")
    return q__getOpacityLevel(element);
  if (property == "position")
    return q__getElementPos(element, true);
  if (property == "rectangle")
    return q__getElementBorderRectangle(element, true);

  return q__getElementStyleProperty(element, property);
}

function q__setElementEffectProperty(element, property, value) {
  if (property == "opacity")
    q__setOpacityLevel(element, value);
  else if (property == "position")
    q__setElementPos(element);
  else if (property == "rectangle")
    q__setElementBorderRectangle(element, value);
  else
    element.style[property] = value;
}

function q__runTransitionEffect(element, propertyNames, newValues, transitionPeriod, updateInterval, events) {
  if (transitionPeriod === undefined || transitionPeriod < 0)
    transitionPeriod = 0;
  if (!updateInterval)
    updateInterval = 50;
  var initialValues = {};
  var propertyCount = propertyNames.length;
  q__assertEquals(propertyCount, newValues.length, "q__runTransitionEffect: checking propertyNames.length == newValues.length");

  var startTime = new Date().getTime();
  var endTime = startTime + transitionPeriod;
  var transition = {
    active: true,
    propertyValues: {},
    completionProportion: 0,
    getValueForCompletionProportion: function(propertyName, proportion) {
      return q__getInterpolatedValue(initialValues[propertyName], newValues[propertyName], proportion);
    },
    update: function(forceProportion) {
      var time = new Date().getTime();
      var timeElapsed = time - startTime;
      this.completionProportion = forceProportion === undefined ? timeElapsed / (endTime - startTime) : forceProportion;
      if (this.completionProportion > 1)
        this.completionProportion = 1;

      for (var i = 0; i < propertyCount; i++) {
        var propertyName = propertyNames[i];
        if (element._q_performingTransitionForProperties[propertyName] != this) {
          // another transition has begun before this one has finished
          this.propertyValues[propertyName] = undefined;
          if (propertyNames.length == 1)
            this.stop();
          continue;
        }
        var currentValue = this.getValueForCompletionProportion(propertyName, this.completionProportion);
        this.propertyValues[propertyName] = currentValue;
        q__setElementEffectProperty(element, propertyName, currentValue);
      }
      if (this.onupdate)
        this.onupdate();
    },
    stop: function(forceCompletionProportion) {
      if (!this.active)
        return;
      this.active = false;
      if (forceCompletionProportion !== undefined)
        this.update(forceCompletionProportion);
      clearInterval(transition.intervalId);
      for (var i = 0; i < propertyCount; i++) {
        var propertyName = propertyNames[i];
        if (element._q_performingTransitionForProperties[propertyName] == this)
          element._q_performingTransitionForProperties[propertyName] = undefined;
      }
      if (this.onstop)
        this.onstop();
    },
    intervalId: setInterval(function() {
      transition.update();
      if (transition.completionProportion == 1) {
        transition.stop();
        if (transition.oncomplete)
          transition.oncomplete();
      }
    }, updateInterval)
  }
  q__assignEvents(transition, events, true);

  if (!element._q_performingTransitionForProperties)
    element._q_performingTransitionForProperties = {};
  for (var i = 0; i < propertyCount; i++) {
    var propertyName = propertyNames[i];
    element._q_performingTransitionForProperties[propertyName] = transition;
    initialValues[propertyName] = q__getElementEffectProperty(element, propertyName);
    newValues[propertyName] = newValues[i];
  }
  if (transitionPeriod == 0) {
    transition.stop(1.0);
    if (transition.oncomplete)
      transition.oncomplete();
  }

  return transition;
}

//AUTO GENERATED CODE

window['q_loadedLibrary:/qk_internalResource/teamdev/jsf/renderkit/util/util-2.0.js'] = true;