ASPxSplitterHelper = _aspxCreateClass(null, {
 constructor: function(splitter) {
  this.splitter = splitter;
  this.cache = {};
  this.clientStateElementId = this.splitter.name + "_CS";
 },
 GetClientStateElement: function() {
  return ASPxSplitterHelper.GetCachedValue(this, this.clientStateElementId, this, function(){
   return _aspxGetElementById(this.clientStateElementId);
  });
 },
 GetMoveMaxDeltaSize: function(deltaSize) {
  if(deltaSize == 0)
   return 0;
  if(this.isHeavyUpdate) {
   var parent = this.splitter.moveLeftPane.parent;
   var totalSize = 0, minSize = 0;
   for(var i = 0; i < parent.panes.length; i++) {
    var pane = parent.panes[i];
    if(pane.isSizePx)
     continue;
    if(pane.collapsed) {
     totalSize += pane.GetSizeDiff(pane.isVertical);
     minSize += pane.GetSizeDiff(pane.isVertical);
    }
    else {
     totalSize += pane.GetOffsetSize();
     minSize += pane.GetMinSize();
    }
   }
   if(this.moveRightPane.isSizePx) {
    deltaSize = this.GetPaneMaxDeltaSize(this.splitter.moveRightPane, -deltaSize);
    deltaSize = this.GetMaxDeltaSize(totalSize, minSize, Number.MAX_VALUE, -deltaSize);
   }
   else {
    deltaSize = this.GetMaxDeltaSize(totalSize, minSize, Number.MAX_VALUE, -deltaSize);
    deltaSize = this.GetPaneMaxDeltaSize(this.splitter.moveLeftPane, -deltaSize);
   }
  }
  else {
   deltaSize = this.GetPaneMaxDeltaSize(this.splitter.moveRightPane, -deltaSize);
   deltaSize = this.GetPaneMaxDeltaSize(this.splitter.moveLeftPane, -deltaSize);
  }
  return deltaSize;
 },
 GetPaneMaxDeltaSize: function(pane, deltaSize) {
  return this.GetMaxDeltaSize(pane.GetOffsetSize(), pane.GetMinSize(), pane.maxSize, deltaSize);
 },
 GetMaxDeltaSize: function(size, min, max, deltaSize) {
  var minDeltaSize = Math.floor(min - size);
  var maxDeltaSize = Math.floor(max - size);
  if(deltaSize < minDeltaSize)
   return (size < min) ? 0 : minDeltaSize;
  else if(deltaSize > maxDeltaSize)
   return (size > max) ? 0 : maxDeltaSize;
  return deltaSize;
 },
 GetCurrentPos: function() {
  return this.splitter.moveIsVertical ? ASPxClientSplitter.CurrentYPos : ASPxClientSplitter.CurrentXPos;
 },
 SetResizingPanelVisibility: function(visible) {
  var resizingPanel = ASPxSplitterHelper.GetCachedValue(this, "resizingPanel", this, function(){
   var resizingPanel = document.createElement("DIV");
   resizingPanel.style.overflow = "hidden";
   resizingPanel.style.position = "absolute";
   if(__aspxIE) {
    resizingPanel.style.backgroundColor = "White";
    resizingPanel.style.filter = "alpha(opacity=1)";
   }
   resizingPanel.isVisible = false;
   return resizingPanel;
  });
  if(resizingPanel.isVisible != visible) {
   if(visible) {
    var mainElement = this.splitter.GetMainElement();
    _aspxSetStylePosition(resizingPanel, _aspxGetAbsoluteX(mainElement), _aspxGetAbsoluteY(mainElement));
    _aspxSetStyleSize(resizingPanel, mainElement.offsetWidth, mainElement.offsetHeight);
    mainElement.parentNode.appendChild(resizingPanel);
   }
   else
    resizingPanel.parentNode.removeChild(resizingPanel);
   resizingPanel.isVisible = visible;
  }
 }
});
ASPxSplitterHelper.GetCachedValue = function(cacheObj, cacheName, obj, func) {
 if(!_aspxIsExists(cacheObj.cache[cacheName]))
  cacheObj.cache[cacheName] = func.apply(obj, []);
 return cacheObj.cache[cacheName];
};
ASPxSplitterHelper.DropCachedValue = function(cacheObj, cacheName) {
 cacheObj.cache[cacheName] = null;
};  
ASPxSplitterHelper.Resize = function(pane1, pane2, deltaSize) {
 if(pane1.isSizePx || pane2.isSizePx) {
  if(pane1.isSizePx)
   pane1.size += deltaSize;
  if(pane2.isSizePx)
   pane2.size -= deltaSize;
 }
 else {
  var c = (pane1.size + pane2.size) / (pane1.GetOffsetSize() + pane2.GetOffsetSize());
  pane1.size = c * (pane1.GetOffsetSize() + deltaSize);
  pane2.size = c * (pane2.GetOffsetSize() - deltaSize);
 }
};
ASPxSplitterPaneHelper = _aspxCreateClass(null, {
 constructor: function(pane) {
  this.pane = pane;
  this.cache = {};
  this.indexPath = this.GetIndexPath();
  var paneIdPostfix = this.pane.isRootPane ? "" : "_" + this.indexPath;
  var separatorIdPostfix = paneIdPostfix + "_S";
  this.postfixes = {
   pane: paneIdPostfix,
   separator: separatorIdPostfix,
   table: paneIdPostfix + "_T",
   contentContainer: paneIdPostfix + "_CC",
   collapseForwardButton: separatorIdPostfix + "_CF",
   collapseBackwardButton: separatorIdPostfix + "_CB",
   collapseButtonsSeparator: separatorIdPostfix + "_CS"
  };
  this.buttonsTableExists = _aspxIsExists(this.GetCollapseBackwardButton());
  this.separatorImageExists = _aspxIsExists(this.GetCollapseButtonsSeparatorImage());
  this.buttonsExists = this.buttonsTableExists || this.separatorImageExists;
 },
 GetCachedValue: function(name, func) {
  return ASPxSplitterHelper.GetCachedValue(this, name, this, func);
 },
 DropCachedValue: function(name) {
  ASPxSplitterHelper.DropCachedValue(this, name);
 },
 GetIndexPath: function() {
  if(this.pane.isRootPane)
   return "";
  var parentPane = this.pane.parent;
  if(parentPane.isRootPane)
   return "" + this.pane.index;
  return parentPane.helper.indexPath + __aspxItemIndexSeparator + this.pane.index;
 },
 GetCachedElement: function(idPostfix) {
  return this.GetCachedValue(idPostfix, function(){
   return this.pane.splitter.GetChild(idPostfix);
  });
 },
 DropCachedElement: function(idPostfix) {
  this.DropCachedValue(idPostfix);
 },
 GetPaneElement: function() {
  return this.GetCachedElement(this.postfixes.pane);
 },
 GetTableElement: function() {
  return this.GetCachedElement(this.postfixes.table);
 },
 GetContentContainerElement: function() {
  return this.GetCachedElement(this.postfixes.contentContainer);
 },
 DropContentContainerElementFromCache: function() {
  this.DropCachedElement(this.postfixes.contentContainer);
 },
 GetSeparatorElementId: function() {
  return this.pane.splitter.name + this.postfixes.separator;
 },
 GetSeparatorElement: function() {
  return this.GetCachedElement(this.postfixes.separator);
 },
 GetSeparatorDivElement: function() {
  return this.GetCachedValue("separatorDivElement", function(){
   var separatorElement = this.GetSeparatorElement();
   return _aspxIsExists(separatorElement) ? separatorElement.childNodes[0] : null;
  });
 },
 GetCollapseBackwardButton: function() {
  return this.GetCachedElement(this.postfixes.collapseBackwardButton);
 },
 GetCollapseForwardButton: function() {
  return this.GetCachedElement(this.postfixes.collapseForwardButton);
 },
 GetCollapseButtonsSeparator: function() {
  return this.GetCachedElement(this.postfixes.collapseButtonsSeparator);
 },
 GetCollapseButtonsTable: function() {
  return this.GetCachedValue("collapseButtonsTable", function(){
   return this.buttonsTableExists ? _aspxGetParentByTagName(this.GetCollapseForwardButton(), "TABLE") : null;
  });
 },
 GetCollapseButtonsSeparatorImage: function() {
  return this.GetCachedValue("collapseButtonsSeparatorImage", function(){
   var separator = this.GetCollapseButtonsSeparator();
   if(!_aspxIsExists(separator)) {
    if(!this.buttonsTableExists)
     separator = this.GetSeparatorElement();
    else
     return null;
   }
   return _aspxGetChildByTagName(separator, "IMG", 0);
  });
 },
 GetButtonUpdateElement: function(buttonElement) {
  return !this.pane.isVertical ? buttonElement.parentNode : buttonElement;
 },
 GetClientStateObject: function() {
  var result = {};
  if(!this.pane.isRootPane) {
   result.s = Math.round(this.pane.size * 1000) / 1000;
   result.st = this.pane.sizeType;
   result.c = this.pane.collapsed;
  }
  if(this.pane.panes.length > 0) {
   result.i = [];
   for(var i = 0; i < this.pane.panes.length; i++)
    result.i[i] = this.pane.panes[i].helper.GetClientStateObject();
  }
  return result;
 },
 SetEmptyDivVisible: function(visible) {
  var emptyDiv = this.GetCachedValue("emptyDiv", function(){
   var emptyDiv = document.createElement("DIV");
   emptyDiv.style.cssText = "overflow: hidden; width: 0px; height: 0px";
   emptyDiv.isVisible = false;
   return emptyDiv;
  });
  if(visible != emptyDiv.isVisible) {
   if(visible)
    this.GetPaneElement().appendChild(emptyDiv);
   else 
    this.GetPaneElement().removeChild(emptyDiv);
   emptyDiv.isVisible = visible;
  }
 }
});
ASPxSplitterResizingPointer = _aspxCreateClass(null, {
 constructor: function(elementId) {
  this.elementId = elementId;
  this.element = _aspxGetElementById(this.elementId);
  this.x = 0;
  this.y = 0;
 },
 SetCursor: function(cursor) {
  this.element.style.cursor = cursor;
 },
 SetPosition: function(x, y) {
  this.x = x;
  this.y = y;
  _aspxSetAbsoluteY(this.element, this.y);
  _aspxSetAbsoluteX(this.element, this.x);
 },
 SetVisibility: function(isVisible) {
  _aspxSetElementDisplay(this.element, isVisible);
 },
 Move: function(delta, isX) {
  if(isX)
   this.x += delta;
  else
   this.y += delta;
  this.SetPosition(this.x, this.y);
 },
 AttachToElement: function(element, isShow) {
  _aspxSetStyleSize(this.element, element.offsetWidth, element.offsetHeight);
  this.SetVisibility(true);
  this.SetPosition(_aspxGetAbsoluteX(element), _aspxGetAbsoluteY(element));
 }
});
ASPxClientSplitter = _aspxCreateClass(ASPxClientControl, {
 constructor: function(name) {
  this.constructor.prototype.constructor.call(this, name);
  this.emptyUrls = [
   "javascript:false",
   "about:blank",
   "#"
  ];
  this.width = "100%";
  this.height = "200px";
  this.helper = new ASPxSplitterHelper(this);
  this.resizingPointer = new ASPxSplitterResizingPointer(this.name + "_RP");
  this.rootPane = new ASPxClientSplitterPane(this, null, 0, {});
  this.liveResizing = false;
  this.allowResize = true;
  this.defaultMinSize = 5;
  this.showSeparatorImage = true;
  this.showCollapseBackwardButton = false;  
  this.showCollapseForwardButton = false;
  this.prepared = false;
  this.PaneResizing = new ASPxClientEvent();
  this.PaneResized = new ASPxClientEvent();
  this.PaneCollapsing = new ASPxClientEvent();
  this.PaneCollapsed = new ASPxClientEvent();
  this.PaneExpanding = new ASPxClientEvent();
  this.PaneExpanded = new ASPxClientEvent();
  this.PaneResizeCompleted = new ASPxClientEvent();
  this.isASPxClientSplitter = true;
 },
 Initialize: function() {
  this.constructor.prototype.Initialize.call(this);
  this.rootPane.ForEach("Initialize");
  this.rootPane.ForEach("ChangeEmptySizes");
  this.rootPane.ForEach("RefreshContentUrl", true);
  this.Prepare();
 },
 Prepare: function() {
  if(this.prepared || !this.IsDisplayed())
   return;
  this.rootPane.ForEach("Prepare", true);
  ASPxClientSplitter.instances[this.name] = this;
  this.prepared = true;
 },
 AdjustControlCore: function() {
  this.Prepare();
  this.UpdateControlSizes();
  this.rootPane.ForEach("AdjustControls", true);
  this.SynchronizeProperties();
 },
 UpdateControlSizes: function() {
  var element = this.GetMainElement();
  element.style.width = this.width;
  element.style.height = this.height;
  var focusedElement = _aspxGetFocusedElement(); 
  this.UpdatePanesVisible(_aspxChangeStyleAttribute);
  if(__aspxWebKitFamily) {
   var webkitSpecialElement = document.createElement("DIV");
   element.parentNode.appendChild(webkitSpecialElement);
   var offsetHeight = element.offsetHeight;
   element.parentNode.removeChild(webkitSpecialElement);
  }
  var newWidth = _aspxGetClearClientWidth(element);
  var newHeight = _aspxGetClearClientHeight(element);
  this.UpdatePanesVisible(_aspxRestoreStyleAttribute);
  if((this.rootPane.offsetWidth != newWidth) || (this.rootPane.offsetHeight != newHeight)) {
   this.rootPane.offsetWidth = newWidth;
   this.rootPane.offsetHeight = newHeight;
   this.rootPane.UpdatePanes();
  }
  if(focusedElement) { 
   focusedElement.blur();
   if(__aspxIE && __aspxBrowserVersion < 8 && focusedElement.tagName == "TD") {
    var childInput = _aspxGetChildByTagName(focusedElement, "INPUT", 0);
    if(childInput && _aspxElementIsVisible(childInput))
     focusedElement = childInput;
   }
   try { 
    focusedElement.focus();
   }
   catch(e) { }
  }
 },
 UpdatePanesVisible: function(func) {
  var firstTD = this.rootPane.panes[0].helper.GetPaneElement();
  func(firstTD, "width", "1px");
  func(firstTD, "height", "1px");
  func(this.rootPane.panes[0].helper.GetContentContainerElement(), "display", "none");
  for(var i = 1; i < this.rootPane.panes.length; i++) {
   var pane = this.rootPane.panes[i];
   func(pane.helper.GetPaneElement(), "display", "none");
   func(pane.helper.GetSeparatorElement(), "display", "none");
  }
 },
 SynchronizeProperties: function() {
  var clientStateElement = this.helper.GetClientStateElement();
  if(_aspxIsExists(clientStateElement)) {
   var stateString = _aspxToJson(this.rootPane.helper.GetClientStateObject());
   this.helper.GetClientStateElement().value = stateString;
   if(this.cookieName != "") {
    _aspxDelCookie(this.cookieName);
    _aspxSetCookie(this.cookieName, stateString);
   }
  }
 },
 GetPaneByPath: function(panePath, parentPane) {
  var pane = _aspxIsExists(parentPane) ? parentPane : this.rootPane;
  for(var i = 0; i < panePath.length; i++)
   pane = pane.panes[panePath[i]];
  return pane;
 },
 GetPaneByStringPath: function(paneStringPath, paneIndexSeparator) {
  if(!_aspxIsExists(paneIndexSeparator))
   paneIndexSeparator = __aspxItemIndexSeparator;
  return this.GetPaneByPath(paneStringPath.split(paneIndexSeparator));
 },
 OnWindowResize: function() {
  if(!this.IsDisplayed())
   return;
  this.UpdateControlSizes();
 },
 OnSeparatorMouseDown: function(moveRightPanePath) {
  var pane = this.GetPaneByStringPath(moveRightPanePath);
  this.moveRightPane = pane;
  this.moveLeftPane = pane.prevPane;
  this.moveIsVertical = this.moveRightPane.isVertical;
  this.moveStartPos = this.helper.GetCurrentPos();
  this.moveLastPos = this.moveStartPos;
  this.isHeavyUpdate = (this.moveLeftPane.isSizePx && !this.moveRightPane.isSizePx) ||
   (!this.moveLeftPane.isSizePx && this.moveRightPane.isSizePx);
  if(!this.moveLeftPane.IsAllowResize() || !this.moveRightPane.IsAllowResize())
   return false;
  if(this.moveLeftPane.collapsed || this.moveRightPane.collapsed)
   return false;
  if(this.RaiseCancelEvent("PaneResizing", this.moveRightPane) || this.RaiseCancelEvent("PaneResizing", this.moveLeftPane))
   return false;
  var cursor = this.moveIsVertical ? "n-resize" : "w-resize";
  if(!this.liveResizing) {
   this.resizingPointer.SetCursor(cursor);
   this.resizingPointer.AttachToElement(this.moveRightPane.helper.GetSeparatorElement(), true);
  }
  this.helper.SetResizingPanelVisibility(true);
  _aspxChangeStyleAttribute(document.body, "cursor", cursor);
  return true;
 },
 OnSeparatorMouseUp: function() {
  this.helper.SetResizingPanelVisibility(false);
  _aspxRestoreStyleAttribute(document.body, "cursor");
  if(!this.liveResizing || !this.isHeavyUpdate) {
   var deltaSize = this.moveLastPos - this.moveStartPos;
   this.moveLeftPane.SetOffsetSize(this.moveLeftPane.GetOffsetSize() - deltaSize);
   this.moveRightPane.SetOffsetSize(this.moveRightPane.GetOffsetSize() + deltaSize);
   ASPxSplitterHelper.Resize(this.moveLeftPane, this.moveRightPane, deltaSize);
   this.moveLeftPane.parent.ForEach("UpdateChildrenSize");
  }
  if(!this.liveResizing)
   this.resizingPointer.SetVisibility(false);
  this.moveLeftPane.parent.ForEach("AdjustControls");
  this.SynchronizeProperties();
  this.RaiseEvent("PaneResizeCompleted", this.moveLeftPane);
  this.RaiseEvent("PaneResizeCompleted", this.moveRightPane);
 },
 OnMouseMove: function() {
  var deltaSize = this.helper.GetMoveMaxDeltaSize(this.helper.GetCurrentPos() - this.moveLastPos);
  if(deltaSize == 0) return;
  this.moveLeftPane.SetOffsetSize(this.moveLeftPane.GetOffsetSize() + deltaSize);
  this.moveRightPane.SetOffsetSize(this.moveRightPane.GetOffsetSize() - deltaSize);
  if(this.liveResizing){
   var changePaneSize = function(pane, deltaSize) {
    pane.SetContentVisible(false);
    if(pane.ApplyElementSize()) {
    pane.ForEach("UpdateChildrenSize");
    pane.SetContentVisible(true);
     pane.RaiseResizedEvent();
    }
   };
   if(this.isHeavyUpdate) {
    ASPxSplitterHelper.Resize(this.moveLeftPane, this.moveRightPane, deltaSize);
    this.moveLeftPane.parent.ForEach("UpdateChildrenSize");
   }
   else {
    changePaneSize(this.moveLeftPane, deltaSize, this.helper);
    changePaneSize(this.moveRightPane, -deltaSize, this.helper);
   }
  }
  else
   this.resizingPointer.Move(deltaSize, !this.moveIsVertical);
  this.moveLastPos += deltaSize;
 },
 OnCollapseButtonClick: function(panePath, forwardDirection) {
  var rightPane = this.GetPaneByStringPath(panePath);
  var pane1 = forwardDirection ? rightPane.prevPane : rightPane;
  var pane2 = forwardDirection ? rightPane : rightPane.prevPane;
  if(pane1.collapsed && pane1.maximizedPane == pane2) {
   if(!this.RaiseCancelEvent("PaneExpanding", pane1))
    pane1.Expand();
  }
  else {
   if(!this.RaiseCancelEvent("PaneCollapsing", pane2))
    pane2.Collapse(pane1);
  }
  this.SynchronizeProperties();
 },
 IsEmptyUrl: function(url) {
  for(var i = 0; i < this.emptyUrls.length; i++)
   if(url == this.emptyUrls[i])
    return true;
  return false;
 },
 RaiseEvent: function(eventName, pane) {
  this[eventName].FireEvent(this, new ASPxClientSplitterPaneEventArgs(pane));
 },
 RaiseCancelEvent: function(eventName, pane) {
  var args = new ASPxClientSplitterPaneCancelEventArgs(pane);
  this[eventName].FireEvent(this, args);
  return args.cancel;
 },
 GetPaneCount: function() {
  return this.rootPane.GetPaneCount();
 },
 GetPane: function(index) {
  return this.rootPane.GetPane(index);
 },
 GetPaneByName: function(name) {
  return this.rootPane.GetPaneByName(name);
 },
 SetAllowResize: function(allowResize) {
  if(this.allowResize == allowResize)
   return;
  this.allowResize = allowResize;
  this.rootPane.ForEach("UpdateSeparatorStyle", true);
 },
 SetWidth: function(width) {
  this.width = width + "px";
  this.UpdateControlSizes();
 },
 SetHeight: function(height) {
  this.height = height + "px";
  this.UpdateControlSizes();
 }
});
ASPxClientSplitter.Cast = ASPxClientControl.Cast;
ASPxClientSplitterPane = _aspxCreateClass(null, {
 constructor: function(splitter, parent, index, paneProperties) {
  this.splitter = splitter;
  this.parent = parent;
  this.index = index;
  this.name = _aspxIsExists(paneProperties.name) ? paneProperties.name : "";
  this.isRootPane = (this.parent == null);
  this.helper = new ASPxSplitterPaneHelper(this);
  this.prevPane = null;
  this.nextPane = null;
  this.panes = [];
  this.isVertical = this.isRootPane ? false : !parent.isVertical;
  this.hasSeparator = (this.index > 0);
  this.collapsed = _aspxIsExists(paneProperties.collapsed) ? paneProperties.collapsed : false;
  this.size = _aspxIsExists(paneProperties.size) ? paneProperties.size : 0;
  this.sizeType = _aspxIsExists(paneProperties.sizeType) ? paneProperties.sizeType : null;
  this.maxSize = _aspxIsExists(paneProperties.maxSize) ? paneProperties.maxSize : Number.MAX_VALUE;
  this.minSize = _aspxIsExists(paneProperties.minSize) ? paneProperties.minSize : this.splitter.defaultMinSize;
  this.allowResize = _aspxIsExists(paneProperties.allowResize) ? paneProperties.allowResize : true;
  this.showCollapseForwardButton = _aspxIsExists(paneProperties.showCollapseForwardButton) ? paneProperties.showCollapseForwardButton : false;
  this.showCollapseBackwardButton = _aspxIsExists(paneProperties.showCollapseBackwardButton) ? paneProperties.showCollapseBackwardButton : false;
  this.iframe = {};
  if(_aspxIsExists(paneProperties.iframe)) {
   this.iframe = {
    src: paneProperties.iframe[0],
    scrolling: paneProperties.iframe[1]
   };
   if(paneProperties.iframe.length > 2)
    this.iframe.name = paneProperties.iframe[2];
   this.isContentUrl = true;
  }
  this.isSizePx = (this.sizeType == "px");
  this.maximizedPane = null;
  this.dragPrevented = false;
  this.offsetWidth = 0;
  this.offsetHeight = 0;
  this.widthDiff = 0;
  this.heightDiff = 0;
  this.minimizedWidthDiff = 0;
  this.minimizedHeightDiff = 0;
  this.contentContainerWidthDiff = 0;
  this.contentContainerHeightDiff = 0;
  this.isASPxClientSplitterPane = true;
 },
 CreatePanes: function(panesProperties) {
  var prevPane = null;
  var pane = null;
  for(var i = 0; i < panesProperties.length; i ++) {
   this.panes.push(pane = new ASPxClientSplitterPane(this.splitter, this, i, panesProperties[i]));
   pane.prevPane = prevPane;
   if(prevPane != null)
    prevPane.nextPane = pane;
   prevPane = pane;
   if(_aspxIsExists(panesProperties[i].panes))
    pane.CreatePanes(panesProperties[i].panes);
  }
 },
 Initialize: function() {
  this.InitializePreventDragging();
  if(this.isRootPane)
   return;
  if(this.collapsed) {
   if(this.IsFirstPane())
    this.maximizedPane = this.parent.panes[1];
   else if (this.prevPane.maximizedPane != this)
    this.maximizedPane = this.prevPane;
   else
    this.maximizedPane = this.nextPane;
   if (this.maximizedPane == null)
    this.collapsed = false;
  }
 },
 Prepare: function() {
  var EvaluateWidthDiff = function(element) {
   return element.offsetWidth - element.clientWidth;
  };
  var EvaluateHeightDiff = function(element) {
   var elementClientHeight = ((__aspxSafari && (__aspxBrowserVersion < 4)) || (__aspxChrome && (__aspxBrowserVersion < 2))) ? (element.offsetHeight - element.clientTop * 2) : element.clientHeight;
   return element.offsetHeight - elementClientHeight;
  };
  this.GetSeparatorSize();
  var element = this.helper.GetPaneElement();
  this.widthDiff = EvaluateWidthDiff(element);
  this.heightDiff = EvaluateHeightDiff(element);
  if(this.panes.length == 0) {
    var contentContainerElement = this.helper.GetContentContainerElement();
   _aspxSetScrollBarVisibility(contentContainerElement, false);
   _aspxSetStyleSize(contentContainerElement, 1, 1);
   this.contentContainerWidthDiff = contentContainerElement.offsetWidth - 1;
   this.contentContainerHeightDiff = contentContainerElement.offsetHeight - 1;
   _aspxSetScrollBarVisibility(contentContainerElement, true);
  }
  this.UpdateStyle(element, true);
  this.collapsedWidthDiff = EvaluateWidthDiff(element);
  this.collapsedHeightDiff = EvaluateHeightDiff(element);
  this.UpdateStyle(element, false);
  var separator = this.helper.GetSeparatorElement();
  if(_aspxIsExists(separator)) {
   _aspxSetElementDisplay(this.helper.GetSeparatorDivElement(), false);
   if(!this.isVertical)
    this.separatorSizeDiff = separator.offsetWidth - separator.clientWidth;
   else
    this.separatorSizeDiff = separator.offsetHeight - separator.clientHeight;
   _aspxSetElementDisplay(this.helper.GetSeparatorDivElement(), true);
  }
  else
   this.separatorSizeDiff = 0;
  this.PrepareSeparatorButtons();
 },
 PrepareSeparatorButtons: function() {
  if(!(this.hasSeparator && this.helper.buttonsExists))
   return;
  var sizeProperty = this.isVertical ? "offsetWidth" : "offsetHeight";
  if(this.helper.buttonsTableExists) {
   this.collapseBackwardButtonSize = this.helper.GetButtonUpdateElement(this.helper.GetCollapseBackwardButton())[sizeProperty];
   this.collapseForwardButtonSize = this.helper.GetButtonUpdateElement(this.helper.GetCollapseForwardButton())[sizeProperty];
   this.buttonsTableDiffSize = this.helper.GetCollapseButtonsTable()[sizeProperty] - this.collapseBackwardButtonSize - this.collapseForwardButtonSize;
   if(this.helper.separatorImageExists) {
    this.collapseButtonsSeparatorSize = this.helper.GetButtonUpdateElement(this.helper.GetCollapseButtonsSeparator())[sizeProperty];
    this.buttonsTableDiffSize -= this.collapseButtonsSeparatorSize;
   }
  }
  else
   this.collapseButtonsSeparatorSize = this.helper.GetCollapseButtonsSeparatorImage()[sizeProperty];
 },
 InitializePreventDragging: function() {
  if(!this.dragPrevented && this.helper.separatorImageExists) {
   _aspxPreventElementDrag(this.helper.GetCollapseButtonsSeparatorImage());
   this.dragPrevented = true;
  }
 },
 ForEach: function(funcName, skippSelf) {
  if(!_aspxIsExists(skippSelf) || !skippSelf)
   this[funcName]();
  for(var i = 0; i < this.panes.length; i++)
   this.panes[i].ForEach(funcName);
 },
 SetContentVisible: function(visible) {
  _aspxSetElementDisplay(this.helper.GetContentContainerElement(), visible);
  if(__aspxIE)
   this.helper.SetEmptyDivVisible(!visible);
 },
 AdjustControls: function() {
  if(this.panes.length == 0 && !this.collapsed && !this.isContentUrl)
   aspxGetControlCollection().AdjustControls(this.helper.GetContentContainerElement(), false);
 },
 UpdatePanes: function() {
  this.ForEach("UpdateChildrenSize");
  this.ForEach("UpdateVisualElements", true);
 },
 UpdateVisualElements: function() {
  this.UpdateButtonsVisibility();
  this.UpdateSeparatorStyle();
  this.UpdatePaneStyle();
 },
 IsBackwardButtonVisible: function() {
  return ASPxSplitterHelper.GetCachedValue(this.helper, "isBackwardButtonVisible", this, function() {
   if(!this.helper.buttonsTableExists)
    return false;
   if(this.collapsed && (this.maximizedPane == this.prevPane))
    return true;
   if(this.prevPane.collapsed)
    return false;
   return this.showCollapseBackwardButton;
  });
 },
 IsForwardButtonVisible: function() {
  return ASPxSplitterHelper.GetCachedValue(this.helper, "isForwardButtonVisible", this, function(){
   if(!this.helper.buttonsTableExists)
    return false;
   if(this.prevPane.collapsed && (this.prevPane.maximizedPane == this))
    return true;
   if(this.collapsed)
    return false;
   return this.showCollapseForwardButton;
  });
 },
 DropCachedButtonsVisible: function() {
  ASPxSplitterHelper.DropCachedValue(this.helper, "isBackwardButtonVisible");
  ASPxSplitterHelper.DropCachedValue(this.helper, "isForwardButtonVisible");
 },
 IsAllowResize: function() {
  return this.allowResize && this.splitter.allowResize;
 },
 UpdateSeparatorStyle: function() {
  if(!this.hasSeparator)
   return;
  var prevPaneCollapsed = this.prevPane != null && this.prevPane.collapsed;
  var prevPaneAllowResize = this.prevPane != null && this.prevPane.IsAllowResize();
  var isCollapsed = this.collapsed || prevPaneCollapsed;
  var resizingEnabled = this.IsAllowResize() && prevPaneAllowResize;
  aspxGetStateController().SetMouseStateItemsEnabled(this.helper.GetSeparatorElementId(), null, !isCollapsed && resizingEnabled);
  this.UpdateStyle(this.helper.GetSeparatorElement(), isCollapsed);
 },
 UpdatePaneStyle: function() {
  this.UpdateStyle(this.helper.GetPaneElement(), this.collapsed);
 },
 UpdateStyle: function(element, isSelect) {
  if(isSelect)
   aspxGetStateController().SelectElementBySrcElement(element);
  else
   aspxGetStateController().DeselectElementBySrcElement(element);
 },
 UpdateButtonsVisibility: function() {
  if(!(this.hasSeparator && this.helper.buttonsExists))
   return;
  var separatorSize = this.GetOffsetSize(!this.isVertical) - this.separatorSizeDiff;
  if(this.helper.buttonsTableExists) {
   var buttonsSize = this.buttonsTableDiffSize;
   if(this.IsBackwardButtonVisible())
    buttonsSize += this.collapseBackwardButtonSize;
   if(this.IsForwardButtonVisible())
    buttonsSize += this.collapseForwardButtonSize;
   var buttonsVisible = (buttonsSize <= separatorSize);
   var backwardButtonVisible = buttonsVisible && this.IsBackwardButtonVisible();
   var forwardButtonVisible = buttonsVisible && this.IsForwardButtonVisible();
   _aspxSetElementDisplay(this.helper.GetButtonUpdateElement(this.helper.GetCollapseBackwardButton()), backwardButtonVisible);
   _aspxSetElementDisplay(this.helper.GetButtonUpdateElement(this.helper.GetCollapseForwardButton()), forwardButtonVisible);
   if(this.helper.separatorImageExists) {
    if(!buttonsVisible)
     buttonsSize = this.buttonsTableDiffSize;
    buttonsSize += this.collapseButtonsSeparatorSize;
    var separatorImageVisible = this.splitter.showSeparatorImage && (backwardButtonVisible === forwardButtonVisible) && (buttonsSize <= separatorSize);
    _aspxSetElementDisplay(this.helper.GetButtonUpdateElement(this.helper.GetCollapseButtonsSeparator()), separatorImageVisible);
   }
  }
  else {
   var separatorImageVisible = this.splitter.showSeparatorImage && (this.collapseButtonsSeparatorSize <= separatorSize);
   _aspxSetElementDisplay(this.helper.GetCollapseButtonsSeparatorImage(), separatorImageVisible);
  }
 },
 GetSeparatorSize: function() {
  return ASPxSplitterHelper.GetCachedValue(this.helper, "separatorSize", this, function() {
   var separator = this.helper.GetSeparatorElement();
   return _aspxIsExists(separator) ? (this.isVertical ? separator.offsetHeight : separator.offsetWidth) : 0;
  });
 },
 GetTotalSeparatorsSize: function(isVertical) {
  if(!_aspxIsExists(isVertical) || (isVertical == this.isVertical))
   return 0;
  var cacheKey = (isVertical ? "v" : "h") + "TotalSeparatorsSize"; 
  return ASPxSplitterHelper.GetCachedValue(this.helper, cacheKey, this, function() {
   var result = 0;
   for(var i = 0; i < this.panes.length; i++)
    result += this.panes[i].GetSeparatorSize();
   return result;
  });
 },
 GetMinSize: function(isVertical) {
  if(!_aspxIsExists(isVertical))
   isVertical = this.isVertical;
  var cacheKey = (isVertical ? "v" : "h") + "ItemMinSize";
  return ASPxSplitterHelper.GetCachedValue(this.helper, cacheKey, this, function() {
   var result = 0;
   for(var i = 0; i < this.panes.length; i++)
    if(isVertical != this.isVertical)
     result += this.panes[i].GetMinSize(isVertical);
    else
     result = Math.max(result, this.panes[i].GetMinSize(isVertical));
   result += this.GetTotalSeparatorsSize(isVertical);
   var minSize = (isVertical == this.isVertical) ? this.minSize : this.splitter.defaultMinSize;
   result = Math.max(result, Math.max(minSize, this.GetSizeDiff(isVertical)));
   return result;
  });
 },
 GetMaxSize: function() {
  return Math.max(this.maxSize, this.GetSizeDiff(this.isVertical));
 },
 ChangeEmptySizes: function() {
  var prcSum = 0;
  var emptyPanesCount = 0;
  for(var i = 0; i < this.panes.length; i++) {
   var pane = this.panes[i];
   if(pane.sizeType == "%")
    prcSum += pane.size;
   else if(pane.sizeType == null)
    emptyPanesCount++;
  }
  var freePrcSize = 100 - prcSum;
  if((emptyPanesCount > 0) && (freePrcSize > 0)) {
   for(var i = 0; i < this.panes.length; i++) {
    var pane = this.panes[i];
    if(pane.sizeType == null) {
     pane.sizeType = "%";
     pane.size = freePrcSize / emptyPanesCount;
    }
   }
  }
 },
 PrepareUpdateInfo: function() {
  var updateInfo = {};
  var prepareUpdateInfoPart = function() {
   return {
    panes: [],
    sum: 0,
    sumMin: 0,
    sumMax: 0,
    addPane: function() {
     this.panes.push(pane);
     if(pane.collapsed) {
      var sizeDiff = pane.GetSizeDiff(pane.isVertical);
      this.sum += sizeDiff;
      this.sumMin += sizeDiff;
     }
     else {
      this.sum += pane.size;
      this.sumMin += pane.GetMinSize();
     }
     this.sumMax += pane.GetMaxSize();
    },
    IsIgnoreMaxSize: function() {
     return this.sumMax < this.sum;
    }
   };
  };
  updateInfo.px = prepareUpdateInfoPart();
  updateInfo.prc = prepareUpdateInfoPart();
  updateInfo.collapsed = prepareUpdateInfoPart();
  updateInfo.onlyPxPanes = true; 
  updateInfo.hasPxPanesShown = false;
  updateInfo.hasPrcPanesShown = false;
  for(var i = 0; i < this.panes.length; i++) {
   var pane = this.panes[i];
   if(pane.collapsed)
    updateInfo.collapsed.addPane(pane);
   else if(pane.isSizePx) {
    updateInfo.px.addPane(pane);
    updateInfo.hasPxPanesShown = true;
   }
   else {
    updateInfo.prc.addPane(pane);
    updateInfo.hasPrcPanesShown = true;
   }
   if(!pane.isSizePx)
    updateInfo.onlyPxPanes = false;
  }
  updateInfo.px.isIgnoreMaxSize = (!updateInfo.hasPrcPanesShown && (updateInfo.px.sumMax < updateInfo.px.sum));
  updateInfo.prc.isIgnoreMaxSize = (updateInfo.prc.sumMax < updateInfo.prc.sum);
  return updateInfo;
 },
 SetChildrenSecondSize: function() {
  var orientation = this.isVertical;
  var size = this.GetClientSize(orientation);
  for(var i = 0; i < this.panes.length; i++)
   this.panes[i].SetOffsetSize(size, orientation);
 },
 GetChildrenTotalSize: function() {
  return this.GetClientSize(!this.isVertical) - this.GetTotalSeparatorsSize(!this.isVertical);
 },
 UpdateChildrenSize: function() {
  if(this.collapsed || (this.panes.length == 0))
   return;
  var updateInfo = this.PrepareUpdateInfo();
  var childrenTotalSize = this.GetChildrenTotalSize();
  var pxMaxSize = childrenTotalSize - (updateInfo.prc.sumMin + updateInfo.collapsed.sumMin);
  var pxTotalSize = 0;
  if((pxMaxSize > 0) && updateInfo.hasPxPanesShown) {
   var c = !updateInfo.hasPrcPanesShown ? (pxMaxSize / updateInfo.px.sum) : 1;
   for(var i = 0; i < updateInfo.px.panes.length; i++) {
    var pane = updateInfo.px.panes[i];
    var newSize = Math.max(Math.round(pane.size * c), pane.GetMinSize());
    if(!updateInfo.px.isIgnoreMaxSize)
     newSize = Math.min(newSize, pane.GetMaxSize());
    pane.SetOffsetSize(newSize);
    pxTotalSize += newSize;
   }
   if(!updateInfo.hasPrcPanesShown || (pxTotalSize > pxMaxSize))
    pxTotalSize = this.NormalizePanesSizes(updateInfo.px.panes, pxTotalSize, pxMaxSize);
   if (updateInfo.onlyPxPanes) {
    for(var i = 0; i < updateInfo.px.panes.length; i++) {
     var pane = updateInfo.px.panes[i];
     pane.size = pane.GetOffsetSize();
    }
   }
  }
  var prcMaxSize = pxMaxSize - pxTotalSize + updateInfo.prc.sumMin;
  var prcTotalSize = 0;
  if((prcMaxSize > 0) && updateInfo.hasPrcPanesShown) {
   var c = 1 / updateInfo.prc.sum;
   for(var i = 0; i < updateInfo.prc.panes.length; i++) {
    var pane = updateInfo.prc.panes[i];
    var newSize = Math.max(Math.round(pane.size * c * (childrenTotalSize - pxTotalSize)), pane.GetMinSize());
    if(!updateInfo.prc.isIgnoreMaxSize)
     newSize = Math.min(newSize, pane.GetMaxSize());
    pane.SetOffsetSize(newSize);
    prcTotalSize += newSize;
   }
   if(prcTotalSize != prcMaxSize)
    prcTotalSize = this.NormalizePanesSizes(updateInfo.prc.panes, prcTotalSize, prcMaxSize);
  }
  for(var i = 0; i < updateInfo.collapsed.panes.length; i++) {
   var pane = updateInfo.collapsed.panes[i];
   pane.SetOffsetSize(pane.GetSizeDiff(pane.isVertical));
  }
  this.SetChildrenSecondSize();
  for(var i = 0; i < this.panes.length; i++) {
   var pane = this.panes[i];
   if(pane.collapsed)
    pane.SetContentVisible(false);
   else
    pane.SetContentVisible(true);
   if(pane.ApplyElementSize())
    pane.RaiseResizedEvent();
  }
  this.ForEach("UpdateButtonsVisibility", true);
 },
 GetPossibleUp: function() {
  return this.GetMaxSize() - this.GetOffsetSize();
 },
 GetPossibleDown: function() {
  return this.GetOffsetSize() - this.GetMinSize();
 },
 NormalizePanesSizes: function(panes, size, maxSize) {
  var insufficientSize = maxSize - size;
  var changeStep = (insufficientSize > 0) ? 1 : -1;
  var possibleChangeFunction = (insufficientSize > 0) ? "GetPossibleUp" : "GetPossibleDown";
  var changed = true;
  while((insufficientSize != 0) && changed) {
   changed = false;
  for(var i = 0; i < panes.length; i++) {
   var pane = panes[i];
    if(pane[possibleChangeFunction]() > 0) {
     pane.SetOffsetSize(pane.GetOffsetSize() + changeStep);
     insufficientSize -= changeStep;
     changed = true;
     if(insufficientSize == 0)
      break;
  }
   }
  }
  return maxSize - insufficientSize;
 },
 GetOffsetSize: function(isVertical) {
  if(!_aspxIsExists(isVertical))
   isVertical = this.isVertical;
  return isVertical ? this.offsetHeight : this.offsetWidth;
 },
 GetClientSize: function(isVertical) {
  return isVertical ? this.GetClientHeightInternal(true) : this.GetClientWidthInternal(true);
 },
 SetOffsetSize: function(value, isVertical) {
  if(!_aspxIsExists(isVertical))
   isVertical = this.isVertical;
  if(isVertical)
   this.offsetHeight = value;
  else
   this.offsetWidth = value;
 },
 GetSizeDiff: function(isVertical) {
  return isVertical ? this.GetHeightDiff(true) : this.GetWidthDiff(true);
 },
 GetWidthDiff: function(isContainer) {
  if(this.collapsed)
   return this.collapsedWidthDiff;
  return this.widthDiff + (isContainer ? this.contentContainerWidthDiff : 0);
 },
 GetHeightDiff: function(isContainer) {
  if(this.collapsed)
   return this.collapsedHeightDiff;
  return this.heightDiff + (isContainer ? this.contentContainerHeightDiff : 0);
 },
 GetClientWidthInternal: function(isContainer) {
  return this.offsetWidth - this.GetWidthDiff(isContainer);
 },
 GetClientHeightInternal: function(isContainer) {
  return this.offsetHeight - this.GetHeightDiff(isContainer);
 },
 ApplyElementSize: function() {
  if(this.IsSizeChanged()) {
   var paneWidth = this.GetClientWidthInternal(false);
   var paneHeight = this.GetClientHeightInternal(false);
   var contentContainerWidth = this.GetClientWidthInternal(true);
   var contentContainerHeight = this.GetClientHeightInternal(true);
   if(contentContainerWidth < 0) {
    paneWidth -= contentContainerWidth;
    contentContainerWidth = 0;
   }
   if(contentContainerHeight < 0) {
    paneHeight -= contentContainerHeight;
    contentContainerHeight = 0;
   }
   _aspxSetStyleSize(this.helper.GetPaneElement(), paneWidth, paneHeight);
   var contentContainerElement = this.helper.GetContentContainerElement();
   _aspxSetStyleSize(contentContainerElement, contentContainerWidth, contentContainerHeight);
   if(__aspxChrome && __aspxBrowserMajorVersion >= 3
     || __aspxSafari && __aspxBrowserMajorVersion >= 5) {
    var marginRight = _aspxPxToInt(contentContainerElement.style.marginRight);
    marginRight -= _aspxPxToInt(_aspxGetCurrentStyle(contentContainerElement).marginRight);
    contentContainerElement.style.marginRight = marginRight + "px";
   }
   if(__aspxWebKitFamily) {
    var updated = _aspxSetScrollBarVisibilityCore(contentContainerElement, "overflowY", this.GetClientWidthInternal(true) > _aspxGetVerticalScrollBarWidth());
    if(updated && this.isContentUrl)
     this.RefreshContentUrl();
   }
   return true;
  }
  return false;
 },
 IsSizeChanged: function() {
  if(!_aspxIsExists(this.lastWidth) || !_aspxIsExists(this.lastHeight) ||
   (this.offsetWidth != this.lastWidth) || (this.offsetHeight != this.lastHeight)) {
   this.lastWidth = this.offsetWidth;
   this.lastHeight = this.offsetHeight;
   return true;
  }
  return false;
 },
 GetSplitter: function() {
  return this.splitter;
 },
 GetParentPane: function() {
  return this.parent;
 },
 GetPrevPane: function() {
  return this.prevPane;
 },
 GetNextPane: function() {
  return this.nextPane;
 },
 IsFirstPane: function() {
  return (this.prevPane == null);
 },
 IsLastPane: function() {
  return (this.nextPane == null);
 },
 IsVertical: function() {
  return this.isVertical;
 },
 GetPaneCount: function() {
  return this.panes.length;
 },
 GetPane: function(index) {
  return (0 <= index && index < this.panes.length) ? this.panes[index] : null;
 },
 GetPaneByName: function(name) {
  for(var i = 0; i < this.panes.length; i++)
   if(this.panes[i].name == name) return this.panes[i];
  for(var i = 0; i < this.panes.length; i++) {
   var pane = this.panes[i].GetPaneByName(name);
   if(pane != null) return pane;
  }
  return null;
 },
 GetClientWidth: function() {
  var clientWidth = this.GetClientWidthInternal(true);
  if(!this.IsContentUrlPane()){
   var contentContainer = this.helper.GetContentContainerElement();
   if((contentContainer.style.overflow == "auto" && contentContainer.scrollHeight > contentContainer.clientHeight) 
     || contentContainer.style.overflow == "scroll"
     || contentContainer.style.overflowY == "scroll"){
    clientWidth = clientWidth - _aspxGetVerticalScrollBarWidth();
   }
  }
  return clientWidth;
 },
 GetClientHeight: function() {
  return this.GetClientHeightInternal(true);
 },
 Collapse: function(maximizedPane) {
  if(!this.splitter.prepared)
   return false;
  if(this.collapsed)
   return false;
  if(!_aspxIsExists(maximizedPane) || !maximizedPane.isASPxClientSplitterPane)
   return false;
  return this.CollapseExpandCore(true, maximizedPane, "PaneCollapsed");
 },
 Expand: function() {
  if(!this.splitter.prepared)
   return false;
  if(!this.collapsed)
   return false;
  return this.CollapseExpandCore(false, null, "PaneExpanded");
 },
 CollapseExpandCore: function(collapsed, maximizedPane, eventName) {
  this.collapsed = collapsed;
  this.maximizedPane = maximizedPane;
  this.DropCachedButtonsVisible();
  if(this.nextPane != null)
   this.nextPane.DropCachedButtonsVisible();
  this.GetParentPane().UpdatePanes();
  this.GetParentPane().ForEach("AdjustControls");
  this.splitter.RaiseEvent(eventName, this);
  return true;
 },
 IsCollapsed: function() {
  return this.collapsed;
 },
 IsContentUrlPane: function() {
  return this.isContentUrl;
 },
 GetContentUrl: function() {
  return this.iframe.src;
 },
 SetContentUrl: function(url) {
  if(!this.isContentUrl)
   return;
  if(_aspxIsExists(url) && this.iframe.src != url) {
   this.iframe.src = url;
   this.RefreshContentUrl();
  }
 },
 RefreshContentUrl: function() {
  if(!this.isContentUrl)
   return;
  this.GetCreateContentUrlIFrame().src = this.GetContentUrl();
 },
 GetCreateContentUrlIFrame: function() {
  var contentContainer = this.helper.GetContentContainerElement();
  if(contentContainer.tagName == "DIV") {
   contentContainer.parentNode.removeChild(contentContainer);
   var iframe = _aspxCreateIFrame({
    id: contentContainer.id,
    name: this.iframe.name,
    scrolling: this.iframe.scrolling,
    src: this.iframe.src
   });
   iframe.style.width = contentContainer.style.width;
   iframe.style.height = contentContainer.style.height;
   this.helper.GetPaneElement().appendChild(iframe);
   this.helper.DropContentContainerElementFromCache();
   return iframe;
  }
  else
   return contentContainer;
 },
 SetAllowResize: function(allowResize) {
  this.allowResize = allowResize;
  this.UpdateSeparatorStyle();
  if(!this.IsLastPane())
   this.nextPane.UpdateSeparatorStyle();
 },
 RaiseResizedEvent: function() {
  this.splitter.RaiseEvent("PaneResized", this);
 },
 GetElement: function() {
  return this.helper.GetPaneElement();
 },
 SetSize: function(size) {
  if(!this.splitter.prepared)
   return;
  if(this.SetSizeCore(size)) {
   this.parent.ForEach("UpdateChildrenSize");
   this.parent.ForEach("AdjustControls");
   this.splitter.SynchronizeProperties();
  }
 },
 GetSize: function() {
  return this.size + this.sizeType;
 },
 SetSizeCore: function(size) {
  if(!_aspxIsExists(size))
   return false;
  if(typeof(size) == "string") {
   var parsedSize = parseInt(size);
   if(isNaN(parsedSize))
    return false;
   this.size = parsedSize;
   this.sizeType = (size.indexOf("%") > -1) ? "%" : "px";
  }
  else if(typeof(size) == "number") {
   this.size = size;
   this.sizeType = "px";
  }
  else
   return false;
  this.isSizePx = this.sizeType == "px";
  return true;
 }
});
ASPxClientSplitter.instances = {};
ASPxClientSplitter.GetInstance = function(name) {
 var instance = ASPxClientSplitter.instances[name];
 if(_aspxIsExists(instance)) {
  if(_aspxIsExists(instance.GetMainElement()))
   return instance;
  delete ASPxClientSplitter.instances[name]; 
 }
 return null;
};
ASPxClientSplitter.timerInterval = 0;
ASPxClientSplitter.GetRegEx = function(idPostfix) {
 if(!_aspxIsExists(this.regExs))
  this.regExs = {};
 if(!_aspxIsExists(this.regExs[idPostfix]))
  this.regExs[idPostfix] = "_\\d+(" + __aspxItemIndexSeparator + "\\d+)*_" + idPostfix + "$";
 return this.regExs[idPostfix];
};
ASPxClientSplitter.IsActualWindowResize = function() {
 var width = _aspxGetDocumentClientWidth();
 var height = _aspxGetDocumentClientHeight();
 if(width != ASPxClientSplitter.lastWindowResizeWidth || height != ASPxClientSplitter.lastWindowResizeHeight) {
  ASPxClientSplitter.lastWindowResizeWidth = width;
  ASPxClientSplitter.lastWindowResizeHeight = height;
  return true;
 }
 return false;
};
ASPxClientSplitter.SuspendedWindowResizeCore = function() {
 for(var name in ASPxClientSplitter.instances) {
  var instance = ASPxClientSplitter.GetInstance(name);
  if(_aspxIsExists(instance))
   instance.OnWindowResize();
 }
};
ASPxClientSplitter.mainWindowResizeTimeout = -1;
ASPxClientSplitter.additionalWindowResizeTimeout = -1;
ASPxClientSplitter.MainSuspendedWindowResize = function() {
 ASPxClientSplitter.SuspendedWindowResizeCore();
 ASPxClientSplitter.mainWindowResizeTimeout = _aspxClearTimer(ASPxClientSplitter.mainWindowResizeTimeout);
};
ASPxClientSplitter.AdditionalSuspendedWindowResize = function() {
 ASPxClientSplitter.SuspendedWindowResizeCore();
 ASPxClientSplitter.additionalWindowResizeTimeout = _aspxClearTimer(ASPxClientSplitter.additionalWindowResizeTimeout);
};
ASPxClientSplitter.OnWindowResize = function() {
 if(!ASPxClientSplitter.IsActualWindowResize())
  return;
 if(ASPxClientSplitter.additionalWindowResizeTimeout != -1)
  ASPxClientSplitter.additionalWindowResizeTimeout = _aspxClearTimer(ASPxClientSplitter.additionalWindowResizeTimeout);
 if(ASPxClientSplitter.mainWindowResizeTimeout == -1)
  ASPxClientSplitter.mainWindowResizeTimeout = _aspxSetTimeout(ASPxClientSplitter.MainSuspendedWindowResize, ASPxClientSplitter.timerInterval);
 else
  ASPxClientSplitter.additionalWindowResizeTimeout = _aspxSetTimeout(ASPxClientSplitter.AdditionalSuspendedWindowResize, 100);
};
ASPxClientSplitter.SaveCurrentPos = function(evt) {
 evt = _aspxGetEvent(evt);
 ASPxClientSplitter.CurrentXPos = _aspxGetEventX(evt);
 ASPxClientSplitter.CurrentYPos = _aspxGetEventY(evt);
};
ASPxClientSplitter.FindParentCell = function(element) {
 if(element.tagName != "TD") 
  element = _aspxGetParentByTagName(element, "TD");
 return element;
};
ASPxClientSplitter.FindSplitterInfo = function(evt, regex, suffixLength) {
 var element = ASPxClientSplitter.FindParentCell(_aspxGetEventSource(evt));
 if(_aspxIsExists(element)) {
  var matchResult = element.id.match(regex);
  if(_aspxIsExists(matchResult)) {
   var name = element.id.substring(0, matchResult.index);
   var splitter = ASPxClientSplitter.GetInstance(name);
   if(splitter != null) {
    var panePath = element.id.substring(matchResult.index + 1, element.id.length - suffixLength);
    return { "splitter" : splitter, "panePath" : panePath };
   }
  }  
 }
 return null;
};
ASPxClientSplitter.OnMouseClick = function(evt) {
 var info = ASPxClientSplitter.FindSplitterInfo(evt, ASPxClientSplitter.GetRegEx("S_CF"), 5);
 if(_aspxIsExists(info))
  info.splitter.OnCollapseButtonClick(info.panePath, true);
 else {
  info = ASPxClientSplitter.FindSplitterInfo(evt, ASPxClientSplitter.GetRegEx("S_CB"), 5);
  if(_aspxIsExists(info))
   info.splitter.OnCollapseButtonClick(info.panePath, false);
 } 
};
ASPxClientSplitter.OnMouseDown = function(evt) {
 var info = ASPxClientSplitter.FindSplitterInfo(evt, ASPxClientSplitter.GetRegEx("S"), 2);
 if(!_aspxIsExists(info)) 
  info = ASPxClientSplitter.FindSplitterInfo(evt, ASPxClientSplitter.GetRegEx("S_CS"), 5);
 if(_aspxIsExists(info) && _aspxIsExists(info.splitter)) {
  _aspxSetElementSelectionEnabled(document.body, false);
  ASPxClientSplitter.current = info.splitter;
  ASPxClientSplitter.SaveCurrentPos(evt);
  ASPxClientSplitter.isInMove = info.splitter.OnSeparatorMouseDown(info.panePath);
 }
};
ASPxClientSplitter.OnMouseUp = function() {
 if(ASPxClientSplitter.isInMove) {
  ASPxClientSplitter.isInMove = false;
  _aspxSetElementSelectionEnabled(document.body, true);
  ASPxClientSplitter.current.OnSeparatorMouseUp();
 }
};
ASPxClientSplitter.mouseMoveTimeoutId = -1;
ASPxClientSplitter.SuspendedMouseMove = function() {
 if(ASPxClientSplitter.isInMove)
  ASPxClientSplitter.current.OnMouseMove();
 ASPxClientSplitter.mouseMoveTimeoutId = _aspxClearTimer(ASPxClientSplitter.mouseMoveTimeoutId);
};
ASPxClientSplitter.OnMouseMove = function(evt) {
 if(!ASPxClientSplitter.isInMove)
  return;
 if(__aspxIE && !_aspxGetIsLeftButtonPressed(evt)) {
  ASPxClientSplitter.OnMouseUp(evt);
  return;
 }
 ASPxClientSplitter.SaveCurrentPos(evt);
 if(ASPxClientSplitter.mouseMoveTimeoutId == -1)
  ASPxClientSplitter.mouseMoveTimeoutId = _aspxSetTimeout(ASPxClientSplitter.SuspendedMouseMove, ASPxClientSplitter.timerInterval);
};
_aspxAttachEventToElement(window, "resize", ASPxClientSplitter.OnWindowResize);
_aspxAttachEventToDocument("click", ASPxClientSplitter.OnMouseClick);
_aspxAttachEventToDocument("mousedown", ASPxClientSplitter.OnMouseDown);
_aspxAttachEventToDocument("mouseup", ASPxClientSplitter.OnMouseUp);
_aspxAttachEventToDocument("mousemove", ASPxClientSplitter.OnMouseMove);
ASPxClientSplitterPaneEventArgs = _aspxCreateClass(ASPxClientEventArgs, {
 constructor: function(pane) {
  this.constructor.prototype.constructor.call(this, pane);
  this.pane = pane;
 }
});
ASPxClientSplitterPaneCancelEventArgs = _aspxCreateClass(ASPxClientSplitterPaneEventArgs, {
 constructor: function(pane) {
  this.constructor.prototype.constructor.call(this, pane);
  this.cancel = false;
 }
});
var __aspxCalendarWeekCount = 6;
var __aspxCalendarMsPerDay = 86400000;
var __aspxActiveCalendar = null;
ASPxClientCalendar = _aspxCreateClass(ASPxClientEdit, {
 constructor: function(name) {
  this.constructor.prototype.constructor.call(this, name);
  this.SelectionChanging = new ASPxClientEvent();
  this.SelectionChanged = new ASPxClientEvent();
  this.VisibleMonthChanged = new ASPxClientEvent();
  this.isMouseDown = false;  
  this.forceMouseDown = false;
  this.selection = new ASPxClientCalendarSelection();
  this.selectionTransaction = null;  
  this.selectionStartDate = null;
  this.selectionPrevStartDate = null;
  this.lastSelectedDate = null;
  this.selectionCtrl = false;
  this.selectionByWeeks = false;  
  this.nodeCache = { };
  this.titleFormatter = null;
  this.visibleDate = new Date();
  this.firstDayOfWeek = 0;    
  this.columns = 1;
  this.rows = 1;
  this.enableFast = true;
  this.enableMulti = false;
  this.minDate = null;
  this.maxDate = null;
  this.customDraw = false;  
  this.showWeekNumbers = true;
  this.showDayHeaders = true;
  this.isDateEditCalendar = false;
  this.sizingConfig.allowSetHeight = false;
  this.isDateChangingByKeyboard = false;
  this.MainElementClick = new ASPxClientEvent();      
 },
 Initialize: function() {
  this.selectionTransaction = new ASPxClientCalendarSelectionTransaction(this);
  this.selectionPrevStartDate = this.selection.GetFirstDate();
  this.SaveClientState(); 
  ASPxClientEdit.prototype.Initialize.call(this);
 },
 InlineInitialize: function(){
  this.CreateViews();
  if(this.enableFast)
   this.fastNavigation = new ASPxClientCalendarFastNavigation(this);
  this.InitSpecialKeyboardHandling();
  this.MakeDisabledStateItems();
  ASPxClientEdit.prototype.InlineInitialize.call(this);
 },
 MakeDisabledStateItems: function(){
  for(var key in this.views) {
   var view = this.views[key];
   if(view.constructor != ASPxClientCalendarView) continue;
   view.MakeDisabledStateItems();
  }
 },
 FindInputElement: function() {
  return this.GetChild("_KBS");
 },
 FindStateInputElement: function() {
  return _aspxGetElementById(this.name + "_STATE");
 },
 GetClearButton: function() {
  return this.GetChild("_BC");
 },
 GetTodayButton: function() {
  return this.GetChild("_BT");
 },
 GetValue: function() {
  return this.selection.GetFirstDate();
 },
 GetValueString: function() {
  var value = this.GetValue();
  return value == null ? null : _aspxGetInvariantDateString(value);
 },
 SetValue: function(date) {
  if(date != null)
   this.SetVisibleDate(date);
  this.SetSelectedDate(date);
 },
 GetFastNavigation: function() {
  return this.fastNavigation;
 },    
 GetViewKey: function(row, column) {
  return row + "x" + column;
 },
 GetView: function(row, column) {
  var key = this.GetViewKey(row, column);
  return this.views[key];
 },
 CreateViews: function() {
  this.views = { };
  var key;
  for(var row = 0 ; row < this.rows; row++) {   
   for(var col = 0; col < this.columns; col++) {
    key = this.GetViewKey(row, col);
    var view = new ASPxClientCalendarView(this, row, col);
    view.Initialize();
    this.views[key] = view;
   }
  }
 },
 IsFastNavigationActive: function() {
  if (_aspxIsExists(this.fastNavigation))
   return this.fastNavigation.GetPopup().IsVisible();
  return false;
 },
 IsDateSelected: function(date) {
  return this.selection.Contains(date);
 },
 IsDateVisible: function(date) {
  var startDate = ASPxClientCalendar.CloneDate(this.GetView(0, 0).visibleDate);
  startDate.setDate(1);  
  var endDate = ASPxClientCalendar.CloneDate(this.GetView(this.rows - 1, this.columns - 1).visibleDate);
  endDate.setDate(ASPxClientCalendar.GetDaysInMonth(endDate.getMonth(), endDate.getFullYear()));
  return (date >= startDate) && (date < endDate);
 },
 IsDateWeekend: function(date) {
  var day = date.getDay();
  return day == 0 || day == 6;
 }, 
 IsMultiView: function() {
  return this.columns > 1 || this.rows > 1;
 },
 IsDateInRange: function(date) {
  return date == null || 
   ((this.minDate == null || date >= this.minDate) && 
    (this.maxDate == null || date <= this.maxDate));
 },
 GetCachedElementById: function(id) {
  if(!_aspxIsExistsElement(this.nodeCache[id]))
   this.nodeCache[id] = _aspxGetElementById(id);
  return this.nodeCache[id]; 
 },
 ShowLoadingPanel: function(){
  var element = this.GetMainElement();
  var divElement = element.parentNode;
  this.CreateLoadingDiv(divElement, element);
  this.CreateLoadingPanelWithAbsolutePosition(divElement, element);
 },
 Update: function() {
  if(this.customDraw) {
   if(this.callBack) {
    this.ShowLoadingPanel();
    this.CreateCallback("UPDATE");
   }
   else {
    this.SendPostBack("");
   }
  }
  else {
   this.UpdateInternal();
  }
 }, 
 UpdateInternal: function() {
  for(var key in this.views) {
   var view = this.views[key];
   if(view.constructor != ASPxClientCalendarView) continue;
    view.Update();
  }
 }, 
 ApplySelectionByDiff: function(selection, save) {
  var toShow = [ ];
  var toHide = [ ];
  var dates =  selection.GetDates();
  var oldDates = this.selection.GetDates();
  var date;
  for(var i = 0; i < dates.length; i++) {
   date = dates[i];
   if(!this.selection.Contains(date))
    toShow.push(date);
  }
  for(var i = 0; i < oldDates.length; i++) {
   date = oldDates[i];
   if(!selection.Contains(date))
    toHide.push(date);
  }
  for(var key in this.views) {
   var view = this.views[key];
   if(view.constructor != ASPxClientCalendarView) continue;
   view.UpdateSelection(toHide, false);
   view.UpdateSelection(toShow, true);   
  }
  this.selection.Assign(selection);
  if(save)
   this.SaveClientState();
 },
 ImportEtalonStyle: function(info, suffix) {
  var cell = this.GetEtalonStyleCell(suffix);
  if(_aspxIsExistsElement(cell))
   info.Import(cell);   
 },
 GetEtalonStyleCell: function(name) {
  return this.GetCachedElementById(this.name + "_EC_" + name);
 },
 SaveClientState: function() {
  var element = this.FindStateInputElement();
  if (element != null) {
   var state = _aspxGetInvariantDateString(this.visibleDate);   
   if(this.selection.count > 0) 
    state += ":" + this.FormatDates(this.selection.GetDates(), ":");
   element.value = state;
  }
 },  
 FormatDates: function(dates, separator) {
  var result = "";
  for(var i = 0; i < dates.length; i++) {
   if (result.length > 0)
    result += separator;
   result += _aspxGetInvariantDateString(dates[i]);     
  }
  return result;
 },
 InitializeKeyHandlers: function() {
  this.AddKeyDownHandler(ASPxKey.Enter, "OnEnter");
  this.AddKeyDownHandler(ASPxKey.Esc, "OnEscape");
  this.AddKeyDownHandler(ASPxKey.PageUp, "OnPageUp");
  this.AddKeyDownHandler(ASPxKey.PageDown, "OnPageDown");
  this.AddKeyDownHandler(ASPxKey.End, "OnEndKeyDown");
  this.AddKeyDownHandler(ASPxKey.Home, "OnHomeKeyDown");
  this.AddKeyDownHandler(ASPxKey.Left, "OnArrowLeft");
  this.AddKeyDownHandler(ASPxKey.Right, "OnArrowRight");
  this.AddKeyDownHandler(ASPxKey.Up, "OnArrowUp");
  this.AddKeyDownHandler(ASPxKey.Down, "OnArrowDown");
 },
 OnArrowUp: function(evt) {
  if (this.IsFastNavigationActive()) 
   this.GetFastNavigation().OnArrowUp(evt);
  else if (!this.readOnly) {
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate))
    newDate = ASPxClientCalendar.GetPrevWeekDate(this.lastSelectedDate);
   this.CorrectVisibleMonth(newDate, false);
   this.DoKeyboardSelection(newDate, evt.shiftKey);
  }
  return true;
 },
 OnArrowDown: function(evt) {  
  if (this.IsFastNavigationActive()) 
   this.GetFastNavigation().OnArrowDown(evt);
  else if (!this.readOnly) {
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate))  
    newDate = ASPxClientCalendar.GetNextWeekDate(this.lastSelectedDate);
   this.CorrectVisibleMonth(newDate, true);
   this.DoKeyboardSelection(newDate, evt.shiftKey);
  }
  return true;
 },
 OnArrowLeft: function(evt) { 
  if (this.IsFastNavigationActive()) 
   this.GetFastNavigation().OnArrowLeft(evt);
  else if (!this.readOnly) {  
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate)) 
    newDate = ASPxClientCalendar.GetTomorrowDate(this.lastSelectedDate);
   this.CorrectVisibleMonth(newDate, false);
   this.DoKeyboardSelection(newDate, evt.shiftKey);
  }
  return true;
 },
 OnArrowRight: function(evt) {
  if (this.IsFastNavigationActive()) 
   this.GetFastNavigation().OnArrowRight(evt);
  else if (!this.readOnly) {  
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate))
    newDate = ASPxClientCalendar.GetYesterDate(this.lastSelectedDate);
   this.CorrectVisibleMonth(newDate, true);
   this.DoKeyboardSelection(newDate, evt.shiftKey);
  }
  return true;
 },
 OnCallback: function(result){
  _aspxSetInnerHtml(this.GetMainElement().parentNode, result);
 },
 OnPageUp: function(evt) {
  if (this.IsFastNavigationActive()) 
   this.GetFastNavigation().OnPageUp(evt);
  else if (!this.readOnly) {
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate)) {
    if (evt.ctrlKey)
     newDate = ASPxClientCalendar.GetPrevYearDate(this.lastSelectedDate);
    else
     newDate = ASPxClientCalendar.GetPrevMonthDate(this.lastSelectedDate);   
   }
   this.CorrectVisibleMonth(newDate, false);  
   this.DoKeyboardSelection(newDate);
  }
  return true; 
 },
 OnPageDown: function(evt) {
  if (this.IsFastNavigationActive()) 
   this.GetFastNavigation().OnPageDown(evt);
  else if (!this.readOnly) {
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate)) {
    if (evt.ctrlKey)
     newDate = ASPxClientCalendar.GetNextYearDate(this.lastSelectedDate);
    else
     newDate = ASPxClientCalendar.GetNextMonthDate(this.lastSelectedDate);
   }
   this.CorrectVisibleMonth(newDate, true);
   this.DoKeyboardSelection(newDate);
  }
  return true;
 },
 OnEndKeyDown: function(evt) {
  if (!this.readOnly && !this.IsFastNavigationActive()) { 
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate))   
    newDate = ASPxClientCalendar.CloneDate(this.lastSelectedDate);
   newDate = ASPxClientCalendar.GetLastDayInMonthDate(newDate);
   this.CorrectVisibleMonth(newDate, false);
   this.DoKeyboardSelection(newDate, evt.shiftKey);
  }
  return true;
 },
 OnHomeKeyDown: function(evt) {
  if (!this.readOnly && !this.IsFastNavigationActive()) {
   var newDate = this.GetNearestDayForToday();
   if (_aspxIsExists(this.lastSelectedDate))   
    newDate = ASPxClientCalendar.CloneDate(this.lastSelectedDate);
   newDate = ASPxClientCalendar.GetFirstDayInMonthDate(newDate);   
   this.CorrectVisibleMonth(newDate, false);
   this.DoKeyboardSelection(newDate, evt.shiftKey);
  }
  return true; 
 },
 OnEnter: function() {
  if (this.IsFastNavigationActive())
   this.GetFastNavigation().OnEnter();
  return true;
 },
 OnEscape: function() {
  if (this.IsFastNavigationActive())
   this.GetFastNavigation().OnEscape();
  return true;
 },
 OnShiftMonth: function(offset) {
  if(offset) {
   var date = ASPxClientCalendar.AddMonths(this.visibleDate, offset);     
   this.OnVisibleMonthChanged(date);
  }
 },
 OnDayMouseDown: function(date, shift, ctrl, byWeeks) {
  this.isMouseDown = true;
  this.selectionByWeeks = byWeeks;
  this.selectionTransaction.Start();
  if(this.enableMulti) {
   if(ctrl) {
    this.selectionCtrl = true;
    this.selectionTransaction.CopyFromBackup();
   } else
    this.selectionCtrl = false;
   if(shift && _aspxIsExists(this.selectionPrevStartDate)) {
    this.selectionStartDate = this.selectionPrevStartDate;         
    this.selectionTransaction.selection.AddRange(this.selectionStartDate, date);
    if(byWeeks)
     this.selectionTransaction.selection.AddWeek(date);
   } else {
    this.selectionStartDate = date;
    this.selectionPrevStartDate = date;
    if(byWeeks)
     this.selectionTransaction.selection.AddWeek(date);
    else
     this.selectionTransaction.selection.Add(date);
   }
  } else
   this.selectionTransaction.selection.Add(date);
  this.ApplySelectionByDiff(this.selectionTransaction.selection, false);
 },
 OnDayMouseOver: function(date) {
  if(this.enableMulti) {
   if(this.selectionCtrl)
    this.selectionTransaction.CopyFromBackup();
   else
    this.selectionTransaction.selection.Clear();
   this.selectionTransaction.selection.AddRange(this.selectionStartDate, date);
   if(this.selectionByWeeks) {
    this.selectionTransaction.selection.AddWeek(date);
    this.selectionTransaction.selection.AddWeek(this.selectionStartDate);
   }
  } else {
   this.selectionTransaction.selection.Clear();
   this.selectionTransaction.selection.Add(date);
  }
  this.ApplySelectionByDiff(this.selectionTransaction.selection, false);
 },
 OnDayMouseUp: function(date) {
  if (!__aspxIE && this.isMouseDown)
   this.OnMainElementClick();
  this.isMouseDown = false;
  if(this.enableMulti && this.selectionCtrl && this.selectionTransaction.backup.Contains(date) &&
   ASPxClientCalendar.AreDatesEqual(date, this.selectionStartDate)) {
   if(this.selectionByWeeks)
    this.selectionTransaction.selection.RemoveWeek(date);
   else
    this.selectionTransaction.selection.Remove(date);
  }
  this.lastSelectedDate = ASPxClientCalendar.CloneDate(date);
  this.OnSelectionChanging(); 
 },
 OnTodayClick: function() {
  var now = new Date(); 
  var date = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  if(this.IsDateInRange(date)) {
   this.selectionTransaction.Start();
   this.selectionTransaction.selection.Add(date);
   this.OnSelectionChanging();
   if(!ASPxClientCalendar.AreDatesOfSameMonth(date, this.visibleDate))
    this.OnVisibleMonthChanged(date);  
  }
 },
 OnClearClick: function() {
  this.selectionTransaction.Start();
  this.OnSelectionChanging();
  this.selectionStartDate = null;
  this.selectionPrevStartDate = null;    
  this.lastSelectedDate = null;
 },
 OnSelectMonth: function(row, column) {  
  var txn = this.selectionTransaction;
  txn.Start();
  var date = ASPxClientCalendar.CloneDate(this.GetView(row, column).visibleDate);
  date.setDate(1);
  do {  
   if(this.IsDateInRange(date))
    txn.selection.Add(date);
   date = ASPxClientCalendar.AddDays(date, 1);
  } while(date.getDate() > 1);
  this.OnSelectionChanging();
 },
 OnTitleClick: function(row, column) {
  this.fastNavigation.activeView = this.GetView(row, column);
  this.fastNavigation.Prepare();
  this.fastNavigation.Show();
 },
 OnMainElementClick: function() {
  this.MainElementClick.FireEvent(this);
 },
 OnSelectionChanging: function() {
  if(!this.SelectionChanging.IsEmpty()){
   var args = new ASPxClientCalendarSelectionEventArgs(false, this.selectionTransaction.selection);
   this.SelectionChanging.FireEvent(this, args);  
  }
  var changed = this.selectionTransaction.IsChanged();
  this.selectionTransaction.Commit();
  if(changed)
   this.OnValueChanged();  
 },
 OnVisibleMonthChanged: function(date) {
  var offsetInternal = ASPxClientCalendar.GetOffsetInMonths(this.visibleDate, date);
  this.SetVisibleDate(date);
  var processOnServer = this.RaiseVisibleMonthChanged(offsetInternal);
  if(processOnServer)
   this.SendPostBackInternal("");  
 },
 OnSelectionCancelled: function() {
  this.isMouseDown = false;  
  this.selectionTransaction.Rollback();
 },
 RaiseValueChangedEvent: function() {
  var processOnServer = ASPxClientEdit.prototype.RaiseValueChangedEvent.call(this);
  processOnServer = this.RaiseSelectionChanged(processOnServer);
  return processOnServer;
 },
 SetVisibleDate: function(date) {
  var old = this.visibleDate;
  this.visibleDate = date;
  this.SaveClientState();
  if(!ASPxClientCalendar.AreDatesOfSameMonth(date, old)){
   this.Update(); 
  }
 },
 SetSelectedDate: function(date) {
  if(this.IsDateInRange(date)) {   
   var selection = new ASPxClientCalendarSelection();
   if(date != null) {
    selection.Add(date);
    this.lastSelectedDate = ASPxClientCalendar.CloneDate(date);
   }
   this.ApplySelectionByDiff(selection, true);
  }
 },
 CorrectVisibleMonth: function(newDate, isForwardDirection) {
  var offset = ASPxClientCalendar.GetOffsetInMonths(this.visibleDate, newDate);
  if (this.IsMultiView() && offset != 0) {
   var view = isForwardDirection ? this.GetView(this.rows - 1, this.columns - 1) : 
            this.GetView(0, 0);
   offset = this.IsDateVisible(newDate) ? 0 :
       ASPxClientCalendar.GetOffsetInMonths(view.visibleDate, newDate);
  }
  if (!this.IsDateInRange(newDate))
   offset = 0;
  if (offset != 0)
   this.OnShiftMonth(offset);
 },
 DoKeyboardSelection: function(date, shift) {
  if (this.IsDateInRange(date)) {
   this.isDateChangingByKeyboard = true;
   this.selectionTransaction.Start();
   if(this.enableMulti && shift && _aspxIsExists(this.selectionStartDate))
    this.selectionTransaction.selection.AddRange(this.selectionStartDate, date);
   else {
    this.selectionTransaction.selection.Add(date);
    this.selectionStartDate = date;
   }
   this.lastSelectedDate = ASPxClientCalendar.CloneDate(date);
   this.OnSelectionChanging();
   this.isDateChangingByKeyboard = false;
  }
 },
 GetNearestDayForToday: function() {
  var now = new Date();
  var ret = new Date(now.getFullYear(), now.getMonth(), now.getDate());
  if (_aspxIsExists(this.minDate) && !this.IsDateInRange(ret))
   ret = ASPxClientCalendar.CloneDate(this.minDate);
  return ret;
 },
 UseDelayedSpecialFocus: function() { 
  return true;
 },
 GetDelayedSpecialFocusTriggers: function() {
  var list = ASPxClientEdit.prototype.GetDelayedSpecialFocusTriggers.call(this);
  if(this.enableFast)
   list.push(this.GetFastNavigation().GetPopup().GetWindowElement(-1));
  return list;
 },
 GetSelectedDate: function() {
  return this.GetValue();
 },
 GetVisibleDate: function() {
  return this.visibleDate;
 },
 SelectDate: function(date) {
  if(_aspxIsExists(date)) {
   this.selection.Add(date);
   this.Update();
  }
 },
 SelectRange: function(start, end) {
  if(_aspxIsExists(start) && _aspxIsExists(end)) {
   this.selection.AddRange(start, end);
   this.Update();
  }
 },
 DeselectDate: function(date) {
  if(_aspxIsExists(date)) {
   this.selection.Remove(date);
   this.Update(); 
  }
 },
 DeselectRange: function(start, end) {
  if(_aspxIsExists(start) && _aspxIsExists(end)) {
   this.selection.RemoveRange(start, end);
   this.Update();
  }
 },
 ClearSelection: function() {
  this.selection.Clear();
  this.Update();
 },
 GetSelectedDates: function() {
  return this.selection.GetDates();
 },
 RaiseSelectionChanged: function(processOnServer){
  if(!this.SelectionChanged.IsEmpty()){
   var args = new ASPxClientProcessingModeEventArgs(processOnServer);  
   this.SelectionChanged.FireEvent(this, args);
   processOnServer = args.processOnServer;
  }
  return processOnServer;
 },
 RaiseVisibleMonthChanged: function(offsetInternal){
  var processOnServer = this.autoPostBack;
  if(!this.VisibleMonthChanged.IsEmpty()){
   var args = new ASPxClientProcessingModeEventArgs(processOnServer);
   args.offsetInternal = offsetInternal;
   this.VisibleMonthChanged.FireEvent(this, args);
   processOnServer = args.processOnServer;
  }
  return processOnServer;
 },
 ChangeEnabledAttributes: function(enabled){
  _aspxChangeDocumentEventsMethod(enabled)("mouseup", aspxCalDocMouseUp);
  _aspxChangeEventsMethod(enabled)(this.GetMainElement(), "click", new Function("aspxCalMainElemClick('" + this.name + "');"));
  var inputElement = this.GetInputElement();
  if(_aspxIsExists(inputElement)) 
   this.ChangeSpecialInputEnabledAttributes(inputElement, _aspxChangeEventsMethod(enabled));
  var btnElement = this.GetTodayButton();
  if(_aspxIsExists(btnElement))
   this.ChangeButtonEnabledAttributes(btnElement, _aspxChangeAttributesMethod(enabled));
  btnElement = this.GetClearButton();
  if(_aspxIsExists(btnElement))
   this.ChangeButtonEnabledAttributes(btnElement, _aspxChangeAttributesMethod(enabled));
  for(var key in this.views) {
   var view = this.views[key];
   if(view.constructor != ASPxClientCalendarView) continue;
   view.ChangeEnabledAttributes(enabled);
  }
 },
 ChangeEnabledStateItems: function(enabled){
  aspxGetStateController().SetElementEnabled(this.GetMainElement(), enabled);
  var btnElement = this.GetTodayButton();
  if(_aspxIsExists(btnElement))
   aspxGetStateController().SetElementEnabled(btnElement, enabled);
  btnElement = this.GetClearButton();
  if(_aspxIsExists(btnElement))
   aspxGetStateController().SetElementEnabled(btnElement, enabled);
  for(var key in this.views) {
   var view = this.views[key];
   if(view.constructor != ASPxClientCalendarView) continue;  
   view.ChangeEnabledStateItems(enabled);
  }
  this.UpdateInternal();   
 },
 ChangeButtonEnabledAttributes: function(element, method){
  method(element, "onclick");
  method(element, "ondblclick");
 },
 GetMinDate: function() {
  return this.minDate;
 },
 SetMinDate: function(date) {
  this.minDate = date;
  this.Update();
 },
 GetMaxDate: function() {
  return this.maxDate;
 },
 SetMaxDate: function(date) {
  this.maxDate = date;
  this.Update();
 }
});
ASPxClientCalendar.Cast = ASPxClientControl.Cast;
ASPxClientCalendar.AreDatesEqual = function(date1, date2) {
 if(date1 == date2)  
  return true;
 if(!date1 || !date2)
  return false;
 return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth() && date1.getDate() == date2.getDate();
}
ASPxClientCalendar.AreDatesOfSameMonth = function(date1, date2) {
 if(!date1 || !date2)
  return false;
 return date1.getFullYear() == date2.getFullYear() && date1.getMonth() == date2.getMonth();
}
ASPxClientCalendar.GetUTCTime = function(date) {
 return Date.UTC(date.getFullYear(), date.getMonth(), date.getDate());
}
ASPxClientCalendar.GetFirstDayOfYear = function(date) {
 return new Date(date.getFullYear(), 0, 1);  
}
ASPxClientCalendar.GetDayOfYear = function(date) {
 var ms = ASPxClientCalendar.GetUTCTime(date) - 
  ASPxClientCalendar.GetUTCTime(ASPxClientCalendar.GetFirstDayOfYear(date));
 return 1 + Math.floor(ms / __aspxCalendarMsPerDay);
}
ASPxClientCalendar.GetISO8601WeekOfYear = function(date) {
 var firstDate = new Date(date.getFullYear(), 0, 1);
 var firstDayOfWeek = firstDate.getDay();
 if(firstDayOfWeek == 0)
  firstDayOfWeek = 7;
 var daysInFirstWeek = 8 - firstDayOfWeek;
 var lastDate = new Date(date.getFullYear(), 11, 31);   
 var lastDayOfWeek = lastDate.getDay();
 if(lastDayOfWeek == 0)
  lastDayOfWeek = 7;
 var daysInLastWeek = 8 - lastDayOfWeek; 
 var fullWeeks = Math.ceil((ASPxClientCalendar.GetDayOfYear(date) - daysInFirstWeek) / 7);
 var result = fullWeeks;   
 if(daysInFirstWeek > 3)
  result++;
 var isThursday = firstDayOfWeek == 4 || lastDayOfWeek == 4;
 if(result > 52 && !isThursday)
  result = 1;
 if(result == 0)
  return ASPxClientCalendar.GetISO8601WeekOfYear(new Date(date.getFullYear() - 1, 11, 31));
 return result;
}
ASPxClientCalendar.GetNextWeekDate = function(date) {
 var ret = new Date(date.getTime()); 
 var newDay = date.getDate() + 7;
 ret.setDate(newDay);
 return ret;
}
ASPxClientCalendar.GetPrevWeekDate = function(date) {
 var ret = new Date(date.getTime());
 var newDay = date.getDate() - 7;
 ret.setDate(newDay);
 return ret;
}
ASPxClientCalendar.GetTomorrowDate = function(date) {
 var ret = new Date(date.getTime());
 ret.setDate(ret.getDate() - 1);
 return ret;
}
ASPxClientCalendar.GetYesterDate = function(date) {
 var ret = new Date(date.getTime());
 ret.setDate(ret.getDate() + 1);
 return ret;
}
ASPxClientCalendar.GetNextMonthDate = function(date) {
 var ret = new Date(date.getTime());
 var maxDateInNextMonth = ASPxClientCalendar.GetDaysInMonth(ret.getMonth() + 1, ret.getFullYear());
 if (ret.getDate() > maxDateInNextMonth)
  ret.setDate(maxDateInNextMonth);
 ret.setMonth(ret.getMonth() + 1);
 return ret;
}
ASPxClientCalendar.GetNextYearDate = function(date) {
 var ret = new Date(date.getTime());
 var maxDateInPrevYearMonth = ASPxClientCalendar.GetDaysInMonth(ret.getMonth(), ret.getFullYear() + 1);
 if (ret.getDate() > maxDateInPrevYearMonth)
  ret.setDate(maxDateInPrevYearMonth);
 ret.setFullYear(ret.getFullYear() + 1);
 return ret;
}
ASPxClientCalendar.GetPrevMonthDate = function(date) {
 var ret = new Date(date.getTime());
 var maxDateInPrevMonth = ASPxClientCalendar.GetDaysInMonth(ret.getMonth() - 1, ret.getFullYear());
 if (ret.getDate() > maxDateInPrevMonth)
  ret.setDate(maxDateInPrevMonth);
 ret.setMonth(ret.getMonth() - 1);
 return ret;
}
ASPxClientCalendar.GetPrevYearDate = function(date) {
 var ret = new Date(date.getTime());
 var maxDateInPrevYearMonth = ASPxClientCalendar.GetDaysInMonth(ret.getMonth(), ret.getFullYear() - 1);
 if (ret.getDate() > maxDateInPrevYearMonth)
  ret.setDate(maxDateInPrevYearMonth);
 ret.setFullYear(ret.getFullYear() - 1);
 return ret;
}
ASPxClientCalendar.GetFirstDayInMonthDate = function(date) {
 var ret = new Date(date.getTime());
 ret.setDate(1);
 return ret;
}
ASPxClientCalendar.GetLastDayInMonthDate = function(date) {
 var ret = new Date(date.getTime());
 var maxDateInYearMonth = ASPxClientCalendar.GetDaysInMonth(ret.getMonth(), ret.getFullYear());
 ret.setDate(maxDateInYearMonth);
 return ret;
}
ASPxClientCalendar.AddDays = function(date, count) {
 var newDate = ASPxClientCalendar.CloneDate(date);
 newDate.setUTCDate(count + newDate.getUTCDate());
 ASPxClientCalendar.FixTimezoneGap(date, newDate);
 return newDate;
}
ASPxClientCalendar.AddMonths = function(date, count) {
 var newDate = ASPxClientCalendar.CloneDate(date);
 newDate.setMonth(count + newDate.getMonth());
 ASPxClientCalendar.FixTimezoneGap(date, newDate);
 if(newDate.getDate() < date.getDate())
  newDate = ASPxClientCalendar.AddDays(newDate, -newDate.getDate()); 
 return newDate;
}
ASPxClientCalendar.CloneDate = function(date) {
 var cloned = new Date();
 cloned.setTime(date.getTime());
 return cloned;
}
ASPxClientCalendar.GetDecadeStartYear = function(year) {
 return 10 * Math.floor(year / 10);
}
ASPxClientCalendar.GetDaysInRange = function(start, end) {
 return 1 + (ASPxClientCalendar.GetUTCTime(end) - ASPxClientCalendar.GetUTCTime(start)) / __aspxCalendarMsPerDay;
};
ASPxClientCalendar.GetDaysInMonth = function(month, year) {
 var d = new Date(year, month + 1, 0);
 return d.getDate();
};
ASPxClientCalendar.GetOffsetInMonths = function(start, end) {
 return end.getMonth() - start.getMonth() + 12 * (end.getFullYear() - start.getFullYear());
};
ASPxClientCalendar.FixTimezoneGap = function(oldDate, newDate) {
 var diff = newDate.getHours() - oldDate.getHours();
 if(diff == 0)
  return;
 var sign = (diff == 1 || diff == -23) ? -1 : 1;
 var trial = new Date(newDate.getTime() + sign * 3600000);
 if(sign > 0 || trial.getDate() == newDate.getDate())
  newDate.setTime(trial.getTime());
};
ASPxClientCalendarSelection = _aspxCreateClass(null, {
 constructor: function() {
  this.dates = { };
  this.count = 0;  
 },
 Assign: function(source) {
  this.Clear();
  for(var key in source.dates) {
   var item = source.dates[key];
   if(item.constructor != Date) continue;
   this.Add(item);
  }
 },
 Clear: function() {
  if(this.count > 0) {
   this.dates = { };
   this.count = 0;
  }
 },
 Equals: function(selection) {
  if(this.count != selection.count)
   return false;
  for(var key in this.dates) {
   if(this.dates[key].constructor != Date) continue;
   if(!selection.ContainsKey(key))
    return false;
  }
  return true;
 },
 Contains: function(date) {
  var key = this.GetKey(date);
  return this.ContainsKey(key);
 },
 ContainsKey: function(key) {
  return _aspxIsExists(this.dates[key]);
 },
 Add: function(date) {
  var key = this.GetKey(date);
  if(!this.ContainsKey(key)) {
   this.dates[key] = ASPxClientCalendar.CloneDate(date);
   this.count++;
  }
 },
 AddArray: function(dates) {
  for(var i = 0; i < dates.length; i++)
   this.Add(dates[i]);
 },
 AddRange: function(start, end)  {
  if(end < start) {
   this.AddRange(end, start);
   return;
  }
  var count = ASPxClientCalendar.GetDaysInRange(start, end);
  var date = ASPxClientCalendar.CloneDate(start);  
  for(var i = 0; i < count; i++) {
   this.Add(date);
   date = ASPxClientCalendar.AddDays(date, 1);
  }
 },
 AddWeek: function(startDate) {
  this.AddRange(startDate, ASPxClientCalendar.AddDays(startDate, 6));
 },
 Remove: function(date) {
  var key = this.GetKey(date);
  if(this.ContainsKey(key)) {
   delete this.dates[key];
   this.count--;
  }
 },
 RemoveArray: function(dates) {
  for(var i = 0; i < dates.length; i++)
   this.Remove(dates[i]);
 },
 RemoveRange: function(start, end) {
  if(end < start) {
   this.RemoveRange(end, start);
   return;
  }
  var count = ASPxClientCalendar.GetDaysInRange(start, end);
  var date = ASPxClientCalendar.CloneDate(start);  
  for(var i = 0; i < count; i++) {
   this.Remove(date);
   date = ASPxClientCalendar.AddDays(date, 1);
  }
 },
 RemoveWeek: function(startDate) {
  this.RemoveRange(startDate, ASPxClientCalendar.AddDays(startDate, 6));
 },
 GetDates: function() {
  var result = [ ];
  for(var key in this.dates) {
   var item = this.dates[key];
   if(item.constructor != Date) continue;
   result.push(ASPxClientCalendar.CloneDate(item));
  }
  return result;  
 },
 GetFirstDate: function() {
  if(this.count == 0)
   return null;
  for(var key in this.dates) {
   var item = this.dates[key];
   if(item.constructor != Date) continue;
   return ASPxClientCalendar.CloneDate(item);
  }
  return null;
 },
 GetKey: function(date) {  
  return _aspxGetInvariantDateString(date);
 }
});
ASPxClientCalendarSelectionTransaction = _aspxCreateClass(null, {
 constructor: function(calendar) {
  this.calendar = calendar;
  this.isActive = false;
  this.backup = new ASPxClientCalendarSelection();
  this.selection = new ASPxClientCalendarSelection;
 },
 Start: function() {
  if(this.isActive)
   this.Rollback();
  this.backup.Assign(this.calendar.selection);
  this.selection.Clear();
  this.isActive = true;
  __aspxActiveCalendar = this.calendar;
 },
 Commit: function() {  
  this.calendar.ApplySelectionByDiff(this.selection, true);
  this.Reset();
 },
 Rollback: function() {
  this.calendar.ApplySelectionByDiff(this.backup);  
  this.Reset();
 },
 Reset: function() {
  this.backup.Clear();
  this.selection.Clear();
  this.isActive = false;
  __aspxActiveCalendar = null;
 },
 CopyFromBackup: function() {
  this.selection.Assign(this.backup);
 },
 IsChanged: function() {
  return !this.backup.Equals(this.selection);
 }
});
ASPxClientCalendarView = _aspxCreateClass(null, {
 constructor: function(calendar, row, column) {
  this.row = row;
  this.column = column;
  this.calendar = calendar; 
  var temp = column + row;
  this.isLowBoundary = temp == 0;
  this.isHighBoundary = temp == calendar.rows + calendar.columns - 2; 
  this.visibleDate = null;
  this.startDate = null;  
  this.dayFunctions = {};
  this.dayFunctionsWithWeekSelection = {};
 },
 Initialize: function() {
  this.dayCellCache = { };
  this.dayStyleCache = { }; 
  this.UpdateDate();
  this.UpdateSelection(this.calendar.selection.GetDates(), true);  
  var cell = this.GetMonthCell();
  if(_aspxIsExistsElement(cell))
   _aspxPreventElementDragAndSelect(cell, false);
 },
 AttachMouseEvents: function(eventMethod, styleMethod) {
  var index;
  var cell;
  if(this.calendar.showDayHeaders) {
   var headCells = this.GetMonthTable().rows[0].cells; 
   var dayNameIndex = 0;
   if(this.calendar.showWeekNumbers) {
    dayNameIndex++;
    cell = headCells[0];
    if(this.calendar.enableMulti) {
     eventMethod(cell, "click", 
      new Function("aspxCalSelectMonth('" + this.calendar.name + "', " + this.row + ", " + this.column + ")"));     
     styleMethod(cell, "cursor", _aspxGetPointerCursor());
    }
    this.AttachCancelSelect(eventMethod, cell);
   }   
   for(var j = 0; j < 7; j++)
    this.AttachCancelSelect(eventMethod, headCells[dayNameIndex++]);
  }
  for(var i = 0; i < __aspxCalendarWeekCount; i++) {
   if(this.calendar.showWeekNumbers) {
    cell = this.GetWeekNumberCell(i);
    if(this.calendar.enableMulti)
     this.AttachDayMouseEvents(eventMethod, cell, this.GetDayMouseEventFunction(7 * i, true));    
    else
     this.AttachCancelSelect(eventMethod, cell);
   }
   var date;
   for(var j = 0; j < 7; j++) {
    index = i * 7 + j;
    cell = this.GetDayCell(index);
    date = this.GetDateByIndex(index);
    if(!this.calendar.enableMulti && this.IsDateVisible(date) && this.calendar.IsDateInRange(date)) {
     if(!cell.style.cursor || cell.style.cursor == _aspxGetPointerCursor())
      styleMethod(cell, "cursor", _aspxGetPointerCursor());
    }
    this.AttachDayMouseEvents(eventMethod, cell, this.GetDayMouseEventFunction(index, false));    
   }
  }
 },
 AttachDayMouseEvents: function(method, cell, handler) {
  var types = ["down", "up", "over"];
  for(var i = 0; i < types.length; i++)
   method(cell, "mouse" + types[i], handler);
 },
 AttachCancelSelect: function(method, element) {
  method(element, "mouseup", aspxCalCancelSelect);
 },
 GetDayMouseEventFunction: function(index, selectWeeks) {
  var hash = selectWeeks ? this.dayFunctionsWithWeekSelection : this.dayFunctions;
  if(!_aspxIsExists(hash[index]))
   hash[index] = new Function("e", "aspxCalDayMouseEvt('" + this.calendar.name + "', " + this.row + ", " + this.column + ", " + index + ", e, " + selectWeeks + ");");
  return hash[index];
 },
 UpdateDate: function() {
  this.visibleDate = ASPxClientCalendar.AddMonths(this.calendar.visibleDate, 
   this.row * this.calendar.columns + this.column);
  var date = ASPxClientCalendar.CloneDate(this.visibleDate);
  date.setDate(1);
  var offset = date.getDay() - this.calendar.firstDayOfWeek;
  if(offset < 0)
   offset += 7;
  this.startDate = ASPxClientCalendar.AddDays(date, -offset);
 },
 GetDateByIndex: function(index) {
  return ASPxClientCalendar.AddDays(this.startDate, index);
 },
 GetIndexByDate: function(date) {
  return ASPxClientCalendar.GetDaysInRange(this.startDate, date) - 1;
 },
 IsDateOtherMonth: function(date) {
  if(date == null)
   return false;
  return date.getMonth() != this.visibleDate.getMonth() ||
   date.getFullYear() != this.visibleDate.getFullYear();
 },
 GetDayCell: function(index) {
  if(_aspxIsExists(this.dayCellCache[index]))
   return this.dayCellCache[index];
  var mt = this.GetMonthTable();
  var colIndex = index % 7;
  var rowIndex = (index - colIndex) / 7;
  if(this.calendar.showDayHeaders)
   rowIndex++;  
  if(this.calendar.showWeekNumbers)
   colIndex++;
  var cell = mt.rows[rowIndex].cells[colIndex];
  this.dayCellCache[index] = cell;
  return cell;
 },
 GetMonthTable: function() {
  return this.GetCachedElementById("mt");
 }, 
 GetMonthCell: function() {
  return this.GetCachedElementById("mc");
 },
 GetWeekNumberCell: function(index) {
  if(this.calendar.showDayHeaders)
   index++;
  return this.GetMonthTable().rows[index].cells[0];
 },
 GetPrevYearCell: function() {
  return this.GetCachedElementById("PYC");
 },
 GetPrevMonthCell: function() {
  return this.GetCachedElementById("PMC");
 },
 GetTitleCell: function() {
  return this.GetCachedElementById("TC");
 },
 GetTitleElement: function() {
  return this.GetCachedElementById("T");
 },
 GetNextMonthCell: function() {
  return this.GetCachedElementById("NMC");
 },
 GetNextYearCell: function() {
  return this.GetCachedElementById("NYC");
 },
 Update: function() {
  this.dayStyleCache = { };
  this.UpdateDate();  
  this.UpdateDays();
  this.UpdateTitle();  
  this.UpdateSelection(this.calendar.selection.GetDates(), true);
 },
 UpdateDays: function() {  
  var date = ASPxClientCalendar.CloneDate(this.startDate);
  var offset = this.calendar.firstDayOfWeek - 1;
  if(offset < 0)
   offset += 7;    
  var weekNumber = ASPxClientCalendar.GetISO8601WeekOfYear(ASPxClientCalendar.AddDays(date, offset));
  var cell;
  for(var i = 0; i < __aspxCalendarWeekCount; i++) {
   if(this.calendar.showWeekNumbers)    
    this.GetWeekNumberCell(i).innerHTML = (weekNumber < 10 ? "0" : "") + weekNumber.toString();   
   for(var j = 0; j < 7; j++) {    
    cell = this.GetDayCell(i * 7 + j);    
    cell.innerHTML = this.IsDateVisible(date) ? date.getDate() : "&nbsp;";
    this.ApplyDayCellStyle(cell, date);
    date = ASPxClientCalendar.AddDays(date, 1);
   } 
   if(++weekNumber > 52)
    weekNumber = ASPxClientCalendar.GetISO8601WeekOfYear(ASPxClientCalendar.AddDays(date, offset));
  }   
 },
 UpdateTitle: function() {  
  var el = this.GetTitleElement();
  if(!el) return;
  if(!this.titleFormatter) {
   this.titleFormatter = new ASPxDateFormatter();
   this.titleFormatter.SetFormatString(__aspxCultureInfo.yearMonth);
  }
  el.innerHTML = this.titleFormatter.Format(this.visibleDate);
 },
 UpdateSelection: function(dates, showSelection) {  
  var index;  
  var maxIndex = 7 * __aspxCalendarWeekCount - 1;  
  for(var i = 0; i < dates.length; i++) {
   index = this.GetIndexByDate(dates[i]);
   if(index < 0 || index > maxIndex || !this.IsDateVisible(dates[i]))
    continue;
   this.ApplySelectionToCell(index, showSelection);
  }
 },
 ApplySelectionToCell: function(index, showSelection) {
  var cell = this.GetDayCell(index);
  if(showSelection) {
   var info;
   if(!_aspxIsExists(this.dayStyleCache[index])) {
    var backup = new ASPxClientCalendarStyleInfo();
    backup.Import(cell);    
    this.dayStyleCache[index] = backup;
    info = backup.Clone();
   } else
    info = this.dayStyleCache[index].Clone();
   this.calendar.ImportEtalonStyle(info, "DS");
  } else
   info = this.dayStyleCache[index];
  info.Apply(cell);
 }, 
 ApplyDayCellStyle: function(cell, date) {
  cell.style.cursor = "";
  var cal = this.calendar;
  var info = new ASPxClientCalendarStyleInfo();
  var needPointer = false;
  cal.ImportEtalonStyle(info, "D");
  if(this.IsDateVisible(date)) {
   if(cal.IsDateWeekend(date))
    cal.ImportEtalonStyle(info, "DW");    
   if(this.IsDateOtherMonth(date))
    cal.ImportEtalonStyle(info, "DA");    
   if(!cal.IsDateInRange(date))
    cal.ImportEtalonStyle(info, "DO");
   if(ASPxClientCalendar.AreDatesEqual(new Date(), date))
    cal.ImportEtalonStyle(info, "DT");
   if(!cal.clientEnabled)
    cal.ImportEtalonStyle(info, "DD");
   else if(!cal.enableMulti)
    needPointer = true;
  }
  info.Apply(cell);
  if(needPointer)
   _aspxSetPointerCursor(cell);
 },
 GetIDPostfix: function() {
  return "_" + this.row.toString() + "x" + this.column.toString();
 },
 GetCachedElementById: function(postfix) {
  if(this.calendar.IsMultiView())
   postfix += this.GetIDPostfix(); 
  return this.calendar.GetCachedElementById(this.calendar.name + "_" + postfix);
 },
 IsDateVisible: function(date) {
  var result = !this.calendar.IsMultiView() || !this.IsDateOtherMonth(date);
  if(!result) {   
   result = result || this.isLowBoundary && date <= this.visibleDate ||
    this.isHighBoundary && date >= this.visibleDate;
  }  
  return result;
 },
 MakeDisabledStateItems: function() {
  var cells = this.GetAuxCells();
  for(var i = 0; i < cells.length; i++)
   this.AddAuxDisabledStateItem(cells[i], this.GetAuxId(i));
  var element = this.GetTitleCell();
  if(_aspxIsExists(element))
   this.AddHeaderDisabledStateItem(element);
  var element = this.GetTitleElement();
  if(_aspxIsExists(element))
   this.AddHeaderDisabledStateItem(element);
 },
 AddAuxDisabledStateItem: function(element, id){
  var cell = this.calendar.GetEtalonStyleCell("DD");
  element.id = id;
  aspxGetStateController().AddDisabledItem(id, cell.className, cell.style.cssText, null, null, null);
 },
 AddHeaderDisabledStateItem: function(element){
  var cell = this.calendar.GetEtalonStyleCell("DD");
  aspxGetStateController().AddDisabledItem(element.id, cell.className, cell.style.cssText, null, null, null);
 },
 ChangeEnabledAttributes: function(enabled){
  var element = this.GetPrevYearCell();
  if(_aspxIsExists(element))
   this.ChangeButtonEnabledAttributes(element, _aspxChangeAttributesMethod(enabled));
  var element = this.GetPrevMonthCell();
  if(_aspxIsExists(element))
   this.ChangeButtonEnabledAttributes(element, _aspxChangeAttributesMethod(enabled));
  var element = this.GetTitleElement();
  if(_aspxIsExists(element)){
   this.ChangeButtonEnabledAttributes(element, _aspxChangeAttributesMethod(enabled));
   this.ChangeTitleElementEnabledAttributes(element, _aspxChangeStyleAttributesMethod(enabled));
  }
  var element = this.GetNextMonthCell();
  if(_aspxIsExists(element))
   this.ChangeButtonEnabledAttributes(element, _aspxChangeAttributesMethod(enabled));
  var element = this.GetNextYearCell();
  if(_aspxIsExists(element))
   this.ChangeButtonEnabledAttributes(element, _aspxChangeAttributesMethod(enabled));
  if(this.calendar.enabled && !this.calendar.readOnly)
   this.AttachMouseEvents(_aspxChangeEventsMethod(enabled), _aspxInitiallyChangeStyleAttributesMethod(enabled));
 },
 ChangeEnabledStateItems: function(enabled){
  this.SetAuxCellsEnabled(enabled);
  this.SetHeaderCellsEnabled(enabled);
 }, 
 ChangeTitleElementEnabledAttributes: function(element, method){
  method(element, "cursor");
 },
 ChangeButtonEnabledAttributes: function(element, method){
  method(element, "onclick");
  method(element, "ondblclick");
 },
 SetAuxCellsEnabled: function(enabled){
  var cells = this.GetAuxCells();
  for(var i = 0; i < cells.length; i++)
   aspxGetStateController().SetElementEnabled(cells[i], enabled);
 },
 SetHeaderCellsEnabled: function(enabled){
  var element = this.GetPrevYearCell();
  if(_aspxIsExists(element))
   aspxGetStateController().SetElementEnabled(element, enabled);
  var element = this.GetPrevMonthCell();
  if(_aspxIsExists(element))
   aspxGetStateController().SetElementEnabled(element, enabled);
  var element = this.GetTitleCell();
  if(_aspxIsExists(element))
   aspxGetStateController().SetElementEnabled(element, enabled);
  var element = this.GetTitleElement();
  if(_aspxIsExists(element))
   aspxGetStateController().SetElementEnabled(element, enabled);
  var element = this.GetNextMonthCell();
  if(_aspxIsExists(element))
   aspxGetStateController().SetElementEnabled(element, enabled);
  var element = this.GetNextYearCell();
  if(_aspxIsExists(element))
   aspxGetStateController().SetElementEnabled(element, enabled);
 },   
 GetAuxCells: function(){
  if(this.auxCells == null){
   this.auxCells = [];
   var table = this.GetMonthTable();
   for(var i = 0; i < table.rows.length; i++) {
    var row = table.rows[i];
    if(i == 0 && this.calendar.showDayHeaders) {    
     for(var j = 0; j < row.cells.length; j++)
      this.auxCells.push(row.cells[j]);
    }
    if(i > 0 && this.calendar.showWeekNumbers)
     this.auxCells.push(row.cells[0]);
   }
  }
  return this.auxCells;
 },
 GetAuxId: function(index) {
  return this.calendar.name + "_AUX_" + this.row + "_" + this.column + "_" + index;
 }
});
ASPxClientCalendarFastNavigation = _aspxCreateClass(null, {
 constructor: function(calendar) {
  this.calendar = calendar;
  this.activeMonth = -1;
  this.activeYear = -1;
  this.startYear = -1;
  this.activeView = null;
  this.InitializeUI();  
 },
 InitializeUI: function() {
  var item;
  var prefix = this.GetId();
  for(var m = 0; m < 12; m++) {
   item = this.GetMonthItem(m);
   if(!_aspxIsExistsElement(item))
    break;
   item.id = prefix + "_M" + m;
   _aspxAttachEventToElement(item, "click", new Function("aspxCalFNMClick('" + this.calendar.name + "', " + m + ")"));
  }
  for(var i = 0; i < 10; i++) {
   item = this.GetYearItem(i);
   if(!_aspxIsExistsElement(item))
    break;   
   item.id = prefix + "_Y" + i;
   _aspxAttachEventToElement(item, "click", new Function("aspxCalFNYClick('" + this.calendar.name + "', " + i + ")"));
  }
  _aspxAttachEventToElement(this.GetPopup().GetWindowElement(-1), "click", new Function("aspxCalMainElemClick('" + this.calendar.name + "')"));
 },
 Show: function() {
  this.GetPopup().ShowAtElement(this.activeView.GetTitleElement());
 },
 Hide: function() {
  this.GetPopup().Hide();
 },
 SetMonth: function(month) {
  if(month != this.activeMonth) {
   var prevCell = this.GetMonthItem(this.activeMonth);
   var cell = this.GetMonthItem(month);
   if(_aspxIsExistsElement(prevCell))
    this.ApplyItemStyle(prevCell, false, "M");
   this.ApplyItemStyle(cell, true, "M");
   this.activeMonth = month;   
  } 
 },
 ShiftMonth: function(offset) {
  var month = (this.activeMonth + offset) % 12;
  month = (month < 0) ? month + 12 : month;
  this.SetMonth(month);
 },
 SetYear: function(year) {
  var startYear = Math.floor(year / 10) * 10;
  this.SetStartYear(startYear);
  this.SetYearIndex(year - startYear);
 },
 SetYearIndex: function(index) {
  var prevIndex = this.activeYear - this.startYear;
  if(index != prevIndex) {
   var prevCell = this.GetYearItem(prevIndex);
   if(_aspxIsExistsElement(prevCell))
    this.ApplyItemStyle(prevCell, false, "Y");
   var cell = this.GetYearItem(index);
   this.ApplyItemStyle(cell, true, "Y");
   this.activeYear = index + this.startYear;
  } 
 },
 SetStartYear: function(year) {
  if(this.startYear == year) return;
  this.startYear = year;  
  this.PrepareYearList();
 },
 ShiftYear: function(offset) {
  this.SetYear(this.activeYear + offset);
 },
 ShiftStartYear: function(offset) {
  this.SetStartYear(this.startYear + offset);
 },
 ApplyChanges: function() {
  this.GetPopup().Hide();  
  var offset = ASPxClientCalendar.GetOffsetInMonths(this.calendar.visibleDate, new Date(this.activeYear, this.activeMonth, 1));
  offset -= this.activeView.row * this.calendar.columns + this.activeView.column;  
  if(offset != 0) {
   var date = ASPxClientCalendar.AddMonths(this.calendar.visibleDate, offset);
   this.calendar.OnVisibleMonthChanged(date);  
  }
  this.calendar.OnMainElementClick();
 },
 CancelChanges: function() {
  this.GetPopup().Hide();
  this.calendar.OnMainElementClick();
 },
 Prepare: function() {
  var date = this.activeView.visibleDate;
  this.activeYear = date.getFullYear();
  this.activeMonth = date.getMonth();
  this.startYear = ASPxClientCalendar.GetDecadeStartYear(this.activeYear);
  this.PrepareMonthList();
  this.PrepareYearList();
 }, 
 PrepareMonthList: function() {  
  var item;
  for(var month = 0; month < 12; month++) {
   item = this.GetMonthItem(month);
   if(item == null)
    return;
   this.ApplyItemStyle(item, month == this.activeMonth, "M");
  }  
 },
 PrepareYearList: function() {
  var year = this.startYear;
  var item;
  for(var index = 0; index < 10; index++) {
   item = this.GetYearItem(index);
   if(item == null)
    return;
   item.innerHTML = year;
   this.ApplyItemStyle(item, year == this.activeYear, "Y");
   year++;
  }   
 },
 GetMonthItem: function(month) {
  var t = this.GetCachedElementById("m");
  if(!_aspxIsExistsElement(t))
   return null;
  var colIndex = month % 4;
  var rowIndex = (month - colIndex) / 4;
  return t.rows[rowIndex].cells[colIndex];
 },
 GetYearItem: function(index) {
  var t = this.GetCachedElementById("y");
  if(!_aspxIsExistsElement(t) || index < 0 || index > 9)
   return null;
  var colIndex = index % 5;
  var rowIndex = (index - colIndex) / 5;
  if(rowIndex == 0)
   colIndex++;
  return t.rows[rowIndex].cells[colIndex];
 },
 GetPopup: function() {
  return aspxGetControlCollection().Get(this.GetId());
 },
 ApplyItemStyle: function(item, isSelected, type) {
  var info = new ASPxClientCalendarStyleInfo();
  this.calendar.ImportEtalonStyle(info, "FN" + type);
  if(isSelected)
   this.calendar.ImportEtalonStyle(info, "FN" + type + "S");
  info.Apply(item);  
 },
 GetCachedElementById: function(postfix) { 
  return this.calendar.GetCachedElementById(this.GetId() + "_" + postfix);
 },
 GetId: function() {
  return this.calendar.name + "_FNP";
 },
 OnArrowUp: function(evt) {
  if(!evt.shiftKey)
   this.ShiftYear(-5);
  else
   this.ShiftMonth(-4);
 },
 OnArrowDown: function(evt) {  
  if(!evt.shiftKey)
   this.ShiftYear(5);
  else
   this.ShiftMonth(4);
 },
 OnArrowLeft: function(evt) { 
  if(!evt.shiftKey)
   this.ShiftYear(-1);
  else
   this.ShiftMonth(-1);
 },
 OnArrowRight: function(evt) {
  if(!evt.shiftKey)
   this.ShiftYear(1);
  else
   this.ShiftMonth(1);
 },
 OnPageUp: function(evt) {
  this.ShiftYear(-10);
 },
 OnPageDown: function(evt) {
  this.ShiftYear(10);
 },
 OnEnter: function() {
  this.ApplyChanges();
 },
 OnEscape: function() {
  this.CancelChanges();
 },
 OnMonthClick: function(month) {
  this.SetMonth(month);
 },
 OnYearClick: function(index) {
  this.SetYearIndex(index);
 },
 OnYearShuffle: function(offset) {
  this.ShiftStartYear(offset);
 },
 OnOkClick: function() {
  this.ApplyChanges();
 },
 OnCancelClick: function() {
  this.CancelChanges();
 }
});
ASPxClientCalendarStyleInfo = _aspxCreateClass(null, {
 constructor: function() {
  this.className = "";
  this.cssText = "";
 },
 Clone: function() {
  var clone = new ASPxClientCalendarStyleInfo();
  clone.className = this.className;
  clone.cssText = this.cssText;
  return clone;
 },
 Apply: function(element) {
  if(element.className != this.className)
   element.className = this.className;
  if(element._style != this.cssText) {
   element.style.cssText = this.cssText; 
   element._style = this.cssText; 
  } 
 },
 Import: function(element) {
  if(element.className.length > 0) {
   if(this.className.length > 1)
    this.className += " ";
   this.className +=  element.className;
  }  
  var cssText = element.style.cssText;
  if(cssText.length > 0) {
   var pos = cssText.length - 1;
   while(pos > -1 && cssText.charAt(pos) == " ")
    --pos;
   if(cssText.charAt(pos) != ";")
    cssText += ";";
   this.cssText += cssText;
  }
 }  
});
ASPxClientCalendarSelectionEventArgs = _aspxCreateClass(ASPxClientProcessingModeEventArgs, {
 constructor: function(processOnServer, selection){
  this.constructor.prototype.constructor.call(this, processOnServer);
  this.selection = selection;
 }
});
function aspxCalShiftMonth(name, monthOffset) {
 if(monthOffset != 0) {
  var edit = aspxGetControlCollection().Get(name);
  if(edit != null) {
   edit.OnShiftMonth(monthOffset);  
  }
 }
}
function aspxCalDayMouseEvt(name, row, column, index, e, byWeeks) {
 var cal = aspxGetControlCollection().Get(name);
 if(cal != null) {
  var view = cal.GetView(row, column);
  var date = view.GetDateByIndex(index);
  if(byWeeks)
   date = ASPxClientCalendar.AddDays(date, cal.firstDayOfWeek - date.getDay());
  var allowed = cal.IsDateInRange(date) && (view.IsDateVisible(date) || byWeeks);
  switch(e.type) {
   case "mousedown":
    if(allowed && _aspxGetIsLeftButtonPressed(e))
     cal.OnDayMouseDown(date, e.shiftKey, e.ctrlKey, byWeeks);
    break;
   case "mouseover":
    if(allowed) {
     if(cal.forceMouseDown)
      cal.OnDayMouseDown(date, false, false, false);
     else if(cal.isMouseDown)
      cal.OnDayMouseOver(date);
    }
    break;
   case "mouseup":
    if(cal.isMouseDown) {
     if(allowed)
      cal.OnDayMouseUp(date);
     else
      cal.OnSelectionCancelled();
    }
    break;
  }
 }
}
function aspxCalTodayClick(name) { 
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.OnTodayClick();
}
function aspxCalClearClick(name) { 
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.OnClearClick();  
}
function aspxCalSelectMonth(name, row, column) {
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.OnSelectMonth(row, column);
}
function aspxCalTitleClick(name, row, column) {
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.OnTitleClick(row, column);
}
function aspxCalFNMClick(name, month) {
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.fastNavigation.OnMonthClick(month);
}
function aspxCalFNYClick(name, index) {
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.fastNavigation.OnYearClick(index);
}
function aspxCalFNYShuffle(name, offset) {
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.fastNavigation.OnYearShuffle(offset);
}
function aspxCalFNBClick(name, action) {
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null) {
  switch(action) {
   case "ok":
    edit.fastNavigation.OnOkClick(); 
    break;
   case "cancel":
    edit.fastNavigation.OnCancelClick();
    break;
  }    
 }
}
function aspxCalMainElemClick(name) {
 var edit = aspxGetControlCollection().Get(name);
 if(edit != null)
  edit.OnMainElementClick();
}
function aspxCalDocMouseUp(evt) {
 var target = _aspxGetEventSource(evt);
 if(__aspxActiveCalendar != null && _aspxIsExistsElement(target)) {
  __aspxActiveCalendar.forceMouseDown = false;
  if(__aspxActiveCalendar.isMouseDown) {   
   for(var key in __aspxActiveCalendar.views) {   
    var view = __aspxActiveCalendar.views[key];
    if(view.constructor != ASPxClientCalendarView) continue;
    var monthCell = view.GetMonthCell();
    var parent = target.parentNode;
    while(_aspxIsExistsElement(parent)) {
     if(parent == monthCell)
      return;
     parent = parent.parentNode;
    }
   }
   __aspxActiveCalendar.OnSelectionCancelled();   
  }
  __aspxActiveCalendar = null;
 }
}
function aspxCalCancelSelect() {
 if(__aspxActiveCalendar != null) {
  __aspxActiveCalendar.forceMouseDown = false;
  __aspxActiveCalendar.OnSelectionCancelled();  
 }
}
